246 lines
8.2 KiB
Markdown
246 lines
8.2 KiB
Markdown
# Call-to-Text
|
||
|
||
Транскрипция звонков из **Novofon DATA API** с сохранением в **Directus**.
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
Novofon DATA API ──► call-to-text ──► Directus (Postgres)
|
||
│ │
|
||
│ ┌──────┴──────┐
|
||
│ calls calls_* contacts
|
||
│
|
||
┌────┴────┐
|
||
│ FFmpeg │ конвертация аудио → WAV 16 кГц
|
||
└────┬────┘
|
||
│
|
||
┌────┴──────────┐
|
||
│ faster-whisper │ распознавание речи (модель turbo / large-v3)
|
||
└────┬──────────┘
|
||
│
|
||
┌────┴──────┐
|
||
│ aligner │ маркировка спикеров: caller / callee
|
||
└───────────┘
|
||
```
|
||
|
||
- Звонки получаются через JSON-RPC API (`get.calls_report`)
|
||
- Аудио скачивается по прямой ссылке
|
||
- Стерео-файлы разделяются на каналы: левый = callee, правый = caller
|
||
- Каждый канал транскрибируется через faster-whisper на CUDA
|
||
- Результат сохраняется в Directus (коллекции `calls` / `calls_*`)
|
||
|
||
## Требования
|
||
|
||
- **Python** 3.10+
|
||
- **FFmpeg** (в PATH) — для конвертации аудио
|
||
- **NVIDIA GPU** с CUDA (опционально, для ускорения)
|
||
- **Docker** + **Docker Compose** (для Directus + Postgres)
|
||
|
||
## Установка и запуск
|
||
|
||
### 1. Клонировать
|
||
|
||
```bash
|
||
git clone https://git.itoservice.ru/dosnav/call-to-text.git
|
||
cd call-to-text
|
||
```
|
||
|
||
### 2. Настроить окружение
|
||
|
||
```bash
|
||
python -m venv venv
|
||
venv\Scripts\activate # Windows
|
||
# source venv/bin/activate # Linux
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
### 3. Поднять Directus
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
Создадутся контейнеры:
|
||
- `postgres` (порт не наружу)
|
||
- `directus` (порт `8055`)
|
||
|
||
После первого запуска инициализировать коллекции:
|
||
|
||
```bash
|
||
python setup_directus.py
|
||
```
|
||
|
||
Создаст коллекции: `calls`, `calls_74951284933`, `contacts` — с полной схемой полей.
|
||
|
||
### 4. Настроить `.env`
|
||
|
||
Скопировать `.env.example` → `.env` и заполнить:
|
||
|
||
```env
|
||
# Novofon DATA API
|
||
NOVOFON_ACCESS_TOKEN=ваш_токен
|
||
NOVOFON_DATE_FROM=2024-01-01
|
||
|
||
# Directus
|
||
DIRECTUS_URL=http://localhost:8055
|
||
DIRECTUS_TOKEN=call-to-text-admin-token
|
||
|
||
# Whisper
|
||
WHISPER_MODEL_SIZE=turbo # tiny/base/small/medium/large-v3/turbo
|
||
WHISPER_DEVICE=cuda # cpu / cuda
|
||
WHISPER_COMPUTE_TYPE=float16 # int8 / float16
|
||
```
|
||
|
||
### 5. Настроить Novofon
|
||
|
||
IP-адрес сервера, откуда будет запускаться скрипт, должен быть **внесён в белый список** в админ-панели Novofon:
|
||
|
||
**Настройки → Правила и настройки безопасности → API**
|
||
|
||
Токен доступа (permanent API key) создаётся там же.
|
||
|
||
### 6. Загрузить звонки
|
||
|
||
```bash
|
||
python -m main process --limit 50
|
||
```
|
||
|
||
Первая загрузка — модель Whisper скачается автоматически (HuggingFace Hub).
|
||
|
||
## CLI-команды
|
||
|
||
### `process`
|
||
|
||
Пакетная загрузка и транскрипция звонков из Novofon API.
|
||
|
||
```bash
|
||
python -m main process --limit 100 --date-from "2024-06-01"
|
||
```
|
||
|
||
Опции:
|
||
- `--limit N` — максимальное количество звонков за запуск
|
||
- `--date-from YYYY-MM-DD` — начальная дата (по умолчанию из .env)
|
||
|
||
### `process-file`
|
||
|
||
Транскрипция одного аудиофайла (для тестов).
|
||
|
||
```bash
|
||
python -m main process-file --file "путь/к/файлу.wav" --caller "79161234567" --callee "74951284933"
|
||
```
|
||
|
||
### `export`
|
||
|
||
Выгрузка всех звонков из Directus в JSON.
|
||
|
||
```bash
|
||
python -m main export --output calls.json
|
||
```
|
||
|
||
### `daemon`
|
||
|
||
Фоновый режим — проверяет новые звонки каждые 5 минут.
|
||
|
||
```bash
|
||
python -m main daemon --max 10 --hours-back 6
|
||
```
|
||
|
||
## Модели Whisper
|
||
|
||
| Модель | Размер | Качество | Скорость |
|
||
|--------|--------|----------|----------|
|
||
| `tiny` | 39 MB | низкое | 🚀 |
|
||
| `base` | 74 MB | среднее | 🚀 |
|
||
| `small` | 244 MB | хорошее | ⚡ |
|
||
| `medium` | 769 MB | очень хорошее | ⚡ |
|
||
| `large-v3` | 1.5 GB | **лучшее** | 🐢 |
|
||
| `turbo` | 809 MB | как large-v3 | 🚀 (в 5x быстрее) |
|
||
|
||
Рекомендуется `turbo` — качество large-v3 при заметно меньшем времени транскрипции.
|
||
|
||
Переключение — одной строкой в `.env`:
|
||
|
||
```env
|
||
WHISPER_MODEL_SIZE=turbo
|
||
```
|
||
|
||
Модель кешируется после первой загрузки в `~/.cache/huggingface/hub/`.
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
├── main.py # CLI-точка входа
|
||
├── config.py # Настройки из .env
|
||
├── setup_directus.py # Инициализация Directus
|
||
├── requirements.txt # Зависимости
|
||
├── docker-compose.yml # Directus + Postgres
|
||
├── .env # Локальные настройки (в .gitignore)
|
||
├── .env.example # Шаблон настроек
|
||
│
|
||
├── ingestor/
|
||
│ ├── novofon_api.py # Клиент Novofon DATA API
|
||
│ └── downloader.py # Скачивание аудио по URL
|
||
│
|
||
├── audio/
|
||
│ ├── stt.py # Распознавание (faster-whisper)
|
||
│ ├── preprocessor.py # FFmpeg конвертация, разделение каналов
|
||
│ └── diarization.py # Диаризация (pyannote)
|
||
│
|
||
├── aligner/
|
||
│ └── aligner.py # Маркировка спикеров
|
||
│
|
||
├── storage/
|
||
│ ├── directus.py # HTTP-клиент Directus
|
||
│ ├── contacts.py # Поиск контактов по номеру
|
||
│ └── exporter.py # Экспорт в JSON
|
||
│
|
||
├── old/ # Архив: email-парсинг (не используется)
|
||
└── temp/ # Временные WAV-файлы (в .gitignore)
|
||
```
|
||
|
||
## Управление Directus
|
||
|
||
**Админка:** http://localhost:8055/admin
|
||
|
||
**Данные по умолчанию:**
|
||
- Email: `admin@example.com`
|
||
- Пароль: `admin-password-123`
|
||
|
||
**Остановить:**
|
||
|
||
```bash
|
||
docker compose down
|
||
```
|
||
|
||
**Удалить данные:**
|
||
|
||
```bash
|
||
docker compose down -v
|
||
```
|
||
|
||
## Коллекции Directus
|
||
|
||
### `calls`
|
||
|
||
Основная коллекция звонков (не на номер 74951284933).
|
||
|
||
### `calls_74951284933`
|
||
|
||
Звонки, где одна из сторон — 74951284933.
|
||
|
||
### `contacts`
|
||
|
||
Телефонная книга. Поля: `phone_number`, `name`, `company`, `notes`.
|
||
|
||
При транскрипции номера автоматически резолвятся в имена из `contacts`.
|
||
|
||
## Принцип работы
|
||
|
||
1. `get.calls_report` получает звонки чанками по 90 дней (максимум API)
|
||
2. Скачивается аудио по `full_record_file_link` или `call_records`
|
||
3. FFmpeg конвертирует в WAV: 16 кГц, pcm_s16le, моно или стерео
|
||
4. Если каналы разные (реальное стерео) — левый = callee, правый = caller
|
||
5. Каждый канал транскрибируется faster-whisper на CUDA (float16)
|
||
6. Сегменты выравниваются по времени и маркируются спикером
|
||
7. Результат сохраняется в Directus
|
||
8. Звонки с `talk_duration=0` и без аудио — пропускаются
|