priyansh-saxena1 commited on
Commit
7f00c10
·
1 Parent(s): 27b1ed4

refactor: remove regex extraction, pure LLM-driven

Browse files
Files changed (1) hide show
  1. 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
- # --- Extraction ---
123
- if "chest pain" in t and not state.get("chief_complaint"):
124
- state["chief_complaint"] = "chest pain"
125
- if any(w in t for w in ["yesterday", "this morning", "last night", "hours ago", "days ago", "since"]):
126
- if not state.get("onset"):
127
- if "yesterday" in t:
128
- state["onset"] = "yesterday"
129
- elif "this morning" in t or "morning" in t:
130
- state["onset"] = "this morning"
131
- else:
132
- state["onset"] = "recently"
133
- if any(w in t for w in ["center", "left", "right", "chest", "stomach", "head", "arm"]):
134
- if not state.get("location"):
135
- if "center" in t:
136
- state["location"] = "center of chest"
137
- elif "left" in t:
138
- state["location"] = "left side of chest"
139
- if any(w in t for w in ["constant", "intermittent", "comes and goes", "all day", "hours"]):
140
- if not state.get("duration"):
141
- state["duration"] = "constant" if "constant" in t else "intermittent"
142
- if any(w in t for w in ["pressure", "tight", "squeezing", "sharp", "dull", "burning", "stabbing"]):
143
- if not state.get("character"):
144
- if "tight" in t or "squeezing" in t:
145
- state["character"] = "tight, squeezing pressure"
146
- elif "sharp" in t:
147
- state["character"] = "sharp"
148
- # Severity match "N out of 10", "N/10", or isolated score digit
149
- sev_match = re.search(r'\b([1-9]|10)\s*(?:out of|/|over)\s*10\b', t, re.IGNORECASE)
150
- if not sev_match:
151
- sev_match = re.search(r'\bseverity\s+(?:is\s+)?([1-9]|10)\b', t, re.IGNORECASE)
152
- if sev_match and not state.get("severity"):
153
- state["severity"] = f"{sev_match.group(1)}/10"
154
- if any(w in t for w in ["walk", "run", "climb", "exert", "stress", "eating", "lying"]):
155
- if not state.get("aggravating"):
156
- if "walk" in t: state["aggravating"] = "walking"
157
- elif "run" in t: state["aggravating"] = "running"
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
- cc = state.get("chief_complaint", "chest pain")
200
- if "cardiac" not in ros:
201
- state["reply"] = "Any heart-related symptoms — palpitations or leg swelling?"
202
- elif "respiratory" not in ros:
203
- state["reply"] = "Any shortness of breath, wheezing, or coughing?"
204
- elif "gi" not in ros:
205
- state["reply"] = "Any nausea, vomiting, or heartburn?"
 
 
 
 
 
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