build: first commit
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
# 3_diarization — микросервисная транскрибация с диаризацией
|
||||
|
||||
Три Docker-контейнера: Whisper (GPU) + pyannote (CPU) + API Gateway.
|
||||
Работают параллельно. Итоговое время ≈ max(whisper, pyannote), не сумма.
|
||||
|
||||
## Архитектура
|
||||
|
||||
```
|
||||
POST /process (audio.aac)
|
||||
│
|
||||
┌──────┴──────┐
|
||||
│ Gateway │ :8000
|
||||
└──────┬──────┘
|
||||
┌───────────┴───────────┐
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐
|
||||
│ Whisper │ │ Pyannote │
|
||||
│ (GPU) │ │ (CPU) │
|
||||
│ :8001 │ │ :8002 │
|
||||
└──────┬───────┘ └──────┬───────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
текст + слова кто когда говорил
|
||||
с таймкодами SPEAKER_00: 0–4с
|
||||
│ │
|
||||
└───────────┬───────────┘
|
||||
▼
|
||||
reconciliation
|
||||
(сшивка по словам)
|
||||
│
|
||||
▼
|
||||
SPEAKER_00: Привет, как дела с проектом?
|
||||
SPEAKER_01: Нормально, закончил doctype.
|
||||
```
|
||||
|
||||
## Предварительные требования
|
||||
|
||||
1. **Docker** + **Docker Compose** v2+
|
||||
2. **NVIDIA Container Toolkit** (`nvidia-ctk`)
|
||||
|
||||
```bash
|
||||
# проверить, что GPU виден Docker'у
|
||||
docker run --rm --gpus all nvidia/smi
|
||||
```
|
||||
|
||||
3. **HuggingFace-токен** для pyannote
|
||||
|
||||
- Создать токен: https://huggingface.co/settings/tokens
|
||||
- Принять условия (заполнить форму на каждой странице):
|
||||
- https://huggingface.co/pyannote/segmentation-3.0
|
||||
- https://huggingface.co/pyannote/speaker-diarization-3.1
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
```bash
|
||||
# 1. Клонировать / скопировать папку 3_diarization
|
||||
cd 3_diarization
|
||||
|
||||
# 2. Создать .env из примера и вставить свой HF-токен
|
||||
cp .env.example .env
|
||||
nano .env # вставить HF_TOKEN=hf_...
|
||||
|
||||
# 3. Собрать и запустить
|
||||
docker compose up --build -d
|
||||
|
||||
# 4. Подождать ~1–2 минуты, пока модели загрузятся
|
||||
docker compose logs -f
|
||||
# Ждём:
|
||||
# whisper-service: "Model loaded in X.Xs"
|
||||
# pyannote-service: "Pipeline loaded in X.Xs"
|
||||
|
||||
# 5. Проверить здоровье
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### POST /transcribe — только транскрибация
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/transcribe \
|
||||
-F "file=@audio.aac" \
|
||||
-F "language=ru" \
|
||||
-F "initial_prompt=Event Forge, Frappe, doctype" \
|
||||
-F "batch_size=16"
|
||||
```
|
||||
|
||||
Ответ (JSON):
|
||||
```json
|
||||
{
|
||||
"language": "ru",
|
||||
"language_probability": 0.99,
|
||||
"duration": 197.6,
|
||||
"processing_time": 8.2,
|
||||
"segments": [
|
||||
{
|
||||
"start": 0.0,
|
||||
"end": 3.2,
|
||||
"text": "Привет, это запись.",
|
||||
"words": [
|
||||
{"start": 0.0, "end": 0.4, "word": " Привет"},
|
||||
{"start": 0.4, "end": 0.6, "word": ","},
|
||||
{"start": 0.7, "end": 1.1, "word": " это"},
|
||||
{"start": 1.1, "end": 1.5, "word": " запись."}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### POST /diarize — только диаризация
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/diarize \
|
||||
-F "file=@audio.aac" \
|
||||
-F "num_speakers=2"
|
||||
```
|
||||
|
||||
Ответ:
|
||||
```json
|
||||
{
|
||||
"speakers": ["SPEAKER_00", "SPEAKER_01"],
|
||||
"num_speakers": 2,
|
||||
"processing_time": 45.3,
|
||||
"turns": [
|
||||
{"start": 0.0, "end": 4.2, "speaker": "SPEAKER_00"},
|
||||
{"start": 4.2, "end": 9.1, "speaker": "SPEAKER_01"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### POST /process — транскрибация + диаризация (параллельно)
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/process \
|
||||
-F "file=@audio.aac" \
|
||||
-F "language=ru" \
|
||||
-F "initial_prompt=Event Forge, Frappe, doctype, Vladimir" \
|
||||
-F "num_speakers=2" \
|
||||
-F "batch_size=16"
|
||||
```
|
||||
|
||||
Ответ:
|
||||
```json
|
||||
{
|
||||
"language": "ru",
|
||||
"duration": 197.6,
|
||||
"processing_time": 47.1,
|
||||
"whisper_time": 8.2,
|
||||
"pyannote_time": 45.3,
|
||||
"speakers": ["SPEAKER_00", "SPEAKER_01"],
|
||||
"num_speakers": 2,
|
||||
"utterances": [
|
||||
{
|
||||
"speaker": "SPEAKER_00",
|
||||
"start": 0.0,
|
||||
"end": 4.1,
|
||||
"text": "Привет, как дела с проектом?",
|
||||
"words": [...]
|
||||
},
|
||||
{
|
||||
"speaker": "SPEAKER_01",
|
||||
"start": 4.2,
|
||||
"end": 9.0,
|
||||
"text": "Нормально, закончил doctype для метрик.",
|
||||
"words": [...]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Форматы вывода
|
||||
|
||||
Добавьте `response_format` в `/transcribe` или `/process`:
|
||||
|
||||
```bash
|
||||
# SRT-субтитры с именами спикеров
|
||||
curl -X POST http://localhost:8000/process \
|
||||
-F "file=@audio.aac" \
|
||||
-F "language=ru" \
|
||||
-F "response_format=srt"
|
||||
|
||||
# VTT
|
||||
-F "response_format=vtt"
|
||||
|
||||
# Текст (спикер: реплика)
|
||||
-F "response_format=txt"
|
||||
```
|
||||
|
||||
## Параметры
|
||||
|
||||
| Параметр | Где | По умолчанию | Описание |
|
||||
|------------------|---------------|--------------|---------------------------------------|
|
||||
| `language` | whisper | auto | Код языка (ru, en, de, ...) |
|
||||
| `initial_prompt` | whisper | — | Термины/имена через запятую |
|
||||
| `beam_size` | whisper | 5 | Размер beam search |
|
||||
| `batch_size` | whisper | 16 | Размер батча (1–32) |
|
||||
| `num_speakers` | pyannote | auto | Точное число спикеров |
|
||||
| `min_speakers` | pyannote | — | Минимум спикеров |
|
||||
| `max_speakers` | pyannote | — | Максимум спикеров |
|
||||
| `response_format`| gateway | json | json / srt / vtt / txt |
|
||||
|
||||
## Конфигурация через .env
|
||||
|
||||
```bash
|
||||
# Обязательные
|
||||
HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# Опциональные
|
||||
WHISPER_MODEL=large-v3 # tiny/base/small/medium/large-v3/turbo
|
||||
WHISPER_BATCH_SIZE=16 # размер батча
|
||||
PYANNOTE_DEVICE=cpu # cpu или cuda
|
||||
```
|
||||
|
||||
## Полезные команды
|
||||
|
||||
```bash
|
||||
# Логи конкретного сервиса
|
||||
docker compose logs -f whisper-service
|
||||
docker compose logs -f pyannote-service
|
||||
|
||||
# Перезапустить один сервис (например, после смены модели)
|
||||
docker compose restart whisper-service
|
||||
|
||||
# Остановить всё
|
||||
docker compose down
|
||||
|
||||
# Пересобрать всё с нуля
|
||||
docker compose down && docker compose up --build -d
|
||||
```
|
||||
|
||||
## Производительность (RTX 5060 16 ГБ)
|
||||
|
||||
Ориентировочные цифры для 1 часа аудио:
|
||||
|
||||
| Операция | Время |
|
||||
|-----------------------|------------|
|
||||
| Whisper large-v3 b=16 | ~2–4 мин |
|
||||
| Pyannote CPU | ~5–10 мин |
|
||||
| /process (параллельно)| ~5–10 мин |
|
||||
| Reconciliation | ~1 сек |
|
||||
|
||||
Bottleneck — pyannote на CPU. Если нужно ещё быстрее — поменяйте
|
||||
`PYANNOTE_DEVICE=cuda` в `.env` и пересоберите pyannote-service с GPU-версией
|
||||
PyTorch (потребует изменения Dockerfile).
|
||||
|
||||
## Траблшутинг
|
||||
|
||||
**Контейнер whisper-service не стартует / `no CUDA-capable device`** — проверьте
|
||||
`nvidia-container-toolkit`. Тест: `docker run --rm --gpus all nvidia/smi`.
|
||||
|
||||
**pyannote-service падает с `401 Unauthorized`** — невалидный HF_TOKEN или не
|
||||
приняты условия моделей на HuggingFace.
|
||||
|
||||
**`CUBLAS_STATUS_NOT_SUPPORTED`** — int8 на Blackwell. В конфиге уже стоит
|
||||
`WHISPER_COMPUTE_TYPE=float16`.
|
||||
|
||||
**OOM при batch_size=16** — уменьшите `WHISPER_BATCH_SIZE=8` в `.env`.
|
||||
|
||||
**Первый запрос медленный** — модели загружаются при старте контейнера
|
||||
(large-v3 ~3 ГБ, pyannote ~500 МБ). Дождитесь `Model loaded` в логах.
|
||||
Дальнейшие запросы используют загруженные модели.
|
||||
Reference in New Issue
Block a user