Spaces:
Sleeping
Sleeping
priyansh-saxena1 commited on
Commit ·
7f00c10
1
Parent(s): 27b1ed4
refactor: remove regex extraction, pure LLM-driven
Browse files- app/llm.py +49 -86
app/llm.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
import os
|
| 2 |
import json
|
| 3 |
-
import re
|
| 4 |
from pydantic import BaseModel
|
| 5 |
|
| 6 |
INTAKE_PROMPT = """You are a clinical intake assistant. The patient just arrived.
|
|
@@ -111,98 +110,62 @@ class CombinedOutput(BaseModel):
|
|
| 111 |
|
| 112 |
|
| 113 |
class MockLLM:
|
|
|
|
| 114 |
def combined_call(self, transcript: str, current_json: str, stage: str = "intake") -> CombinedOutput:
|
| 115 |
-
"""Single call: extract + generate reply. No real inference in mock mode."""
|
| 116 |
-
t = transcript.lower()
|
| 117 |
try:
|
| 118 |
state = json.loads(current_json)
|
| 119 |
except Exception:
|
| 120 |
state = {}
|
| 121 |
|
| 122 |
-
#
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
if
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
if
|
| 134 |
-
if not state.get("
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
elif "climb" in t: state["aggravating"] = "climbing stairs"
|
| 159 |
-
if any(w in t for w in ["rest", "sit", "antacid", "medication", "nitroglycerin"]):
|
| 160 |
-
if not state.get("relieving"):
|
| 161 |
-
state["relieving"] = "resting"
|
| 162 |
-
if "palpitation" in t:
|
| 163 |
-
ros = state.get("ros", {})
|
| 164 |
-
ros["cardiac"] = ["palpitations present"] + (["no leg swelling"] if "no" in t and "swell" in t else [])
|
| 165 |
-
state["ros"] = ros
|
| 166 |
-
if "breath" in t or "wheez" in t or "cough" in t:
|
| 167 |
-
ros = state.get("ros", {})
|
| 168 |
-
ros["respiratory"] = ["shortness of breath" if "breath" in t else "no shortness of breath",
|
| 169 |
-
"no cough" if ("no" in t and "cough" in t) else ("cough" if "cough" in t else "no cough")]
|
| 170 |
-
state["ros"] = ros
|
| 171 |
-
if "nausea" in t or "vomit" in t or "heartburn" in t:
|
| 172 |
-
ros = state.get("ros", {})
|
| 173 |
-
ros["gi"] = ["no nausea" if ("no" in t and "nausea" in t) else "nausea",
|
| 174 |
-
"no vomiting" if ("no" in t and "vomit" in t) else "vomiting present"]
|
| 175 |
-
state["ros"] = ros
|
| 176 |
-
|
| 177 |
-
state["emergency"] = any(e in t for e in ["crushing chest pain", "heart attack", "can't breathe", "suicide", "kill myself"])
|
| 178 |
-
|
| 179 |
-
# --- Determine next question ---
|
| 180 |
-
if not state.get("chief_complaint"):
|
| 181 |
-
state["reply"] = "What brings you in today?"
|
| 182 |
-
elif not state.get("onset"):
|
| 183 |
-
cc = state.get("chief_complaint", "this")
|
| 184 |
-
state["reply"] = f"When did the {cc} start?"
|
| 185 |
-
elif not state.get("location"):
|
| 186 |
-
state["reply"] = "Where exactly do you feel it?"
|
| 187 |
-
elif not state.get("duration"):
|
| 188 |
-
state["reply"] = "Is it constant or does it come and go?"
|
| 189 |
-
elif not state.get("character"):
|
| 190 |
-
state["reply"] = "How would you describe it — sharp, dull, pressure, or tightness?"
|
| 191 |
-
elif not state.get("severity"):
|
| 192 |
-
state["reply"] = "On a scale of 1 to 10, how severe is it right now?"
|
| 193 |
-
elif not state.get("aggravating"):
|
| 194 |
-
state["reply"] = "Does anything make it worse, like physical activity?"
|
| 195 |
-
elif not state.get("relieving"):
|
| 196 |
-
state["reply"] = "What helps relieve it?"
|
| 197 |
-
else:
|
| 198 |
ros = state.get("ros", {})
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
else:
|
| 207 |
state["reply"] = "Thank you — I have everything I need."
|
| 208 |
|
|
|
|
| 1 |
import os
|
| 2 |
import json
|
|
|
|
| 3 |
from pydantic import BaseModel
|
| 4 |
|
| 5 |
INTAKE_PROMPT = """You are a clinical intake assistant. The patient just arrived.
|
|
|
|
| 110 |
|
| 111 |
|
| 112 |
class MockLLM:
|
| 113 |
+
"""Minimal mock for testing — no regex, no extraction logic. Just walks through fields."""
|
| 114 |
def combined_call(self, transcript: str, current_json: str, stage: str = "intake") -> CombinedOutput:
|
|
|
|
|
|
|
| 115 |
try:
|
| 116 |
state = json.loads(current_json)
|
| 117 |
except Exception:
|
| 118 |
state = {}
|
| 119 |
|
| 120 |
+
# Mock just steps through HPI fields in order, using the patient's last message as the value
|
| 121 |
+
lines = transcript.strip().split("\n")
|
| 122 |
+
last_patient_msg = ""
|
| 123 |
+
for line in reversed(lines):
|
| 124 |
+
if line.startswith("Patient:"):
|
| 125 |
+
last_patient_msg = line.replace("Patient:", "").strip()
|
| 126 |
+
break
|
| 127 |
+
|
| 128 |
+
hpi_fields = ["chief_complaint", "onset", "location", "duration", "character", "severity", "aggravating", "relieving"]
|
| 129 |
+
ros_systems = ["cardiac", "respiratory", "gi"]
|
| 130 |
+
|
| 131 |
+
if stage == "intake":
|
| 132 |
+
if last_patient_msg and not state.get("chief_complaint"):
|
| 133 |
+
state["chief_complaint"] = last_patient_msg
|
| 134 |
+
state["reply"] = "What brings you in today?" if not state.get("chief_complaint") else f"When did the {state['chief_complaint']} start?"
|
| 135 |
+
|
| 136 |
+
elif stage == "hpi":
|
| 137 |
+
# Fill the first empty HPI field with the patient's answer
|
| 138 |
+
for field in hpi_fields[1:]: # skip chief_complaint, already filled
|
| 139 |
+
if not state.get(field):
|
| 140 |
+
if last_patient_msg:
|
| 141 |
+
state[field] = last_patient_msg
|
| 142 |
+
break
|
| 143 |
+
# Ask about the next missing field
|
| 144 |
+
for field in hpi_fields[1:]:
|
| 145 |
+
if not state.get(field):
|
| 146 |
+
labels = {"onset": "when it started", "location": "where you feel it",
|
| 147 |
+
"duration": "how long it's lasted", "character": "what it feels like",
|
| 148 |
+
"severity": "how severe it is (1-10)", "aggravating": "what makes it worse",
|
| 149 |
+
"relieving": "what makes it better"}
|
| 150 |
+
state["reply"] = f"Can you tell me {labels.get(field, field)}?"
|
| 151 |
+
break
|
| 152 |
+
else:
|
| 153 |
+
state["reply"] = "Thank you, moving on to review of systems."
|
| 154 |
+
|
| 155 |
+
elif stage == "ros":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
ros = state.get("ros", {})
|
| 157 |
+
# Fill the first empty ROS system
|
| 158 |
+
for sys_name in ros_systems:
|
| 159 |
+
if sys_name not in ros:
|
| 160 |
+
if last_patient_msg:
|
| 161 |
+
ros[sys_name] = [last_patient_msg]
|
| 162 |
+
state["ros"] = ros
|
| 163 |
+
break
|
| 164 |
+
# Ask about next missing system
|
| 165 |
+
for sys_name in ros_systems:
|
| 166 |
+
if sys_name not in ros:
|
| 167 |
+
state["reply"] = f"Any {sys_name} symptoms?"
|
| 168 |
+
break
|
| 169 |
else:
|
| 170 |
state["reply"] = "Thank you — I have everything I need."
|
| 171 |
|