Files
diarization/README.md
T
2026-05-19 10:12:57 +00:00

263 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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: 04с
│ │
└───────────┬───────────┘
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 | ~24 мин |
| Pyannote CPU | ~510 мин |
| /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` в логах.
Дальнейшие запросы используют загруженные модели.