diff --git a/index.html b/index.html
index 4b58b9b..613ef61 100644
--- a/index.html
+++ b/index.html
@@ -12,6 +12,10 @@
.narrative {
max-width: 40rem;
}
+ /* Handle markdown output */
+ #recommendations li p {
+ margin-bottom: 0;
+ }
@@ -39,16 +43,28 @@
-
Report Gen
+
Automated letter generation
+
+
+
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.
+
The solution consists of three main components:
+
+ Data Layer : Structured Data, Knowledge Repository, Document Templates, Research Artifacts, etc.
+ Processing Layer : Generative AI & business rules
+ Visualization Layer : inal document in desired format
+
+
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.
+
-
+
+
VAPT test
Generate a VAPT test report.
-
Generate
-
Download
+
Generate
+
Download
@@ -68,7 +84,6 @@
Custom Report
-
@@ -76,18 +91,6 @@
Custom Report
-
-
diff --git a/script.js b/script.js
index bfb3c6c..f96d4d5 100644
--- a/script.js
+++ b/script.js
@@ -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 });
@@ -161,7 +167,16 @@ const vaptReport = ({ Summary, ...data }) => html`
Recommended Actions
-
+
+
+
+
`;
@@ -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', '
');
+ oldOutput.insertAdjacentHTML("afterend", '
');
oldOutput.remove();
const summarySheet = workbook.SheetNames.includes("Summary")
@@ -208,14 +223,20 @@ 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"), {
@@ -223,16 +244,59 @@ function renderWorkbook(workbook) {
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 `
\n${headers}\n${values}\n `;
+ })
+ .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`
`, 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`
${message}
`, document.querySelector("#output"));
}