docker / build (push) Successful in 1m20s
Переразбор всех страниц data/raw: legacy-страницы импорта, форматы префиксов ([*]Перевод (1):, Озвучка:, №2, диапазоны), дорожки только в строках «Аудио» (в т.ч. «(Русский, X)», «| Rus | Звук: …»), «Язык озвучки», несколько студий в одной строке, студия без типа. Кодек-строки: «Аудио #N Русский:», «Аудио pic RUS:», «Звук N:», «Аудиодорожка 01:», кириллические АVO/МVO. «Авторский» без числа голосов -> авт. одноголосый, «двугоголосый». Чистка студий: языки, кодеки, «по заказу», «в составе контейнера», отказы от озвучки. Итог: страниц с метками 30 260 (85.5 %), страниц с дорожкой без меток 1 259 -> 223; data/pages 30 444; после prepare_data 60 944 строки (train 54 686 / test 6 258). Новый tools/coverage_audit.py + reports/coverage_audit.md, docs/dataset-coverage.md. Переобучен models/best (base): на общем тесте type acc 0.976 против 0.949 у прежней, span 0.674 против 0.643; e2e kinozal 0.805/0.867, rt 0.771/0.740, nnm 0.752/0.693.
9.0 KiB
9.0 KiB
grabber-ai — нейро-модель «тип озвучки + автор + 18+»
По тексту дорожки озвучки (или HTML-странице релиза с трекеров rutracker / kinozal / nnm-club) модель определяет:
- тип озвучки (
translation_type, 15 классов: проф. дубляж, проф. многоголосый, авт. одноголосый, …) — классификация; - автора (
studio: студия или переводчик) — извлечение имени прямо из текста (работает и для авторов, которых не было в обучении) + нормализация по словарю алиасов («HDRezka Studio» →HDrezka, «Ю. Сербин» → «Юрий Сербин»); - 18+ дорожка или нет — бинарная голова.
Обучено на датасете из 60 944 строк (71 339 размеченных строк из 30 401 релиза
data/raw + морфологическая аугментация). Как страницы превращаются в строки и
что было исправлено в сборщике — docs/dataset-coverage.md.
Multi-task RuBERT: сравниваются rubert-tiny2 и ruBert-base,
лучшая кладётся в models/best.
Квикстарт (5 минут)
# 1. окружение (Windows, Python 3.13; GPU требует колёс cu128 — см. docs/training-windows.md)
python -m venv .venv
.venv\Scripts\python -m pip install torch --index-url https://download.pytorch.org/whl/cu128
.venv\Scripts\python -m pip install -r requirements.txt
# 2. данные -> подготовка (data/labels.csv уже в репозитории)
.venv\Scripts\python -m src.prepare_data
# 3. обучение (обе модели, 5-fold CV; ~15-20 мин на RTX 5070 Ti)
.venv\Scripts\python -m src.train
# результат: models/best, reports/summary.md, reports/*.png
# 4. инференс
.venv\Scripts\python -m src.predict --text "Перевод: Профессиональный (многоголосый закадровый) | HDRezka Studio 18+"
.venv\Scripts\python -m src.predict --html data/samples/rt-topic.html
.venv\Scripts\python -m src.predict --file data/pages/6907007.txt --out result.json
Python API:
from src.predict import DubPredictor
model = DubPredictor() # models/best по умолчанию
model.predict_text("Авторский (одноголосый закадровый) - Ю. Сербин")
# {'translation_type': 'авт. одноголосый', 'studio': 'Юрий Сербин', 'is_18plus': False, ...}
model.predict_html(open("data/samples/rt-topic.html", encoding="utf-8").read())
# [ {...дорожка 1...}, {...дорожка 2...}, ... ]
HTTP-сервис и интеграция из Rust/TypeScript (ONNX без Python) — см. docs/integration.md.
Структура
data/ датасет (labels.csv — снимок) и HTML-дампы страниц
data/processed/ подготовленные данные (dataset.json, label_maps.json)
src/ код: подготовка, модель, обучение, инференс, сервис, ONNX-экспорт
models/ чекпоинты (best — итоговая модель)
reports/ метрики, аудит датасета, confusion matrix, ONNX-parity
tests/ юнит-тесты (tests/run_tests.py)
examples/ клиенты: rust (HTTP, ONNX), typescript (HTTP, ONNX)
docs/ документация
Документация
- docs/architecture.md — устройство модели и пайплайна
- docs/dataset.md — схема датасета, семантика классов, аудит
- docs/dataset-coverage.md — покрытие всех страниц
data/raw, найденные дыры сборщика и что исправлено - docs/training-windows.md — обучение на Windows+GPU, troubleshooting
- docs/api-reference.md — все значения ответа сервиса (15 классов
translation_typeи др.) и принцип работы;labels.csvдля этого открывать не нужно - docs/inference.md — CLI/API, JSON-контракт
- docs/integration.md — Rust/TypeScript: HTTP-сервис и ONNX
Качество
Held-out test (6 258 строк, группировка по релизам и текстам; после полной
переиндексации data/raw 09.11.2026). Обе модели оценены на одном и том же
тесте (python -m src.runs --dirs … --refresh):
| модель | type acc | type macro-F1 | span exact | 18+ acc | lang acc | joint exact |
|---|---|---|---|---|---|---|
прежняя models/best (02.11) |
0.949 | 0.880 | 0.643 | 1.000 | 0.994 | 0.615 |
новая models/best (09.11) |
0.976 | 0.906 | 0.674 | 1.000 | 0.995 | 0.658 |
- joint exact — строка распознана полностью (тип + автор + 18+).
- Абсолютный
span exactниже прежних 0.922 не потому, что модель стала хуже: тест теперь включает форматы, которых раньше в датасете не было (авторы из кодек-строк и списков, аниме-раздачи, «Язык озвучки», nnmАудио … (Русский, X)), и в нём много одиночных имён в перечислениях. На одном и том же тесте новая модель лучше прежней по всем головам (+2.7 п.п. type acc, +3.1 п.п. span). - E2E по релизам (
tests/e2e_segmenter.py, по 400 тестовых страниц на трекер, пары тип + студия, precision / recall) — новая модель на тех же страницах: kinozal 0.805 / 0.867, rutracker 0.771 / 0.740, nnm 0.752 / 0.693; прежняя модель там же: 0.752 / 0.830, 0.729 / 0.700, 0.669 / 0.604. Справочно, правила: 0.792 / 0.859, 0.697 / 0.721, 0.670 / 0.646. - Сегментатор (
models/segmenter) переобучен на расширенном наборе страниц (models/segmenter_v2, line precision 0.933 / recall 0.977), но e2e новых весов хуже по nnm (0.610 / 0.560) — вmodels/segmenterоставлены прежние веса. models/best-onnxне пересобран под новую модель:python -m src.export_onnx. Паритет предыдущего экспорта — reports/onnx_parity.md.
Ограничения
- Метки датасета сгенерированы регулярками (пайплайн deepseek-harness) — метрики измеряют согласование с этой разметкой; ценность модели — обобщение на новые формулировки без сопровождения регулярок.
- Датасет: 71 339 строк из 30 401 релиза (kinozal 23 969 / nnm 27 092 /
rutracker 20 278); после подготовки 60 944 строки. Покрытие страниц
data/raw— 85.5 % (30 260 из 35 385); оставшиеся — почти все без озвучки (русский оригинал, «не требуется», музыка/сканы), см. docs/dataset-coverage.md. - Извлечение автора уверенно работает на форматах записи, представленных в датасете (имя после типа через разделитель, в скобках у AVO/MVO/DVO-дорожек, после тире); на непривычных форматах («Одноголосый закадровый (Фамилия)») модель может не выделить имя — span остаётся пустым, тип при этом верный.
- kinozal-страницы: авторы озвучки лежат во вкладках, которые сайт подгружает
JavaScript-ом. По
urlсервис скачивает их сам (fetch_html,showtab); в присланномhtml/textбез этих вкладок студий может не быть. - Классы с 1–8 примерами почти не выучиваются (видно в macro-F1 и confusion matrix); морфологическая аугментация (458 вариантов: «многоголосое» и т.п.) частично закрывает этот пробел.