Files
PTSRaiAgent/app/config.py
T
ElebobaandClaude Opus 5.5 9ec61b9a03
CI / ruff · pytest (pull_request) Successful in 2m5s
feat(bot): chat agent on Gemini 2.5 Flash-Lite — grounded first turn, current-prescription defaults
Live-tested on OpenRouter: Flash-Lite answers in 3–8 s with correct findings at ~$0.10/$0.40 per 1M tokens
(qwen3.7-flash and gpt-oss-120b took 26–32 s). Force a tool call on the first turn, give the model the
current prescription, let check_drug_for_patient default to it and return composition, intolerance check
and general interactions (alcohol); retry once on an empty final message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 14:59:38 +03:00

57 lines
2.4 KiB
Python

"""Typed application settings. The only place that reads environment variables."""
from functools import lru_cache
from pathlib import Path
from typing import Literal
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
ROOT_DIR = Path(__file__).resolve().parent.parent
class Settings(BaseSettings):
# Empty values in .env (e.g. `TG_BOT_TOKEN=`) fall back to defaults instead of failing validation.
model_config = SettingsConfigDict(env_file=".env", extra="ignore", env_ignore_empty=True)
# Two separate databases (ADR-003): identity holds direct identifiers, clinical holds pseudonymised data.
identity_db_url: str = "postgresql+asyncpg://identity_app:identity_app@localhost:5432/identity"
clinical_db_url: str = "postgresql+asyncpg://clinical_app:clinical_app@localhost:5432/clinical"
# HMAC key linking identity and clinical records (hex, 32+ bytes).
pseudo_key: str = Field(default="dev-only-insecure-key-change-me-0000000000000000", min_length=32)
# LLM: GigaChat only (152-FZ: no foreign APIs). `mock` is the offline default (ADR-004).
llm_provider: Literal["mock", "gigachat"] = "mock"
gigachat_credentials: str = ""
gigachat_scope: str = "GIGACHAT_API_PERS"
gigachat_model: str = "GigaChat"
gigachat_verify_ssl: bool = False
# Chat agent (tool-using LLM over RAG + patient record). `auto` = OpenRouter if a key is set, else off
# (extractive RAG / instruction answers stay). OpenRouter is a TEMPORARY prototype provider on synthetic
# data only — prod must use GigaChat (152-FZ, foreign services are forbidden for real PII).
chat_agent: Literal["auto", "off", "mock", "openrouter", "gigachat"] = "auto"
openrouter_api_key: str = ""
openrouter_model: str = "google/gemini-2.5-flash-lite"
openrouter_base_url: str = "https://openrouter.ai/api/v1"
chat_agent_timeout_s: float = 25.0
chat_agent_max_steps: int = 5
# Telegram is used only for the prototype on synthetic data; prod channel is MAX / Gosuslugi.
tg_bot_token: str = ""
doctor_notify_chat_id: int | None = None
# Virtual clock for the demo (ADR-005).
demo_clock: bool = True
tz: str = "Europe/Moscow"
api_base_url: str = "http://localhost:8000"
config_dir: Path = ROOT_DIR / "config"
data_dir: Path = ROOT_DIR / "data"
@lru_cache
def get_settings() -> Settings:
return Settings()