DealDocumentScreening/README.md
2026-08-12 21:29:36 +03:00

152 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Контракт-чек
LLM-сервис скрининга рисков в договорах (PDF/DOCX) по ГК РФ / ГК РБ.
Telegram-бот MVP + B2B API сейчас; веб + подписки — позже.
Pipeline: `PDF/DOCX → текст (pymupdf/tesseract OCR) → чанки → Ollama Cloud (LLM, json-schema + repair-loop) → markdown-отчёт` с цитатами, ссылкой на пункт и дисклеймером «не заменяет юриста».
## Документы
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — **единственный источник истины** для production-рефакторинга. Hexagonal-архитектура, RabbitMQ-конвейер, схемы БД, очередь/ретраи/DLQ, конфиг, deploy, observability.
- [`docs/DEPLOY.md`](docs/DEPLOY.md) — руководство по развёртыванию: локально, Docker Compose, VPS, seed-token, backup, troubleshooting.
- [`docs/BUSINESS_IDEA.md`](docs/BUSINESS_IDEA.md) — идея и бизнес-модель.
- [`docs/IMPLEMENTATION_PLAN.md`](docs/IMPLEMENTATION_PLAN.md) — исходный «ленивый» план. Этап 0 (прототип) актуален; этапы 1+ superseded в `docs/ARCHITECTURE.md`.
- [`docs/TICKETS.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)
```
## Быстрый старт
### Локально (разработка)
```bash
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
```bash
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`, шаги 15
реализованы; шаг 6 — позже).
Порты на хосте (смещены, чтобы не конфликтовать): Postgres `15432`, Redis `17379`,
RabbitMQ AMQP `5672` / UI `15672`, MinIO `9000` / console `9001`, api `8000` / metrics `9100`,
worker metrics `9101`/`9102`.
### Stage-0 прототип (бенчмарк)
```bash
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)
```bash
uv run ruff check . && uv run mypy src && uv run pytest -q # unit, быстро
uv run pytest -m integration -q # интеграционные (нужны контейнеры)
```