Seth0330 commited on
Commit
afd64ba
·
verified ·
1 Parent(s): cf6097f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +172 -92
app.py CHANGED
@@ -20,14 +20,14 @@ st.set_page_config(
20
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
21
  client = OpenAI(api_key=OPENAI_API_KEY) if OPENAI_API_KEY else None
22
 
23
- VISION_MODEL = "gpt-4.1-mini" # vision-capable OpenAI model
24
  REASONING_MODEL = "gpt-4.1-mini" # reasoning / agent model
25
  ASR_MODEL = "whisper-1" # transcription model
26
 
27
  # Health Canada Drug Product Database API
28
  DPD_BASE_URL = "https://health-products.canada.ca/api/drug/drugproduct"
29
 
30
- # Recalls & Safety Alerts JSON feed (example; can override via env if GC changes path)
31
  RECALLS_FEED_URL = os.getenv(
32
  "RECALLS_FEED_URL",
33
  "https://recalls-rappels.canada.ca/static-data/items-en.json"
@@ -36,7 +36,7 @@ RECALLS_FEED_URL = os.getenv(
36
  # CIHI wait-times info (general reference)
37
  WAIT_TIMES_INFO_URL = "https://www.cihi.ca/en/topics/access-and-wait-times"
38
 
39
- # Postal code to province mapping (first letter)
40
  POSTAL_PREFIX_TO_PROVINCE = {
41
  "A": "Newfoundland and Labrador",
42
  "B": "Nova Scotia",
@@ -73,7 +73,7 @@ def safe_get_json(url, params=None, timeout=6):
73
  return None
74
 
75
 
76
- def shorten(text, max_chars=400):
77
  if not text:
78
  return ""
79
  text = text.strip()
@@ -107,12 +107,12 @@ def tool_region_context(postal_code: str) -> str:
107
  )
108
 
109
  telehealth_note = (
110
- f"In {province}, suggest the official provincial Telehealth / 811-style nurse advice line "
111
- "and Ministry of Health website for region-specific guidance."
112
  )
113
  wait_note = (
114
- "For non-urgent issues, users can check provincial or regional health authority pages and CIHI indicators "
115
- f"for access and wait-time information. Reference (general): {WAIT_TIMES_INFO_URL}"
116
  )
117
 
118
  return (
@@ -122,6 +122,74 @@ def tool_region_context(postal_code: str) -> str:
122
  )
123
 
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  # =========================
126
  # DRUG PRODUCT LOOKUP (DPD)
127
  # =========================
@@ -156,7 +224,7 @@ def tool_lookup_drug_products(candidates):
156
  )
157
 
158
  found_lines.append(
159
- "For definitive product information, users must consult the official Health Canada Drug Product Database."
160
  )
161
  return "\n".join(found_lines)
162
 
@@ -172,7 +240,6 @@ def tool_get_recent_recalls_snippet():
172
  if isinstance(data, list):
173
  items = data[:5]
174
  elif isinstance(data, dict):
175
- # some feeds use { items: [...] }
176
  items = (data.get("items") or data.get("results") or [])[:5]
177
 
178
  if not items:
@@ -181,7 +248,7 @@ def tool_get_recent_recalls_snippet():
181
  "Recalls and Safety Alerts website for up-to-date information."
182
  )
183
 
184
- lines = ["Recent recalls & safety alerts (high-level snapshot):"]
185
  for item in items:
186
  title = (
187
  item.get("title")
@@ -191,9 +258,10 @@ def tool_get_recent_recalls_snippet():
191
  )
192
  date = item.get("date_published") or item.get("date") or ""
193
  category = item.get("category") or item.get("type") or ""
194
- lines.append(f"- {shorten(title, 90)} ({category}, {date})")
 
195
  lines.append(
196
- "For full details or to check a specific product, direct users to the official Recalls and Safety Alerts portal."
197
  )
198
  return "\n".join(lines)
199
 
@@ -205,11 +273,11 @@ def tool_get_recent_recalls_snippet():
205
  def tool_get_wait_times_awareness():
206
  return textwrap.dedent(f"""
207
  Use Canadian open-data wait-time indicators conceptually:
208
- - CIHI and several provinces publish average wait-time dashboards.
209
- - These are not real-time triage.
210
  Guidance:
211
- - For mild/non-urgent issues: consider local clinics or urgent care; check provincial resources.
212
- - For red-flag or severe symptoms: skip tools and go directly to ER or call 911.
213
  General reference: {WAIT_TIMES_INFO_URL}
214
  """).strip()
215
 
@@ -241,12 +309,12 @@ def call_vision_summarizer(image_bytes: bytes) -> str:
241
 
242
  prompt = (
243
  "You are a cautious Canadian health-information assistant.\n"
244
- "Describe only what is visibly observable in neutral terms.\n"
245
- "- If skin: describe general appearance (location, size, colour, pattern). Do NOT name diseases.\n"
246
- "- If pill/box: mention visible drug name/strength/markings if legible.\n"
247
- "- If document: say what type (e.g., lab report, appointment letter) without copying identifiers.\n"
248
- "- If irrelevant/unclear: say that it is not medically interpretable.\n"
249
- "Never diagnose. Never prescribe. Limit to about 80-100 words."
250
  )
251
 
252
  try:
@@ -302,11 +370,12 @@ def call_reasoning_agent(
302
  recalls_context: str,
303
  wait_times_context: str,
304
  region_context: str,
 
305
  ) -> str:
306
  if not client:
307
  return (
308
  "AI backend not configured. With a valid API key, this agent would combine your inputs and "
309
- "open-data context into cautious, non-diagnostic guidance."
310
  )
311
 
312
  narrative_parts = []
@@ -321,23 +390,43 @@ def call_reasoning_agent(
321
  system_prompt = """
322
  You are CareCall AI, an agentic Canadian health information assistant.
323
 
324
- Rules:
325
- - Do NOT diagnose.
326
- - Do NOT prescribe or give dosing.
327
- - Do NOT claim exact real-time wait times.
328
- - Use only the information and tool outputs provided.
329
- - Use open-data-style context (Drug Product DB, recalls, wait-time awareness, region) to improve safety.
330
- - Map concerns to broad categories only (e.g., irritation vs infection vs allergy vs medication vs admin).
331
- - Give practical next steps in Canada:
332
- * self-care when clearly mild,
333
- * pharmacist / family doctor / walk-in clinic,
334
- * provincial Telehealth / nurse line,
335
- * ER / 911 for red-flag symptoms.
336
- - Red flags (chest pain, breathing trouble, stroke signs, severe bleeding, suicidal thoughts,
337
- major trauma, high fever with stiff neck, rapidly worsening symptoms, etc.) -> clearly say ER/911.
338
- - Mention official sources: Health Canada, Public Health Agency of Canada, CIHI,
339
- and the user's provincial health services.
340
- - Maximum length: 350 words. Clear and calm.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  """
342
 
343
  user_prompt = f"""
@@ -358,22 +447,25 @@ INPUT CONTEXT
358
  5) Wait-time awareness context:
359
  {wait_times_context}
360
 
361
- 6) Region (postal-code-based) context:
362
  {region_context}
363
 
 
 
 
364
  TASK
365
 
366
- Based only on this information:
367
-
368
- 1. Briefly summarize what the user seems concerned about (neutral; no diagnosis).
369
- 2. Briefly outline broad possible categories (without asserting any specific disease).
370
- 3. Provide clear next steps in bullet form, aligned with Canadian context and region info where available:
371
- - when self-care might be reasonable,
372
- - when to speak with a pharmacist, family doctor, or walk-in clinic,
373
- - when to use provincial Telehealth / nurse lines,
374
- - when to go to ER or call 911.
375
- 4. If medication/recall context looks relevant, remind them to confirm via official Health Canada resources.
376
- 5. End with a short disclaimer that this is informational only and not medical care.
377
  """
378
 
379
  try:
@@ -389,7 +481,7 @@ Based only on this information:
389
  except Exception as e:
390
  return (
391
  f"(Reasoning agent unavailable: {e})\n\n"
392
- "Please contact a licensed provider, Telehealth service, or emergency care as appropriate."
393
  )
394
 
395
 
@@ -401,37 +493,35 @@ st.title("CareCall AI (Canada)")
401
  st.caption("Agentic, vision + voice + postal-aware health info companion. Not a doctor. Not a diagnosis.")
402
 
403
  if not OPENAI_API_KEY:
404
- st.warning("Set OPENAI_API_KEY in your Hugging Face Space secrets to enable the AI backend.")
405
 
406
  st.markdown(
407
  """
408
- **How it works**
409
-
410
- 1. Optionally enter your **Canadian postal code** (to tailor guidance to your province).
411
- 2. Optionally upload a **photo** (rash, pill bottle, letter, etc.).
412
- 3. Optionally upload a **voice note**, and/or type a **short description**.
413
- 4. The agent:
414
- - analyzes the image with a vision model (safely),
415
- - transcribes your voice with Whisper,
416
- - looks up related info via:
417
- - Health Canada Drug Product Database (high-level),
418
- - Recalls & Safety Alerts feed (snapshot),
419
- - CIHI/provincial wait-time context (awareness),
420
- - then generates structured, non-diagnostic next steps.
421
  """
422
  )
423
 
424
  # 1) Postal code
425
  st.markdown("### 1. Postal code (optional, Canada only)")
426
  postal_code = st.text_input(
427
- "Canadian postal code (e.g., M5V 2T6). Leave blank to keep guidance general.",
428
  max_chars=7,
429
  )
430
 
431
  # 2) Image upload
432
  st.markdown("### 2. Upload an image (optional)")
433
  image_file = st.file_uploader(
434
- "Upload a photo (JPG/PNG). Avoid very identifying or explicit content.",
435
  type=["jpg", "jpeg", "png"],
436
  accept_multiple_files=False,
437
  )
@@ -439,7 +529,7 @@ image_file = st.file_uploader(
439
  image_bytes = None
440
  if image_file is not None:
441
  try:
442
- # Convert to RGB to avoid RGBA -> JPEG error
443
  img = Image.open(image_file).convert("RGB")
444
  st.image(img, caption="Image received", use_container_width=True)
445
  buf = io.BytesIO()
@@ -461,7 +551,7 @@ audio_file = st.file_uploader(
461
  st.markdown("### 4. Or type a short description")
462
  user_text = st.text_area(
463
  "Describe what’s going on:",
464
- placeholder='Example: "Red itchy patch on forearm for 3 days, mild burning, no fever, using a new soap."',
465
  height=120,
466
  )
467
 
@@ -482,7 +572,7 @@ if st.button("Run CareCall Agent"):
482
  if audio_file is not None:
483
  voice_text = call_asr(audio_file)
484
 
485
- # Candidate terms (for Drug DB)
486
  combined_for_terms = " ".join(
487
  t for t in [user_text or "", voice_text or "", vision_summary or ""] if t
488
  )
@@ -492,14 +582,20 @@ if st.button("Run CareCall Agent"):
492
  # Recalls
493
  recalls_context = tool_get_recent_recalls_snippet()
494
 
495
- # Wait-times awareness
496
  wait_times_context = tool_get_wait_times_awareness()
497
 
498
  # Region context
499
  region_context = (
500
  tool_region_context(postal_code)
501
  if postal_code
502
- else "No postal code provided. Use Canada-wide guidance and suggest provincial resources."
 
 
 
 
 
 
503
  )
504
 
505
  # Final reasoning
@@ -511,24 +607,8 @@ if st.button("Run CareCall Agent"):
511
  recalls_context=recalls_context,
512
  wait_times_context=wait_times_context,
513
  region_context=region_context,
 
514
  )
515
 
516
  st.markdown("### CareCall AI Summary (Informational Only)")
517
  st.write(final_answer)
518
-
519
- st.markdown(
520
- """
521
- ---
522
- **Critical Safety Notice**
523
-
524
- - This tool does **not** provide medical diagnoses, prescriptions, or emergency triage.
525
- - It may be incomplete or incorrect and must **not** replace a doctor, nurse, pharmacist,
526
- Telehealth service, or emergency department.
527
- - If you have severe or rapidly worsening symptoms (chest pain, trouble breathing, signs of stroke,
528
- heavy bleeding, suicidal thoughts, major injury, high fever with stiff neck, etc.),
529
- call **911** or go to the **nearest emergency department** immediately.
530
- - For trusted information, consult:
531
- Health Canada, the Public Health Agency of Canada, CIHI,
532
- and your provincial/territorial health services.
533
- """
534
- )
 
20
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
21
  client = OpenAI(api_key=OPENAI_API_KEY) if OPENAI_API_KEY else None
22
 
23
+ VISION_MODEL = "gpt-4.1-mini" # vision-capable model
24
  REASONING_MODEL = "gpt-4.1-mini" # reasoning / agent model
25
  ASR_MODEL = "whisper-1" # transcription model
26
 
27
  # Health Canada Drug Product Database API
28
  DPD_BASE_URL = "https://health-products.canada.ca/api/drug/drugproduct"
29
 
30
+ # Recalls & Safety Alerts JSON feed (can override with env variable if path changes)
31
  RECALLS_FEED_URL = os.getenv(
32
  "RECALLS_FEED_URL",
33
  "https://recalls-rappels.canada.ca/static-data/items-en.json"
 
36
  # CIHI wait-times info (general reference)
37
  WAIT_TIMES_INFO_URL = "https://www.cihi.ca/en/topics/access-and-wait-times"
38
 
39
+ # Postal code to province mapping (by first letter)
40
  POSTAL_PREFIX_TO_PROVINCE = {
41
  "A": "Newfoundland and Labrador",
42
  "B": "Nova Scotia",
 
73
  return None
74
 
75
 
76
+ def shorten(text, max_chars=280):
77
  if not text:
78
  return ""
79
  text = text.strip()
 
107
  )
108
 
109
  telehealth_note = (
110
+ f"In {province}, advise the user to use the official provincial Telehealth or 811-style nurse advice line "
111
+ "for real-time clinical advice."
112
  )
113
  wait_note = (
114
+ "For non-urgent issues, they can check provincial or regional health authority websites and CIHI indicators "
115
+ f"for access/wait-time information. Reference (general): {WAIT_TIMES_INFO_URL}"
116
  )
117
 
118
  return (
 
122
  )
123
 
124
 
125
+ def tool_find_nearby_clinics_and_waits(postal_code: str) -> str:
126
+ """
127
+ Province-aware pointers to official 'find a clinic' / wait-time resources.
128
+ Not real-time; we send the user to authoritative tools.
129
+ """
130
+ province = infer_province_from_postal(postal_code)
131
+ if not postal_code or not province:
132
+ return (
133
+ "No precise local clinic data. Suggest the user search 'walk-in clinic near me' plus their city, and use "
134
+ "their provincial health website or health authority finder for verified locations and hours."
135
+ )
136
+
137
+ base = f"For users in {province}, suggest these options to find nearby care and typical waits:\n"
138
+ province_links = []
139
+
140
+ # Very high-level, non-exhaustive hints (you can refine for your production app)
141
+ if province == "Ontario":
142
+ province_links.append(
143
+ "- Use Ontario's official 'Health811' and 'Find a clinic/hospital' tools from Ontario Health."
144
+ )
145
+ elif province == "British Columbia":
146
+ province_links.append(
147
+ "- Use HealthLink BC (811) and the 'Find Health Services' directory for clinics and urgent care."
148
+ )
149
+ elif province == "Alberta":
150
+ province_links.append(
151
+ "- Use Alberta Health Services 'Find Healthcare' directory for walk-ins and urgent care clinics."
152
+ )
153
+ elif province == "Quebec":
154
+ province_links.append(
155
+ "- Use your local CISSS/CIUSSS websites and provincial resources (e.g., Bonjour-santé) for clinic bookings."
156
+ )
157
+ elif province == "Manitoba":
158
+ province_links.append(
159
+ "- Use Manitoba Health / regional health authority sites to locate walk-in and primary care clinics."
160
+ )
161
+ elif province == "Saskatchewan":
162
+ province_links.append(
163
+ "- Use Saskatchewan Health Authority tools to find urgent care and clinics."
164
+ )
165
+ elif province == "Nova Scotia":
166
+ province_links.append(
167
+ "- Use Nova Scotia Health 'Find a Location/Service' for primary care and walk-in options."
168
+ )
169
+ elif province == "New Brunswick":
170
+ province_links.append(
171
+ "- Use Horizon / Vitalité Health Network resources for clinics and after-hours care."
172
+ )
173
+ elif province == "Newfoundland and Labrador":
174
+ province_links.append(
175
+ "- Use provincial health authority websites to locate clinics and ERs."
176
+ )
177
+ elif province == "Prince Edward Island":
178
+ province_links.append(
179
+ "- Use Health PEI resources to find walk-in clinics and primary care."
180
+ )
181
+ else:
182
+ province_links.append(
183
+ "- Use your territorial/provincial health authority website and Telehealth for locations and typical waits."
184
+ )
185
+
186
+ province_links.append(
187
+ "- For emergencies or red-flag symptoms, emphasize going to the nearest emergency department or calling 911 immediately."
188
+ )
189
+
190
+ return base + "\n".join(province_links)
191
+
192
+
193
  # =========================
194
  # DRUG PRODUCT LOOKUP (DPD)
195
  # =========================
 
224
  )
225
 
226
  found_lines.append(
227
+ "For definitive product information, they must consult the official Health Canada Drug Product Database."
228
  )
229
  return "\n".join(found_lines)
230
 
 
240
  if isinstance(data, list):
241
  items = data[:5]
242
  elif isinstance(data, dict):
 
243
  items = (data.get("items") or data.get("results") or [])[:5]
244
 
245
  if not items:
 
248
  "Recalls and Safety Alerts website for up-to-date information."
249
  )
250
 
251
+ lines = ["Recent recalls & safety alerts (snapshot):"]
252
  for item in items:
253
  title = (
254
  item.get("title")
 
258
  )
259
  date = item.get("date_published") or item.get("date") or ""
260
  category = item.get("category") or item.get("type") or ""
261
+ lines.append(f"- {shorten(title)} ({category}, {date})")
262
+
263
  lines.append(
264
+ "For details or to check a specific product, direct users to the official Recalls and Safety Alerts portal."
265
  )
266
  return "\n".join(lines)
267
 
 
273
  def tool_get_wait_times_awareness():
274
  return textwrap.dedent(f"""
275
  Use Canadian open-data wait-time indicators conceptually:
276
+ - CIHI and several provinces publish average wait-time dashboards for ER, surgeries, diagnostics.
277
+ - These are not real-time triage tools.
278
  Guidance:
279
+ - For mild issues: local clinics/urgent care may be suitable; check provincial wait-time/clinic-finder tools.
280
+ - For red-flag or severe symptoms: skip online tools and go directly to ER or call 911.
281
  General reference: {WAIT_TIMES_INFO_URL}
282
  """).strip()
283
 
 
309
 
310
  prompt = (
311
  "You are a cautious Canadian health-information assistant.\n"
312
+ "Describe only visible features in neutral terms.\n"
313
+ "- If skin/toenail etc.: describe colour, texture, dryness, cracks, swelling, but DO NOT name diseases.\n"
314
+ "- If medication label: read visible drug name/strength if legible.\n"
315
+ "- If health letter/report: say what type it appears to be, without copying identifiers.\n"
316
+ "- If unclear: say it is not medically interpretable.\n"
317
+ "Never diagnose. Never prescribe. 80-100 words max."
318
  )
319
 
320
  try:
 
370
  recalls_context: str,
371
  wait_times_context: str,
372
  region_context: str,
373
+ nearby_services_context: str,
374
  ) -> str:
375
  if not client:
376
  return (
377
  "AI backend not configured. With a valid API key, this agent would combine your inputs and "
378
+ "open-data context into cautious, structured guidance."
379
  )
380
 
381
  narrative_parts = []
 
390
  system_prompt = """
391
  You are CareCall AI, an agentic Canadian health information assistant.
392
 
393
+ HARD RULES:
394
+ - DO NOT give a medical diagnosis.
395
+ - DO NOT prescribe or specify individual dosing.
396
+ - DO NOT guarantee exact real-time wait times or locations.
397
+ - Use ONLY the provided content and tool outputs (vision summary, DPD, recalls, wait-times context, region info, nearby services guide).
398
+ - You MUST classify guidance into a clear, practical structure without pretending to be a doctor.
399
+
400
+ WHAT YOU SHOULD DO:
401
+
402
+ 1. Identify red-flag indicators (e.g., chest pain, trouble breathing, stroke signs, rapidly spreading infection,
403
+ severe pain, heavy bleeding, high fever with stiff neck, suicidal thoughts, major trauma).
404
+ - If any such red flags are present or strongly implied:
405
+ PRIMARY PATHWAY = ER/911.
406
+ 2. If no red flags and issue seems mild/local (e.g., minor rash, mild toe pain, dry skin, chipped nail, etc.):
407
+ - You may choose PRIMARY PATHWAY = Home care + possibly pharmacist.
408
+ 3. If there is uncertainty, ongoing pain, risk factors (diabetes, immune issues, poor circulation),
409
+ or symptoms that are not clearly mild:
410
+ - You may choose PRIMARY PATHWAY = Clinic / family doctor / Telehealth.
411
+
412
+ ALWAYS:
413
+
414
+ - Output a section called "Primary Recommended Pathway" with ONE of:
415
+ * "Home care likely reasonable (monitor closely)"
416
+ * "Pharmacist / Walk-in clinic / Family doctor recommended"
417
+ * "Call provincial Telehealth / nurse line for guidance"
418
+ * "Go to Emergency / Call 911 now"
419
+ - Then:
420
+ * Give a short explanation for WHY that pathway was chosen.
421
+ * Provide a "Home Care (if appropriate)" section with 3–6 simple, generic measures
422
+ (e.g., keep area clean/dry, rest, elevation, cold compress, OTC pain relief as per label, avoid friction),
423
+ ONLY when not clearly contradicted.
424
+ * Provide "When to seek clinic/Telehealth" with concrete triggers.
425
+ * Provide "When this is an emergency" with explicit red-flag bullets.
426
+ * Mention provincial/nearby resources using the region and nearby-services context.
427
+ * If medications/recalls context is relevant, remind the user to verify via Health Canada DPD and Recalls portal.
428
+ - Keep total answer under ~350 words.
429
+ - Reiterate that this is informational only, not medical care, and that professionals/Telehealth/ER override all advice.
430
  """
431
 
432
  user_prompt = f"""
 
447
  5) Wait-time awareness context:
448
  {wait_times_context}
449
 
450
+ 6) Region (postal code) context:
451
  {region_context}
452
 
453
+ 7) Nearby services & finder resources:
454
+ {nearby_services_context}
455
+
456
  TASK
457
 
458
+ Using ONLY the above, produce a structured response with these sections:
459
+
460
+ 1. "Primary Recommended Pathway": one of the four options (see system rules) + 1–2 sentence reasoning.
461
+ 2. "What this might relate to (in general terms)": 3–5 bullets of broad categories, no diagnoses.
462
+ 3. "Home Care (if appropriate)": 3–6 safe, generic self-care steps OR a note that home care alone is not advised.
463
+ 4. "When to see a Pharmacist / Clinic / Telehealth": 3–6 concrete triggers.
464
+ 5. "When this is an Emergency (ER/911)": bullet list of red-flag situations.
465
+ 6. "Local & Official Resources": 2–5 bullets using the region + nearby-services context and open-data style info.
466
+ 7. "Important Disclaimer": 2–4 lines stating this is informational only and not medical care.
467
+
468
+ Be firm and clear but never overconfident.
469
  """
470
 
471
  try:
 
481
  except Exception as e:
482
  return (
483
  f"(Reasoning agent unavailable: {e})\n\n"
484
+ "Please contact a licensed provider, Telehealth, or emergency services as appropriate."
485
  )
486
 
487
 
 
493
  st.caption("Agentic, vision + voice + postal-aware health info companion. Not a doctor. Not a diagnosis.")
494
 
495
  if not OPENAI_API_KEY:
496
+ st.warning("Set OPENAI_API_KEY in your Space secrets to enable the AI backend.")
497
 
498
  st.markdown(
499
  """
500
+ **How to use**
501
+
502
+ 1. Enter your **Canadian postal code** (optional but helps tailor guidance).
503
+ 2. Upload a **photo** related to your concern (e.g., rash, nail, pill bottle, letter) — optional.
504
+ 3. Upload a **voice note** and/or type a **short description**.
505
+ 4. Click **Run CareCall Agent** to get:
506
+ - A clear **primary recommended pathway**,
507
+ - Safe **home-care tips** when appropriate,
508
+ - Triggers for **clinic/Telehealth**,
509
+ - **Emergency red-flag guidance**,
510
+ - Links to **official & provincial resources**.
 
 
511
  """
512
  )
513
 
514
  # 1) Postal code
515
  st.markdown("### 1. Postal code (optional, Canada only)")
516
  postal_code = st.text_input(
517
+ "Canadian postal code (e.g., M5V 2T6). Leave blank for general guidance.",
518
  max_chars=7,
519
  )
520
 
521
  # 2) Image upload
522
  st.markdown("### 2. Upload an image (optional)")
523
  image_file = st.file_uploader(
524
+ "Upload a photo (JPG/PNG). Avoid highly identifying or explicit content.",
525
  type=["jpg", "jpeg", "png"],
526
  accept_multiple_files=False,
527
  )
 
529
  image_bytes = None
530
  if image_file is not None:
531
  try:
532
+ # Convert to RGB so we can safely save as JPEG (avoids RGBA error)
533
  img = Image.open(image_file).convert("RGB")
534
  st.image(img, caption="Image received", use_container_width=True)
535
  buf = io.BytesIO()
 
551
  st.markdown("### 4. Or type a short description")
552
  user_text = st.text_area(
553
  "Describe what’s going on:",
554
+ placeholder='Example: "Pain and discoloration around big toenail when wearing shoes for 1 week, no fever, no major swelling."',
555
  height=120,
556
  )
557
 
 
572
  if audio_file is not None:
573
  voice_text = call_asr(audio_file)
574
 
575
+ # Candidate terms for Drug DB
576
  combined_for_terms = " ".join(
577
  t for t in [user_text or "", voice_text or "", vision_summary or ""] if t
578
  )
 
582
  # Recalls
583
  recalls_context = tool_get_recent_recalls_snippet()
584
 
585
+ # Wait-time awareness
586
  wait_times_context = tool_get_wait_times_awareness()
587
 
588
  # Region context
589
  region_context = (
590
  tool_region_context(postal_code)
591
  if postal_code
592
+ else "No postal code provided. Use Canada-wide guidance and mention provincial resources generally."
593
+ )
594
+
595
+ # Nearby clinics / wait finder resources
596
+ nearby_services_context = tool_find_nearby_clinics_and_waits(postal_code) if postal_code else (
597
+ "No postal code. Suggest searchable options like 'walk-in clinic near me' plus city, "
598
+ "and provincial clinic/ER finder tools."
599
  )
600
 
601
  # Final reasoning
 
607
  recalls_context=recalls_context,
608
  wait_times_context=wait_times_context,
609
  region_context=region_context,
610
+ nearby_services_context=nearby_services_context,
611
  )
612
 
613
  st.markdown("### CareCall AI Summary (Informational Only)")
614
  st.write(final_answer)