from pydantic import BaseModel from typing import List, Optional from datetime import datetime # ═══════════════════════════════════════════════════════════════════════════════ # AUTH SCHEMAS # ═══════════════════════════════════════════════════════════════════════════════ class UserRegistration(BaseModel): """User registration request""" email: str password: str full_name: Optional[str] = "" dob: Optional[str] = "" sex: Optional[str] = "" medical_history: Optional[str] = "" geolocation: Optional[str] = "" class UserCredentials(BaseModel): """User login credentials""" email: str password: str class UserProfile(BaseModel): """User profile information""" user_id: str email: str full_name: Optional[str] = "" dob: Optional[str] = "" sex: Optional[str] = "" medical_history: Optional[str] = "" geolocation: Optional[str] = "" created_at: str conversation_count: int = 0 class UserProfileUpdate(BaseModel): """User profile update request""" email: Optional[str] = "" full_name: Optional[str] = "" dob: Optional[str] = "" sex: Optional[str] = "" medical_history: Optional[str] = "" geolocation: Optional[str] = "" class PasswordChange(BaseModel): """Password change request""" old_password: str new_password: str class TokenResponse(BaseModel): """JWT token response""" access_token: str token_type: str = "bearer" user: UserProfile class AuthResponse(BaseModel): """Generic auth response""" success: bool message: str data: Optional[dict] = None class Conversation(BaseModel): """Conversation metadata""" conversation_id: str user_id: str title: str created_at: str last_updated: str message_count: int = 0 has_diagnosis: bool = False last_message_preview: str = "" class ConversationMessage(BaseModel): """Individual message in conversation""" timestamp: str role: str # "user" or "assistant" content: str language: Optional[str] = "en" symptoms: list[str] = [] quick_replies: list[str] = [] class ConversationDetail(BaseModel): """Full conversation with messages and diagnosis""" conversation_id: str user_id: str title: str created_at: str messages: list[ConversationMessage] = [] diagnosis: Optional[dict] = None recommendations: Optional[str] = None # === INPUT === class PatientInfo(BaseModel): """Reçu depuis le frontend, contient les infos du patient.""" age: int = 0 sex: str = "Male" medical_history: str = "" geolocation: str = "" class ChatMessage(BaseModel): """Message individuel dans l'historique de chat, avec un rôle (user ou assistant) et le contenu textuel.""" role: str # "user" or "assistant" content: str language: Optional[str] = "en" class ChatRequest(BaseModel): """Reçu depuis le frontend, contient l'historique complet du chat et le nouveau message de l'utilisateur.""" history: list[ChatMessage] # full conversation so far message: str # new user message patient_info: PatientInfo # infos du patient, pour contexte additionnel # === OUTPUT === class DiagnosisResultPerDisease(BaseModel): """Prediction atomique pour une condition médicale donnée.""" name: str # exp. "Malaria" probability: float # exp. 0.87 level: str # exp. level_low, level_medium, level_high symptoms: List[str] class DiagnosisResponse(BaseModel): """Reponse envoyée au frontend, contient une liste de diagnostics possibles et une recommandation.""" statistics: List[DiagnosisResultPerDisease] recommendation: str class ChatResponse(BaseModel): lang: str reply: str quick_replies: list[str] = [] # Quand le LLM a suffisament d'infos pour faire un diagnostic, on peut aussi inclure les résultats: symptoms: list[str] = [] diagnosis: dict = {} # reponse finale de notre modele diseases_info: list[dict] = [] recommendations: str = ""