Потоковая диктовка

Parakeet-EOU-120M — это небольшая потоковая ASR-модель RNN-T с явной головой end-of-utterance (EOU), созданная для диктовки в реальном времени на Neural Engine Apple Silicon. Это руководство также охватывает DictateDemo — референсное приложение в меню-баре macOS, которое связывает потоковую модель с Silero VAD для диктовки без рук со вставкой в любое место.

Что это

Архитектура

Три CoreML-модели, работающие в пайплайне для каждого аудиочанка:

КомпонентОписание
EncoderCache-aware Conformer. Принимает 64-кадровый мел-чанк (640 мс) плюс шесть тензоров состояния — KV-кеш attention, кеш depthwise-свёртки и pre_cache мел-обратной связи, который добавляет аудио из недавнего прошлого, чтобы FFT видел непрерывный сигнал на границах чанков.
DecoderОдношаговая LSTM-сеть предсказания. Принимает предыдущий не-blank токен, выдаёт эмбеддинг плюс обновлённое состояние (h, c).
Joint + EOU headСливает выходы encoder и decoder в логиты по vocab + blank + EOU. Класс EOU — это жёсткий сигнал модели о том, что реплика закончена.

Зачем отдельный EOU-токен

Обычный RNNT выдаёт blank-токены во время тишины, которые decoder спокойно поглощает, не сигнализируя «реплика завершена». Выделенная EOU-голова позволяет модели сделать жёсткий срез для подтверждения частичного результата как финального, сброса состояния пунктуации/регистра и запуска последующих действий вроде вставки в приложение.

EOU зашумлён в реальном мире

Клики клавиатуры, движения мыши и комнатный шум во время «тихой» паузы могут приводить к тому, что joint изредка выдаёт не-blank токен, сбрасывая таймер дебаунса EOU и останавливая коммит. Продакшн-пайплайны сочетают EOU от joint с внешним forceEndOfUtterance() на основе VAD — см. DictateDemo ниже.

Модель

МодельРазмерHuggingFace
Parakeet-EOU-120M (CoreML INT8)~120 МБaufklarer/Parakeet-EOU-120M-CoreML-INT8

Производительность

МетрикаЗначение
Память весов~120 МБ (INT8)
Пиковая память инференса~200 МБ
Задержка чанка (M-серия)~30 мс вычислений / 640 мс аудио (RTF ~0.056)
Сквозная задержка частичных результатов~340 мс (один чанк)
Задержка коммита (путь VAD)~1 с после окончания речи
Цель вычисленийNeural Engine (CoreML)

Быстрый старт — пакетная транскрипция

Потоковая модель также соответствует SpeechRecognitionModel, так что она работает как замена для любого кода, принимающего универсальную STT-модель:

import ParakeetStreamingASR

let model = try await ParakeetStreamingASRModel.fromPretrained()
let text = try model.transcribeAudio(audioSamples, sampleRate: 16000)

Быстрый старт — async-потоковый режим

for await partial in model.transcribeStream(audio: samples, sampleRate: 16000) {
    if partial.isFinal { print("FINAL: \(partial.text)") }
    else               { print("... \(partial.text)") }
}

Каждый PartialTranscript содержит text, isFinal, confidence, eouDetected (joint сработал или force-finalize) и монотонный segmentIndex.

API долгоживущей сессии (вход с микрофона)

Для живой диктовки создайте сессию один раз и подавайте ей чанки по мере их поступления с микрофона. Сессия внутренне буферизирует и запускает encoder, когда накопится достаточно сэмплов, поэтому вы можете отправлять чанки произвольного размера:

let session = try model.createSession()

// каждый чанк с микрофона:
let partials = try session.pushAudio(float32Chunk16kHz)
for p in partials {
    if p.isFinal { commit(p.text) }
    else          { showPartial(p.text) }
}

// когда поток заканчивается:
let trailing = try session.finalize()

Паттерн force-finalize по VAD

Когда в вашем пайплайне уже работает Silero VAD, используйте его для управления запасным коммитом, чтобы фоновый шум не останавливал таймер дебаунса EOU:

if hasPendingUtterance && !vadSpeechActive && vadSilentChunks >= 30 {
    // ~960 мс непрерывной тишины по Silero
    if let forced = session.forceEndOfUtterance() {
        commit(forced.text)
    }
    hasPendingUtterance = false
}

// защита: не делать двойной коммит, если joint уже выдал EOU
if partials.contains(where: { $0.isFinal }) {
    hasPendingUtterance = false
}

DictateDemo — референсное приложение в меню-баре macOS

DictateDemo — это полноценный агент в меню-баре macOS, построенный поверх потоковой сессии. Работает как фоновое приложение, транскрибирует с микрофона с живыми частичными результатами, автоматически подтверждает реплики по EOU или тишине VAD и вставляет результат в активное приложение.

cd Examples/DictateDemo
swift build
.build/debug/DictateDemo

Полная реализация находится в Examples/DictateDemo/DictateDemo/DictateViewModel.swift: аудио-приёмник не на главном потоке с буфером под lock, тик таймера на 300 мс, который его сливает, Silero VAD с переносом остаточных сэмплов и защищённый force-finalize. Соответствующие регрессионные тесты в Examples/DictateDemo/Tests/DictateDemoTests.swift покрывают сценарии нескольких реплик, залипшего EOU и шумной тишины.

Потоковый vs пакетный Parakeet

Parakeet-EOU-120M (потоковый)Parakeet TDT 0.6B (пакетный)
СценарийЖивая диктовка, субтитры в реальном времениТранскрипция файлов, офлайн-задачи
ДекодерRNN-T + EOU-головаToken-and-Duration Transducer
Размер чанка640 мс, потоковыйВесь файл, пакетно
Память весов~120 МБ500 МБ
Пропускная способность~18x быстрее реального времени~32x быстрее реального времени
Задержка~340 мс частичныеТолько в конце файла
Выбирайте потоковую модель, когда…

…нужны частичные результаты до того, как пользователь закончит говорить. Для пакетной транскрипции аудиофайлов более крупная Parakeet TDT 0.6B быстрее end-to-end и точнее. Обе модели используют один и тот же словарь SentencePiece, так что можно переключаться между ними без изменения токенизации.