Files
aionboarding/ai-patient-onboarding/app/ai/orchestrator.py
T

150 lines
5.6 KiB
Python

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
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)
# Real OpenAI Call if valid API key is set
if OPENAI_API_KEY and OPENAI_API_KEY.strip() not in ["your_openai_api_key", "your_openai_key", ""]:
try:
raw_response = await self.openai.generate_response(
system_prompt=prompt,
user_message=user_message,
)
parsed = json.loads(raw_response)
validated = validate_ai_response(parsed)
return validated.model_dump()
except Exception as e:
print(f"[OpenAI Orchestrator Error]: {e}")
# Fallback simulator for offline development with concise clinical flow
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")
msg_lower = user_message.lower().strip()
is_negative = msg_lower in ["no", "no more", "nothing", "nothing else", "know nothing", "none", "illness none"]
# Fast conclusion if patient says "No" or already had 4 turns
if is_negative or turn_count >= 6:
return {
"reply": "Thank you. I have recorded your intake details for the doctor to review.",
"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":
if code == "cardiology":
reply = "Could you please share what cardiac or chest symptoms you are experiencing?"
else:
reply = "Could you please describe what primary symptoms you are experiencing today?"
return {
"reply": reply,
"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":
reply = "How long have you had these symptoms, and have you taken any medicines?"
return {
"reply": reply,
"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":
reply = "Thank you. Do you have any known drug allergies or existing health conditions?"
return {
"reply": reply,
"next_stage": "allergies",
"state_updates": {
"reason_for_visit": None,
"symptoms": [],
"medical_history": [],
"medications": [user_message] if not is_negative else [],
"allergies": []
},
"completed": False
}
else:
return {
"reply": "Thank you. I have recorded your intake details for the doctor to review.",
"next_stage": "confirmation",
"state_updates": {
"reason_for_visit": None,
"symptoms": [],
"medical_history": [],
"medications": [],
"allergies": ["None"] if is_negative else [user_message]
},
"completed": True
}