Legendas (speech to text)¶
O Sapsan pode reconhecer fala num stream gravado e escrevê-la numa faixa de legendas separada. O reconhecimento roda no motor Whisper embutido (whisper.cpp) sobre o arquivo DVR: um worker em segundo plano lê o áudio gravado, transcreve-o e acrescenta de volta no arquivo quadros de legendas. A faixa de legendas é então servida em HLS e DASH como WebVTT.
Como o worker lê do arquivo e não toca no stream ao vivo, ele não pode quebrá-lo: se o reconhecimento não dá conta, as legendas simplesmente atrasam e depois se põem em dia. Por isso o stream precisa ter o DVR ligado.
Pré-requisitos¶
-
Uma compilação com a feature
whisper. O reconhecimento de fala enlaça uma pilha nativa whisper.cpp + ffmpeg, por isso vem desligado por padrão:bash make release FEATURES=whisper # ou: cargo build --release --features whisperNo Apple Silicon adicione Metal para aceleração por GPU (bem mais rápido):
--features whisper,metal. -
DVR ligado no stream (o worker lê e escreve o arquivo).
-
Um arquivo de modelo. Os modelos são nomeados por um nome curto (
tiny,base,small,medium,large-v3); o Sapsan resolve o nome num arquivo GGMLggml-<nome>.binno diretório de modelos:WHISPER_MODELS_DIR, se definido, senão~/.cache/whisper-models.
Baixe um modelo uma única vez, por exemplo
medium:bash mkdir -p ~/.cache/whisper-models curl -L -o ~/.cache/whisper-models/ggml-medium.bin \ https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium.bin
Configuração¶
Adicione um bloco speech2text a um stream que já tenha DVR:
streams:
news:
inputs:
- rtsp:
url: rtsp://admin:password@10.0.0.5/stream0
dvr:
root: /storage
speech2text:
model: medium # tiny | base | small | medium (padrão) | large-v3
language: ru # ISO-639-1; omita para detecção automática
audio_track: a1 # trilha de áudio de origem (padrão: a primeira trilha de áudio)
max_window_secs: 30 # limite da janela de reconhecimento, s (padrão 30, máx. 120)
Campos:
| Campo | Significado | Padrão |
|---|---|---|
model |
Modelo por nome curto; resolvido em ggml-<nome>.bin |
medium |
language |
Idioma do reconhecimento (ISO-639-1) | auto |
audio_track |
Identificador da trilha de áudio de origem | a primeira trilha de áudio |
max_window_secs |
Limite superior da janela de análise | 30 |
Validação: um stream com speech2text, mas sem dvr, é rejeitado; max_window_secs precisa estar em 1..=120; language precisa ser um código de 2–3 letras.
As mudanças são aplicadas no reload (SIGHUP / central): o worker é reiniciado apenas se o bloco speech2text tiver mudado de fato.
Verificação offline (antes de ligar num stream)¶
O CLI subtitle (compilado com a feature whisper) roda exatamente o mesmo reconhecedor de produção num arquivo local, grava o resultado ao lado e, se o arquivo já tem uma faixa de legendas, calcula uma métrica de proximidade. É a forma mais rápida de escolher modelo e idioma e de avaliar a qualidade:
subtitle recognize movie.mkv --lang ru --model medium
# processar apenas um trecho (p. ex., 2 minutos a partir de 25:00) para uma verificação rápida:
subtitle recognize movie.mkv --lang ru --start-sec 1500 --limit-sec 120
Arquivos de saída, junto do arquivo de entrada:
movie.subtitles.json— quadros estruturados de legendas com procedência completa (janela de áudio, modelo, hash, prompt, diagnóstico por cue), o bastante para reproduzir uma execução;movie.vtt— a projeção em WebVTT;movie.diff.txt— um lado a lado do texto de referência contra o reconhecido (quando o arquivo tem uma faixa de legendas de referência).
Se o arquivo tem legendas de referência, o CLI imprime WER (word error rate) e CER (character error rate), globalmente e por janela. Atenção: contra uma faixa de legendas feita de forma independente, o WER mede a divergência de tradução, não o erro de ASR — leia-o como um sinal relativo entre execuções e olhe o diff.
Qualquer arquivo .mkv/.mp4 serve como entrada.
Verificação num stream¶
Depois de ligar o speech2text num stream com DVR:
-
As informações de mídia do stream ganham uma faixa de legendas. Verifique a playlist mestra do HLS — ela agora contém um rendition
EXT-X-MEDIA:TYPE=SUBTITLES, e as variantes o referenciam comSUBTITLES="subs":bash curl -s "http://server/streaming/<stream>/index.m3u8" | grep -i subtitleNo DASH o manifesto ganha um
AdaptationSetcomcontentType="text". -
Abra o arquivo num reprodutor com suporte a legendas (ou o URL de HLS/DASH) e ligue a faixa de legendas. As legendas aparecem com atraso, enquanto o worker alcança a borda ao vivo, e depois a acompanham.
-
Acompanhe os contadores do reconhecimento no endpoint de métricas (segundos processados, tamanho da lacuna / atraso, erros).
Como o worker é stateless — o progresso é derivado da borda da faixa de legendas no arquivo —, depois de um restart ele continua da mesma lacuna, completa com legendas o arquivo já acumulado e nunca duplica um quadro.
Como funciona¶
A unidade de trabalho do worker é a lacuna entre a cobertura do áudio e a cobertura das legendas no arquivo. Ele lê o áudio da lacuna, decodifica-o em PCM mono de 16 kHz, roda o Whisper em janelas deslizantes (com um gate de silêncio contra alucinações e reancoragem em segmentos completos) e acrescenta quadros estruturados de legendas. O WebVTT entregue aos reprodutores é uma projeção desses quadros; os quadros armazenados guardam adicionalmente procedência e diagnóstico do Whisper para depuração.