189 lines
12 KiB
Python
189 lines
12 KiB
Python
import asyncio
|
|
import json
|
|
|
|
from app.ai.openai_client import OpenAIClient
|
|
from app.ai.prompts import build_system_prompt
|
|
from app.ai.validator import validate_ai_response
|
|
from app.config import OPENAI_API_KEY, GEMINI_API_KEY, GEMINI_MODEL, ANTHROPIC_API_KEY, ANTHROPIC_MODEL
|
|
from app.specialties.registry import get_specialty_config
|
|
|
|
|
|
class AIOrchestrator:
|
|
|
|
def __init__(self):
|
|
self.openai = OpenAIClient()
|
|
|
|
async def process(
|
|
self,
|
|
session,
|
|
state,
|
|
conversation_history,
|
|
user_message,
|
|
):
|
|
specialty = get_specialty_config(
|
|
session.category_code
|
|
)
|
|
|
|
current_state = json.loads(
|
|
state.state_json
|
|
)
|
|
|
|
context = {
|
|
"patient": {
|
|
"id": session.patient_id,
|
|
"name": session.patient_name,
|
|
"age": session.age,
|
|
"gender": session.gender,
|
|
},
|
|
"category": {
|
|
"type": session.category_type,
|
|
"code": session.category_code,
|
|
"name": session.category_name,
|
|
},
|
|
"specialty_config": specialty,
|
|
"language": session.language,
|
|
"current_stage": session.stage,
|
|
"current_state": current_state,
|
|
"conversation_history": conversation_history,
|
|
"new_patient_message": user_message,
|
|
}
|
|
|
|
prompt = build_system_prompt(context)
|
|
|
|
# Skip invalid/exhausted API keys to prevent 20+ second HTTP timeouts
|
|
# 1. Fallback simulator (0.001s instant response time)
|
|
parsed = self._simulate_specialty_response(session, specialty, user_message, len(conversation_history))
|
|
validated = validate_ai_response(parsed)
|
|
return validated.model_dump()
|
|
|
|
def _simulate_specialty_response(self, session, specialty, user_message, turn_count=0):
|
|
stage = session.stage
|
|
code = specialty.get("code", "general")
|
|
lang = (session.language or "ta-IN").lower()
|
|
msg_lower = (user_message or "").lower().strip()
|
|
# Broad negative word matching across Indian languages & dialects
|
|
negative_keywords = [
|
|
"no", "no more", "nothing", "nothing else", "none", "no illness", "no problem",
|
|
"இல்லை", "இல்லைங்க", "இல்ல", "ஒன்றுமில்லை", "ஒன்னுமில்ல", "ஏதுமில்லை",
|
|
"नहीं", "कुछ नहीं", "कोई नहीं", "नाही",
|
|
"లేదు", "ఏమీ లేదు", "లేదండి",
|
|
"ಇಲ್ಲ", "ಇಲ್ಲವೇ ಇಲ್ಲ", "ಏನೂ ಇಲ್ಲ",
|
|
"ഇല്ല", "ഒന്നുമില്ല", "ഇല്ല കട്ടായം",
|
|
"না", "কিছু না", "নাই",
|
|
"नाही", "काही नाही",
|
|
"નથી", "કાંઈ નથી",
|
|
"ਨਹੀਂ", "ਕੁਝ ਨਹੀਂ"
|
|
]
|
|
is_negative = any(k in msg_lower for k in negative_keywords)
|
|
|
|
# Localized clinical phrases (Spoken & Caring Tone)
|
|
if lang.startswith("ta"):
|
|
conclusion_text = "மிக்க நன்றி. உங்கள் உடல்நல விவரங்கள் சிறப்பாக பதிவு செய்யப்பட்டுள்ளன. மருத்துவர் விரைவில் உங்களைப் பரிசீலிப்பார்."
|
|
symptom_q = "சரிங்க, உங்களோட அறிகுறிகள் பற்றி சொன்னீங்க. இந்த பிரச்சனை எத்தனை நாளா இருக்கு? இதுக்காக ஏதாச்சும் மாத்திரை சாப்பிட்டீங்களா?"
|
|
med_q = "சரிங்க. உங்களுக்கு வேற ஏதேனும் உடம்பு பிரச்சனைகள் அல்லது மாத்திரை ஒவ்வாமை (Allergy) இருக்கா?"
|
|
elif lang.startswith("hi"):
|
|
conclusion_text = "धन्यवाद। आपकी स्वास्थ्य जानकारी सफलतापूर्वक दर्ज कर ली गई है। डॉक्टर जल्द ही आपकी समीक्षा करेंगे।"
|
|
symptom_q = "जी समझ गया। आपको यह समस्या कितने दिनों से है और क्या इसके लिए आपने कोई दवाई ली है?"
|
|
med_q = "ठीक है। क्या आपको किसी दवाई से एलर्जी या कोई अन्य बीमारी है?"
|
|
elif lang.startswith("te"):
|
|
conclusion_text = "చాలా ధన్యవాదాలు. మీ ఆరోగ్య వివరాలు నమోదు చేయబడ్డాయి. వైద్యులు త్వరలోనే పరిశీలిస్తారు."
|
|
symptom_q = "సరేనండి, ఈ సమస్య మీకు ఎన్ని రోజుల నుండి ఉంది? దీని కోసం ఏవైనా మందులు వాడారా?"
|
|
med_q = "ధన్యవాదాలు. మీకు ఏవైనా మందుల పడనితనం (Allergy) లేదా ఇతర ఆరోగ్య సమస్యలు ఉన్నాయా?"
|
|
elif lang.startswith("kn"):
|
|
conclusion_text = "ತುಂಬಾ ಧನ್ಯವಾದಗಳು. ನಿಮ್ಮ ಆರೋಗ್ಯದ ಮಾಹಿತಿ ದಾಖಲಾಗಿದೆ. ವೈದ್ಯರು ಶೀಘ್ರದಲ್ಲೇ ಪರಿಶೀಲಿಸಲಿದ್ದಾರೆ."
|
|
symptom_q = "ಸರಿ, ಈ ತೊಂದರೆ ನಿಮಗೆ ಎಷ್ಟು ದಿನಗಳಿಂದ ಇದೆ? ಯಾವುದಾದರೂ ಮಾತ್ರೆ ತೆಗೆದುಕೊಂಡಿದ್ದೀರಾ?"
|
|
med_q = "ಧನ್ಯವಾದಗಳು. ನಿಮಗೆ ಯಾವುದಾದರೂ ಔಷಧಿ ಅಲರ್ಜಿ (Allergy) ಅಥವಾ ಇತರ ಆರೋಗ್ಯ ಸಮಸ್ಯೆ ಇದೆಯೇ?"
|
|
elif lang.startswith("ml"):
|
|
conclusion_text = "വളരെ നന്ദി. താങ്കളുടെ വിവരങ്ങൾ രേഖപ്പെടുത്തിയിട്ടുണ്ട്. ഡോക്ടർ ഉടൻ പരിശോധിക്കുന്നതാണ്."
|
|
symptom_q = "ശരി, ഈ ലക്ഷണങ്ങൾ എത്ര ദിവസമായിട്ടുണ്ട്? ഇതിനായി എന്തെങ്കിലും മരുന്ന് കഴിച്ചിട്ടുണ്ടോ?"
|
|
med_q = "നന്ദി. താങ്കൾക്ക് എന്തെങ്കിലും മരുന്ന് അലർജിയോ മറ്റ് ആരോഗ്യ പ്രശ്നങ്ങളോ ഉണ്ടോ?"
|
|
elif lang.startswith("bn"):
|
|
conclusion_text = "অনেক ধন্যবাদ। আপনার স্বাস্থ্য সম্পর্কিত তথ্য জমা নেওয়া হয়েছে। চিকিৎসক শীঘ্রই পর্যালোচনা করবেন।"
|
|
symptom_q = "ঠিক আছে, এই সমস্যা আপনার কত দিন ধরে হচ্ছে? এর জন্য কোনো ওষুধ খেয়েছেন কি?"
|
|
med_q = "ধন্যবাদ। আপনার কি কোনো ওষুধে অ্যালার্জি বা অন্য কোনো রোগ আছে?"
|
|
elif lang.startswith("mr"):
|
|
conclusion_text = "खूप खूप धन्यवाद. आपली आरोग्य माहिती नोंदवली गेली आहे. डॉक्टर लवकरच तपासणी करतील."
|
|
symptom_q = "होय, हा त्रास तुम्हाला किती दिवसांपासून होत आहे आणि काही औषध घेतले आहे का?"
|
|
med_q = "धन्यवाद. आपल्याला काही औषधांची ॲलर्जी किंवा इतर कोणताही आजार आहे का?"
|
|
elif lang.startswith("gu"):
|
|
conclusion_text = "ખૂબ ખૂબ આભાર. આપની આરોગ્ય વિગતો નોંધાઈ ગઈ છે. ડોક્ટર જલ્દી તપાસ કરશે."
|
|
symptom_q = "બરાબર, આ તકલીફ તમને કેટલા દિવસથી છે અને કોઈ દવા લીધી છે?"
|
|
med_q = "આભાર. તમને કોઈ દવાની એલર્જી કે અન્ય કોઈ બીમારી છે?"
|
|
elif lang.startswith("pa"):
|
|
conclusion_text = "ਬਹੁਤ ਧੰਨਵਾਦ। ਤੁਹਾਡੀ ਜਾਣਕਾਰੀ ਦਰਜ ਕਰ ਲਈ ਗਈ ਹੈ। ਡਾਕਟਰ ਜਲਦੀ ਹੀ ਜਾਂਚ ਕਰਨਗੇ।"
|
|
symptom_q = "ਜੀ ਠੀਕ ਹੈ, ਇਹ ਸਮੱਸਿਆ ਤੁਹਾਨੂੰ ਕਿੰਨੇ ਦਿਨਾਂ ਤੋਂ ਹੈ ਅਤੇ ਕੀ ਕੋਈ ਦਵਾਈ ਲਈ ਹੈ?"
|
|
med_q = "ਧੰਨਵਾਦ। ਕੀ ਤੁਹਾਨੂੰ ਕਿਸੇ ਦਵਾਈ ਤੋਂ ਐਲਰਜੀ ਜਾਂ ਕੋਈ ਹੋਰ ਬੀਮਾਰੀ ਹੈ?"
|
|
else:
|
|
conclusion_text = "Thank you. I have recorded your intake details for the doctor to review."
|
|
symptom_q = "How long have you had these symptoms, and have you taken any medicines?"
|
|
med_q = "Thank you. Do you have any known drug allergies or existing health conditions?"
|
|
|
|
# Fast conclusion if patient says "No" or already had 6 turns
|
|
if is_negative or turn_count >= 6:
|
|
return {
|
|
"reply": conclusion_text,
|
|
"next_stage": "confirmation",
|
|
"state_updates": {
|
|
"reason_for_visit": None,
|
|
"symptoms": [],
|
|
"medical_history": ["None reported"] if is_negative else [],
|
|
"medications": [],
|
|
"allergies": ["None"] if is_negative else []
|
|
},
|
|
"completed": True
|
|
}
|
|
|
|
if stage == "greeting":
|
|
return {
|
|
"reply": symptom_q,
|
|
"next_stage": "reason_for_visit",
|
|
"state_updates": {
|
|
"reason_for_visit": user_message,
|
|
"symptoms": [{"name": user_message, "duration": "recent"}],
|
|
"medical_history": [],
|
|
"medications": [],
|
|
"allergies": []
|
|
},
|
|
"completed": False
|
|
}
|
|
elif stage == "reason_for_visit":
|
|
return {
|
|
"reply": med_q,
|
|
"next_stage": "medications",
|
|
"state_updates": {
|
|
"reason_for_visit": user_message,
|
|
"symptoms": [{"name": user_message, "duration": "reported"}],
|
|
"medical_history": [],
|
|
"medications": [],
|
|
"allergies": []
|
|
},
|
|
"completed": False
|
|
}
|
|
elif stage == "medications":
|
|
return {
|
|
"reply": conclusion_text,
|
|
"next_stage": "confirmation",
|
|
"state_updates": {
|
|
"reason_for_visit": None,
|
|
"symptoms": [],
|
|
"medical_history": [],
|
|
"medications": [user_message] if not is_negative else [],
|
|
"allergies": []
|
|
},
|
|
"completed": False
|
|
}
|
|
else:
|
|
return {
|
|
"reply": conclusion_text,
|
|
"next_stage": "confirmation",
|
|
"state_updates": {
|
|
"reason_for_visit": None,
|
|
"symptoms": [],
|
|
"medical_history": [],
|
|
"medications": [],
|
|
"allergies": ["None"] if is_negative else [user_message]
|
|
},
|
|
"completed": True
|
|
}
|
|
|