"""Patient-facing dialog texts from `config/texts/dialog.yaml` (ADR-008: texts live in config, not code).""" from functools import lru_cache from pathlib import Path import yaml from pydantic import BaseModel, ConfigDict, Field from app.config import get_settings class _Strict(BaseModel): # A typo in a YAML key must fail at load time, not silently show an empty message to a patient. model_config = ConfigDict(extra="forbid", frozen=True) class DialogSettings(_Strict): cssrs_cooldown_hours: float = 24 max_safety_events: int = 50 crisis_flags: list[str] = Field(default_factory=list) risk_screen_scale: str = "cssrs_screen" abandon_after_hours: float = 6 class Commands(_Strict): revoke: list[str] class ConsentTexts(_Strict): version: str text: str accept: str decline: str refused: str reconsider: str code_invalid: str class AgeGateTexts(_Strict): question: str adult: str minor: str unclear: str minor_stop: str class IdleButtons(_Strict): checkin: str med_question: str kb_question: str contact_doctor: str revoke: str class IdleTexts(_Strict): welcome: str menu_prompt: str buttons: IdleButtons stub_checkin: str stub_med_question: str contact_doctor_ack: str visit_stub: str class RevokedTexts(_Strict): confirm: str class CrisisTexts(_Strict): repeat: str hold: str closed: str class ScaleTexts(_Strict): intro: str question: str clarify: str buttons_only: str done: str risk_screen_intro: str class SafetyPlanTexts(_Strict): title: str template: list[str] means_restriction: str class ReachOutTexts(_Strict): silence: str missed_doses: str default: str class VisitTexts(_Strict): button: str class DialogTexts(_Strict): status: str settings: DialogSettings commands: Commands consent: ConsentTexts age_gate: AgeGateTexts idle: IdleTexts revoked: RevokedTexts crisis: CrisisTexts scale: ScaleTexts safety_plan: SafetyPlanTexts reach_out: ReachOutTexts visit: VisitTexts unavailable: str def dialog_texts_path() -> Path: return get_settings().config_dir / "texts" / "dialog.yaml" @lru_cache def load_dialog_texts(path: Path | None = None) -> DialogTexts: path = path or dialog_texts_path() return DialogTexts.model_validate(yaml.safe_load(path.read_text(encoding="utf-8")))