Commit ·
f21e0aa
1
Parent(s): b7e0aa2
Fix UI: switch to plain fetch, works now
Browse files- static/index.html +62 -58
static/index.html
CHANGED
|
@@ -5,16 +5,13 @@
|
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
<title>RustVital‑AMD | Zero‑Trust Medical AI</title>
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
-
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
| 9 |
<style>
|
| 10 |
-
.htmx-indicator { display: none; }
|
| 11 |
-
.htmx-request .htmx-indicator { display: inline; }
|
| 12 |
-
.htmx-request.htmx-indicator { display: inline; }
|
| 13 |
.pii-highlight { background-color: #fee2e2; padding: 0 2px; border-radius: 3px; font-weight: bold; }
|
| 14 |
</style>
|
| 15 |
</head>
|
| 16 |
<body class="bg-gray-50 min-h-screen flex flex-col items-center p-4">
|
| 17 |
<div class="max-w-3xl w-full">
|
|
|
|
| 18 |
<div id="device-banner" class="bg-purple-100 text-purple-800 px-4 py-2 rounded-lg mb-2 text-sm text-center font-medium"></div>
|
| 19 |
<script>
|
| 20 |
fetch('/status')
|
|
@@ -35,7 +32,7 @@
|
|
| 35 |
<div class="flex flex-col md:flex-row gap-4">
|
| 36 |
<div class="flex-1">
|
| 37 |
<label class="block text-sm font-medium text-gray-700 mb-1">Original Note</label>
|
| 38 |
-
<textarea id="patient-note"
|
| 39 |
class="w-full border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
| 40 |
placeholder="Enter patient note...">Patient John Smith, 45 yo, chest pain</textarea>
|
| 41 |
</div>
|
|
@@ -45,14 +42,9 @@
|
|
| 45 |
</div>
|
| 46 |
</div>
|
| 47 |
|
| 48 |
-
<button
|
| 49 |
-
hx-vals='{"patient_note": document.getElementById("patient-note").value, "consent_hash": "abc123"}'
|
| 50 |
class="mt-4 w-full bg-purple-600 hover:bg-purple-700 text-white font-semibold py-3 rounded-lg transition flex items-center justify-center gap-2">
|
| 51 |
-
|
| 52 |
-
<svg id="spinner" class="htmx-indicator animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
| 53 |
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
| 54 |
-
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
|
| 55 |
-
</svg>
|
| 56 |
</button>
|
| 57 |
</div>
|
| 58 |
|
|
@@ -64,58 +56,70 @@
|
|
| 64 |
return text.replace(/\[([A-Z_]+)_(\d+)\]/g, '<span class="pii-highlight">[$1_$2]</span>');
|
| 65 |
}
|
| 66 |
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
const redactedDiv = document.getElementById('redacted-preview');
|
| 72 |
-
redactedDiv.classList.remove('hidden');
|
| 73 |
-
document.getElementById('redacted-text').innerHTML = highlightPlaceholders(data.redacted_prompt);
|
| 74 |
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
|
|
|
|
|
|
| 81 |
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
|
|
|
| 85 |
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
<
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
<
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
</div>
|
| 114 |
</div>
|
| 115 |
-
|
| 116 |
-
|
|
|
|
|
|
|
| 117 |
}
|
| 118 |
-
}
|
| 119 |
</script>
|
| 120 |
</body>
|
| 121 |
</html>
|
|
|
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
<title>RustVital‑AMD | Zero‑Trust Medical AI</title>
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
|
|
|
| 8 |
<style>
|
|
|
|
|
|
|
|
|
|
| 9 |
.pii-highlight { background-color: #fee2e2; padding: 0 2px; border-radius: 3px; font-weight: bold; }
|
| 10 |
</style>
|
| 11 |
</head>
|
| 12 |
<body class="bg-gray-50 min-h-screen flex flex-col items-center p-4">
|
| 13 |
<div class="max-w-3xl w-full">
|
| 14 |
+
<!-- Device banner -->
|
| 15 |
<div id="device-banner" class="bg-purple-100 text-purple-800 px-4 py-2 rounded-lg mb-2 text-sm text-center font-medium"></div>
|
| 16 |
<script>
|
| 17 |
fetch('/status')
|
|
|
|
| 32 |
<div class="flex flex-col md:flex-row gap-4">
|
| 33 |
<div class="flex-1">
|
| 34 |
<label class="block text-sm font-medium text-gray-700 mb-1">Original Note</label>
|
| 35 |
+
<textarea id="patient-note" rows="5"
|
| 36 |
class="w-full border border-gray-300 rounded-lg p-3 focus:ring-2 focus:ring-purple-500 focus:border-transparent"
|
| 37 |
placeholder="Enter patient note...">Patient John Smith, 45 yo, chest pain</textarea>
|
| 38 |
</div>
|
|
|
|
| 42 |
</div>
|
| 43 |
</div>
|
| 44 |
|
| 45 |
+
<button onclick="runTriage()"
|
|
|
|
| 46 |
class="mt-4 w-full bg-purple-600 hover:bg-purple-700 text-white font-semibold py-3 rounded-lg transition flex items-center justify-center gap-2">
|
| 47 |
+
Start Triage
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
</button>
|
| 49 |
</div>
|
| 50 |
|
|
|
|
| 56 |
return text.replace(/\[([A-Z_]+)_(\d+)\]/g, '<span class="pii-highlight">[$1_$2]</span>');
|
| 57 |
}
|
| 58 |
|
| 59 |
+
async function runTriage() {
|
| 60 |
+
const note = document.getElementById('patient-note').value;
|
| 61 |
+
const resultDiv = document.getElementById('result');
|
| 62 |
+
resultDiv.innerHTML = '<div class="text-center text-purple-500 py-4">Processing...</div>';
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
+
try {
|
| 65 |
+
const response = await fetch('/triage', {
|
| 66 |
+
method: 'POST',
|
| 67 |
+
headers: { 'Content-Type': 'application/json' },
|
| 68 |
+
body: JSON.stringify({ patient_note: note, consent_hash: 'abc123' })
|
| 69 |
+
});
|
| 70 |
+
if (!response.ok) throw new Error('Server error');
|
| 71 |
+
const data = await response.json();
|
| 72 |
|
| 73 |
+
// Show redacted preview
|
| 74 |
+
const redactedDiv = document.getElementById('redacted-preview');
|
| 75 |
+
redactedDiv.classList.remove('hidden');
|
| 76 |
+
document.getElementById('redacted-text').innerHTML = highlightPlaceholders(data.redacted_prompt);
|
| 77 |
|
| 78 |
+
const stepsHtml = data.agent_steps.map(step => `
|
| 79 |
+
<div class="flex items-center gap-2 text-sm">
|
| 80 |
+
<span class="px-2 py-1 bg-green-100 text-green-700 rounded-full">✅ ${step.name}</span>
|
| 81 |
+
<span class="text-gray-500">${step.reasoning} (${step.duration_ms}ms)</span>
|
| 82 |
+
</div>
|
| 83 |
+
`).join('');
|
| 84 |
+
|
| 85 |
+
const piiHtml = data.pii_map.map(p => `
|
| 86 |
+
<li class="text-sm">🔴 <strong>${p.original}</strong> → <code>${p.placeholder}</code></li>
|
| 87 |
+
`).join('');
|
| 88 |
+
|
| 89 |
+
resultDiv.innerHTML = `
|
| 90 |
+
<div class="bg-white rounded-2xl shadow-xl p-6 space-y-4">
|
| 91 |
+
<div class="text-sm text-purple-700 bg-purple-50 px-3 py-1 rounded-full inline-block">
|
| 92 |
+
${data.device_info} · Model: Qwen2.5-${data.model_used}
|
| 93 |
+
</div>
|
| 94 |
+
<div>
|
| 95 |
+
<h3 class="font-semibold text-gray-700 mb-2">Agent Progress</h3>
|
| 96 |
+
<div class="space-y-1">${stepsHtml}</div>
|
| 97 |
+
</div>
|
| 98 |
+
<div>
|
| 99 |
+
<h3 class="font-semibold text-gray-700">Triage Result</h3>
|
| 100 |
+
<div class="bg-purple-50 p-3 rounded-lg text-lg font-medium">${data.triage_result}</div>
|
| 101 |
+
</div>
|
| 102 |
+
<div>
|
| 103 |
+
<h3 class="font-semibold text-gray-700">PII Redaction Map</h3>
|
| 104 |
+
<ul class="list-disc list-inside text-sm text-gray-600">${piiHtml}</ul>
|
| 105 |
+
</div>
|
| 106 |
+
<div>
|
| 107 |
+
<h3 class="font-semibold text-gray-700">Redaction Proof (SHA‑256)</h3>
|
| 108 |
+
<code class="text-xs bg-gray-100 p-2 rounded block mt-1">${data.redaction_proof}</code>
|
| 109 |
+
</div>
|
| 110 |
+
<div>
|
| 111 |
+
<h3 class="font-semibold text-gray-700">On‑Chain Audit</h3>
|
| 112 |
+
<div class="text-sm">
|
| 113 |
+
<p><strong>CID:</strong> <code>${data.cid}</code></p>
|
| 114 |
+
<p><strong>Transaction:</strong> <a href="https://sepolia.basescan.org/tx/${data.transaction_hash}" target="_blank" class="text-purple-600 underline">${data.transaction_hash}</a></p>
|
| 115 |
</div>
|
| 116 |
</div>
|
| 117 |
+
</div>
|
| 118 |
+
`;
|
| 119 |
+
} catch (e) {
|
| 120 |
+
resultDiv.innerHTML = `<div class="bg-red-100 text-red-700 p-4 rounded-lg">Error: ${e.message}</div>`;
|
| 121 |
}
|
| 122 |
+
}
|
| 123 |
</script>
|
| 124 |
</body>
|
| 125 |
</html>
|