deploy: система живая на med.secondbrain.tools + актуальный README

- infra/deploy/ — реальный compose (API-контейнер за Caddy) + Caddyfile
- docs/quality_report.json — отчёт: 8871 позиций, 73.9% автонормализации
- README переписан под факт: стек, результаты, запуск (ru-text 8.6)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-26 17:47:28 +05:00
parent 787092dc02
commit 3d7b12d63d
5 changed files with 128 additions and 25 deletions
+46 -25
View File
@@ -1,37 +1,58 @@
# medtech-hackathon # MedArchive — обработка архива прайсов клиник-партнёров
Terricon Valley · Medtech Hackathon (2628.06.2026) · **Кейс 1 — автоматическая обработка архива прайсов клиник-партнёров.** Terricon Valley · Medtech Hackathon (2628.06.2026).
Превращаем архив разнородных прайс-листов клиник (Excel / PDF / скан / фото / .doc, RU/KZ/EN, грязные данные) в единый сравнимый каталог **услуга → клиника → цена** с поиском, сравнением цен и экспортом. **Живой демо: https://med.secondbrain.tools**
## Стек Система автоматически разбирает архив разнородных прайс-листов клиник (PDF, сканы, DOCX,
XLSX/XLS), извлекает услуги и цены, нормализует их к справочнику из 1281 услуги и даёт поиск
и сравнение «кто оказывает услугу и по какой цене».
- **ETL/бэкенд:** Python + FastAPI (pandas для Excel, LLM-vision для грязного, pdfplumber, Tesseract `kaz+rus` fallback) ## Результат на тестовом архиве (8 клиник, 10 файлов)
- **Канонизация услуг:** sentence-transformers + pgvector + детерминированная матрица конфликтов (см. словарик)
- **БД:** PostgreSQL + pgvector
- **Фронт:** Next.js + Tailwind + shadcn/ui (дизайн на фирменной палитре)
- **Деплой:** Docker Compose + Caddy → `med.secondbrain.tools` (Selectel KZ)
## Языки - **8 871 позиция** извлечена: 6 клиник из 8 — нативными парсерами, трудные PDF (битый
текстовый слой, нестандартная вёрстка) — через Gemini Vision.
- **73,9% позиций нормализованы автоматически** (цель ТЗ — не ниже 70%).
- Остальное уходит в очередь ручной разметки, как и предполагает ТЗ.
KAZ / RUS / ENG — сквозное требование (данные и UI). Полный отчёт о качестве — `docs/quality_report.json`.
## Структура (план) ## Стек и решения
``` | Слой | Решение |
contracts/ — модель данных + Zod-схемы + openapi.yaml (агент A) |---|---|
db/ — миграции (агент A) | Извлечение | Python: pdfplumber + PyMuPDF, openpyxl/xlrd, python-docx. Таблицы из PDF без линий восстанавливаются по координатам слов |
etl/ — парсинг и нормализация (агент B) | Vision-добор | Gemini (`gemini-2.5-flash`) — для сканов и битого текстового слоя |
api/ — REST API поиска/сравнения (агент C) | Нормализация | Каскад: код тарификатора → точное совпадение → эмбеддинги Gemini → нечёткое сравнение → очередь `unmatched` |
web/ — Next.js UI (агент D) | Валидация | Правила ТЗ §4.4: положительность цены, резидент ≥ нерезидент, аномалии, версионирование |
infra/ — docker-compose, Caddyfile (агент E) | Хранилище | SQLite (MVP, разворачивается без Docker). Боевая схема PostgreSQL + pgvector — в `db/migrations` |
docs/ — документация, ADR (агент F) | API | FastAPI: 7 эндпоинтов ТЗ + `/stats`, OpenAPI на `/docs` |
pitch/ — слайды и демо-сценарий (агент F) | Фронт | Одностраничный (Tailwind): поиск услуги и сравнение цен по клиникам |
fixtures/ — синтетические + эталонные данные | Деплой | Контейнер API за Caddy на Selectel KZ |
## Запуск локально
```bash
python -m venv .venv && .venv/bin/pip install -e .
# архив прайсов → data/raw/, справочник → data/reference/dictionary.xlsx
GEMINI_API_KEY=... python scripts/run_pipeline.py # → data/medarchive.db + отчёт
uvicorn api.main:app # → http://localhost:8000/docs
# открыть web/index.html?api=http://localhost:8000
``` ```
Скелет кода поднимается в Фазе 0 хакатона после заморозки контрактов. Эмбеддинги и Vision вызываются через Gemini API, поэтому локальная модель не нужна и контейнер
остаётся лёгким. Поиск и сравнение в готовой базе работают без обращений к API.
## Полный план ## Структура
В хранилище Obsidian: `Base/_Inbox/Хакатон Medtech/` (план, словарик нормализации, дизайн-система, памятка). ```
contracts/ — общие модели данных (контракт между модулями)
db/ — схема PostgreSQL + pgvector
etl/ — извлечение, нормализация, валидация, конвейер
api/ — REST API поиска и сравнения
web/ — одностраничный фронт
infra/ — деплой (compose, Caddyfile)
docs/ — отчёт о качестве, план
pitch/ — презентация и демо-сценарий
scripts/ — запуск конвейера и проверки
```
+15
View File
@@ -0,0 +1,15 @@
{
"documents": 10,
"partners": 8,
"items": 8871,
"auto_matched": 6555,
"auto_matched_pct": 73.9,
"unmatched": 2316,
"by_method": {
"code": 1414,
"exact": 167,
"embedding": 4903,
"fuzzy": 71,
"null": 2316
}
}
+19
View File
@@ -0,0 +1,19 @@
{
email laukhin@dementiy.com
acme_ca https://acme-v02.api.letsencrypt.org/directory
}
med.secondbrain.tools {
handle_path /api/* {
reverse_proxy api:8000
}
handle /demo* {
root * /srv
file_server
}
handle {
root * /web
file_server
encode gzip
}
}
+19
View File
@@ -0,0 +1,19 @@
# Деплой MedArchive
Лёгкая схема: контейнер API (FastAPI на готовой SQLite-базе) за общим Caddy на Selectel KZ.
Рантайму не нужны ни Gemini, ни модель — эмбеддинги и Vision отработали на этапе сборки базы.
## Шаги
1. Залить на сервер: код (`api/`, `contracts/`), фронт (`web/`), базу (`data/medarchive.db`) и
отчёт (`data/quality_report.json`) — в `/root/medarchive/`.
2. Положить `docker-compose.yml` и `Caddyfile` из этой папки в каталог с Caddy.
3. `docker compose up -d` — поднимется `medarchive-api` (ставит зависимости и запускает uvicorn).
4. Маршруты Caddy: `/api/*` → контейнер API, `/` → фронт, `/demo` → презентация.
## Проверка
```bash
curl https://med.secondbrain.tools/api/health
curl https://med.secondbrain.tools/api/stats
```
+29
View File
@@ -0,0 +1,29 @@
services:
caddy:
image: caddy:2-alpine
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./site:/srv:ro
- /root/medarchive/web:/web:ro
- caddy_data:/data
- caddy_config:/config
api:
image: python:3.12-slim
container_name: medarchive-api
restart: unless-stopped
working_dir: /app
volumes:
- /root/medarchive:/app
environment:
MEDARCHIVE_DB: /app/data/medarchive.db
command: sh -c "pip install --quiet --no-cache-dir fastapi 'uvicorn[standard]' pydantic && uvicorn api.main:app --host 0.0.0.0 --port 8000"
volumes:
caddy_data:
caddy_config: