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