스트리밍 받아쓰기

Parakeet-EOU-120M은 명시적 발화 종료(EOU) 헤드를 갖춘 소형 RNN-T 스트리밍 ASR 모델이며, Apple Silicon의 Neural Engine에서 실시간 받아쓰기를 위해 제작되었습니다. 이 가이드는 핸즈프리, 어디에든 붙여넣기 받아쓰기를 위해 스트리밍 모델을 Silero VAD와 연결한 macOS 메뉴 바 레퍼런스 앱인 DictateDemo도 다룹니다.

무엇인가

아키텍처

오디오 청크마다 세 개의 CoreML 모델이 파이프라인으로 연결됩니다:

구성 요소설명
EncoderCache-aware Conformer. 64프레임 멜 청크(640 ms)와 6개의 상태 텐서(어텐션 KV 캐시, depthwise conv 캐시, 청크 경계에 걸쳐 FFT가 연속 신호를 볼 수 있도록 최근 오디오를 앞에 추가하는 pre_cache 멜 루프백)를 입력으로 받습니다.
Decoder단일 스텝 LSTM 예측 네트워크. 이전 non-blank 토큰을 소비하고 임베딩과 업데이트된 (h, c) 상태를 방출합니다.
Joint + EOU 헤드encoder와 decoder 출력을 vocab + blank + EOU에 대한 logits로 결합합니다. EOU 클래스는 발화가 끝났다는 모델의 확정적 신호입니다.

EOU 토큰을 별도로 두는 이유

일반 RNNT는 침묵 동안 blank를 방출하며 디코더는 "발화 종료" 신호 없이 이를 흡수합니다. 전용 EOU 헤드는 모델이 파셜을 최종으로 커밋하고, 문장부호/대문자 상태를 리셋하며, 앱에 붙여넣기 같은 다운스트림 작업을 트리거하는 확정적 컷을 만들 수 있게 해줍니다.

실제 환경에서의 EOU는 노이지하다

"조용한" 일시 정지 동안의 키보드 클릭, 마우스 이동, 룸톤 때문에 joint가 때때로 non-blank 토큰을 방출해 EOU debounce 타이머를 리셋하고 커밋을 지연시킬 수 있습니다. 프로덕션 파이프라인은 joint EOU를 외부 VAD 기반 forceEndOfUtterance() 백스탑과 함께 사용합니다 — 아래의 DictateDemo를 참조하세요.

모델

모델크기HuggingFace
Parakeet-EOU-120M (CoreML INT8)약 120 MBaufklarer/Parakeet-EOU-120M-CoreML-INT8

성능

지표
웨이트 메모리약 120 MB (INT8)
피크 추론 메모리약 200 MB
청크 지연 (M 시리즈)연산 약 30 ms / 오디오 640 ms (RTF 약 0.056)
엔드투엔드 파셜 지연약 340 ms (한 청크)
커밋 지연 (VAD 경로)음성 종료 후 약 1초
연산 타겟Neural Engine (CoreML)

빠른 시작 — 배치 전사

스트리밍 모델은 SpeechRecognitionModel도 준수하므로 범용 STT 모델을 받는 어떤 코드에서도 그대로 사용할 수 있습니다:

import ParakeetStreamingASR

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

빠른 시작 — 비동기 스트리밍

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

PartialTranscripttext, isFinal, confidence, eouDetected (joint가 발화한 것인지 강제 파이널라이즈된 것인지), 그리고 단조 증가하는 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()

VAD 강제 파이널라이즈 패턴

파이프라인에서 이미 Silero VAD가 실행 중이라면 이를 사용해 폴백 커밋을 구동함으로써 배경 소음이 EOU debounce 타이머를 멈추게 하지 않도록 할 수 있습니다:

if hasPendingUtterance && !vadSpeechActive && vadSilentChunks >= 30 {
    // Silero 기준 지속 침묵 약 960 ms
    if let forced = session.forceEndOfUtterance() {
        commit(forced.text)
    }
    hasPendingUtterance = false
}

// 가드레일: joint가 이미 EOU를 발화했다면 이중 커밋 방지
if partials.contains(where: { $0.isFinal }) {
    hasPendingUtterance = false
}

DictateDemo — macOS 메뉴 바 레퍼런스 앱

DictateDemo는 스트리밍 세션 위에 구축된 완전한 macOS 메뉴 바 agent입니다. 백그라운드 앱으로 실행되며, 라이브 파셜과 함께 마이크에서 전사하고, EOU 또는 VAD 침묵에 따라 발화를 자동 커밋한 뒤 결과를 최전면 앱에 붙여넣습니다.

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

전체 구현은 Examples/DictateDemo/DictateDemo/DictateViewModel.swift에 있습니다: 메인 스레드 밖의 오디오 싱크와 락 보호 버퍼, 300 ms 타이머 틱으로 버퍼를 비우는 구조, leftover-sample 이월을 적용한 Silero VAD, 가드된 강제 파이널라이즈. 대응하는 리그레션 테스트는 Examples/DictateDemo/Tests/DictateDemoTests.swift에 있으며, 다중 발화, 멈춘 EOU, 잡음 섞인 침묵 시나리오를 다룹니다.

스트리밍 대 배치 Parakeet

Parakeet-EOU-120M (스트리밍)Parakeet TDT 0.6B (배치)
유스 케이스라이브 받아쓰기, 실시간 캡션파일 전사, 오프라인 작업
디코더RNN-T + EOU 헤드Token-and-Duration Transducer
청크 크기640 ms 스트리밍파일 전체 배치
웨이트 메모리약 120 MB500 MB
처리량실시간의 약 18배실시간의 약 32배
지연파셜 약 340 ms파일 종료 후에만
스트리밍 모델을 선택해야 할 때…

…사용자가 말을 끝내기 전에 파셜이 필요한 경우입니다. 오디오 파일의 배치 전사에는 더 큰 Parakeet TDT 0.6B가 엔드투엔드로 더 빠르고 정확합니다. 두 모델은 동일한 SentencePiece 어휘를 공유하므로 토크나이징을 변경하지 않고 서로 교체할 수 있습니다.