Spaces:
Runtime error
Runtime error
| <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> | |