# План доработки: модель озвучки для grabber ## Цель По ссылке на раздачу (rutracker / kinozal / nnm-club) или её HTML определить **на уровне релиза**: какие дорожки озвучки есть, кто их сделал (студия / переводчик), какого они типа (дубляж, многоголосый, …) и есть ли 18+. Модель должна быть маленькой и встраиваемой в grabber. ## Что уже есть (анализ) * Multi-task RuBERT (тип 14 классов + BIO-спан автора + 18+), 3742 строки, joint exact 0.946 (base) / 0.915 (tiny2); ONNX-экспорт с parity 100%; FastAPI-сервис; клиенты Rust/TS/PowerShell; тесты и документация. * grabber (`C:\Users\shats\Dev\grabber`) — **PHP 8.1 + Docker**, интеграции Radarr/Sonarr/qBittorrent/Prowlarr; студии с kinozal разбирает регулярками (`KinozalReleaseParser.php`, `ProwlarrReleaseEnricher.php`), идёт Rust-порт. Естественный путь интеграции — **HTTP-сервис** (PHP ходит curl-ом), ONNX нужен для Rust-порта. ## Пробелы относительно задачи | # | Пробел | Решение | |---|---|---| | 1 | Нет входа «по ссылке» (только `text`/`html`) | `url` в CLI, сервисе, API: fetch (таймаут, UA, cp1251), определение трекера по домену | | 2 | Ответ — плоский список дорожек | Агрегат релиза: дедуп дорожек, уникальные студии с типами, `is_18plus` релиза; поле `tracks` не ломаем | | 3 | Заголовок раздачи (`/ ПМ (LostFilm) /`) не используется | fallback-парсинг title, если дорожек 0 или студии нет в дорожках | | 4 | kinozal: авторы грузятся JS | при работе по URL запросить вкладку озвучки напрямую (эндпоинт — из `data/samples/kinozal*.html`, не угадывать) | | 5 | «Маленькая» модель: best = base (~440 МБ) | tiny2 (30M) + ONNX + int8-квантизация; решение по цифрам parity/размера | | 6 | Precision 0.83 на rutracker | разобрать ложные срабатывания e2e — скорее всего регулярки сегментации | | 7 | В git закоммичен `examples/rust/*/target/` | `.gitignore` + удалить из индекса | ## Порядок работ 1. **Baseline**: tests + e2e на текущих моделях (цифры в конец документа). 2. **URL + агрегат релиза** (`src/fetch.py`, `src/release.py`, эндпоинт `POST /predict` с `url`, CLI `--url`). 3. **Title-fallback** в `html_extract.py`. 4. **kinozal-вкладка** (если эндпоинт найден в сэмплах). 5. **Разбор false-positives** сегментации. 6. **tiny2 + int8 ONNX**, замер размера/parity. 7. **Тесты** на каждый пункт, обновление docs/README. 8. `.gitignore` + чистка `target/`. ## Критерии готовности * `python -m src.predict --url <ссылка>` печатает агрегат релиза; * e2e precision/recall не хуже baseline; * малая модель < ~40 МБ (int8), parity ≥ 99%; * тесты зелёные, docs обновлены. ## Baseline Модель `models/best` (ruBert-base), `tests/e2e_check.py`: * rutracker: precision 0.826 / recall 0.984 (n=290); * kinozal: 0.107 / 0.107 (n=28) — в текстовых дампах нет авторов (JS), потолок данных; * smoke вне датасета: тип 9/10, автор 5/10, 18+ 10/10; * `tests/run_tests.py`: 34 ok. ## Статус | Шаг | Состояние | |---|---| | 1 baseline | сделано | | 2 URL + агрегат релиза | сделано: `src/fetch.py`, `src/release.py`, `--url`, `POST /predict {"url"}` | | 3 title-fallback | сделано (`ПМ (LostFilm)` → дорожка с `source: "title"`); заголовок берётся из HTML (`