docs: add PARSER agent documentation and implementation plan
- Add formal PARSER agent description (dots.ocr-based) - Add detailed TODO-PARSER-RAG.md with implementation tasks - Update agents README to include PARSER - PARSER = Document Ingestion & Structuring Agent for RAG
This commit is contained in:
386
TODO-PARSER-RAG.md
Normal file
386
TODO-PARSER-RAG.md
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
# TODO: PARSER Agent + RAG Haystack Stack
|
||||||
|
|
||||||
|
Детальний план реалізації PARSER-агента на базі `dots.ocr` та RAG-системи на базі Haystack.
|
||||||
|
|
||||||
|
**Статус:** 🟡 Планування
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## G. PARSER Agent (dots.ocr)
|
||||||
|
|
||||||
|
### G.1. Runtime моделі PARSER
|
||||||
|
|
||||||
|
- [ ] **G.1.1** Обрати runtime для dots.ocr
|
||||||
|
- [ ] Варіант A: HuggingFace Transformers + vLLM/SGLang
|
||||||
|
- [ ] Варіант B: llama.cpp / GGUF (якщо буде GGUF-версія)
|
||||||
|
- [ ] Варіант C: Ollama (якщо підтримується)
|
||||||
|
- **Примітка:** Обрати найпростіший варіант для старту
|
||||||
|
|
||||||
|
- [ ] **G.1.2** Створити `parser-runtime/` сервіс
|
||||||
|
- [ ] `parser_runtime/__init__.py`
|
||||||
|
- [ ] `parser_runtime/model_loader.py` (lazy init, GPU/CPU fallback)
|
||||||
|
- [ ] `parser_runtime/inference.py` (функції: `parse_image`, `parse_pdf`)
|
||||||
|
- [ ] `parser_runtime/config.py` (конфігурація моделі)
|
||||||
|
|
||||||
|
- [ ] **G.1.3** Додати конфіг
|
||||||
|
- [ ] `PARSER_MODEL_NAME=rednote-hilab/dots.ocr`
|
||||||
|
- [ ] `PARSER_DEVICE=cuda` / `cpu`
|
||||||
|
- [ ] `PARSER_MAX_PAGES=100`
|
||||||
|
- [ ] `PARSER_MAX_RESOLUTION=4096x4096`
|
||||||
|
- [ ] `PARSER_BATCH_SIZE=1` (для початку)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### G.2. HTTP-сервіс `parser-service`
|
||||||
|
|
||||||
|
- [ ] **G.2.1** Створити сервіс `services/parser-service/` (FastAPI)
|
||||||
|
- [ ] `main.py` — FastAPI додаток
|
||||||
|
- [ ] `schemas.py` — Pydantic моделі (ParsedDocument, ParsedBlock, ...)
|
||||||
|
- [ ] `config.py` — конфігурація
|
||||||
|
- [ ] `Dockerfile` — Docker образ
|
||||||
|
- [ ] `requirements.txt` — залежності
|
||||||
|
|
||||||
|
- [ ] **G.2.2** Ендпоінти
|
||||||
|
- [ ] `POST /ocr/parse` — повертає raw JSON
|
||||||
|
- Request: `{doc_url, file_bytes, output_mode: "raw_json"}`
|
||||||
|
- Response: `ParsedDocument`
|
||||||
|
- [ ] `POST /ocr/parse_qa` — Q&A-представлення
|
||||||
|
- Request: `{doc_url, file_bytes}`
|
||||||
|
- Response: `{qa_pairs: [...]}`
|
||||||
|
- [ ] `POST /ocr/parse_markdown` — Markdown-версія
|
||||||
|
- Request: `{doc_url, file_bytes}`
|
||||||
|
- Response: `{markdown: "..."}`
|
||||||
|
- [ ] `POST /ocr/parse_chunks` — семантичні фрагменти для RAG
|
||||||
|
- Request: `{doc_url, file_bytes, dao_id, doc_id}`
|
||||||
|
- Response: `{chunks: [...]}`
|
||||||
|
- [ ] `GET /health` — health check
|
||||||
|
|
||||||
|
- [ ] **G.2.3** Підтримати типи файлів
|
||||||
|
- [ ] PDF (розбиття по сторінках → зображення)
|
||||||
|
- Використати `pdf2image` або `PyMuPDF`
|
||||||
|
- [ ] PNG/JPEG
|
||||||
|
- Пряма обробка через `PIL` / `Pillow`
|
||||||
|
- [ ] TIFF (опційно)
|
||||||
|
- [ ] WebP (опційно)
|
||||||
|
|
||||||
|
- [ ] **G.2.4** Додати pre-/post-processing
|
||||||
|
- [ ] Нормалізація розміру зображень (resize до max resolution)
|
||||||
|
- [ ] Конвертація PDF → зображення (по сторінках)
|
||||||
|
- [ ] Mapping вихідного JSON dots.ocr → внутрішню структуру `ParsedBlock`
|
||||||
|
- [ ] Валідація структури (перевірка наявності обов'язкових полів)
|
||||||
|
|
||||||
|
- [ ] **G.2.5** Додати базові тести
|
||||||
|
- [ ] Створити `tests/fixtures/docs/` з тестовими документами
|
||||||
|
- [ ] 1–2 короткі PDF-файли (2–3 сторінки)
|
||||||
|
- [ ] 1–2 PNG зображення з текстом
|
||||||
|
- [ ] Snapshot-тести JSON-структури (без чутливості до точного тексту)
|
||||||
|
- [ ] Тести на обробку помилок (невалідний PDF, занадто великий файл)
|
||||||
|
|
||||||
|
- [ ] **G.2.6** Додати в `docker-compose.yml`
|
||||||
|
- [ ] Сервіс `parser-service` з залежностями
|
||||||
|
- [ ] Environment variables
|
||||||
|
- [ ] Health check
|
||||||
|
- [ ] Volumes для тимчасових файлів
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### G.3. Інтеграція PARSER у DAGI Router
|
||||||
|
|
||||||
|
- [ ] **G.3.1** Додати LLM-профіль у `router-config.yml`
|
||||||
|
```yaml
|
||||||
|
llm_profiles:
|
||||||
|
parser_dots_ocr:
|
||||||
|
model: "dots.ocr"
|
||||||
|
base_url: "http://parser-runtime:11435" # або Ollama/vLLM endpoint
|
||||||
|
timeout_s: 120
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **G.3.2** Додати provider
|
||||||
|
```yaml
|
||||||
|
providers:
|
||||||
|
parser:
|
||||||
|
type: ocr
|
||||||
|
base_url: "http://parser-service:9400"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **G.3.3** Додати routing rule
|
||||||
|
```yaml
|
||||||
|
routing:
|
||||||
|
- id: doc_parse
|
||||||
|
when:
|
||||||
|
mode: doc_parse
|
||||||
|
use_provider: parser
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **G.3.4** Розширити `RouterRequest` (в `router_client.py` або `types/api.ts`)
|
||||||
|
- [ ] Поля `doc_url: Optional[str]`
|
||||||
|
- [ ] Поля `doc_type: Optional[str]` (`pdf`, `image`)
|
||||||
|
- [ ] Поля `output_mode: Optional[str]` (`raw_json|qa_pairs|markdown|chunks`)
|
||||||
|
- [ ] Поля `file_bytes: Optional[bytes]` (для прямого завантаження)
|
||||||
|
|
||||||
|
- [ ] **G.3.5** E2E curl-тест
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:9102/route \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"mode": "doc_parse",
|
||||||
|
"dao_id": "daarion",
|
||||||
|
"user_id": "test",
|
||||||
|
"payload": {
|
||||||
|
"doc_url": "https://.../example.pdf",
|
||||||
|
"output_mode": "qa_pairs"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### G.4. Опис агента PARSER
|
||||||
|
|
||||||
|
- [ ] **G.4.1** Створити `docs/agents/parser.md` ✅ (вже створено)
|
||||||
|
- [x] Роль: **Document Ingestion & Structuring Agent**
|
||||||
|
- [x] Вхід: `doc_url`, `file_id`, `raw bytes`
|
||||||
|
- [x] Вихід: `ParsedDocument { blocks[], tables[], qa_pairs[] }`
|
||||||
|
- [x] Обмеження: max pages, max file size
|
||||||
|
|
||||||
|
- [ ] **G.4.2** Додати `parser_agent` у CrewAI/оркестратор
|
||||||
|
- [ ] Створити `orchestrator/agents/parser_agent.py`
|
||||||
|
- [ ] Задачі:
|
||||||
|
- [ ] `parse_for_rag` — підготовка chunk'ів для індексації
|
||||||
|
- [ ] `parse_for_summary` — підготовка структурованого огляду doc'а
|
||||||
|
- [ ] `parse_for_qa` — Q&A базу для SecondMe/microDAO
|
||||||
|
- [ ] Інтеграція з CrewAI workflow
|
||||||
|
|
||||||
|
- [ ] **G.4.3** Зв'язати PARSER з RBAC
|
||||||
|
- [ ] Перевірка прав на інжест документів (`role: admin`, `role: researcher`)
|
||||||
|
- [ ] Обмеження на приватні/публічні документи
|
||||||
|
- [ ] Перевірка `dao_id` для ізоляції даних
|
||||||
|
- [ ] Додати в `microdao/rbac.py` (якщо потрібно)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## H. RAG Haystack Stack (PARSER як головний агент)
|
||||||
|
|
||||||
|
Тут PARSER — **головний агент інжесту**, а RAG шар — **Haystack-пайплайни для пошуку відповідей**.
|
||||||
|
|
||||||
|
### H.1. Вибір стеку RAG
|
||||||
|
|
||||||
|
- [ ] **H.1.1** Обрати фреймворк
|
||||||
|
- [ ] Варіант A: **deepset Haystack 2.x** (pipelines, retrievers, document stores)
|
||||||
|
- Переваги: готові компоненти, добра документація
|
||||||
|
- Недоліки: може бути overkill для простого випадку
|
||||||
|
- [ ] Варіант B: власний RAG поверх `pgvector`/Qdrant + простий код
|
||||||
|
- Переваги: легше, більше контролю
|
||||||
|
- Недоліки: треба писати більше коду
|
||||||
|
- **Рекомендація:** Почнути з варіанту B (pgvector вже є), потім можна перейти на Haystack
|
||||||
|
|
||||||
|
- [ ] **H.1.2** Обрати векторне сховище
|
||||||
|
- [ ] Postgres + pgvector (вже є в `city-db`)
|
||||||
|
- [ ] Або [ ] Qdrant / Weaviate / Milvus (якщо потрібна краща продуктивність)
|
||||||
|
- **Рекомендація:** Використати `pgvector` (вже налаштовано)
|
||||||
|
|
||||||
|
- [ ] **H.1.3** Обрати embedding-модель
|
||||||
|
- [ ] Варіант A: `sentence-transformers/all-MiniLM-L6-v2` (легка, швидка)
|
||||||
|
- [ ] Варіант B: `intfloat/multilingual-e5-base` (краще для української)
|
||||||
|
- [ ] Варіант C: Qwen embedding (якщо є)
|
||||||
|
- **Рекомендація:** Почнути з `multilingual-e5-base`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### H.2. Інджест-пайплайн (PARSER → RAG)
|
||||||
|
|
||||||
|
- [ ] **H.2.1** Створити `services/rag_ingest_pipeline.py`
|
||||||
|
- [ ] Функція `ingest_document(doc_id, doc_url, dao_id, user_id)`
|
||||||
|
- [ ] Функція `ingest_chunks(chunks: List[ParsedChunk], dao_id, doc_id)`
|
||||||
|
|
||||||
|
- [ ] **H.2.2** Кроки пайплайну
|
||||||
|
- [ ] Виклик PARSER (`mode=doc_parse`, `output_mode=chunks`)
|
||||||
|
- [ ] Нормалізація блоків у формат для індексації:
|
||||||
|
- [ ] `content` — текст блоку
|
||||||
|
- [ ] `meta` — `dao_id`, `doc_id`, `page`, `bbox`, `section_type`
|
||||||
|
- [ ] Обчислення ембеддингів (окремий embedding-модель/провайдер)
|
||||||
|
- [ ] Створити `services/embedding_service.py` або використати `sentence-transformers`
|
||||||
|
- [ ] Запис у document store (Postgres + pgvector)
|
||||||
|
- [ ] Створити таблицю `document_chunks`:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE document_chunks (
|
||||||
|
id UUID PRIMARY KEY,
|
||||||
|
doc_id TEXT NOT NULL,
|
||||||
|
dao_id TEXT NOT NULL,
|
||||||
|
chunk_text TEXT NOT NULL,
|
||||||
|
embedding vector(768), -- або інший розмір
|
||||||
|
page_num INTEGER,
|
||||||
|
bbox JSONB,
|
||||||
|
section_type TEXT,
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **H.2.3** Тест
|
||||||
|
- [ ] Індексувати 1 PDF (наприклад, "Токеноміка MicroDAO")
|
||||||
|
- [ ] Перевірити, що в storage з'явилися Documents з meta `[dao_id=... , doc_id=...]`
|
||||||
|
- [ ] Перевірити, що embeddings обчислені та збережені
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### H.3. Query-пайплайн (RAG-відповіді)
|
||||||
|
|
||||||
|
- [ ] **H.3.1** Створити `services/rag_query_pipeline.py`
|
||||||
|
- [ ] Функція `answer_query(dao_id, user_id, question: str) -> RAGResponse`
|
||||||
|
|
||||||
|
- [ ] **H.3.2** RAG-пайплайн (якщо використовуємо Haystack)
|
||||||
|
- [ ] `retriever` → top-k документів/фрагментів по `dao_id`
|
||||||
|
- [ ] Використати `pgvector` для similarity search
|
||||||
|
- [ ] Фільтр по `dao_id` для ізоляції даних
|
||||||
|
- [ ] (опційно) `ranker` → rerank за релевантністю
|
||||||
|
- [ ] `generator` → LLM (qwen3:8b або PokeeResearch-7B)
|
||||||
|
- [ ] Формувати промпт з контекстом: `question + retrieved_chunks`
|
||||||
|
|
||||||
|
- [ ] **H.3.3** Вихід `RAGResponse`
|
||||||
|
```python
|
||||||
|
class RAGResponse:
|
||||||
|
answer: str
|
||||||
|
citations: List[Citation]
|
||||||
|
confidence: float
|
||||||
|
|
||||||
|
class Citation:
|
||||||
|
doc_id: str
|
||||||
|
doc_title: str
|
||||||
|
page: int
|
||||||
|
excerpt: str
|
||||||
|
bbox: Optional[Dict] # для виділення в PDF
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **H.3.4** E2E-тест
|
||||||
|
- [ ] `mode="rag_query"` запит до Router:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mode": "rag_query",
|
||||||
|
"dao_id": "daarion",
|
||||||
|
"user_id": "test",
|
||||||
|
"payload": {
|
||||||
|
"question": "Поясни токеноміку microDAO і роль стейкінгу."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- [ ] Очікування: відповідь + 2–3 посилання на індексовані документи
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### H.4. Оркестрація: PARSER як головний агент
|
||||||
|
|
||||||
|
- [ ] **H.4.1** Додати в CrewAI workflow `doc_ingest_workflow`
|
||||||
|
- [ ] Agent `parser_agent`:
|
||||||
|
- [ ] Перевіряє тип документа
|
||||||
|
- [ ] Вирішує: локальний PARSER vs хмарний (якщо важкі PDF)
|
||||||
|
- [ ] Викликає `rag_ingest_pipeline`
|
||||||
|
- [ ] Agent `validation_agent`:
|
||||||
|
- [ ] Робить sanity-check: кількість блоків, чи є таблиці, чи коректна мова
|
||||||
|
- [ ] Перевіряє якість розпізнавання (confidence scores)
|
||||||
|
|
||||||
|
- [ ] **H.4.2** Додати в workflow `rag_answer_workflow`
|
||||||
|
- [ ] Крок 1: `retrieval_agent` (Haystack/pgvector)
|
||||||
|
- [ ] Пошук релевантних фрагментів
|
||||||
|
- [ ] Крок 2: `answer_agent` (LLM)
|
||||||
|
- [ ] Генерація відповіді на основі контексту
|
||||||
|
- [ ] Крок 3: (опційно) `citation_checker`
|
||||||
|
- [ ] Верифікація відповідей по фрагментах
|
||||||
|
- [ ] Перевірка на галлюцинації
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### H.5. Інтеграція з DAARWIZZBot / microDAO
|
||||||
|
|
||||||
|
- [ ] **H.5.1** Додати команди для бота (в `gateway-bot/http_api.py`)
|
||||||
|
- [ ] `/upload_doc` → інжест документу в RAG через PARSER
|
||||||
|
- [ ] Підтримка завантаження файлів через Telegram
|
||||||
|
- [ ] Виклик `doc_ingest_workflow`
|
||||||
|
- [ ] `/ask_doc` → питання до бази документів DAO
|
||||||
|
- [ ] Виклик `rag_answer_workflow`
|
||||||
|
- [ ] Відправка відповіді з цитатами
|
||||||
|
|
||||||
|
- [ ] **H.5.2** RBAC
|
||||||
|
- [ ] Хто може інжестити документи (`role: admin`, `role: researcher`)
|
||||||
|
- [ ] Хто може ставити питання до приватних документів
|
||||||
|
- [ ] Перевірка прав в `microdao/rbac.py`
|
||||||
|
|
||||||
|
- [ ] **H.5.3** UI для Console (опційно)
|
||||||
|
- [ ] Сторінка `/console/documents` — список документів DAO
|
||||||
|
- [ ] Завантаження документів через drag-and-drop
|
||||||
|
- [ ] Перегляд розпарсених документів
|
||||||
|
- [ ] Чат-інтерфейс для питань до документів
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Порядок виконання (рекомендований)
|
||||||
|
|
||||||
|
### Фаза 1: PARSER Runtime (1-2 дні)
|
||||||
|
1. G.1.1 — Обрати runtime
|
||||||
|
2. G.1.2 — Створити `parser-runtime/`
|
||||||
|
3. G.1.3 — Додати конфіг
|
||||||
|
|
||||||
|
### Фаза 2: PARSER Service (2-3 дні)
|
||||||
|
1. G.2.1 — Створити FastAPI сервіс
|
||||||
|
2. G.2.2 — Реалізувати ендпоінти
|
||||||
|
3. G.2.3 — Підтримка PDF/зображень
|
||||||
|
4. G.2.4 — Pre/post-processing
|
||||||
|
5. G.2.5 — Тести
|
||||||
|
6. G.2.6 — Docker Compose
|
||||||
|
|
||||||
|
### Фаза 3: Інтеграція з Router (1 день)
|
||||||
|
1. G.3.1 — LLM-профіль
|
||||||
|
2. G.3.2 — Provider
|
||||||
|
3. G.3.3 — Routing rule
|
||||||
|
4. G.3.4 — Розширити RouterRequest
|
||||||
|
5. G.3.5 — E2E тест
|
||||||
|
|
||||||
|
### Фаза 4: RAG Ingest (2-3 дні)
|
||||||
|
1. H.1.1 — Обрати стек
|
||||||
|
2. H.2.1 — Створити ingest pipeline
|
||||||
|
3. H.2.2 — Реалізувати кроки
|
||||||
|
4. H.2.3 — Тест
|
||||||
|
|
||||||
|
### Фаза 5: RAG Query (2-3 дні)
|
||||||
|
1. H.3.1 — Створити query pipeline
|
||||||
|
2. H.3.2 — Реалізувати RAG-пайплайн
|
||||||
|
3. H.3.3 — Вихід з цитатами
|
||||||
|
4. H.3.4 — E2E тест
|
||||||
|
|
||||||
|
### Фаза 6: Оркестрація (1-2 дні)
|
||||||
|
1. H.4.1 — `doc_ingest_workflow`
|
||||||
|
2. H.4.2 — `rag_answer_workflow`
|
||||||
|
|
||||||
|
### Фаза 7: Інтеграція з ботом (1-2 дні)
|
||||||
|
1. H.5.1 — Команди `/upload_doc`, `/ask_doc`
|
||||||
|
2. H.5.2 — RBAC
|
||||||
|
|
||||||
|
**Загальний час:** ~10-15 днів (залежить від складності моделі та налаштування)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Залежності та ресурси
|
||||||
|
|
||||||
|
### Python пакети
|
||||||
|
- `qwen3-asr-toolkit` (якщо доступний)
|
||||||
|
- `transformers` / `torch` (для моделі)
|
||||||
|
- `pdf2image` / `PyMuPDF` (для PDF)
|
||||||
|
- `Pillow` (для зображень)
|
||||||
|
- `sentence-transformers` (для embeddings)
|
||||||
|
- `pgvector` (вже є)
|
||||||
|
- `haystack` (якщо використовуємо)
|
||||||
|
|
||||||
|
### Системні залежності
|
||||||
|
- `ffmpeg` (може знадобитися)
|
||||||
|
- `poppler` (для PDF → images)
|
||||||
|
|
||||||
|
### GPU
|
||||||
|
- Рекомендовано GPU для dots.ocr (можна CPU fallback)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Посилання
|
||||||
|
|
||||||
|
- [PARSER Agent Documentation](./docs/agents/parser.md)
|
||||||
|
- [DAGI Router Documentation](./docs/agents/dagi-router.md)
|
||||||
|
- [CrewAI Orchestrator](./docs/agents/crewai-orchestrator.md)
|
||||||
|
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
- `crewai-orchestrator.md` — архітектура CrewAI
|
- `crewai-orchestrator.md` — архітектура CrewAI
|
||||||
- `crewai-integration.md` — інтеграція з системою
|
- `crewai-integration.md` — інтеграція з системою
|
||||||
|
|
||||||
|
### PARSER Agent
|
||||||
|
- `parser.md` — Document Ingestion & Structuring Agent (dots.ocr)
|
||||||
|
|
||||||
## Посилання
|
## Посилання
|
||||||
|
|
||||||
- [MicroDAO документація](../microdao/README.md)
|
- [MicroDAO документація](../microdao/README.md)
|
||||||
|
|||||||
278
docs/agents/parser.md
Normal file
278
docs/agents/parser.md
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
# PARSER Agent (dots.ocr)
|
||||||
|
|
||||||
|
**Document Ingestion & Structuring Agent** для DAARION / microDAO / SecondMe.
|
||||||
|
|
||||||
|
## Роль та призначення
|
||||||
|
|
||||||
|
PARSER — це агент, який перетворює неструктуровані документи (PDF, зображення) у структуровані дані для RAG (Retrieval-Augmented Generation) та знань-орієнтованих систем.
|
||||||
|
|
||||||
|
**Основна мета:** Забезпечити якісний інжест документів у базу знань зі збереженням структури, layout та семантики.
|
||||||
|
|
||||||
|
## Технічна база
|
||||||
|
|
||||||
|
### Модель: `rednote-hilab/dots.ocr`
|
||||||
|
|
||||||
|
- **Тип:** Image-Text-to-Text VLM (Vision Language Model)
|
||||||
|
- **Орієнтація:** Документ-орієнтований OCR з layout detection
|
||||||
|
- **GitHub:** https://github.com/QwenLM/Qwen3-ASR-Toolkit (або відповідний репозиторій)
|
||||||
|
|
||||||
|
### Ключові можливості моделі
|
||||||
|
|
||||||
|
1. **Мультимовний OCR + Layout**
|
||||||
|
- Розпізнає текст на багатьох мовах (включаючи low-resource)
|
||||||
|
- Правильно відновлює **reading order** (колонки, блоки, змішаний макет)
|
||||||
|
- Підтримка складних макетів (наукові статті, звіти, форми)
|
||||||
|
|
||||||
|
2. **Єдиний VLM для всього**
|
||||||
|
- Один модельний стек для **layout detection + OCR**
|
||||||
|
- Не потребує окремих моделей для таблиць/тексту/формул
|
||||||
|
- Уніфікований підхід до різних типів контенту
|
||||||
|
|
||||||
|
3. **Структурований вихід**
|
||||||
|
- JSON з блоками (`paragraph`, `heading`, `table`, `formula`, `figure_caption`, ...)
|
||||||
|
- Bbox-координати, сторінка, читальний порядок
|
||||||
|
- Окремі структури для таблиць (рядки/колонки, merged cells)
|
||||||
|
- Markdown/HTML-подібний текст (таблиці можна відтворювати як Markdown)
|
||||||
|
|
||||||
|
4. **Орієнтація на документи**
|
||||||
|
- Підтримка форм, інвойсів, звітів, наукових статей, презентацій
|
||||||
|
- Добре працює із змішаним контентом (текст навколо формул, підписи до рисунків)
|
||||||
|
|
||||||
|
## Вхідні дані
|
||||||
|
|
||||||
|
### Підтримувані формати
|
||||||
|
|
||||||
|
- **PDF:**
|
||||||
|
- Скани (зображення сторінок)
|
||||||
|
- "Цифрові" PDF (текст + векторна графіка)
|
||||||
|
- Багатосторінкові документи
|
||||||
|
|
||||||
|
- **Зображення:**
|
||||||
|
- PNG, JPEG, TIFF
|
||||||
|
- Підтримка різних роздільних здатностей
|
||||||
|
|
||||||
|
- **Документи зі змішаним контентом:**
|
||||||
|
- Текст + таблиці + схеми + формули
|
||||||
|
- Наукові статті, звіти, презентації
|
||||||
|
|
||||||
|
## Режими виводу
|
||||||
|
|
||||||
|
PARSER підтримує кілька режимів виводу (конфігурується через промпт/параметри):
|
||||||
|
|
||||||
|
### 1. `raw_json`
|
||||||
|
Повний структурований JSON з усіма блоками:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"page_num": 1,
|
||||||
|
"blocks": [
|
||||||
|
{
|
||||||
|
"type": "heading",
|
||||||
|
"text": "Заголовок",
|
||||||
|
"bbox": [x, y, width, height],
|
||||||
|
"reading_order": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "paragraph",
|
||||||
|
"text": "Текст параграфу...",
|
||||||
|
"bbox": [...],
|
||||||
|
"reading_order": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "table",
|
||||||
|
"rows": [...],
|
||||||
|
"columns": [...],
|
||||||
|
"merged_cells": [...]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. `markdown`
|
||||||
|
Таблиці/розділи у Markdown форматі:
|
||||||
|
```markdown
|
||||||
|
# Заголовок
|
||||||
|
|
||||||
|
Текст параграфу...
|
||||||
|
|
||||||
|
| Колонка 1 | Колонка 2 |
|
||||||
|
|-----------|-----------|
|
||||||
|
| Значення 1 | Значення 2 |
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. `qa_pairs`
|
||||||
|
Парсер одразу повертає Q&A-пари по документу (через LLM-постпроцес):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"qa_pairs": [
|
||||||
|
{
|
||||||
|
"question": "Що таке токеноміка microDAO?",
|
||||||
|
"answer": "Токеноміка microDAO включає...",
|
||||||
|
"source_page": 1,
|
||||||
|
"source_bbox": [...]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. `chunks`
|
||||||
|
Масив семантичних фрагментів для RAG:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"chunks": [
|
||||||
|
{
|
||||||
|
"text": "Фрагмент тексту...",
|
||||||
|
"page": 1,
|
||||||
|
"bbox": [...],
|
||||||
|
"section": "introduction",
|
||||||
|
"metadata": {
|
||||||
|
"dao_id": "daarion",
|
||||||
|
"doc_id": "tokenomics_v1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Вихідні дані
|
||||||
|
|
||||||
|
### Структура `ParsedDocument`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ParsedDocument {
|
||||||
|
doc_id: string;
|
||||||
|
doc_url?: string;
|
||||||
|
doc_type: "pdf" | "image";
|
||||||
|
pages: ParsedPage[];
|
||||||
|
metadata: {
|
||||||
|
dao_id: string;
|
||||||
|
user_id: string;
|
||||||
|
uploaded_at: string;
|
||||||
|
file_size: number;
|
||||||
|
page_count: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParsedPage {
|
||||||
|
page_num: number;
|
||||||
|
blocks: ParsedBlock[];
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParsedBlock {
|
||||||
|
type: "paragraph" | "heading" | "table" | "formula" | "figure_caption" | "list";
|
||||||
|
text: string;
|
||||||
|
bbox: [x: number, y: number, width: number, height: number];
|
||||||
|
reading_order: number;
|
||||||
|
// Для таблиць:
|
||||||
|
table_data?: {
|
||||||
|
rows: string[][];
|
||||||
|
columns: string[];
|
||||||
|
merged_cells?: Array<{row: number, col: number, rowspan: number, colspan: number}>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Обмеження
|
||||||
|
|
||||||
|
- **Max pages:** Конфігурується через `PARSER_MAX_PAGES` (за замовчуванням: 100)
|
||||||
|
- **Max resolution:** Конфігурується через `PARSER_MAX_RESOLUTION` (за замовчуванням: 4096x4096)
|
||||||
|
- **Max file size:** Залежить від runtime (рекомендовано: до 50MB для PDF)
|
||||||
|
- **Підтримка мов:** Залежить від моделі dots.ocr (українська підтримується)
|
||||||
|
|
||||||
|
## Інтеграція з системою
|
||||||
|
|
||||||
|
### 1. DAGI Router
|
||||||
|
|
||||||
|
PARSER інтегрується як окремий провайдер:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
providers:
|
||||||
|
parser:
|
||||||
|
type: ocr
|
||||||
|
base_url: "http://parser-service:9400"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Routing rule:**
|
||||||
|
```yaml
|
||||||
|
routing:
|
||||||
|
- id: doc_parse
|
||||||
|
when:
|
||||||
|
mode: doc_parse
|
||||||
|
use_provider: parser
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. CrewAI Orchestrator
|
||||||
|
|
||||||
|
PARSER як агент у CrewAI workflow:
|
||||||
|
|
||||||
|
- **`doc_ingest_workflow`:** Перевірка типу документа → виклик PARSER → інжест у RAG
|
||||||
|
- **`rag_answer_workflow`:** Використання розпарсених документів для відповідей
|
||||||
|
|
||||||
|
### 3. RBAC Integration
|
||||||
|
|
||||||
|
- Перевірка прав на інжест документів (`role: admin`, `role: researcher`)
|
||||||
|
- Обмеження на приватні/публічні документи
|
||||||
|
- Перевірка `dao_id` для ізоляції даних
|
||||||
|
|
||||||
|
## Використання
|
||||||
|
|
||||||
|
### Приклад запиту до PARSER
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://parser-service:9400/ocr/parse \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"doc_url": "https://example.com/tokenomics.pdf",
|
||||||
|
"output_mode": "chunks",
|
||||||
|
"dao_id": "daarion",
|
||||||
|
"user_id": "user123"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Приклад через DAGI Router
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://router:9102/route \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"mode": "doc_parse",
|
||||||
|
"dao_id": "daarion",
|
||||||
|
"user_id": "user123",
|
||||||
|
"payload": {
|
||||||
|
"doc_url": "https://example.com/tokenomics.pdf",
|
||||||
|
"output_mode": "qa_pairs"
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Архітектура сервісу
|
||||||
|
|
||||||
|
```
|
||||||
|
parser-service/
|
||||||
|
├── main.py # FastAPI сервіс
|
||||||
|
├── parser_runtime/ # Runtime для dots.ocr
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── model_loader.py # Lazy init, GPU/CPU fallback
|
||||||
|
│ └── inference.py # parse_image, parse_pdf
|
||||||
|
├── schemas.py # Pydantic моделі
|
||||||
|
└── config.py # Конфігурація
|
||||||
|
```
|
||||||
|
|
||||||
|
## Залежності
|
||||||
|
|
||||||
|
- **Runtime:** HuggingFace Transformers + vLLM/SGLang (або llama.cpp/GGUF)
|
||||||
|
- **Модель:** `rednote-hilab/dots.ocr`
|
||||||
|
- **Python:** 3.11+
|
||||||
|
- **GPU:** Рекомендовано (можна CPU fallback)
|
||||||
|
|
||||||
|
## Посилання
|
||||||
|
|
||||||
|
- [TODO: PARSER + RAG Implementation](../TODO-PARSER-RAG.md)
|
||||||
|
- [DAGI Router Documentation](./dagi-router.md)
|
||||||
|
- [CrewAI Orchestrator](./crewai-orchestrator.md)
|
||||||
|
|
||||||
Reference in New Issue
Block a user