10 KiB
Контракт-чек
LLM-сервис скрининга рисков в договорах (PDF/DOCX) по ГК РФ / ГК РБ. Telegram-бот MVP + B2B API сейчас; веб + подписки — позже.
Pipeline: PDF/DOCX → текст (pymupdf/tesseract OCR) → чанки → Ollama Cloud (LLM, json-schema + repair-loop) → markdown-отчёт с цитатами, ссылкой на пункт и дисклеймером «не заменяет юриста».
Документы
docs/ARCHITECTURE.md— единственный источник истины для production-рефакторинга. Hexagonal-архитектура, RabbitMQ-конвейер, схемы БД, очередь/ретраи/DLQ, конфиг, deploy, observability.docs/DEPLOY.md— руководство по развёртыванию: локально, Docker Compose, VPS, seed-token, backup, troubleshooting.docs/BUSINESS_IDEA.md— идея и бизнес-модель.docs/IMPLEMENTATION_PLAN.md— исходный «ленивый» план. Этап 0 (прототип) актуален; этапы 1+ superseded вdocs/ARCHITECTURE.md.docs/TICKETS.md— тикеты реализации со статусами.
Архитектура (одна строка)
Hexagonal (ports & adapters). Ядро contract_check.core владеет всем состоянием
(Postgres/MinIO/RabbitMQ/LLM/кредиты). Четыре сервиса собираются из него:
Telegram ──► bot (aiogram, HTTP-only) ──HTTP──► api (FastAPI) ──publish──► RabbitMQ
владеет: PG, MinIO, │
Redis, кредитами ▼
extract.q ──► worker-extract
(pymupdf+tesseract, CPU) │
▼ publish
analyze.q ──► worker-analyze
(LLM, I/O) → Report
- api — единственный писатель для пользовательских мутаций (upload → reserve credit → MinIO → publish
DocumentUploaded). - worker-extract — CPU: достаёт текст (PDF/DOCX), при необходимости OCR, грузит
.txtв MinIO, публикуетDocumentExtracted. - worker-analyze — I/O: LLM-анализ по чек-листу, валидация/repair, сохраняет
Report,status=done. - bot — адаптер: HTTP-клиент к api, не импортирует core.db/s3/llm/mq (граница проверяется тестом
tests/unit/test_bot_boundary.py).
Структура репозитория
src/contract_check/
__main__.py # указывает на prototype (stage-0 CLI сохранён)
core/ # общий домен (импортируется каждым сервисом)
config.py logging.py telemetry.py sentry.py metrics.py
credits.py tokens.py api_keys.py rate_limit.py redis_client.py
db/ models.py session.py enums.py
mq/ topology.py publisher.py consumer.py messages.py
s3/ port.py minio_storage.py
llm/ port.py ollama_cloud.py factory.py
analysis/ extractor.py chunker.py checklist.py report_schema.py ocr.py analyzer.py
api/ # FastAPI-образ
app.py deps.py middleware.py services.py __main__.py
routes/ health.py documents.py reports.py me.py metrics.py b2b.py
worker_extract/ # CPU-образ (pymupdf + tesseract)
consumer.py handler.py extract_document.py __main__.py
worker_analyze/ # I/O-образ (LLM provider)
consumer.py handler.py __main__.py
bot/ # aiogram-адаптер (самый «тощий» образ: только core.logging)
client.py config.py handlers.py __main__.py
prototype/ # stage-0 standalone CLI (бенчмарк go/no-go)
docs/ # документация проекта (README остаётся в корне)
ARCHITECTURE.md # архитектура, схемы БД, конфиг
DEPLOY.md # руководство по развёртыванию
TICKETS.md # статусы тикетов
IMPLEMENTATION_PLAN.md # исходный план (superseded для этапов 1+)
BUSINESS_IDEA.md # продукт / бизнес-модель
srv/ # Dockerfile-ы (один на сервис, deps заточены)
api/Dockerfile worker-extract/Dockerfile worker-analyze/Dockerfile
bot/Dockerfile prototype/Dockerfile
migrations/ # alembic (async): 0001_initial, 0002_api_keys
tests/
conftest.py
unit/ chunker, extractor, llm_ollama_cloud, credits, messages,
rate_limit, checklist_report, bot_client, bot_boundary
integration/ upload_pipeline, extract_worker, analyze_worker, b2b_api, credits_db
docker-compose.yml # default = инфра; --profile services = стек
pyproject.toml # hatchling + PEP 735 dependency-groups (db/mq/s3/obs/api/extract/analyze/bot/prototype/dev)
.env.example # полный список env (см. docs/ARCHITECTURE.md §11)
Быстрый старт
Локально (разработка)
uv sync --group dev # все группы для локальной разработки
cp .env.example .env # впишите OLLAMA_HOST / OLLAMA_API_KEY
docker compose up -d # только инфра (postgres/redis/rabbitmq/minio)
uv run alembic upgrade head # миграции
uv run python -m contract_check.api # api на :8000
uv run python -m contract_check.worker_extract # воркер экстракции
uv run python -m contract_check.worker_analyze # воркер анализа
uv run python -m contract_check.bot # Telegram-бот
Через Docker Compose
cp .env.example .env # заполнить секреты (DB, Rabbit, MinIO, Ollama, BOT_TOKEN, ...)
docker compose up -d # только инфра с healthchecks
docker compose --profile services up -d --build # + api, worker-extract, worker-analyze, bot
Профиль services собирает 4 образа из srv/<service>/Dockerfile и поднимает их
с depends_on: condition: service_healthy. Observability (Prometheus/Grafana/Tempo/OTel)
и edge (Nginx/certbot) — за будущими профилями obs/edge (docs/ARCHITECTURE.md §20, шаги 1–5
реализованы; шаг 6 — позже).
Порты на хосте (смещены, чтобы не конфликтовать): Postgres 15432, Redis 17379,
RabbitMQ AMQP 5672 / UI 15672, MinIO 9000 / console 9001, api 8000 / metrics 9100,
worker metrics 9101/9102.
Stage-0 прототип (бенчмарк)
uv sync --group prototype
uv run python -m contract_check prototype contract.pdf # отчёт в stdout
uv run contract-check contract.pdf -o report.md # или консольная команда
uv run python -m contract_check prototype contract.pdf --json metrics.json # + метрики go/no-go
API (кратко)
Все роуты под /api/v1. Auth зависит от роута:
- Пользовательские роуты (bot / web / Mini App) —
Authorization: Bearer <user_jwt>. JWT выдаётся через/api/v1/auth/telegram/*после проверки identity от Telegram. - Адаптер-level (только
/api/v1/auth/telegram/bot) —Authorization: Bearer <service_token>. - B2B —
X-API-Key. Управление B2B-ключами требует пользовательский JWT. - Health/metrics — без auth.
| Метод | Путь | Auth | Назначение |
|---|---|---|---|
| GET | /healthz, /readyz, /metrics |
— | liveness / readiness / Prometheus |
| POST | /api/v1/auth/telegram/bot |
service token | бот меняет verified telegram_id на JWT |
| POST | /api/v1/auth/telegram/web |
— | Telegram Login Widget → JWT |
| POST | /api/v1/auth/telegram/miniapp |
— | Mini App initData → JWT |
| GET | /api/v1/auth/me |
user JWT | introspect JWT |
| POST | /api/v1/documents |
user JWT | multipart upload → reserve credit → MinIO → publish → 202 {document_id, correlation_id} |
| GET | /api/v1/documents/{id} |
user JWT | статус + stage (для поллинга) |
| GET | /api/v1/reports/{document_id} |
user JWT | 202 {status, stage} или 200 {markdown, findings, ...} |
| GET | /api/v1/me |
user JWT | {telegram_id, credits_left} |
| POST | /api/v1/analyze |
X-API-Key |
B2B: анализ документа |
| GET | /api/v1/b2b/reports/{id}, /api/v1/b2b/usage |
X-API-Key |
B2B: отчёт / usage |
| POST/GET | /api/v1/b2b/keys, /api/v1/b2b/keys/{id}/revoke, .../usage |
user JWT | управление B2B-ключами |
Полная спецификация — docs/ARCHITECTURE.md §15 (актуализируется).
Проверки (DoD)
uv run ruff check . && uv run mypy src && uv run pytest -q # unit, быстро
uv run pytest -m integration -q # интеграционные (нужны контейнеры)