225 lines
11 KiB
Markdown
225 lines
11 KiB
Markdown
# RIP Help System — Help-файл декомпозитор и viewer
|
||
|
||
Обработва help-файлове (`.html`, `.htm`, `.docx`, `.doc`, `.pdf`, `.txt`), декомпозира ги на секции, извлича картинки, класифицира секциите с Claude API (заглавие + ключови думи), и записва всичко в SQL Server. После генерира интерактивен HTML viewer.
|
||
|
||
**Основен вход в момента:** HTML от Word/LibreOffice „Save as… / уеб страница“ (относителни картинки + H1/H2/MsoNormal структура). PDF и DOCX са вторични.
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
Входни файлове → 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` и `.docx`: bold/цветове/картинки) |
|
||
| 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 → `r:embed` (related_parts) или `r:link` (UNC/`file:///` + sidecar `<stem>_media/` до .docx)
|
||
- `.html` — локални файлове (относителен `src` спрямо HTML папката, вкл. `../` и `%20`) и `data:` URLs; HTTP пропуска; warning при липсващ файл
|
||
- `.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: **`https://rip.inex-project.net`** → Coolify прави HTTPS (Let's Encrypt) автоматично
|
||
|
||
Live: [https://rip.inex-project.net/?prefix=RIP](https://rip.inex-project.net/?prefix=RIP) · health: [/healthz](https://rip.inex-project.net/healthz)
|
||
|
||
## Visual Studio и Git
|
||
|
||
Това е Python/Docker репо, не .NET. Въпреки това се отваря във Visual Studio (2022/2026) за текстовия редактор и за **Commit + Push** — същият ритъм като при C++/.NET.
|
||
|
||
`.sln` стои **до** `.git` (корен на репото). Така Git Changes вижда `origin` → `https://git.inex-project.net/sabo/rip-help-system.git`, клон `master`.
|
||
|
||
### Отваряне
|
||
|
||
- Двоен клик на `RIP_Help_system.sln`, или
|
||
- `open-in-vs.bat` в тази папка, или
|
||
- File → Open → Project/Solution → `C:\~ip\cursor_projects\RIP_Help_system\RIP_Help_system.sln`
|
||
|
||
Алтернатива без `.sln`: File → Open → Folder → същата папка (пак трябва да има `.git`).
|
||
|
||
Други проекти под `c:\~ip\cursor_projects\`: `C:\~ip\cursor_projects\open-in-vs.bat <име-на-папка>`. Ако няма `.sln`, VS отваря папката (Open Folder) и пак вижда Git.
|
||
|
||
### Еднократно във VS
|
||
|
||
1. **Tools → Options → Source Control → Plug-in Selection → Git** (не VisualSVN).
|
||
2. Не натискай **Create Git Repository** — репото вече съществува.
|
||
3. При Push VS ще поиска вход за **git.inex-project.net** (Gitea), не GitHub.
|
||
|
||
### Commit + Push (Git Changes)
|
||
|
||
1. View → Git Changes (или Git → Commit or Stash).
|
||
2. Отметни файловете (не `.env`).
|
||
3. Съобщение → **Commit All**.
|
||
4. **Push** към `origin/master`.
|
||
5. Redeploy в Coolify остава ръчно.
|
||
|
||
Нови файлове, които още не са в `.sln`, пак се виждат в Git Changes. При нужда ги добави като Solution Items или ползвай Open Folder.
|
||
|
||
### Сравнение с production (`/healthz`)
|
||
|
||
След Push + Coolify redeploy сравни `git` от [https://rip.inex-project.net/healthz](https://rip.inex-project.net/healthz) с локалното: Solution Explorer → **scripts** → десен клик `show-version.bat` → **Open Containing Folder** → двоен клик (прозорецът чака Enter). Префиксът (`0.3.0`) е във **VERSION** (Solution Explorer → **deploy**). Production вижда SHA едва след commit + push + redeploy.
|
||
|
||
### Качване на картинки на сървъра
|
||
|
||
Локалният `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-а директно.
|