call-to-text/README.md

8.2 KiB
Raw Blame History

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. Клонировать

git clone https://git.itoservice.ru/dosnav/call-to-text.git
cd call-to-text

2. Настроить окружение

python -m venv venv
venv\Scripts\activate          # Windows
# source venv/bin/activate     # Linux
pip install -r requirements.txt

3. Поднять Directus

docker compose up -d

Создадутся контейнеры:

  • postgres (порт не наружу)
  • directus (порт 8055)

После первого запуска инициализировать коллекции:

python setup_directus.py

Создаст коллекции: calls, calls_74951284933, contactsс полной схемой полей.

4. Настроить .env

Скопировать .env.example.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. Загрузить звонки

python -m main process --limit 50

Первая загрузка — модель Whisper скачается автоматически (HuggingFace Hub).

CLI-команды

process

Пакетная загрузка и транскрипция звонков из Novofon API.

python -m main process --limit 100 --date-from "2024-06-01"

Опции:

  • --limit N — максимальное количество звонков за запуск
  • --date-from YYYY-MM-DD — начальная дата (по умолчанию из .env)

process-file

Транскрипция одного аудиофайла (для тестов).

python -m main process-file --file "путь/к/файлу.wav" --caller "79161234567" --callee "74951284933"

export

Выгрузка всех звонков из Directus в JSON.

python -m main export --output calls.json

daemon

Фоновый режим — проверяет новые звонки каждые 5 минут.

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:

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

Остановить:

docker compose down

Удалить данные:

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 и без аудио — пропускаются