5 architecture
AI Wiki Bot edited this page 2026-09-16 19:34:21 +00:00
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.

Архитектура

Страница описывает внутреннюю структуру GigaAM-Multilingual ASR Server: как взаимодействуют модули FastAPI, конвейер инференса на базе ONNX Runtime и система обнаружения речи (Silero VAD), а также показывает, как эти компоненты связаны между собой.

Общие сведения

Приложение реализовано как единый модуль src/gigam_asr/server.py, который выполняет роль HTTP-сервера, оркестратора загрузки моделей и диспетчера запросов. Такой подход минимизирует количество зависимостей и упрощает развёртывание в контейнере — весь жизненный цикл приложения управляется одним процессом.

Ключевые архитектурные решения:

  • Отсутствие PyTorch/Transformers. Инференс выполняется исключительно через onnx-asr и ONNX Runtime, что снижает размер образа и убирает зависимость от тяжёлых библиотек глубокого обучения.
  • Мульти-модельность. Несколько моделей (large и small) загружаются одновременно и выбираются клиентом полем model в каждом запросе.
  • Асинхронная обработка блокирующих вызовов. Вычисления инференса выносятся в отдельные потоки через asyncio.to_thread, чтобы не блокировать событийный цикл FastAPI.
  • Разделение ответственности за аудио. Декодирование произвольных форматов (mp3, m4a, ogg, flac, wav) выполняется внешним ffmpeg, нормализация до mono 16 кГц float32 — NumPy, распознавание — ONNX Runtime.

Компоненты системы

FastAPI-слой

Сервер построен на FastAPI с использованием контекстного менеджера жизненного цикла (lifespan). При старте приложения происходит однократная загрузка всех моделей из списка, заданного переменной окружения MODELS. После завершения загрузки состояние сохраняется в глобальном словаре _state, доступном всем обработчикам.

Реализованы следующие конечные точки:

Метод Путь Назначение
POST /v1/audio/transcriptions Основной эндпоинт транскрипции, совместимый с OpenAI API
GET /v1/models Список загруженных моделей
GET /health Проверка работоспособности и статус моделей

Авторизация реализуется через Bearer-токены: при наличии переменной API_KEYS каждый запрос проверяется функцией _auth(). CORS-политика настраивается через CORS_ORIGINS и поддерживает preflight-запросы OPTIONS для совместимости с прокси-сервисами вроде LiteLLM.

Подробнее о параметрах запросов и формате ответов см. Справочник API.

Конвейер инференса (ONNX Runtime)

Ядро распознавания опирается на библиотеку onnx-asr версии 0.12, которая предоставляет адаптеры для работы с ONNX-моделями Conformer CTC. Архитектура конвейера следующая:

  1. Загрузка моделей. Для каждой модели из MODELS создаётся экземпляр AsrAdapter из onnx_asr.adapters. Модели размещаются в отдельных подкаталогах {MODEL_DIR}/<имя>/, что позволяет резолверу onnx-asr корректно находить файлы через glob-паттерн multilingual*_ctc.

  2. Выбор провайдера вычислений. Функция _providers() определяет список execution providers ONNX Runtime в зависимости от значения GIGAAm_CUDA:

    • auto или 1 → CUDAExecutionProvider + CPUExecutionProvider
    • 0 → только CPUExecutionProvider
  3. Распознавание. Функция _recognize() вызывает model.recognize(wav, sample_rate=16000) в отдельном потоке. В зависимости от режима (короткая запись или long-form с VAD) возвращаемая структура различается:

    • Короткий режим: объект с полями text, tokens, timestamps (метки времени на уровне символов).
    • Long-form (VAD): итератор сегментов TimestampedSegmentResult, где метки времени относительны началу каждого сегмента и требуют сдвига на seg.start.
  4. Формирование результата. Сырой вывод нормализуется в унифицированную структуру {"text", "segments", "words"}. Группировка символьных меток времени в слова выполняется функцией _chars_to_words(), которая агрегирует последовательности токенов до пробелов.

Настройки производительности (квантизация, размер чанков, максимальная длительность) описаны в разделе Конфигурация. Анализ скорости обработки приведён в Производительность.

Silero VAD (Voice Activity Detection)

Для обработки длинных аудиозаписей (до 1 часа) используется модель Silero VAD в ONNX-формате. Она подключается к адаптеру onnx-asr при условии, что CHUNK_SECONDS > 0.

Роль VAD в системе:

  • Сегментация речи. Длинное аудио разбивается на фрагменты, содержащие активную речь, что исключает распознавание тишины и снижает нагрузку на GPU/CPU.
  • Ограничение размера входного буфера. Каждый сегмент обрабатывается независимо, что предотвращает переполнение памяти при работе с многочасовыми записями.
  • Сохранение временных меток. Результаты VAD включают абсолютные границы сегментов (start, end), которые используются для корректного позиционирования слов в итоговой транскрипции.

Модель VAD скачивается скриптом scripts/download_models.py из репозитория Hugging Face istupakov/silero-vad-onnx и размещается в {VAD_DIR}/silero_vad.onnx.

Обработка аудио

Входной поток аудио проходит несколько этапов преобразования перед подачей на модель:

  1. Декодирование. Функция _to_pcm16() вызывает внешний процесс ffmpeg (или imageio-ffmpeg) для конвертации любого поддерживаемого формата в моно-PCM 16 кГц. Путь к бинарнику может быть переопределён переменной FFMPEG_BIN.
  2. Преобразование типов. Байтовый поток PCM декодируется в массив NumPy типа float32 через np.frombuffer.
  3. Проверка длительности. Если длительность превышает MAX_DURATION, запрос отклоняется с ошибкой.

Такой подход позволяет принимать mp3, m4a, ogg, flac, wav и другие форматы без дополнительных Python-зависимостей для декодирования.

Схема взаимодействия компонентов

sequenceDiagram
    participant Client as Клиент
    participant API as FastAPI
    participant FFmpeg as ffmpeg
    participant ONNX as ONNX Runtime
    participant VAD as Silero VAD

    Client->>API: POST /v1/audio/transcriptions
    API->>API: Проверка авторизации
    API->>FFmpeg: Декодирование аудио в PCM 16kHz
    FFmpeg-->>API: Mono float32 numpy array
    API->>API: Выбор модели по полю model
    alt Long-form mode enabled
        API->>VAD: Сегментация речи
        VAD-->>API: Список сегментов с границами
        loop Для каждого сегмента
            API->>ONNX: Распознавание сегмента
            ONNX-->>API: Текст и метки времени
        end
    else Short-form mode
        API->>ONNX: Распознавание всего аудио
        ONNX-->>API: Текст и метки времени
    end
    API->>API: Нормализация результата
    API-->>Client: JSON ответ с text segments words

Структура проекта

├── src/gigam_asr/
│   ├── __init__.py              # Пустой маркер пакета
│   └── server.py                # Весь сервер: API, загрузка моделей, инференс
├── scripts/
│   └── download_models.py       # Скачивание ONNX-моделей и VAD из Hugging Face
├── tests/
│   ├── test_models.py           # Тесты выбора моделей и CORS
│   └── test_words.py            # Тесты группировки символов в слова
├── Dockerfile                   # Сборка образа на базе nvidia/cuda
├── docker-compose.yml           # Локальное развёртывание с GPU
├── requirements.txt             # Зависимости рантайма
└── pyproject.toml               # Метаданные пакета и настройки инструментов

Связь с другими разделами

  • Обзор проекта — общее описание возможностей и преимуществ сервиса.
  • Установка и запуск — пошаговые инструкции по развёртыванию через Docker Compose или ручной сборке.
  • Справочник API — детальное описание параметров запросов, форматов ответов и кодов ошибок.
  • Конфигурация — полный перечень переменных окружения и их влияние на поведение системы.
  • Производительность — бенчмарки RTF на GPU и CPU, рекомендации по выбору размера модели.
  • Тестирование — описание набора юнит-тестов и покрытие критических путей.
  • CI/CD и автоматизация — конвейеры сборки, линтинга и публикации образов.

Пример использования в коде

Типовой сценарий работы клиента с сервером:

from openai import OpenAI

client = OpenAI(base_url="http://localhost:43000/v1", api_key="none")

# Транскрипция с метками времени на уровне слов
result = client.audio.transcriptions.create(
    model="gigaam-multilingual-large-ctc",
    file=open("interview.mp3", "rb"),
    response_format="verbose_json",
    timestamp_granularities=["word"],
)

print(result.text)
for word in result.words:
    print(f"{word['word']} [{word['start']:.2f}s – {word['end']:.2f}s]")

Под капотом этот запрос проходит путь: парсинг multipart → декодирование ffmpeg → выбор модели из _state → (опционально) сегментация VAD → инференс ONNX Runtime в отдельном потоке → нормализация меток времени → формирование JSON-ответа.