Переименование: DUB-AI → grabber-ai (образ, сервис, документация, примеры)
docker / build (push) Successful in 21s

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
DenozordecandClaude Sonnet 5.5 committed 2026-10-28 18:57:41 +07:00
1 parent a64ced71d2
commit 71d9700f55
26 files changed
+48 -48

No files matched your search

+2 -2
View File
@@ -1,12 +1,12 @@
# Скопируйте в .env и поправьте. Используется docker-compose.yml.
# Образ: локальная сборка или из реестра Gitea (host/owner/repo:tag)
DUB_IMAGE=dub-ai:local
DUB_IMAGE=grabber-ai:local
# Порт на хосте
DUB_PUBLISH_PORT=8000
# FlareSolverr: адрес, по которому ему доступен контейнер dub-ai.
# FlareSolverr: адрес, по которому ему доступен контейнер grabber-ai.
# В compose поднимается рядом (http://flaresolverr:8191); внешний — укажите его адрес.
# Пусто — без обхода Cloudflare.
DUB_FLARESOLVERR_URL=http://flaresolverr:8191
+2 -2
View File
@@ -1,4 +1,4 @@
# Сборка и публикация Docker-образа DUB-AI в реестр контейнеров Gitea.
# Сборка и публикация Docker-образа grabber-ai в реестр контейнеров Gitea.
#
# Запускается: пуш в main/master, тег v*, вручную (workflow_dispatch).
# Нужно один раз настроить (подробно — docs/docker.md, раздел «CI/CD в Gitea»):
@@ -17,7 +17,7 @@ on:
workflow_dispatch:
env:
IMAGE_NAME: dub-ai
IMAGE_NAME: grabber-ai
# Публичный адрес реестра (HTTPS). Нельзя брать из GITHUB_SERVER_URL: внутри раннера это внутренний
# адрес Gitea (http://192.168.x.x:3000), у него нет HTTPS. Переопределяется переменной REGISTRY_HOST.
REGISTRY_HOST: ${{ vars.REGISTRY_HOST || 'git.shx.one' }}
+2 -2
View File
@@ -1,8 +1,8 @@
# syntax=docker/dockerfile:1
# DUB-AI: HTTP-сервис определения дорожек озвучки (FastAPI), CPU.
# grabber-ai: HTTP-сервис определения дорожек озвучки (FastAPI), CPU.
#
# python tools/pack_models.py --stage docker-models # положить модели в образ (необязательно)
# docker build -t dub-ai .
# docker build -t grabber-ai .
#
# Без шага pack_models образ собирается без моделей — тогда смонтируйте каталог: -v ./models:/app/models:ro
FROM python:3.12-slim
+1 -1
View File
@@ -1,4 +1,4 @@
# DUB-AI — нейро-модель «тип озвучки + автор + 18+»
# grabber-ai — нейро-модель «тип озвучки + автор + 18+»
По тексту дорожки озвучки (или HTML-странице релиза с трекеров rutracker /
kinozal / nnm-club) модель определяет:
+4 -4
View File
@@ -1,7 +1,7 @@
# DUB-AI + FlareSolverr. docker compose up -d (настройки — в .env, см. .env.example)
# grabber-ai + FlareSolverr. docker compose up -d (настройки — в .env, см. .env.example)
services:
dub-ai:
image: ${DUB_IMAGE:-dub-ai:local}
grabber-ai:
image: ${DUB_IMAGE:-grabber-ai:local}
build: .
restart: unless-stopped
ports:
@@ -24,4 +24,4 @@ services:
restart: unless-stopped
environment:
LOG_LEVEL: info
# порт 8191 наружу не публикуется: доступен только контейнеру dub-ai
# порт 8191 наружу не публикуется: доступен только контейнеру grabber-ai
+1 -1
View File
@@ -1,4 +1,4 @@
# Документация DUB-AI
# Документация grabber-ai
| Документ | Содержание |
|---|---|
+13 -13
View File
@@ -1,11 +1,11 @@
# Docker: запуск DUB-AI на VPS и сборка в Gitea CI/CD
# Docker: запуск grabber-ai на VPS и сборка в Gitea CI/CD
Контейнер запускает HTTP-сервис (`python -m src.service`): по ссылке на раздачу или по HTML определяет
дорожки озвучки (тип, студия, 18+, язык, роль, параметры аудио). Для трекеров за Cloudflare сервис
обращается к вашему **FlareSolverr**, адрес которого задаётся переменной окружения.
```
клиент ──HTTP──▶ dub-ai (:8000) ──▶ трекер (rutracker / nnmclub / kinozal)
клиент ──HTTP──▶ grabber-ai (:8000) ──▶ трекер (rutracker / nnmclub / kinozal)
(grabber) │ ▲ при 403/503 или странице-заглушке
└─▶ FlareSolverr ──┘ (DUB_FLARESOLVERR_URL)
```
@@ -72,7 +72,7 @@ curl -X POST http://localhost:8000/predict \
| `DUB_SEGMENTER_DIR` | `/app/models/segmenter` | каталог сегментатора страниц; нет каталога — работают правила |
| `DUB_HOST`, `DUB_PORT` | `0.0.0.0`, `8000` | адрес/порт внутри контейнера (наружу — `DUB_PUBLISH_PORT` в compose) |
| `DUB_DEVICE` | авто | `cpu` или `cuda` (в образе только CPU-сборка torch) |
| `DUB_IMAGE` | `dub-ai:local` | (compose) какой образ запускать, напр. из реестра Gitea |
| `DUB_IMAGE` | `grabber-ai:local` | (compose) какой образ запускать, напр. из реестра Gitea |
| `DUB_PUBLISH_PORT` | `8000` | (compose) порт на хосте |
В образе жёстко заданы `HF_HUB_OFFLINE=1` и `TRANSFORMERS_OFFLINE=1`: сервис ничего не скачивает с
@@ -88,19 +88,19 @@ Hugging Face. Все файлы моделей, включая архитект
Три способа подключить:
1. **Вместе с compose (по умолчанию).** Сервис `flaresolverr` поднимается рядом, порт наружу не
публикуется, `dub-ai` ходит к нему по `http://flaresolverr:8191`.
публикуется, `grabber-ai` ходит к нему по `http://flaresolverr:8191`.
2. **Свой FlareSolverr на другом хосте.** В `.env`: `DUB_FLARESOLVERR_URL=http://192.168.0.24:8191`, и
запускайте только `docker compose up -d dub-ai` (контейнер FlareSolverr не нужен). Адрес должен быть
запускайте только `docker compose up -d grabber-ai` (контейнер FlareSolverr не нужен). Адрес должен быть
достижим из контейнера: с VPS до домашней сети — через VPN/туннель, не открывайте FlareSolverr в интернет.
3. **`docker run`:**
```bash
docker run -d --name dub-ai -p 8000:8000 \
docker run -d --name grabber-ai -p 8000:8000 \
-e DUB_FLARESOLVERR_URL=http://flaresolverr:8191 -e DUB_API_TOKEN=... \
--network <сеть_с_flaresolverr> dub-ai:local
--network <сеть_с_flaresolverr> grabber-ai:local
```
Проверить, что адрес подхватился: `GET /health` → `"flaresolverr": true`. Проверка связи:
`docker compose exec dub-ai python -c "import urllib.request as u; print(u.urlopen('http://flaresolverr:8191/').read()[:80])"`.
`docker compose exec grabber-ai python -c "import urllib.request as u; print(u.urlopen('http://flaresolverr:8191/').read()[:80])"`.
Замечания:
* FlareSolverr нестабилен: бывают `Timeout after 15.0 seconds` и ответ ~40 с. Это ошибка 400/502 для
@@ -172,11 +172,11 @@ python tools/pack_models.py # -> models-bundle.tar.gz (≈ 75
# выкладка в реестр пакетов Gitea (версия — любая строка, например дата или хэш модели)
curl --fail -H "Authorization: token <GITEA_TOKEN>" \
--upload-file models-bundle.tar.gz \
https://<gitea>/api/packages/<owner>/generic/dub-ai-models/2026-10-28/models-bundle.tar.gz
https://<gitea>/api/packages/<owner>/generic/grabber-ai-models/2026-10-28/models-bundle.tar.gz
```
Ссылка для скачивания (она же `MODELS_URL`):
`https://<gitea>/api/packages/<owner>/generic/dub-ai-models/2026-10-28/models-bundle.tar.gz`.
`https://<gitea>/api/packages/<owner>/generic/grabber-ai-models/2026-10-28/models-bundle.tar.gz`.
Если у вашей Gitea ограничен размер пакета (`[packages] LIMIT_SIZE_GENERIC`, по умолчанию без лимита, но
nginx перед ней часто режет загрузки ~1 МБ), поднимите лимиты или используйте способ Б.
@@ -186,7 +186,7 @@ nginx перед ней часто режет загрузки ~1 МБ), под
## CI/CD в Gitea
Workflow `.gitea/workflows/docker.yml` собирает образ и публикует его в **реестр контейнеров Gitea**
(`<gitea-host>/<owner>/<repo>/dub-ai`).
(`<gitea-host>/<owner>/<repo>/grabber-ai`).
### Что настроить один раз
@@ -230,7 +230,7 @@ Workflow `.gitea/workflows/docker.yml` собирает образ и публи
```
2. Положить на VPS `docker-compose.yml` и `.env` (из `.env.example`):
```
DUB_IMAGE=<gitea-host>/<owner>/<repo>/dub-ai:latest
DUB_IMAGE=<gitea-host>/<owner>/<repo>/grabber-ai:latest
DUB_API_TOKEN=<openssl rand -hex 24>
DUB_FLARESOLVERR_URL=http://flaresolverr:8191
```
@@ -261,7 +261,7 @@ Workflow `.gitea/workflows/docker.yml` собирает образ и публи
| `/predict` → 400 «страница недоступна: Cloudflare challenge … (задайте FlareSolverr)» | не задан `DUB_FLARESOLVERR_URL` или контейнер его не видит (`/health` → `flaresolverr`), проверьте сеть/имя сервиса |
| 400 `FlareSolverr: … Timeout` | FlareSolverr не успел решить challenge; повторите запрос, увеличьте `DUB_FETCH_TIMEOUT`, перезапустите FlareSolverr |
| 401 | не передан токен или он отличается от `DUB_API_TOKEN` |
| Контейнер `unhealthy` в первые минуты | модель ещё грузится; `docker logs dub-ai`. Если не проходит — не хватает памяти (`docker stats`) |
| Контейнер `unhealthy` в первые минуты | модель ещё грузится; `docker logs grabber-ai`. Если не проходит — не хватает памяти (`docker stats`) |
| CI: `Cannot connect to the Docker daemon` | у раннера нет доступа к Docker (см. «Что настроить один раз») |
| CI: `server gave HTTP response to HTTPS client` | workflow взял внутренний адрес Gitea; должен быть `REGISTRY_HOST` = `git.shx.one` (уже так в workflow) |
| CI: `unauthorized` при push | у `ACTION_PAT` нет `write:package` или токен принадлежит не владельцу/участник пространства имён репозитория |
+2 -2
View File
@@ -145,7 +145,7 @@ kinozal требует авторизации, поэтому grabber скачи
(`KinozalClient`) и отправляет сервису готовый HTML вместе с заголовком раздачи:
```php
$ch = curl_init('http://dub-ai:8000/predict');
$ch = curl_init('http://grabber-ai:8000/predict');
curl_setopt_array($ch, [
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
@@ -192,7 +192,7 @@ python -m src.export_onnx # -> models/best-onnx/ + reports/onnx_parit
```bash
cd examples/rust/onnx_local && cargo build
ORT_DYLIB_PATH="$(find ../../.venv -name onnxruntime.dll | head -1)" \
./target/debug/dub-ai-onnx-local.exe ../../models/best-onnx \
./target/debug/grabber-ai-onnx-local.exe ../../models/best-onnx \
"Перевод: Дублированный | MovieDalen"
```
+1 -1
View File
@@ -10,7 +10,7 @@ torch 2.11.0+cu128).
## Установка (один раз)
```bat
cd C:\Users\shats\Dev\DUB-AI
cd C:\Users\shats\Dev\grabber-ai
python -m venv .venv
.venv\Scripts\python -m pip install --upgrade pip
+1 -1
View File
@@ -1,4 +1,4 @@
# Вызов сервиса DUB-AI из PowerShell.
# Вызов сервиса grabber-ai из PowerShell.
#
# Примеры (из корня проекта):
# powershell -NoProfile -ExecutionPolicy Bypass -File examples\powershell\predict.ps1 -Text "Перевод: Дублированный | MovieDalen"
+1 -1
View File
@@ -98,7 +98,7 @@ dependencies = [
]
[[package]]
name = "dub-ai-client"
name = "grabber-ai-client"
version = "0.1.0"
dependencies = [
"reqwest",
+1 -1
View File
@@ -1,5 +1,5 @@
[package]
name = "dub-ai-client"
name = "grabber-ai-client"
version = "0.1.0"
edition = "2021"
+1 -1
View File
@@ -1,4 +1,4 @@
//! HTTP-клиент DUB-AI (путь А: сервис `python -m src.service`).
//! HTTP-клиент grabber-ai (путь А: сервис `python -m src.service`).
//!
//! Запуск:
//! cargo run -- --text "Перевод: Дублированный | MovieDalen"
+1 -1
View File
@@ -228,7 +228,7 @@ dependencies = [
]
[[package]]
name = "dub-ai-onnx-local"
name = "grabber-ai-onnx-local"
version = "0.1.0"
dependencies = [
"ort",
+1 -1
View File
@@ -1,5 +1,5 @@
[package]
name = "dub-ai-onnx-local"
name = "grabber-ai-onnx-local"
version = "0.1.0"
edition = "2021"
+3 -3
View File
@@ -1,10 +1,10 @@
# onnx_local — локальный инференс DUB-AI на Rust (без Python)
# onnx_local — локальный инференс grabber-ai на Rust (без Python)
```bash
cargo build
# onnxruntime.dll грузится динамически; можно взять из pip-пакета onnxruntime
# (уже есть в .venv проекта) или из официального релиза onnxruntime
ORT_DYLIB_PATH=<путь>/onnxruntime.dll ./target/debug/dub-ai-onnx-local.exe \
ORT_DYLIB_PATH=<путь>/onnxruntime.dll ./target/debug/grabber-ai-onnx-local.exe \
"<путь к models/best-onnx>" "Перевод: Дублированный | MovieDalen"
```
@@ -13,7 +13,7 @@ ORT_DYLIB_PATH=<путь>/onnxruntime.dll ./target/debug/dub-ai-onnx-local.exe \
```bash
cd examples/rust/onnx_local
ORT_DYLIB_PATH="$(find ../../.venv -name onnxruntime.dll | head -1)" \
./target/debug/dub-ai-onnx-local.exe ../../models/best-onnx \
./target/debug/grabber-ai-onnx-local.exe ../../models/best-onnx \
"Авторский (одноголосый закадровый) - Юрий Сербин"
```
+1 -1
View File
@@ -1,4 +1,4 @@
//! Локальный инференс DUB-AI без Python (путь Б: ONNX).
//! Локальный инференс grabber-ai без Python (путь Б: ONNX).
//!
//! cargo run --release -- <путь к models/best-onnx> "Перевод: Дублированный | MovieDalen"
//!
+1 -1
View File
@@ -1,4 +1,4 @@
// Локальный инференс DUB-AI без Python (путь Б: ONNX), Node.js.
// Локальный инференс grabber-ai без Python (путь Б: ONNX), Node.js.
//
// Подготовка (один раз):
// cd examples/typescript && npm init -y && npm i onnxruntime-node @huggingface/transformers
+1 -1
View File
@@ -1,4 +1,4 @@
// HTTP-клиент DUB-AI для Node.js (без зависимостей, node >= 18).
// HTTP-клиент grabber-ai для Node.js (без зависимостей, node >= 18).
//
// Запуск (требуется запущенный сервис `python -m src.service`):
// node predict.mjs --text "Перевод: Дублированный | MovieDalen"
+1 -1
View File
@@ -1,4 +1,4 @@
// Типизированный HTTP-клиент DUB-AI (TypeScript-проекты).
// Типизированный HTTP-клиент grabber-ai (TypeScript-проекты).
// Запуск без компиляции: npx tsx predict.ts --text "Одноголосый закадровый — Дмитрий Есарев"
// Зависимости: не требуются (используется глобальный fetch, Node >= 18).
+1 -1
View File
@@ -1,4 +1,4 @@
"""DUB-AI: нейро-модель «тип озвучки + автор озвучки».
"""grabber-ai: нейро-модель «тип озвучки + автор озвучки».
Модули:
studio_norm — словарь алиасов студий, чистка и канонизация имён, поиск спана
+2 -2
View File
@@ -64,7 +64,7 @@ def env_float(name: str, default: float) -> float:
def create_app(predictor: DubPredictor, api_token: str | None = None,
fetch_timeout: float = 60.0) -> FastAPI:
app = FastAPI(title="DUB-AI", version="0.1.0",
app = FastAPI(title="grabber-ai", version="0.1.0",
description="Тип озвучки + автор озвучки",
default_response_class=Utf8JSONResponse)
@@ -114,7 +114,7 @@ def create_app(predictor: DubPredictor, api_token: str | None = None,
def main() -> None:
env = os.environ.get
ap = argparse.ArgumentParser(
description="HTTP-сервис предсказаний DUB-AI (см. docstring модуля)",
description="HTTP-сервис предсказаний grabber-ai (см. docstring модуля)",
formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("--model", default=env("DUB_MODEL_DIR") or "models/best")
ap.add_argument("--segmenter", default=env("DUB_SEGMENTER_DIR") or "models/segmenter")
+1 -1
View File
@@ -1,4 +1,4 @@
"""Юнит-тесты DUB-AI (запуск: .venv/Scripts/python tests/run_tests.py).
"""Юнит-тесты grabber-ai (запуск: .venv/Scripts/python tests/run_tests.py).
Проверяют ключевые части без обращения к GPU:
* поиск спана автора (точно / алиас / инициалы / кавычки / разделители);
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python
"""Интерактивный сборщик датасета DUB-AI (rutracker / nnm-club / kinozal).
"""Интерактивный сборщик датасета grabber-ai (rutracker / nnm-club / kinozal).
Запуск без аргументов открывает меню:
+1 -1
View File
@@ -1,4 +1,4 @@
"""Переобучение и проверка моделей DUB-AI (используется из tools/collect.py).
"""Переобучение и проверка моделей grabber-ai (используется из tools/collect.py).
Шаги вынесены в функции, чтобы меню вызывало их по очереди:
prepare() data/labels.csv -> data/processed
+1 -1
View File
@@ -214,7 +214,7 @@ def sections_table(site: str, entries: list[dict], rows: int = 14) -> Panel:
def banner(lines: list[str]) -> Panel:
body = Text("\n".join(lines))
return Panel(body, title="[bold]DUB-AI · датасет и модель[/bold]", border_style="green",
return Panel(body, title="[bold]grabber-ai · датасет и модель[/bold]", border_style="green",
padding=(0, 2))