Files
medtech-hackathon/contracts/models.py
T
admins a6a6609c48 feat: Фаза 0 — каркас, контракты, загрузчик справочника
- db/migrations/001_init.sql — схема (4 сущности, prices jsonb, pgvector/pg_trgm)
- contracts/models.py — общие модели (RawRow, ParsedDocument, MatchResult, *Out)
- etl/dictionary.py — загрузчик справочника (1281 услуга, нормализация)
- api/main.py — FastAPI: 7 эндпоинтов ТЗ + /stats (контракт)
- infra/ — docker-compose (pg+pgvector, api, web), Caddyfile
- scripts/proof/phase0_proof.py — проверка каскада на реальных данных (35% без эмбеддингов)
- data/ в .gitignore: данные клиник в публичный репо не коммитятся

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 15:23:06 +05:00

81 lines
2.7 KiB
Python

"""Общие модели данных — контракт между агентами (Pydantic v2).
`RawRow` и `ParsedDocument` — выход любого парсера (граница агентов B → C).
`MatchResult` — выход сопоставления (агент C). `*Out`-модели — выдача API (агент D),
её же потребляет фронт (агент E). Любая правка этих типов проходит через оркестратора.
"""
from __future__ import annotations
from datetime import date
from pydantic import BaseModel, Field
# Карта тарифов: ключ — тип цены, значение — сумма в KZT.
# Возможные ключи: resident, nonresident, cis, far, insurance, partner.
PriceTiers = dict[str, float]
class RawRow(BaseModel):
"""Одна сырая строка прайса — единый выход любого парсера."""
service_name_raw: str
service_code_source: str | None = None
prices: PriceTiers = Field(default_factory=dict)
unit: str | None = None
section: str | None = None # заголовок секции — контекст специальности
class ParsedDocument(BaseModel):
"""Результат разбора одного файла прайса."""
file_name: str
file_format: str # pdf / scan_pdf / docx / xlsx / xls
partner_name: str | None = None
city: str | None = None
effective_date: date | None = None
rows: list[RawRow] = Field(default_factory=list)
raw_content: str = ""
parse_log: list[str] = Field(default_factory=list)
class MatchResult(BaseModel):
"""Результат сопоставления строки со справочником."""
service_id: str | None = None
method: str | None = None # code / exact / embedding / fuzzy / manual
confidence: float = 0.0
# --- выдача API ---
class ServiceOut(BaseModel):
service_id: str
specialty: str
name_ru: str
tarificator_code: str | None = None
class PartnerOut(BaseModel):
partner_id: str
name: str
city: str | None = None
is_active: bool = True
class PriceOut(BaseModel):
partner_id: str
partner_name: str
price_resident_kzt: float | None = None
price_nonresident_kzt: float | None = None
prices: PriceTiers = Field(default_factory=dict)
effective_date: date | None = None
class Stats(BaseModel):
"""Сводка для дашборда и отчёта о качестве."""
documents_total: int = 0
documents_done: int = 0
items_total: int = 0
auto_matched_pct: float = 0.0
unmatched_total: int = 0