Backend migration: - Replace pyodbc/SQL Server with psycopg2/PostgreSQL throughout - Rewrite Database class with portable SQL: SERIAL, ON CONFLICT, NOW() - Lowercase table names (rip_help_files, rip_help_sections) - Postgres convention - libpq connection string format in HELP_DB_CONN Webapp (webapp/): - FastAPI app: GET /, GET /images/<f>, GET /home-image, GET /api/sections, POST /api/keywords/<code>, GET /healthz - Jinja2 template extracted from generate_html.py with HTTP image URLs - Direct keyword save to DB (no JSON download detour) - Same prefix scoping as CLI tools (?prefix=RIP) Deployment: - Dockerfile (python:3.12-slim + uvicorn) - docker-compose.yml for local dev - requirements-webapp.txt (minimal, no Windows-only deps) - .dockerignore excludes pipeline scripts and BAT files - README updated with webapp section and Coolify deploy guide Also: switch AI model to claude-haiku-4-5 (~3x cheaper, same quality for this task) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
185 lines
8.4 KiB
Markdown
185 lines
8.4 KiB
Markdown
# RIP Help System — Help-файл декомпозитор и viewer
|
||
|
||
Обработва help-файлове (`.html`, `.htm`, `.docx`, `.doc`, `.pdf`, `.txt`), декомпозира ги на секции, извлича картинки, класифицира секциите с Claude API (заглавие + ключови думи), и записва всичко в SQL Server. После генерира интерактивен HTML viewer.
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
Входни файлове → help_processor.py → SQL Server → generate_html.py → help_viewer.html
|
||
(.docx, .html, (RIP_help_*) (Home / Редактор /
|
||
.pdf, .doc) Търсене / Генератор)
|
||
↑
|
||
│
|
||
save_keywords.py ← keywords_changes.json
|
||
(от Редактора на viewer-а)
|
||
```
|
||
|
||
## Инсталация
|
||
|
||
```
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
За стар `.doc` формат — едно от:
|
||
- **LibreOffice** в PATH (кросплатформено)
|
||
- **MS Word** (Windows, чрез pywin32 COM — автоматичен fallback)
|
||
|
||
## Конфигурация
|
||
|
||
Копирай `.env.example` като `.env` и попълни:
|
||
|
||
```
|
||
ANTHROPIC_API_KEY=sk-ant-...
|
||
HELP_DB_CONN=DRIVER={ODBC Driver 18 for SQL Server};TrustServerCertificate=yes;SERVER=host,port;DATABASE=db;UID=user;PWD=password
|
||
```
|
||
|
||
`.env` е gitignore-нат. Bat файловете го зареждат автоматично през `_load_env.bat`.
|
||
|
||
## Употреба (Windows)
|
||
|
||
### Обработка на нов проект
|
||
|
||
Първо създай `<PROJECT>_load.bat` и `<PROJECT>_view.bat` (вж. `RIP_load.bat`, `RIP_view.bat` като образец).
|
||
|
||
| BAT | Какво прави |
|
||
|---|---|
|
||
| `RIP_load.bat` | Incremental — обработва само нови/променени файлове по SHA-256 hash |
|
||
| `RIP_load_force.bat` | `--force --purge-missing` — преобработва всичко, изтрива orphans |
|
||
| `RIP_view.bat` | Генерира `help_viewer.html` за prefix=RIP и го отваря в браузъра |
|
||
|
||
### Директно от CLI
|
||
|
||
```
|
||
python help_processor.py --prefix=<PREFIX> <input_dir> <output_dir>
|
||
python help_processor.py --prefix=<PREFIX> --force --purge-missing <input_dir> <output_dir>
|
||
|
||
python generate_html.py --prefix=<PREFIX> # без Home таб
|
||
python generate_html.py --prefix=<PREFIX> --home img.png # с Home таб
|
||
```
|
||
|
||
## Prefix scoping
|
||
|
||
Всеки проект има свой `--prefix` (напр. `RIP`, `INEX_TM`). Прави следните неща изолирани между проектите:
|
||
|
||
- Кодовете на секциите: `RIP_0001_SEC_0001` vs `INEX_TM_0001_SEC_0001`
|
||
- skip-by-hash (incremental) — само в рамките на prefix-а
|
||
- `--purge-missing` — изтрива orphans само в текущия prefix
|
||
- `generate_html.py --prefix=X` — viewer-а филтрира по prefix
|
||
|
||
## Структура на базата
|
||
|
||
### `RIP_help_files`
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| id | INT IDENTITY | PK |
|
||
| prefix | NVARCHAR(50) | Project scope |
|
||
| file_path | NVARCHAR(1000) | Пълен път до файла |
|
||
| file_hash | CHAR(64) | SHA-256 за incremental |
|
||
| processed_at | DATETIME2 | Последна обработка |
|
||
| section_count | INT | Брой секции |
|
||
|
||
UNIQUE constraint: `(prefix, file_path)`
|
||
|
||
### `RIP_help_sections`
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| id | INT IDENTITY | PK |
|
||
| prefix | NVARCHAR(50) | Project scope |
|
||
| code | NVARCHAR(80) | `<PREFIX>_NNNN_SEC_NNNN` (UNIQUE) |
|
||
| source_file | NVARCHAR(1000) | Източник |
|
||
| title | NVARCHAR(500) | AI-генерирано заглавие |
|
||
| keywords | NVARCHAR(300) | До 5 ключови думи |
|
||
| char_count | INT | Размер на чистия текст |
|
||
| output_path | NVARCHAR(1000) | Път до `.txt` файла |
|
||
| images | NVARCHAR(MAX) | JSON масив с относителни пътища |
|
||
| html_text | NVARCHAR(MAX) | Rich HTML с форматиране (само за `.html` източници) |
|
||
| created_at, updated_at | DATETIME2 | |
|
||
|
||
## HTML Viewer — 3 / 4 таба
|
||
|
||
- **Home** (опционален, ако `--home <image>` е подаден) — началов екран с изображение
|
||
- **Редактор** — таблица със секции; inline редактиране на ключови думи; ✓ Save → JSON download → `save_keywords.py` → UPDATE в БД
|
||
- **Търсене** — карти със секции; multi-keyword (intervals = AND, "phrase" = literal); preview с картинки
|
||
- **Генератор** — drag & drop ordering → export като HTML (self-contained, всички картинки base64-embed-нати)
|
||
|
||
## Картинки
|
||
|
||
Извличат се по време на парсване:
|
||
- `.docx` — `<a:blip>` в paragraph drawings → bytes от related_parts
|
||
- `.html` — локални файлове и `data:` URLs; HTTP пропуска
|
||
- `.pdf` — `pdfplumber.page.crop(bbox).to_image()` като PNG
|
||
- `.doc` — след LibreOffice/MS Word конверсия до `.docx`
|
||
|
||
Филтър ≥ 50×50 px (PIL детектва), за да отрязва иконки/булети.
|
||
|
||
Записват се в `<output_dir>/images/<code>_img_NN.<ext>`. В текста placeholder `[IMG: images/...]`. В DB `images` колоната съдържа JSON масив с пътищата.
|
||
|
||
## Constants (в `help_processor.py`)
|
||
|
||
| Константа | Default | Описание |
|
||
|---|---|---|
|
||
| `MIN_SECTION_TOKENS` | 60 | Под този праг секцията се слива с предишната |
|
||
| `MAX_AI_CHARS` | 4000 | Символи, пращани към Claude |
|
||
| `AI_MODEL` | claude-haiku-4-5 | Модел за класификация |
|
||
| `MIN_IMAGE_PX` | 50 | Картинки под NxN px се пропускат |
|
||
|
||
---
|
||
|
||
## Webapp (FastAPI)
|
||
|
||
`webapp/` съдържа FastAPI app за server deploy (Coolify / Docker).
|
||
|
||
### Endpoint-и
|
||
|
||
| Метод | Път | Описание |
|
||
|---|---|---|
|
||
| GET | `/` | HTML viewer (Home/Editor/Search/Generator); query `?prefix=RIP&home=1` |
|
||
| GET | `/images/<file>` | Сервира картинка от `OUTPUT_DIR/images/` |
|
||
| GET | `/home-image` | Home image (от `HOME_IMAGE` env var или `Bairaci.png`) |
|
||
| GET | `/api/sections` | JSON списък със секции; query `?prefix=` |
|
||
| POST | `/api/keywords/<code>` | `{keywords: "..."}` → UPDATE в DB |
|
||
| GET | `/healthz` | Health check (DB ping) |
|
||
|
||
### Env vars
|
||
|
||
| Var | Default | Описание |
|
||
|---|---|---|
|
||
| `HELP_DB_CONN` | — | libpq формат за Postgres (задължително) |
|
||
| `OUTPUT_DIR` | `./data` | Директория с `images/` подпапка |
|
||
| `HOME_IMAGE` | — | Абсолютен път към home картинка (опционален) |
|
||
|
||
### Локален dev
|
||
|
||
```
|
||
pip install -r requirements-webapp.txt
|
||
$env:HELP_DB_CONN="host=192.168.88.18 port=5432 dbname=rip_help_system user=sa password=..."
|
||
$env:OUTPUT_DIR="q:\RIP_Help_Source\Output"
|
||
python -m uvicorn webapp.main:app --reload
|
||
# отвори http://127.0.0.1:8000/?prefix=RIP&home=1
|
||
```
|
||
|
||
### Coolify deploy
|
||
|
||
1. В Coolify: New Resource → Application → Public/Private Repository
|
||
2. URL: `https://git.inex-project.net/sabo/rip-help-system.git`
|
||
3. Build pack: **Dockerfile**
|
||
4. Environment variables (в Coolify UI, не в git):
|
||
- `HELP_DB_CONN=host=... port=5432 dbname=rip_help_system user=... password=...`
|
||
- `OUTPUT_DIR=/data/help_output`
|
||
- `HOME_IMAGE=/data/help_output/Bairaci.png` (по избор)
|
||
5. Persistent storage (volume): `/data/help_output` (там качваш картинките с WinSCP/rsync)
|
||
6. Port: 8000
|
||
7. Custom domain → Coolify прави HTTPS (Let's Encrypt) автоматично
|
||
|
||
### Качване на картинки на сървъра
|
||
|
||
Локалният `help_processor.py` пише в `q:\RIP_Help_Source\Output\` (включително `images/` подпапка). За deploy:
|
||
|
||
```
|
||
# с WinSCP — sync на цялата директория
|
||
local: q:\RIP_Help_Source\Output\
|
||
remote: /home/sabo/share/help_output/ ← Coolify volume mount
|
||
```
|
||
|
||
Базата (Postgres на 192.168.88.18) се ползва от webapp-а директно.
|