feat: complete production hardening implementation, specialty canonicalization, google-genai migration, voice reliability, sqlite concurrency, and test suite consolidation
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
"""
|
||||
Medication extraction engine supporting structured dosage, frequency, and confirmed_none status.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Dict, Any, List, Optional, Union
|
||||
|
||||
KNOWN_MED_PATTERNS = [
|
||||
(r"(metformin(?:\s+\d+\s*mg)?(?:\s+twice\s+a\s+day)?)", "Metformin"),
|
||||
(r"(paracetamol(?:\s+\d+\s*mg)?)", "Paracetamol"),
|
||||
(r"(dolo(?:\s*650)?)", "Dolo 650 (Paracetamol)"),
|
||||
(r"(pantocid|pan-d|pan 40|omez|omeprazole)", "Pantoprazole / Antacid"),
|
||||
(r"(telmisartan|telma\s*\d+)", "Telmisartan (BP)"),
|
||||
(r"(amlodipine|amlong\s*\d+)", "Amlodipine (BP)"),
|
||||
(r"((?:bp|பிபி|blood\s*pressure)\s*(?:மாத்திரை|medicine|tablet|tablets|மருந்து))", "BP Medication"),
|
||||
(r"((?:sugar|சுகர்|சர்க்கரை)\s*(?:மாத்திரை|medicine|tablet|tablets|மருந்து))", "Diabetes Medication"),
|
||||
(r"((?:thyroid|தைராய்டு)\s*(?:மாத்திரை|medicine|tablet|tablets|மருந்து))", "Thyroid Medication"),
|
||||
]
|
||||
|
||||
|
||||
def extract_medications(
|
||||
message: str,
|
||||
normalized_msg: str,
|
||||
last_ai_message: Optional[str] = None,
|
||||
is_allergy_utterance: bool = False
|
||||
) -> Optional[Union[List[Dict[str, Any]], Dict[str, Any]]]:
|
||||
"""
|
||||
Extracts structured medications or confirmed_none container.
|
||||
"""
|
||||
msg_lower = normalized_msg.lower()
|
||||
|
||||
# Check for explicit negation of medicines
|
||||
neg_phrases = [
|
||||
"no medicines", "no medication", "don't take any medicine", "don't take medicines",
|
||||
"no tablets", "not taking any medicine", "no daily medicines", "no regular medicines",
|
||||
"மாத்திரை எதுவும் இல்லை", "எந்த மாத்திரையும் சாப்பிடல", "மருந்து எதுவும் இல்லை",
|
||||
"कोई दवा नहीं", "दवाई नहीं लेते", "दवा नहीं लेता", "ఏ మందులు లేవు", "ಯಾವ ಮಾತ್ರೆ ಇಲ್ಲ"
|
||||
]
|
||||
if any(neg in msg_lower for neg in neg_phrases):
|
||||
return {"status": "confirmed_none", "items": []}
|
||||
|
||||
meds: List[Dict[str, Any]] = []
|
||||
|
||||
# Known medicine matchers
|
||||
for pat, med_label in KNOWN_MED_PATTERNS:
|
||||
m_match = re.search(pat, msg_lower)
|
||||
if m_match:
|
||||
matched_str = m_match.group(1).strip()
|
||||
med_obj: Dict[str, Any] = {"name": med_label}
|
||||
|
||||
dosage_m = re.search(r"(\d+\s*mg|\d+\s*ml)", matched_str)
|
||||
if dosage_m:
|
||||
med_obj["dosage"] = dosage_m.group(1).strip()
|
||||
|
||||
freq_m = re.search(r"(twice\s+a\s+day|once\s+a\s+day|\d+\s+times\s+a\s+day|daily|twice)", matched_str)
|
||||
if freq_m:
|
||||
med_obj["frequency"] = freq_m.group(1).strip()
|
||||
|
||||
if not any(x.get("name") == med_obj["name"] for x in meds):
|
||||
meds.append(med_obj)
|
||||
|
||||
# Generic medicine indicator matchers (only if not an allergy utterance)
|
||||
if not meds and not is_allergy_utterance:
|
||||
generic_pat = r"(tablets|goli|mathirai|மாத்திரை|மருந்து|दवाई|दवा|మాత్రలు|ಮಾತ್ರೆಗಳು)"
|
||||
if re.search(generic_pat, msg_lower) and any(verb in msg_lower for verb in ["take", "taking", "சாப்பிடுறேன்", "சாப்பிட்டேன்", "வாங்குறேன்", "लेता", "लेती", "వాడుతున్నాను"]):
|
||||
meds.append({"name": "Unspecified medication"})
|
||||
|
||||
return meds if meds else None
|
||||
Reference in New Issue
Block a user