feat: AI patient onboarding backend and documentation
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user