patient_bot / static /frontend.html
WebashalarForML's picture
Update static/frontend.html
798ece2 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Patient Assistant Chat</title>
<style>
/* your existing styles here */
:root { --bg:#0f172a; --panel:#111827; --soft:#1f2937; --text:#e5e7eb; --muted:#9ca3af; --accent:#22c55e; }
* { box-sizing: border-box; }
body { margin:0; font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background: var(--bg); color: var(--text); }
.app { max-width: 900px; margin: 0 auto; padding: 20px; }
.card { background: var(--panel); border: 1px solid #242b3a; border-radius: 16px; overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,.25); }
.header { padding: 16px 20px; border-bottom: 1px solid #242b3a; display: flex; align-items: center; gap: 12px; }
.badge { background: #0b3b26; color: #8bf2c0; padding: 6px 10px; border-radius: 999px; font-weight: 600; font-size: 12px; letter-spacing: .3px; }
.row { display:flex; gap:12px; align-items:center; flex-wrap: wrap; }
label { font-size: 13px; color: var(--muted); }
input[type="text"] { background: var(--soft); color: var(--text); border: 1px solid #2b3346; padding: 10px 12px; border-radius: 10px; min-width: 200px; outline: none; }
input[type="text"]:focus { border-color: #374462; box-shadow: 0 0 0 3px rgba(59,130,246,.15); }
button { background: var(--accent); color: #052e19; border: none; padding: 10px 14px; border-radius: 10px; font-weight: 700; cursor: pointer; }
button.secondary { background: #334155; color: #dbeafe; }
button:disabled { opacity: .6; cursor: not-allowed; }
.chat { height: 420px; overflow-y: auto; padding: 18px; display: flex; flex-direction: column; gap: 10px; background: #0b1220; }
.msg { max-width: 80%; padding: 10px 12px; border-radius: 12px; border: 1px solid #1f2937; white-space: pre-wrap; word-break: break-word; }
.user   { align-self: flex-end; background: #0b3b26; border-color: #14532d; }
.assist { align-self: flex-start; background: #111827; border-color: #1f2937; }
.composer { display: grid; grid-template-columns: 1fr auto; gap: 10px; padding: 14px; border-top: 1px solid #242b3a; background: #0b1220; }
.composer input { width: 100%; }
.state { padding: 12px 16px; border-top: 1px dashed #243044; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 12px; color: #cbd5e1; background: #0b1220; }
details > summary { cursor: pointer; }
.small { font-size: 12px; color: var(--muted); }
</style>
</head>
<body>
<div class="app">
<div class="card">
<div class="header">
<span class="badge">Patient Assistant</span>
</div>
<div id="chat" class="chat"></div>
<div class="composer">
<input id="message" type="text" placeholder="Type your message…" />
<button id="send">Send</button>
</div>
<div class="state">
<details>
<summary>Agent State (from backend)</summary>
<pre id="stateView">{}</pre>
</details>
</div>
</div>
<p class="small" style="margin-top:10px; opacity:.8">
This version allows the agent to ask for your Patient ID (PID) during the conversation.
</p>
</div>
<script>
const NODE_CHAT_ENDPOINT = "/chat";
const chatEl = document.getElementById("chat");
const msgEl = document.getElementById("message");
const sendBtn = document.getElementById("send");
const stateView = document.getElementById("stateView");
let chatHistory = JSON.parse(localStorage.getItem("chatHistory")) || [];
let patientState = JSON.parse(localStorage.getItem("patientState")) || {};
sendBtn.addEventListener("click", onSend);
msgEl.addEventListener("keydown", (e) => {
if (e.key === "Enter") onSend();
});
function saveState() {
localStorage.setItem("chatHistory", JSON.stringify(chatHistory));
localStorage.setItem("patientState", JSON.stringify(patientState));
}
function renderChat() {
chatEl.innerHTML = "";
for (const m of chatHistory) {
const div = document.createElement("div");
div.className = `msg ${m.role === "user" ? "user" : "assist"}`;
div.textContent = `${m.role === "user" ? "You" : "Assistant"}: ${m.content}`;
chatEl.appendChild(div);
}
chatEl.scrollTop = chatEl.scrollHeight;
}
async function onSend() {
const message = (msgEl.value || "").trim();
if (!message) return;
// Clear the input and disable the button while we wait for the response
msgEl.value = "";
sendBtn.disabled = true;
// Add the user's message to the chat history
chatHistory.push({ role: "user", content: message });
renderChat();
saveState();
try {
// Send the chat history and patient state to the backend
const res = await fetch(NODE_CHAT_ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ chat_history: chatHistory, patient_state: patientState })
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
const reply = data.assistant_reply || "(no reply)";
patientState = data.updated_state || patientState;
// Add the assistant's reply to the chat history
chatHistory.push({ role: "assistant", content: reply });
renderChat();
saveState();
// Display the raw agent state for debugging
stateView.textContent = JSON.stringify(patientState, null, 2);
} catch (err) {
// Handle any errors and display them in the chat
chatHistory.push({ role: "assistant", content: `Error: ${err.message}` });
renderChat();
saveState();
} finally {
sendBtn.disabled = false;
}
}
// Initial greeting
if (chatHistory.length === 0) {
chatHistory.push({ role: "assistant", content: "Hello! I am your patient assistant. Please tell me your Patient ID to get started." });
saveState();
}
renderChat();
</script>
</body>
</html>