build: first commit

This commit is contained in:
2026-05-19 10:12:57 +00:00
commit dc77aaed9e
13 changed files with 1258 additions and 0 deletions
+262
View File
@@ -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: 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` в логах.
Дальнейшие запросы используют загруженные модели.