PearlIsa commited on
Commit
b472580
·
verified ·
1 Parent(s): df53b47

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +311 -93
app.py CHANGED
@@ -48,15 +48,33 @@ class MedicalTriageBot:
48
  self.model = None
49
  self.embeddings = None
50
  self.vector_store = None
51
- self.chunk_size = 300
52
- self.chunk_overlap = 100
53
- self.num_relevant_chunks = 3
54
  self.last_interaction_time = time.time()
55
  self.interaction_cooldown = 1.0
56
  self.safety_phrases = [
57
  "999", "111", "emergency", "GP", "NHS",
58
  "consult a doctor", "seek medical attention"
59
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  self.current_case = None
61
  self.location_services = {
62
  "London": {"A&E": ["St Thomas' Hospital", "Royal London Hospital"],
@@ -69,6 +87,45 @@ class MedicalTriageBot:
69
  ("emergency_signs", "Any difficulty breathing, chest pain, or confusion?")
70
  ]
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  def setup_model(self, model_name="google/gemma-7b-it"):
73
  """Initialize the medical AI model with 4-bit quantization"""
74
  if self.model is not None:
@@ -121,34 +178,211 @@ class MedicalTriageBot:
121
 
122
  def build_medical_index(self):
123
  medical_knowledge = {
124
- "emergency_protocols.txt": """Emergency Protocols:
125
- - Chest pain: Call 999 immediately
126
- - Breathing difficulties: Urgent 999 call
127
- - Severe bleeding: Apply pressure, call 999""",
128
-
129
- "triage_guidelines.txt": """Triage Guidelines:
130
- - Persistent fever >48h: Contact 111
131
- - Minor injuries: Visit urgent care
132
- - Medication questions: Consult GP""",
133
- "gp_care.txt": """GP Management:
134
- - Persistent cough >3 weeks: Book GP
135
- - Medication reviews: Schedule appointment
136
- - Chronic condition management""",
137
-
138
- "urgent_care.txt": """Urgent Care:
139
- - Minor burns: Visit urgent care
140
- - Sprains: Same-day urgent care
141
- - Ear infections: Walk-in centre"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  }
143
-
 
144
  os.makedirs("medical_knowledge", exist_ok=True)
145
  for filename, content in medical_knowledge.items():
146
  with open(f"medical_knowledge/{filename}", "w") as f:
147
  f.write(content)
148
-
149
  text_splitter = RecursiveCharacterTextSplitter(
150
- chunk_size=self.chunk_size,
151
- chunk_overlap=self.chunk_overlap
152
  )
153
 
154
  documents = []
@@ -173,68 +407,51 @@ class MedicalTriageBot:
173
  @torch.inference_mode()
174
  def generate_safe_response(self, message, history):
175
  try:
 
176
  if self.current_case is None:
177
  context = self.get_medical_context(message)
178
  self._initialize_case(context)
179
  return self._next_question()
 
 
 
 
180
 
181
- # Existing state handling code
182
- if self.current_case["stage"] == "investigation":
183
- return self._handle_investigation(message, history)
184
-
185
- # Add model inference HERE
186
- inputs = self.tokenizer(
187
- self._build_prompt(message, history),
188
- return_tensors="pt",
189
- truncation=True,
190
- max_length=1024
191
- ).to(self.model.device)
192
-
193
- # Create safety-focused prompt
194
- prompt = f"""<start_of_turn>system
195
- You are a medical triage assistant. Use this context:
196
- {context}
197
- Current conversation:
198
- {conversation}
199
- Guidelines:
200
- 1. Assess symptom severity
201
- 2. Recommend appropriate care level
202
- 3. Never diagnose or prescribe
203
- 4. Always include safety netting
204
- <end_of_turn>
205
- <start_of_turn>user
206
- {message}
207
- <end_of_turn>
208
- <start_of_turn>assistant"""
209
-
210
- # Generate response
211
- inputs = self.tokenizer(
212
- prompt,
213
- return_tensors="pt",
214
- truncation=True,
215
- max_length=1024
216
- ).to(self.model.device)
217
-
218
- outputs = self.model.generate(
219
- **inputs,
220
- max_new_tokens=256,
221
- temperature=0.7,
222
- top_p=0.9,
223
- repetition_penalty=1.2
224
- )
225
 
226
- # Clean and validate response
227
- full_response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
228
- clean_response = full_response.split("<start_of_turn>assistant")[-1]
229
- clean_response = clean_response.split("<end_of_turn>")[0].strip()
230
 
231
- # Ensure medical safety
232
- if not any(phrase in clean_response.lower() for phrase in self.safety_phrases):
233
- clean_response += "\n\nIf symptoms persist, please contact NHS 111."
234
-
235
- self.last_interaction_time = time.time()
236
- return clean_response[:500] # Limit response length
237
 
 
 
238
  except Exception as e:
239
  logger.error(f"Generation error: {e}")
240
  return "Please contact NHS 111 directly for urgent medical advice."
@@ -311,20 +528,25 @@ Guidelines:
311
 
312
  def _get_location(self, postcode):
313
  return "London" if postcode.startswith("L") else "Manchester"
314
-
315
- def _build_prompt(self, message, history):
316
- conversation = "\n".join([f"User: {user}\nAssistant: {bot}" for user, bot in history[-3:]])
317
- context = self.get_medical_context(message)
318
 
319
- return f"""<start_of_turn>system
 
 
 
 
 
 
 
320
  Context:
321
  {context}
322
- Conversation:
323
  {conversation}
324
- Guidelines:
325
- 1. Follow investigation flow
326
- 2. Consider location: {self.current_case.get('location', 'unknown')}
327
- 3. Maintain safety protocols
 
328
  <end_of_turn>
329
  <start_of_turn>user
330
  {message}
@@ -340,10 +562,6 @@ def create_medical_interface():
340
  bot.setup_model()
341
  bot.setup_rag_system()
342
 
343
- def create_medical_interface():
344
- bot = MedicalTriageBot()
345
- bot.setup_model()
346
- bot.setup_rag_system()
347
 
348
  def handle_conversation(message, history):
349
  try:
 
48
  self.model = None
49
  self.embeddings = None
50
  self.vector_store = None
51
+ self.chunk_size = 512
52
+ self.chunk_overlap = 128
53
+ self.num_relevant_chunks = 5
54
  self.last_interaction_time = time.time()
55
  self.interaction_cooldown = 1.0
56
  self.safety_phrases = [
57
  "999", "111", "emergency", "GP", "NHS",
58
  "consult a doctor", "seek medical attention"
59
  ]
60
+ self.triage_levels = {
61
+ 'Emergency': [
62
+ 'pediatric', 'stroke', 'cardiac', 'unconscious', 'suicidal',
63
+ 'psychotic', 'seizure', 'overdose', 'cyanosis'
64
+ ],
65
+ 'Urgent': [
66
+ 'pregnancy', 'fracture', 'asthma', 'withdrawal',
67
+ 'postpartum', 'harm thoughts', 'panic attack'
68
+ ],
69
+ 'GP Care': [
70
+ 'eczema', 'ocd', 'depression', 'anxiety', 'PTSD',
71
+ 'bipolar', 'migraine', 'chronic'
72
+ ],
73
+ 'Self-Care': [
74
+ 'cold', 'rash', 'stress', 'mild', 'situational',
75
+ 'acne', 'insomnia'
76
+ ]
77
+ }
78
  self.current_case = None
79
  self.location_services = {
80
  "London": {"A&E": ["St Thomas' Hospital", "Royal London Hospital"],
 
87
  ("emergency_signs", "Any difficulty breathing, chest pain, or confusion?")
88
  ]
89
 
90
+ def _determine_triage_level(self, context):
91
+ context_lower = context.lower()
92
+ for level, keywords in triage_levels.items():
93
+ if any(kw in context_lower for kw in keywords):
94
+ return level
95
+ return 'GP Care'
96
+
97
+ def _parse_medical_context(self, context):
98
+ components = {
99
+ 'advice': [], 'red_flags': [],
100
+ 'timeframe': '24 hours', 'special_considerations': []
101
+ }
102
+
103
+ current_section = None
104
+ for line in context.split('\n'):
105
+ line = line.strip()
106
+ if ':' in line:
107
+ key, value = line.split(':', 1)
108
+ key = key.strip().lower()
109
+ if key == 'immediate actions':
110
+ current_section = 'advice'
111
+ components['advice'].append(value.strip())
112
+ elif key == 'red flags':
113
+ current_section = 'red_flags'
114
+ components['red_flags'].append(value.strip())
115
+ elif key == 'action timeline':
116
+ components['timeframe'] = value.strip()
117
+ elif key == 'cultural considerations':
118
+ current_section = 'special_considerations'
119
+ components['special_considerations'].append(value.strip())
120
+ elif current_section:
121
+ components[current_section].append(line)
122
+
123
+ # Convert lists to strings
124
+ for key in components:
125
+ if isinstance(components[key], list):
126
+ components[key] = '\n- '.join(components[key])
127
+ return components
128
+
129
  def setup_model(self, model_name="google/gemma-7b-it"):
130
  """Initialize the medical AI model with 4-bit quantization"""
131
  if self.model is not None:
 
178
 
179
  def build_medical_index(self):
180
  medical_knowledge = {
181
+ # ===== EMERGENCY CONDITIONS (Call 999) =====
182
+ "emergency_pediatric.txt": """
183
+ Triage Level: Emergency
184
+ Conditions: Pediatric Respiratory Distress, Head Injury
185
+ Key Symptoms:
186
+ - Blue lips/tongue (cyanosis)
187
+ - Stridor or wheezing at rest
188
+ - Repeated vomiting post-head injury
189
+ - Unconsciousness >1 minute
190
+ Immediate Actions:
191
+ 1. Call 999 immediately
192
+ 2. Maintain airway if trained
193
+ 3. Monitor breathing rate
194
+ Cultural Considerations:
195
+ - Provide gender-matched responders if requested
196
+ - Accommodate religious head coverings during assessment""",
197
+
198
+ "emergency_mental_health.txt": """
199
+ Triage Level: Emergency
200
+ Conditions: Suicidal Crisis, Psychotic Episode
201
+ Key Symptoms:
202
+ - Expressing concrete suicide plan
203
+ - Hallucinations commanding harm
204
+ - Severe self-injury with blood loss
205
+ - Catatonic state
206
+ Immediate Actions:
207
+ 1. Call 999 if immediate danger
208
+ 2. Remove potential weapons
209
+ 3. Stay with patient until help arrives
210
+ Special Considerations:
211
+ - Avoid physical restraint unless absolutely necessary
212
+ - Use non-judgmental language
213
+ Red Flags:
214
+ - Talking about being a burden
215
+ - Sudden calm after depression
216
+ - Giving away possessions""",
217
+
218
+ # ===== URGENT CARE CONDITIONS (A&E/UTC) =====
219
+ "urgent_mental_health.txt": """
220
+ Triage Level: Urgent
221
+ Conditions: Panic Attacks, Self-Harm
222
+ Key Symptoms:
223
+ - Hyperventilation >30 minutes
224
+ - Superficial self-harm injuries
225
+ - Acute anxiety with derealization
226
+ Action Timeline: Within 4 hours
227
+ While Waiting:
228
+ - Practice grounding techniques
229
+ - Use ice cubes for sensory focus
230
+ - Track panic duration/frequency
231
+ Escalate If:
232
+ - Chest pain develops
233
+ - Dissociation persists >1 hour
234
+ - Urges escalate""",
235
+
236
+ "urgent_pregnancy.txt": """
237
+ Triage Level: Urgent
238
+ Conditions: Pregnancy Complications
239
+ Key Symptoms:
240
+ - Vaginal bleeding + abdominal pain
241
+ - Reduced fetal movement
242
+ - Sudden swelling + headache
243
+ Action Timeline: Within 2 hours
244
+ Cultural Protocols:
245
+ - Offer female clinician if preferred
246
+ - Respect modesty requests
247
+ Red Flags:
248
+ - Fluid leakage + fever
249
+ - Visual disturbances
250
+ - Contractions <37 weeks""",
251
+
252
+ # ===== GP CARE CONDITIONS =====
253
+ "gp_mental_health.txt": """
254
+ Triage Level: GP Care
255
+ Conditions: Anxiety, Depression, PTSD
256
+ Key Symptoms:
257
+ - Persistent low mood >2 weeks
258
+ - Panic attacks 2+/week
259
+ - Sleep disturbances + fatigue
260
+ - Avoidance behaviors
261
+ Action Timeline: 72 hours
262
+ Management Strategies:
263
+ - Keep mood/symptom diary
264
+ - Practice 4-7-8 breathing
265
+ - Maintain routine activities
266
+ Red Flags:
267
+ - Social withdrawal >1 week
268
+ - Weight loss >5% in month
269
+ - Suicidal ideation""",
270
+
271
+ # ===== SELF-CARE CONDITIONS =====
272
+ "selfcare_mental_health.txt": """
273
+ Triage Level: Self-Care
274
+ Conditions: Mild Anxiety, Stress
275
+ Key Symptoms:
276
+ - Situational anxiety
277
+ - Work-related stress
278
+ - Mild sleep difficulties
279
+ Management:
280
+ - Practice box breathing
281
+ - Limit caffeine/alcohol
282
+ - Use worry journal
283
+ - Progressive muscle relaxation
284
+ Escalate If:
285
+ - Symptoms persist >2 weeks
286
+ - Panic attacks develop
287
+ - Daily functioning impaired""",
288
+
289
+ # ===== PEDIATRIC MENTAL HEALTH =====
290
+ "pediatric_mental_health.txt": """
291
+ Triage Level: GP Care
292
+ Conditions: Childhood Anxiety, School Refusal
293
+ Key Symptoms:
294
+ - School avoidance >3 days
295
+ - Somatic complaints (stomachaches)
296
+ - Nightmares/bedwetting regression
297
+ Action Timeline: 1 week
298
+ Parent Guidance:
299
+ - Maintain consistent routine
300
+ - Validate feelings without reinforcement
301
+ - Use gradual exposure techniques
302
+ Red Flags:
303
+ - Food restriction
304
+ - Self-harm marks
305
+ - Social isolation >1 week""",
306
+
307
+ # ===== CULTURAL MENTAL HEALTH =====
308
+ "cultural_mental_health.txt": """
309
+ Triage Level: GP Care
310
+ Conditions: Culturally-Specific Presentations
311
+ Key Symptoms:
312
+ - Somatic complaints without medical cause
313
+ - Religious preoccupation/guilt
314
+ - Migration-related stress
315
+ Cultural Considerations:
316
+ - Use trained interpreters
317
+ - Consider spiritual assessments
318
+ - Respect family hierarchy
319
+ Management:
320
+ - Community support referrals
321
+ - Culturally-adapted CBT
322
+ - Family involvement""",
323
+
324
+ # ===== CHRONIC CONDITIONS =====
325
+ "chronic_mental_health.txt": """
326
+ Triage Level: GP Care
327
+ Conditions: Bipolar, OCD, Eating Disorders
328
+ Key Symptoms:
329
+ - Manic episodes >4 days
330
+ - Compulsions >1hr/day
331
+ - BMI <18.5 with body dysmorphia
332
+ Monitoring:
333
+ - Mood tracking charts
334
+ - Compulsion frequency log
335
+ - Weekly weight checks
336
+ Crisis Signs:
337
+ - Rapid speech + sleeplessness
338
+ - Food restriction >24hrs
339
+ - Contamination fears preventing eating""",
340
+
341
+ # ===== PERINATAL MENTAL HEALTH =====
342
+ "perinatal_mental_health.txt": """
343
+ Triage Level: Urgent
344
+ Conditions: Postpartum Depression, Psychosis
345
+ Key Symptoms:
346
+ - Intrusive harm thoughts
347
+ - Detachment from baby
348
+ - Visual/auditory hallucinations
349
+ Action Timeline: 24 hours
350
+ Safety Measures:
351
+ - Partner supervision
352
+ - Remove harmful objects
353
+ - Breastfeeding support
354
+ Red Flags:
355
+ - Planning infant harm
356
+ - Extreme paranoia
357
+ - Refusing sleep""",
358
+
359
+ # ===== ADDICTION & SUBSTANCE =====
360
+ "addiction_care.txt": """
361
+ Triage Level: Urgent
362
+ Conditions: Withdrawal, Overdose Risk
363
+ Key Symptoms:
364
+ - Seizure history + alcohol use
365
+ - IV drug use + fever
366
+ - Opioid constricted pupils
367
+ Immediate Actions:
368
+ 1. Call 111 for withdrawal management
369
+ 2. Monitor breathing rate
370
+ 3. Provide naloxone if available
371
+ Danger Signs:
372
+ - Jaundice + abdominal pain
373
+ - Chest pain + stimulant use
374
+ - Hallucinations + tremor"""
375
  }
376
+
377
+ # Keep existing index building logic
378
  os.makedirs("medical_knowledge", exist_ok=True)
379
  for filename, content in medical_knowledge.items():
380
  with open(f"medical_knowledge/{filename}", "w") as f:
381
  f.write(content)
382
+
383
  text_splitter = RecursiveCharacterTextSplitter(
384
+ chunk_size=512,
385
+ chunk_overlap=128
386
  )
387
 
388
  documents = []
 
407
  @torch.inference_mode()
408
  def generate_safe_response(self, message, history):
409
  try:
410
+ # Add case initialization check
411
  if self.current_case is None:
412
  context = self.get_medical_context(message)
413
  self._initialize_case(context)
414
  return self._next_question()
415
+
416
+ context = self.get_medical_context(message)
417
+ triage_level = self._determine_triage_level(context)
418
+ components = self._parse_medical_context(context)
419
 
420
+ response_templates = {
421
+ 'Emergency': (
422
+ "🚨 **Emergency Alert**\n"
423
+ "{advice}\n\n"
424
+ "⚠️ **Immediate Action Required:**\n"
425
+ "- Call 999 NOW if:\n{red_flags}\n"
426
+ "🌍 **Special Considerations:**\n{special_considerations}"
427
+ ),
428
+ 'Urgent': (
429
+ "⚠️ **Urgent Care Needed**\n"
430
+ "Visit A&E within {timeframe} if:\n{red_flags}\n\n"
431
+ "🩺 **While Waiting:**\n{advice}\n\n"
432
+ "🌍 **Cultural Notes:**\n{special_considerations}"
433
+ ),
434
+ 'GP Care': (
435
+ "📅 **GP Consultation**\n"
436
+ "Book appointment within {timeframe}\n\n"
437
+ "💡 **Self-Care Advice:**\n{advice}\n\n"
438
+ "⚠️ **Red Flags:**\n{red_flags}"
439
+ ),
440
+ 'Self-Care': (
441
+ "🏡 **Self-Care Management**\n"
442
+ "{advice}\n\n"
443
+ "⚠️ **Seek Help If:**\n{red_flags}"
444
+ )
445
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
 
447
+ response = response_templates[triage_level].format(**components)
 
 
 
448
 
449
+ # Add safety netting
450
+ if not any(phrase in response.lower() for phrase in self.safety_phrases):
451
+ response += "\n\nIf symptoms persist, please contact NHS 111."
 
 
 
452
 
453
+ return response[:500] # Maintain length limit
454
+
455
  except Exception as e:
456
  logger.error(f"Generation error: {e}")
457
  return "Please contact NHS 111 directly for urgent medical advice."
 
528
 
529
  def _get_location(self, postcode):
530
  return "London" if postcode.startswith("L") else "Manchester"
531
+
 
 
 
532
 
533
+
534
+ def _build_prompt(self, message, history):
535
+ conversation = "\n".join([f"User: {user}\nAssistant: {bot}" for user, bot in history[-3:]])
536
+ context = self.get_medical_context(message)
537
+ triage_level = self._determine_triage_level(context)
538
+
539
+ return f"""<start_of_turn>system
540
+ Triage Level: {triage_level}
541
  Context:
542
  {context}
543
+ Conversation History:
544
  {conversation}
545
+ Response Guidelines:
546
+ 1. Use {triage_level} response template
547
+ 2. Include safety netting
548
+ 3. Consider cultural factors
549
+ 4. Maintain NHS protocols
550
  <end_of_turn>
551
  <start_of_turn>user
552
  {message}
 
562
  bot.setup_model()
563
  bot.setup_rag_system()
564
 
 
 
 
 
565
 
566
  def handle_conversation(message, history):
567
  try: