PRMSChallenge / web /analyzer.html
Vineela Gampa
fixing the code yet another time
0946fb8 unverified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document Analyzer | CTRL + ALT + HEAL</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root {
--tropical-indigo: rgb(120, 187, 242);
--wisteria: rgb(197, 217, 251);
--latte-cream: #ffffff;
}
body {
font-family: "Rubik", sans-serif;
background-color: var(--latte-cream);
color: #333;
}
nav a {
color: #333;
transition: color 0.3s ease;
}
nav a:hover {
color: var(--tropical-indigo);
}
.rec-card {
background-color: var(--latte-cream);
border: 1px solid var(--wisteria);
border-radius: 1rem;
padding: 1.25rem;
margin-bottom: 1.5rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
}
.rec-card:hover {
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}
.rec-title {
font-size: 1.125rem;
font-weight: 700;
color: var(--tropical-indigo);
margin-bottom: 0.5rem;
}
.rec-badge {
font-size: 0.75rem;
font-weight: 600;
padding: 0.25rem 0.75rem;
border-radius: 9999px;
}
.badge-high {
background-color: #fee2e2;
color: #b91c1c;
}
.badge-medium {
background-color: #fef3c7;
color: #92400e;
}
.badge-low {
background-color: #d1fae5;
color: #065f46;
}
.rec-content {
list-style-type: disc;
margin-left: 1.25rem;
font-size: 0.875rem;
color: #374151;
}
.rec-link {
color: var(--tropical-indigo);
text-decoration: underline;
}
.rec-link:hover {
color: #4b7bbd;
}
.btn-primary {
background-color: var(--tropical-indigo);
color: white;
transition: background-color 0.3s ease;
}
.btn-primary:hover {
background-color: #5ba5dd;
}
input,
textarea {
border: 1px solid var(--wisteria);
background-color: #fafbfc;
}
input:focus,
textarea:focus {
outline: none;
border-color: var(--tropical-indigo);
box-shadow: 0 0 0 2px rgba(120, 187, 242, 0.3);
}
h2,
h3 {
color: var(--tropical-indigo);
}
#chat-output {
background-color: #f7f9fc;
border: 1px solid var(--wisteria);
}
</style>
</head>
<body class="bg-[var(--latte-cream)] font-sans text-gray-800 min-h-screen">
<!-- NAVBAR -->
<nav
class="fixed top-0 left-0 w-full z-50 backdrop-blur-md bg-white/20 border-b border-white/30 shadow-md"
>
<div class="flex justify-between items-center w-full px-6 py-4">
<!-- Logo -->
<a
href="index.html"
class="text-2xl font-bold text-black hover:text-[var(--tropical-indigo)] transition"
>
CTRL + ALT + HEAL
</a>
<ul class="hidden md:flex space-x-6 font-medium text-gray-800">
<li><a href="index.html" class="nav-link">Home</a></li>
<li><a href="analyzer.html" class="nav-link">Analyzer</a></li>
<li><a href="past_data.html" class="nav-link">Past Reports</a></li>
<li><a href="profile.html" class="nav-link">Profile</a></li>
<li id="authNavItem"><a href="login.html" class="nav-link">Login</a></li>
</ul>
<!-- Hamburger Menu -->
<button
id="hamburger"
class="md:hidden text-[var(--latte-cream)] text-2xl"
>
</button>
</div>
<!-- Mobile Menu -->
<ul
id="mobile-menu"
class="hidden flex-col space-y-4 bg-white/30 backdrop-blur-lg border border-white/20 rounded-xl shadow-lg mt-2 p-4 mx-6 md:hidden"
>
<li>
<a
href="index.html"
class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
>Home</a
>
</li>
<li>
<a
href="analyzer.html"
class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
>Analyzer</a
>
</li>
<li>
<a
href="profile.html"
class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
>Profile</a
>
</li>
<li>
<a
href="login.html"
class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
>Login</a
>
</li>
<li>
<a
href="about.html"
class="block text-gray-800 hover:text-[var(--tropical-indigo)]"
>About</a
>
</li>
>
</li>
</ul>
</nav>
<!--Shared helpers (API base + query params) -->
<script src="script.js"></script>
<script>
const hamburger = document.getElementById("hamburger");
const mobileMenu = document.getElementById("mobile-menu");
hamburger.addEventListener("click", () => {
mobileMenu.classList.toggle("hidden");
});
// Underline the active page only
const currentPath = window.location.pathname.split("/").pop();
document.querySelectorAll(".nav-link").forEach((link) => {
if (link.getAttribute("href") === currentPath) {
link.classList.add("active-page"); // we'll style this in CSS
}
});
document.querySelectorAll("#mobile-menu a").forEach((link) => {
if (link.getAttribute("href") === currentPath) {
link.classList.add("active-page");
}
});
</script>
<!-- CHANGE MARKER TO USE THIS -->
<!-- secound change marker-->
<main class="max-w-5xl mx-auto px-4 mb-16 pt-24">
<!-- Upload Section -->
<div
class="bg-[var(--latte-cream)] border border-[var(--wisteria)] rounded-lg p-6 mb-8"
>
<h2 class="text-xl font-semibold mb-4">
Upload & Analyze Your Medical PDF or Image
</h2>
<input
type="file"
id="pdf-upload"
accept=".pdf, image/*"
class="w-full mb-4 rounded px-3 py-2"
/>
<button id="analyze-btn" class="btn-primary px-4 py-2 rounded">
Analyze with AI
</button>
<p id="loading" class="text-gray-600 mt-2">No file uploaded yet.</p>
<p id="auth-status" class="text-sm text-gray-500 mt-1">
Sign in to save and view past analyses.
</p>
</div>
<!-- Extracted Text -->
<div
class="bg-[var(--latte-cream)] border border-[var(--wisteria)] rounded-lg p-6 mb-8"
>
<h3 class="text-lg font-semibold mb-3">Extracted Text</h3>
<div
id="text-output"
class="whitespace-pre-wrap h-60 overflow-auto bg-[#FAFBFC] text-sm border border-[var(--wisteria)] rounded p-4"
>
OCR results will appear here.
</div>
</div>
<!-- AI Findings -->
<div
class="bg-[var(--latte-cream)] border border-[var(--wisteria)] rounded-lg p-6 mb-8"
>
<h3 class="text-lg font-semibold mb-3">AI Findings</h3>
<div
id="recommendations-output"
class="bg-[#F9FAFB] text-sm border border-[var(--wisteria)] rounded p-4 space-y-4"
>
Findings and Recommendations will appear here.
</div>
</div>
<!-- Chatbot -->
<div
class="bg-[var(--latte-cream)] border border-[var(--wisteria)] rounded-lg p-6 mb-8"
>
<h3 class="text-lg font-semibold mb-3">Ask Chatbot</h3>
<div
id="chat-output"
class="space-y-2 h-48 overflow-auto text-sm rounded p-4"
>
<p><strong>Chatbot:</strong> Ask me something about your report</p>
</div>
<div class="flex mt-4 gap-2">
<input
type="text"
id="user-question"
placeholder="Ask a question..."
class="flex-1 rounded px-3 py-2 focus:outline-none"
/>
<button id="ask-btn" class="btn-primary px-4 py-2 rounded">
Ask
</button>
</div>
</div>
</main>
<!-- Firebase -->
<script type="module">
import {
getFirestore,
collection,
doc,
addDoc,
serverTimestamp,
} from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
import {
getAuth,
onAuthStateChanged,
signOut,
} from "https://www.gstatic.com/firebasejs/9.22.0/firebase-auth.js";
const firebaseConfig = {
apiKey: "AIzaSyAPhM_Ee7cLzyKHs5zyFy8g5ZOk9-pubRI",
authDomain: "login-tutorial-7a9e1.firebaseapp.com",
projectId: "login-tutorial-7a9e1",
storageBucket: "login-tutorial-7a9e1.firebasestorage.app",
messagingSenderId: "491093197824",
appId: "1:491093197824:web:9f866...",
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
window.firebaseAuth = auth;
window.onAuthStateChanged = onAuthStateChanged;
window.firestoreDb = db;
window.firestoreHelpers = { collection, doc, addDoc, serverTimestamp };
onAuthStateChanged(auth, (user) => {
const authNavItem = document.getElementById("authNavItem");
if (authNavItem) {
if (user) {
authNavItem.innerHTML =
'<button onclick="logout()" class="hover:text-[#6B9080] text-red-600">Logout</button>';
} else {
authNavItem.innerHTML =
'<a href="login.html" class="hover:text-[#6B9080]">Login</a>';
}
}
});
window.logout = async () => {
try {
await signOut(auth);
localStorage.clear();
window.location.href = "login.html";
} catch (error) {
console.error("Error signing out:", error);
}
};
</script>
<script type="module">
import {
pipeline,
env,
} from "https://cdn.jsdelivr.net/npm/@xenova/transformers@2.6.0";
const loadingEl = document.getElementById("loading");
const textOutput = document.getElementById("text-output");
const recsOutput = document.getElementById("recommendations-output");
const findingsOutput = document.getElementById(
"detected-measurement-results"
);
const authStatus = document.getElementById("auth-status");
let extractedText = "";
let currentUser = null;
document
.getElementById("pdf-upload")
.addEventListener("change", function () {
loadingEl.textContent = this.files.length
? `File selected: ${this.files[0].name}`
: "No file uploaded yet.";
});
const saveAnalysis = async (uid, payload) => {
try {
const docRef = await firebase
.firestore()
.collection("users")
.doc(uid)
.collection("analyses")
.add({
...payload,
createdAt: serverTimestamp(),
});
return docRef.id;
} catch (e) {
console.error("Failed to save analysis:", e);
}
};
const renderRecCard = (rec, idx) => {
const sev = (rec.severity || "").toLowerCase();
const sevClass = sev.includes("severe")
? "badge-high"
: sev.includes("moderate")
? "badge-medium"
: "badge-low";
return `
<div class="rec-card">
<div class="flex items-center justify-between">
<h4 class="rec-title">Finding ${idx + 1}: ${
rec.findings || "N/A"
}</h4>
<span class="rec-badge ${sevClass}">${rec.severity || "—"}</span>
</div>
<ul class="rec-content space-y-1">
<li><em>Recommendations:</em>
<ul class="list-disc list-inside ml-6">
${(rec.recommendations || [])
.map((r) => `<li>${r}</li>`)
.join("")}
</ul>
</li>
<li><em>Treatment:</em> ${
rec.treatment_suggestions || "Not available"
}</li>
<li><em>Home Care:</em>
<ul class="list-disc list-inside ml-6">
${(rec.home_care_guidance || [])
.map((r) => `<li>${r}</li>`)
.join("")}
</ul>
</li>
${
rec.info_link
? `<li><a href="${rec.info_link}" target="_blank" class="rec-link">Learn more</a></li>`
: ""
}
</ul>
</div>
`;
};
window.onAuthStateChanged(window.firebaseAuth, (user) => {
currentUser = user;
if (user) {
authStatus.textContent = `Signed in as ${user.email || user.uid}`;
} else {
authStatus.textContent =
"Not signed in. Sign in to save and view past analyses.";
}
});
document
.getElementById("analyze-btn")
.addEventListener("click", async () => {
const file = document.getElementById("pdf-upload").files[0];
if (!file) {
loadingEl.textContent = "Please upload a file first.";
return;
}
loadingEl.textContent = "Processing with AI...";
textOutput.textContent = "";
recsOutput.textContent = "";
const formData = new FormData();
formData.append("file", file);
formData.append("model", "bert");
let data;
try {
const res = await fetch(api("analyze/"), {
method: "POST",
body: formData,
});
if (!res.ok) throw new Error(await res.text());
data = await res.json();
} catch (err) {
console.error(err);
loadingEl.textContent = "Error during analysis: " + err.message;
return;
}
extractedText = data.ocr_text || "";
textOutput.textContent = extractedText;
const recs = Array.isArray(data.Detected_Anomolies)
? data.Detected_Anomolies
: data.Detected_Anomolies
? [data.Detected_Anomolies]
: [];
if (data.Detected_Anomolies) {
recsOutput.innerHTML = recs
.map((rec, i) => renderRecCard(rec, i))
.join("");
} else {
recsOutput.textContent = "No recommendations found.";
}
const findings = Array.isArray(data.Detected_Measurement_Values)
? data.Detected_Measurement_Values
: data.Detected_Measurement_Values
? [data.Detected_Measurement_Values]
: [];
if (data.Detected_Measurement_Values) {
findingsOutput.innerHTML = findings
.map((finding, i) => renderRecCard(finding, i))
.join("");
}
if (currentUser) {
/*await saveAnalysis(currentUser.uid, {
reportDate: date,
ocr_text: extractedText,
resolutions: recs,
measurements: findings,
});*/
await postReportToBackend({
user_id: currentUser.email,
report_date: new Date(),
ocr_text: extractedText,
anomalies: JSON.stringify(recs),
measurements: JSON.stringify(findings),
});
}
loadingEl.textContent = "Analysis complete.";
});
async function postReportToBackend(report) {
try {
const response = await fetch(api('save_report/'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(report),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('Report successfully sent to backend:', data);
} catch (error) {
console.error('Error sending report to backend:', error);
}
}
document.getElementById("ask-btn").onclick = async () => {
const q = document.getElementById("user-question").value.trim();
if (!q) return;
if (!extractedText) {
alert("Please analyze a document first before asking questions.");
return;
}
const chat = document.getElementById("chat-output");
chat.innerHTML += `<p><strong>You:</strong> ${q}</p>`;
chat.scrollTop = chat.scrollHeight;
chat.innerHTML += `<p><strong>Chatbot:</strong> <em>Thinking...</em></p>`;
chat.scrollTop = chat.scrollHeight;
try {
const response = await fetch(api('chat/'), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
question: q,
user_id: currentUser ? currentUser.uid : "anonymous"
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
//now addign acctual reposnse
const messages = chat.querySelectorAll('p');
const lastMessage = messages[messages.length - 1];
lastMessage.innerHTML = `<strong>Chatbot:</strong> ${data.answer}`;
} catch (error) {
console.error("Error:", error);
const messages = chat.querySelectorAll('p');
const lastMessage = messages[messages.length - 1];
lastMessage.innerHTML = `<strong>Chatbot:</strong> Sorry, I encountered an error: ${error.message}`;
}
document.getElementById("user-question").value = "";
chat.scrollTop = chat.scrollHeight;
};
</script>
</body>
</html>