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,35 @@
|
||||
"""
|
||||
Domain models package.
|
||||
"""
|
||||
|
||||
from app.domain.models.patient_state import (
|
||||
SymptomItem,
|
||||
MedicationItem,
|
||||
AllergyItem,
|
||||
MedicalHistoryItem,
|
||||
SurgicalHistoryItem,
|
||||
PreviousEpisodeItem,
|
||||
FamilyHistoryItem,
|
||||
FieldContainer,
|
||||
PatientState,
|
||||
)
|
||||
from app.domain.models.extraction import ExtractionResult, QuestionIntent
|
||||
from app.domain.models.contracts import ResponseContext, ResponseResult, ResponseType, FactConfidence
|
||||
|
||||
__all__ = [
|
||||
"SymptomItem",
|
||||
"MedicationItem",
|
||||
"AllergyItem",
|
||||
"MedicalHistoryItem",
|
||||
"SurgicalHistoryItem",
|
||||
"PreviousEpisodeItem",
|
||||
"FamilyHistoryItem",
|
||||
"FieldContainer",
|
||||
"PatientState",
|
||||
"ExtractionResult",
|
||||
"QuestionIntent",
|
||||
"ResponseContext",
|
||||
"ResponseResult",
|
||||
"ResponseType",
|
||||
"FactConfidence",
|
||||
]
|
||||
@@ -0,0 +1,67 @@
|
||||
"""
|
||||
Response contracts, enums, and data models (Rules 102, 103, 104, 105, 116):
|
||||
- ResponseType Enum
|
||||
- QuestionIntent Enum
|
||||
- ResponseContext Input Contract
|
||||
- ResponseResult Output Contract
|
||||
- FactConfidence Model
|
||||
"""
|
||||
|
||||
from enum import Enum
|
||||
from typing import Optional, List, Dict, Any
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ResponseType(str, Enum):
|
||||
GREETING = "greeting"
|
||||
ACKNOWLEDGEMENT = "acknowledgement"
|
||||
FOLLOW_UP = "follow_up"
|
||||
CLARIFICATION = "clarification"
|
||||
REFUSAL = "refusal"
|
||||
UNKNOWN = "unknown"
|
||||
SAFETY = "safety"
|
||||
CRISIS = "crisis"
|
||||
COMPLETION = "completion"
|
||||
|
||||
|
||||
class QuestionIntent(str, Enum):
|
||||
SYMPTOM_NAME = "symptom_name"
|
||||
SYMPTOM_DURATION = "symptom_duration"
|
||||
SYMPTOM_SEVERITY = "symptom_severity"
|
||||
SYMPTOM_LOCATION = "symptom_location"
|
||||
SYMPTOM_ONSET = "symptom_onset"
|
||||
SYMPTOM_FREQUENCY = "symptom_frequency"
|
||||
SYMPTOM_TRIGGER = "symptom_trigger"
|
||||
ASSOCIATED_SYMPTOMS = "associated_symptoms"
|
||||
|
||||
MEDICAL_HISTORY = "medical_history"
|
||||
MEDICATIONS = "medications"
|
||||
ALLERGIES = "allergies"
|
||||
FAMILY_HISTORY = "family_history"
|
||||
SURGICAL_HISTORY = "surgical_history"
|
||||
|
||||
|
||||
class ResponseContext(BaseModel):
|
||||
language: str = "en"
|
||||
patient_message: str
|
||||
intent: str = "fact_extraction"
|
||||
primary_symptom: Optional[str] = None
|
||||
missing_information: Optional[str] = None
|
||||
selected_question: Optional[str] = None
|
||||
question_intent: Optional[QuestionIntent] = None
|
||||
safety_status: str = "normal"
|
||||
onboarding_completed: bool = False
|
||||
current_state: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class ResponseResult(BaseModel):
|
||||
response: str
|
||||
language: str = "en"
|
||||
question_intent: Optional[str] = None
|
||||
response_type: ResponseType = ResponseType.FOLLOW_UP
|
||||
|
||||
|
||||
class FactConfidence(BaseModel):
|
||||
source: str = "patient"
|
||||
method: str = "explicit"
|
||||
confidence: float = 1.0
|
||||
@@ -0,0 +1,28 @@
|
||||
"""
|
||||
Extraction result and question intent domain models.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ExtractedFact(BaseModel):
|
||||
category: str # 'symptom', 'medication', 'allergy', 'medical_history', 'family_history', etc.
|
||||
data: Dict[str, Any]
|
||||
|
||||
|
||||
class ExtractionResult(BaseModel):
|
||||
raw_message: str
|
||||
normalized_message: str
|
||||
detected_language: str = "en"
|
||||
updates: Dict[str, Any] = Field(default_factory=dict)
|
||||
is_emergency: bool = False
|
||||
is_crisis: bool = False
|
||||
emergency_reason: Optional[str] = None
|
||||
|
||||
|
||||
class QuestionIntent(BaseModel):
|
||||
intent_code: str # e.g., 'reason_for_visit', 'symptom_duration', 'medical_history'
|
||||
field: str
|
||||
attribute: Optional[str] = None
|
||||
target_symptom: Optional[str] = None
|
||||
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
Strongly typed domain models for Patient Onboarding state management.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class SymptomItem(BaseModel):
|
||||
name: str
|
||||
canonical_name: Optional[str] = None
|
||||
duration: Optional[str] = None
|
||||
severity: Optional[str] = None
|
||||
location: Optional[str] = None
|
||||
frequency: Optional[str] = None
|
||||
onset: Optional[str] = None
|
||||
pattern: Optional[str] = None
|
||||
trigger: Optional[str] = None
|
||||
relieving_factor: Optional[str] = None
|
||||
associated_findings: Optional[str] = None
|
||||
|
||||
|
||||
class MedicationItem(BaseModel):
|
||||
name: str
|
||||
canonical_name: Optional[str] = None
|
||||
dosage: Optional[str] = None
|
||||
frequency: Optional[str] = None
|
||||
duration: Optional[str] = None
|
||||
purpose: Optional[str] = None
|
||||
|
||||
|
||||
class AllergyItem(BaseModel):
|
||||
name: str
|
||||
canonical_name: Optional[str] = None
|
||||
type: Optional[str] = None # e.g., 'drug', 'food', 'environment'
|
||||
reaction: Optional[str] = None # e.g., 'rash', 'swelling'
|
||||
|
||||
|
||||
class MedicalHistoryItem(BaseModel):
|
||||
condition: str
|
||||
canonical_name: Optional[str] = None
|
||||
duration: Optional[str] = None
|
||||
status: Optional[str] = "active"
|
||||
details: Optional[str] = None
|
||||
|
||||
|
||||
class SurgicalHistoryItem(BaseModel):
|
||||
procedure: str
|
||||
body_site: Optional[str] = None
|
||||
approximate_date: Optional[str] = None
|
||||
reason: Optional[str] = None
|
||||
|
||||
|
||||
class PreviousEpisodeItem(BaseModel):
|
||||
description: str
|
||||
time: Optional[str] = None
|
||||
outcome: Optional[str] = None
|
||||
|
||||
|
||||
class FamilyHistoryItem(BaseModel):
|
||||
relation: str # e.g., 'father', 'mother', 'sibling'
|
||||
condition: str
|
||||
canonical_name: Optional[str] = None
|
||||
|
||||
|
||||
class FieldContainer(BaseModel):
|
||||
status: str = "not_collected" # 'not_collected' | 'reported' | 'confirmed_none' | 'unknown' | 'declined'
|
||||
items: List[Dict[str, Any]] = Field(default_factory=list)
|
||||
|
||||
|
||||
class SpecialtyConfidence(BaseModel):
|
||||
code: str
|
||||
name: str
|
||||
confidence: float = 1.0
|
||||
evidence: List[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class PatientState(BaseModel):
|
||||
reason_for_visit: Optional[str] = None
|
||||
symptoms: List[SymptomItem] = Field(default_factory=list)
|
||||
medical_history: Union[FieldContainer, List[MedicalHistoryItem], Dict[str, Any]] = Field(default_factory=list)
|
||||
medications: Union[FieldContainer, List[MedicationItem], Dict[str, Any]] = Field(default_factory=list)
|
||||
allergies: Union[FieldContainer, List[AllergyItem], Dict[str, Any]] = Field(default_factory=list)
|
||||
surgical_history: List[SurgicalHistoryItem] = Field(default_factory=list)
|
||||
previous_episodes: List[PreviousEpisodeItem] = Field(default_factory=list)
|
||||
family_history: List[FamilyHistoryItem] = Field(default_factory=list)
|
||||
additional_information: List[Dict[str, Any]] = Field(default_factory=list)
|
||||
Reference in New Issue
Block a user