Skip to content

Commit

Permalink
ENH: Add intro and LLM summary
Browse files Browse the repository at this point in the history
  • Loading branch information
sanand0 committed Oct 15, 2024
1 parent 17e41b2 commit 6631f08
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 23 deletions.
37 changes: 20 additions & 17 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
.narrative {
max-width: 40rem;
}
/* Handle markdown output */
#recommendations li p {
margin-bottom: 0;
}
</style>
</head>

Expand Down Expand Up @@ -39,16 +43,28 @@
</nav>

<div class="container">
<h1 class="display-1 my-4 text-center">Report Gen</h1>
<h1 class="display-1 my-4 text-center">Automated letter generation</h1>

<div class="narrative mx-auto">
<p>Automated letter generation is increasingly important in various industries, particularly in compliance and regulatory environments. Organizations often need to generate standardized letters for enforcement actions, notifications, or compliance communications.</p>
<p>The solution consists of three main components:</p>
<ul>
<li><strong>Data Layer</strong>: Structured Data, Knowledge Repository, Document Templates, Research Artifacts, etc.</li>
<li><strong>Processing Layer</strong>: Generative AI & business rules</li>
<li><strong>Visualization Layer</strong> : inal document in desired format</li>
</ul>
<p>This tool aims to streamline the creation of compliance-related documents while ensuring accuracy and adherence to regulations. The use of advanced technology enhances efficiency and reduces manual effort in document preparation.</p>
</div>

<div id="demos" class="row row-cols-1 row-cols-sm-2 row-cols-lg-3 row-cols-xl-4 my-5">

<div id="demos" class="row row-cols-1 row-cols-sm-2 row-cols-lg-3 my-5">
<div class="col py-3">
<div class="demo card h-100 text-decoration-none">
<div class="card-body">
<h5 class="card-title">VAPT test</h5>
<p class="card-text">Generate a VAPT test report.</p>
<button class="btn btn-primary generate" data-src="vapt.xlsx"><i class="bi bi-gear"></i> Generate</button>
<a class="btn btn-secondary" href="vapt.xlsx"><i class="bi bi-download"></i> Download</a>
<button class="btn btn-primary mb-3 generate" data-src="vapt.xlsx"><i class="bi bi-gear"></i> Generate</button>
<a class="btn btn-secondary mb-3" href="vapt.xlsx"><i class="bi bi-download"></i> Download</a>
</div>
</div>
</div>
Expand All @@ -68,26 +84,13 @@ <h5 class="card-title">Custom Report</h5>
<div id="login" class="my-5"></div>

<div id="output"></div>

</div>


<footer class="my-5 vh-100 d-flex align-items-center justify-content-center">
<h1 class="display-4">Designed by <a href="https://gramener.com/" class="text-reset link-offset-3 link-underline link-underline-opacity-25">Gramener</a></h1>
</footer>

<div id="item-modal" class="modal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body"></div>
</div>
</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" type="module"></script>
<script src="https://cdn.jsdelivr.net/npm/@gramex/[email protected]/dist/dark-theme.js" type="module"></script>
<script src="script.js" type="module"></script>
Expand Down
76 changes: 70 additions & 6 deletions script.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { html, render } from "https://cdn.jsdelivr.net/npm/lit-html@3/+esm";
import { unsafeHTML } from "https://cdn.jsdelivr.net/npm/lit-html@3/directives/unsafe-html.js";
import { Marked } from "https://cdn.jsdelivr.net/npm/marked@13/+esm";
import { read, utils } from "https://cdn.jsdelivr.net/npm/xlsx/+esm";
import {
Chart,
Colors,
BarController,
BarElement,
CategoryScale,
LinearScale,
Tooltip,
} from "https://cdn.jsdelivr.net/npm/chart.js@4/+esm";
import { asyncSSE } from "https://cdn.jsdelivr.net/npm/asyncsse@1";

let llmContent;
const marked = new Marked();
const { token } = await fetch("https://llmfoundry.straive.com/token", { credentials: "include" }).then((r) => r.json());
if (!token) {
const url = "https://llmfoundry.straive.com/login?" + new URLSearchParams({ next: location.href });
Expand Down Expand Up @@ -161,7 +167,16 @@ const vaptReport = ({ Summary, ...data }) => html`
<canvas id="session-usage"></canvas>
<h1 class="display-4 my-4 border-bottom border-dark pb-2">Recommended Actions</h1>
<div id="recommendations"></div>
<form id="recommendations-form">
<div class="mb-3">
<label for="recommendations-prompt" class="form-label">Re-generate AI summary</label>
<input type="text" class="form-control" id="recommendations-prompt" placeholder="Enter a prompt to generate recommendations" value="Using provided data, generate recommendations to improve VAPT score. Group into logical sections. Provide specific reasons for recommendations from data.">
</div>
<button type="submit" class="btn btn-primary">Generate</button>
</form>
<div id="recommendations" class="mt-4"></div>
</div>
`;
Expand Down Expand Up @@ -192,9 +207,9 @@ document.querySelector("#file-upload").addEventListener("change", (event) => {
}
});

function renderWorkbook(workbook) {
async function renderWorkbook(workbook) {
const oldOutput = document.querySelector("#output");
oldOutput.insertAdjacentHTML('afterend', '<div id="output"></div>');
oldOutput.insertAdjacentHTML("afterend", '<div id="output"></div>');
oldOutput.remove();

const summarySheet = workbook.SheetNames.includes("Summary")
Expand All @@ -208,31 +223,80 @@ function renderWorkbook(workbook) {

try {
render(vaptReport({ Summary, ...data }), document.querySelector("#output"));
Chart.register(BarController, BarElement, CategoryScale, LinearScale, Tooltip);
Chart.register(Colors, BarController, BarElement, CategoryScale, LinearScale, Tooltip);

new Chart(document.getElementById("bandwidth-usage"), {
type: "bar",
options: { animation: true, plugins: { tooltip: { enabled: true } } },
data: {
labels: data.Bandwidth.map((row) => row.Time),
datasets: [{ label: "Bandwidth Utilization", data: data.Bandwidth.map((row) => row["Bandwidth Utilization"]) }],
datasets: [
{
label: "Bandwidth Utilization",
backgroundColor: "rgba(25, 135, 84, 0.8)",
data: data.Bandwidth.map((row) => row["Bandwidth Utilization"]),
},
],
},
});
new Chart(document.getElementById("session-usage"), {
type: "bar",
options: { animation: true, plugins: { tooltip: { enabled: true } } },
data: {
labels: data.Sessions.map((row) => row.Time),
datasets: [{ label: "Number of Sessions", data: data.Sessions.map((row) => row["Sessions"]) }],
datasets: [
{
label: "Number of Sessions",
backgroundColor: "rgba(25, 135, 84, 0.8)",
data: data.Sessions.map((row) => row["Sessions"]),
},
],
},
});

llmContent = Object.entries(data)
.map(([name, rows]) => {
if (rows.length === 0) return "";
const headers = Object.keys(rows[0]).join("\t");
const values = rows.map((row) => Object.values(row).join("\t")).join("\n");
return `<DATA name="${name}">\n${headers}\n${values}\n</DATA>`;
})
.join("\n\n");

document.querySelector("#recommendations-form").dispatchEvent(new Event("submit", { bubbles: true }));
} catch (error) {
return notify(`Error rendering report: ${error.message}`);
}
}

document.querySelector("body").addEventListener("submit", async (event) => {
if (event.target.id !== "recommendations-form") return;

event.preventDefault();
render(html`<div class="spinner-border"></div>`, document.querySelector("#recommendations"));
let content = "";
for await (const event of asyncSSE("https://llmfoundry.straive.com/openai/v1/chat/completions", {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}:reportgen` },
stream: true,
stream_options: { include_usage: true },
body: JSON.stringify({
model: "gpt-4o-mini",
stream: true,
messages: [
{ role: "system", content: document.querySelector("#recommendations-prompt").value },
{ role: "user", content: llmContent },
],
}),
})) {
if (event.data == "[DONE]") break;
const message = JSON.parse(event.data);
const content_delta = message.choices?.[0]?.delta?.content;
if (content_delta) content += content_delta;
render(unsafeHTML(marked.parse(content)), document.querySelector("#recommendations"));
}
});

function notify(message) {
render(html`<div class="alert alert-danger">${message}</div>`, document.querySelector("#output"));
}

0 comments on commit 6631f08

Please sign in to comment.