Formatos de transcrição
Todos os formatos de transcrição e legendas que o Potato lê: Whisper, WhisperX, Deepgram, AssemblyAI, AWS Transcribe, SRT, WebVTT, TTML, legendas do YouTube, CTM, Praat TextGrid e ELAN EAF, além de ficheiros adjacentes e do modelo de turnos normalizado.
O Potato lê 21 entradas de transcrição e legendas e converte todas para o mesmo modelo de turnos antes de mostrar seja o que for. Seja o que for que a sua cadeia de reconhecimento de fala ou a sua ferramenta de legendagem produziu, pode apontar-lhe o Potato sem escrever um script de conversão. Esta página é a referência do que funciona, de como cada formato é reconhecido e do que cada um traz. Para o passo a passo, consulte Como anotar transcrições do Whisper e Como anotar legendas do YouTube.
Um ficheiro SRT adjacente apresentado como balões de falante, com uma pergunta associada a cada turno
O Potato não transcreve
O reconhecimento de fala e a diarização de falantes acontecem antes de o Potato ver seja o que for. Execute primeiro o Whisper, o WhisperX, o pyannote ou uma API na nuvem; o Potato ingere o resultado. Nada nesta página executa um modelo.
Note: O modo Think-Aloud executa de facto um modelo Whisper local, mas com outro propósito: grava os anotadores a falar enquanto trabalham. Isso é uma função de captura, não de ingestão de transcrições.
A deteção é pelo conteúdo, não pela extensão
O Potato inspeciona o que está dentro do ficheiro em vez de confiar no nome. Um ficheiro WebVTT chamado captions.txt continua a ser interpretado como WebVTT. A consequência prática é que a mesma transcrição funciona incorporada no seu ficheiro de dados ou lida a partir de um ficheiro adjacente em disco, sem alterar a configuração.
Formatos suportados
Saída de reconhecimento de fala
| Formato | Detetado por | Falantes | Tempos por palavra |
|---|---|---|---|
| Whisper JSON | Array segments | Não | Sim, com --word_timestamps |
| WhisperX / JSON diarizado | segments com speaker | Sim | Sim |
| whisper.cpp JSON | Array transcription | Não | Não |
| Whisper TSV | Cabeçalho start/end/text | Não | Não |
| AWS Transcribe | results.items ou results.audio_segments | Sim | Sim |
| Deepgram | results.channels ou results.utterances | Sim, com diarize=true | Sim |
| AssemblyAI | text mais words/utterances | Sim, com speaker_labels | Sim |
| Rev.ai | Array monologues | Sim | Sim |
| SPoRC | Linhas turn_text/turnText | Sim, inferidos | Não |
Legendas
| Formato | Detetado por | Falantes |
|---|---|---|
SubRip (.srt) | Setas de bloco, separador ,mmm | Por um prefixo Name: |
WebVTT (.vtt) | Cabeçalho WEBVTT | Por etiquetas <v Name> ou um prefixo Name: |
SubStation Alpha (.ass, .ssa) | [Script Info] / Dialogue: | Pelo campo Name |
| TTML / DFXP | Elemento raiz <tt> | Por um atributo speaker/agent |
| YouTube srv1/srv2/srv3 | XML <transcript><text> | Por um prefixo Name: |
| YouTube json3 | Array events | Nenhum; as legendas automáticas não os têm |
SubRip e WebVTT cobrem quase tudo o que vai encontrar. O TTML aparece em arquivos de difusão e em exportações de ferramentas profissionais de legendagem.
Alinhamento e anotação linguística
| Formato | Detetado por | Falantes |
|---|---|---|
| NIST CTM | Colunas separadas por espaços, início e duração numéricos | Pelo campo de canal |
| Praat TextGrid | File type = "ooTextFile" | Uma camada por falante |
| ELAN EAF | Raiz ANNOTATION_DOCUMENT | Por PARTICIPANT, senão o id da camada |
Tanto a serialização longa como a curta do TextGrid são interpretadas. Para ficheiros do ELAN, o Potato resolve ALIGNABLE_ANNOTATION e REF_ANNOTATION contra a tabela TIME_ORDER e lê a referência ao conteúdo a partir do cabeçalho.
Cada camada do TextGrid torna-se um falante, e os intervalos vazios entre elas são ignorados
Tudo o resto
Três formas genéricas completam as 21:
- Uma lista simples de dicionários
{speaker, start, end, text}. - Um objeto
{"audio": ..., "turns": [...]}. - Um parágrafo simples sem tempos nenhuns, apresentado como um único balão.
Não suportados
Não existe interpretador para estes. Converta-os primeiro.
- SAMI (
.smi), MicroDVD (.sub), SubViewer (.sbv) - Transcriber (
.trs), EXMARaLDA, CHAT/CHILDES (.cha) - Saída nativa do Montreal Forced Aligner e do Gentle. Exporte antes para CTM ou TextGrid a partir dessas ferramentas.
- Azure Speech, Google Speech-to-Text e o
verbose_jsonda API do Whisper dentro de invólucros pouco comuns - Ficheiros de diarização RTTM isoladamente
A confiança ao nível da palavra é interpretada e guardada no modelo de dados sempre que a fonte a fornece, mas por agora não existe interface para a consultar.
O modelo de turnos normalizado
Todos os formatos acima passam a isto:
{
"audio": "media/interview_01.mp3",
"turns": [
{
"turn_id": "t0",
"speaker": "host",
"start": 0.0,
"end": 6.5,
"text": "Welcome back.",
"words": [{"word": "Welcome", "start": 0.0, "end": 0.4, "confidence": 0.99}],
"confidence": 0.97
}
]
}words e confidence só aparecem quando a fonte os trazia. speaker é null nos turnos não diarizados, que aparecem como Unassigned com um seletor para os anotadores preencherem.
As legendas automáticas do YouTube chegam sem falantes, por isso cada turno fica como Unassigned até um anotador escolher um
turn_id é a chave de persistência das anotações por turno e das atribuições de falante. Vem de uma cadeia turn_id ou step_id explícita na fonte quando existe, e caso contrário de t{índice}. O mesmo ficheiro produz sempre os mesmos identificadores, por isso as anotações sobrevivem a um recarregamento.
Warning: As unidades de tempo variam entre ferramentas. O Whisper e o Deepgram usam segundos em vírgula flutuante; o AssemblyAI, os deslocamentos do whisper.cpp e a saída TSV do Whisper usam milissegundos inteiros. O Potato converte na fronteira para que tudo a jusante esteja em segundos. Se o seu próprio pré-processamento misturar os dois, os tempos saem 1000 vezes errados.
Ficheiros adjacentes
Um valor de campo que seja um caminho curto de uma só linha terminado numa extensão de transcrição conhecida é lido do disco em vez de ser tratado como texto. Assim, a disposição que a sua ferramenta de reconhecimento de fala já produziu, com os ficheiros de conteúdo ao lado do seu .srt ou .json, funciona sem qualquer passo de pré-processamento:
{
"id": "int_001",
"conversation": {
"audio": "media/int_001.mp3",
"transcript": "media/int_001.srt"
}
}Os caminhos são resolvidos relativamente a task_dir e passam pela mesma validação de segurança de caminhos que qualquer outro caminho configurado, portanto um ficheiro de dados não pode ler fora do projeto.
Extensões reconhecidas: .srt .vtt .webvtt .json .json3 .srv1 .srv2 .srv3 .ttml .dfxp .xml .ass .ssa .tsv .ctm .TextGrid .eaf .txt
Se os seus dados contiverem mesmo transcrições de uma linha que se parecem com nomes de ficheiro, desligue a heurística:
display_options:
transcript_is_path: auto # auto (default) | true | falseConfiguração
Visualização: audio_dialogue
A visualização de diálogo com áudio apresenta os turnos como balões de falante sincronizados com o áudio, com um botão de reprodução em cada turno.
instance_display:
fields:
- key: conversation
type: audio_dialogue
label: "Transcript"
span_target: true
display_options:
audio_key: audio
turns_key: turns
speaker_key: speaker
text_key: text
transcript_is_path: auto
show_timestamps: true
allow_speaker_assignment: auto
scroll_height: 460px| Opção | Predefinição | O que faz |
|---|---|---|
audio_key | audio | Subchave do valor do campo que contém o URL ou caminho do áudio. |
turns_key | turns | Subchave que contém a lista de turnos. Aceita também segments. |
speaker_key / text_key | speaker / text | Chaves por turno. |
speakers | [] | Lista de {id, name, color, side}. Falantes não listados recebem uma cor determinística e um lado alternado. |
allow_speaker_assignment | auto | auto liga a atribuição por clique quando há turnos não diarizados ou uma lista a corrigir. true força, false desliga. |
transcript_is_path | auto | Se o valor do campo deve ser lido como caminho para um ficheiro adjacente. |
show_timestamps | true | Mostra mm:ss–mm:ss em cada turno. |
scroll_height | 480px | Altura do painel de transcrição com deslocamento. |
playback_rates | [1, 1.25, 1.5, 2] | Opções do seletor de velocidade. |
Esquemas
Desde a 2.7.1, speech_transcript, voice_interaction e tiered_annotation leem uma transcrição diretamente do registo da instância e aceitam todos os formatos desta página. Antes, só a visualização audio_dialogue o fazia.
annotation_schemes:
- annotation_type: speech_transcript
name: transcript_review
description: "Mark transcription errors"
segments_key: segments # record field holding the transcript
- annotation_type: voice_interaction
name: barge_in
description: "Mark overlaps and barge-in"
turns_key: turnsA anotação em camadas pode pré-preencher uma camada a partir da transcrição, para que os anotadores corrijam um alinhamento existente em vez de voltarem a segmentar a fala à mão:
- annotation_type: tiered_annotation
name: tiers
source_field: audio_url
media_type: audio
transcript_field: asr_output # opt-in; omit to start from a blank timeline
transcript_tier: utterance # defaults to the first tier
tiers:
- name: utterance
labels:
- name: speech
color: "#7c3aed"As anotações pré-preenchidas só são escritas quando o anotador faz uma edição real, portanto nada é atribuído a alguém que apenas abriu a instância.
Construir um ficheiro de dados com potato transcripts
Aponte o conversor a uma pasta de saída de reconhecimento de fala e ele escreve um ficheiro de dados pronto a anotar:
# Pair transcripts to media by basename
potato transcripts ./whisper_out --media-dir ./audio -o data/interviews.json
# Media served from elsewhere
potato transcripts './captions/*.vtt' \
--media-url-prefix https://cdn.example.org/audio -o data/talks.json
# What did it detect? Writes nothing.
potato transcripts ./whisper_out --dry-run--dry-run relata o que encontrou sem escrever nada, que é a forma mais rápida de apanhar uma pasta com o ficheiro de saída do Whisper errado:
Scanned 3 file(s):
talk_01.srt SRT 2 turns 5.0s 2 speaker(s): Alice, Bob
talk_02.vtt WebVTT 1 turns 3.0s undiarized
talk_03.json whisper.cpp JSON 1 turns 2.4s undiarized
3 item(s), 4 turn(s).
1 item(s) have no media. Pass --media-dir or --media-url-prefix to enable playback.
| Opção | Para que serve |
|---|---|
-o, --output | Onde escrever. Obrigatório exceto com --dry-run. |
--format | json (predefinição) ou jsonl. |
--media-dir | Pasta de conteúdos a emparelhar por nome base. |
--media-url-prefix | URL base dos conteúdos em vez de ficheiros locais. |
--field | Campo do item onde vai a transcrição. Predefinição conversation. |
--id-prefix | Cadeia acrescentada antes de cada id gerado. |
--speaker-key | Chave de origem que contém a etiqueta de falante. |
-r, --recursive | Percorre subpastas. |
--dry-run | Relata o formato detetado e o número de turnos por ficheiro. |
--emit-config | Imprime também um fragmento de config.yaml correspondente. |
-q, --quiet | Suprime o relatório por ficheiro. |
Os identificadores de item vêm do nome do ficheiro sem uma extensão de conteúdo final, portanto interview_01.mp3.json do Whisper passa a interview_01 e não a interview_01.mp3.
Exportar de volta
As anotações em camadas exportam para ELAN EAF e Praat TextGrid, portanto uma transcrição pode fazer ida e volta: ingeri-la, anotá-la no Potato, exportá-la, refiná-la no ELAN ou no Praat e voltar a ler o resultado.
python -m potato.export --config config.yaml --format eaf --output ./out/
python -m potato.export --config config.yaml --format textgrid --output ./out/Ambos os exportadores partem da saída de tiered_annotation. Os restantes esquemas exportam através dos formatos padrão.
Resolução de problemas
| Sintoma | O que aconteceu |
|---|---|
| Tudo aparece como um único balão grande | O formato não foi reconhecido e caiu no recurso de parágrafo simples. Execute potato transcripts <file> --dry-run; se relatar plain text, os tempos nunca foram interpretados. Normalmente o ficheiro é um .txt do Whisper, que não tem tempos, em vez do .json ou do .srt. |
| Sem falantes, tudo aparece como Unassigned | A fonte não tem etiquetas de falante. O Whisper sozinho não diariza, e as legendas automáticas do YouTube também não. Execute a diarização a montante ou deixe que os anotadores atribuam falantes na interface. |
| Os tempos estão 1000 vezes errados | Segundos e milissegundos foram misturados a montante. Os offsets do whisper.cpp, o AssemblyAI e o TSV do Whisper estão todos em milissegundos. |
| O caminho da transcrição aparece como o texto | O ficheiro adjacente não pôde ser lido, por isso o caminho foi mostrado como conteúdo. Verifique que se resolve dentro de task_dir. Os registos do servidor indicam o motivo concreto. |
| Uma transcrição de uma linha é lida como nome de ficheiro | Ponha transcript_is_path: false no campo de visualização. |
Projeto de exemplo
examples/audio/transcript-formats/ no repositório do Potato mostra seis formatos lado a lado, cada um carregado a partir de um ficheiro adjacente: SubRip, WebVTT, Whisper JSON, YouTube json3, Praat TextGrid e Deepgram. Os seis produzem os mesmos balões de falante.
python potato/flask_server.py start examples/audio/transcript-formats/config.yaml -p 8000A mesma tarefa está disponível como design descarregável: Ingestão de formatos de transcrição.
Para detalhes de implementação, consulte a documentação de origem.
Leituras adicionais
- Como anotar transcrições do Whisper, o percurso de ponta a ponta
- Como anotar legendas do YouTube, para legendas e as suas limitações
- Anotação de diálogo, a visualização de balões de falante
- Anotação de áudio, segmentação da forma de onda a partir do zero
- Desenhar formatos de dados para anotação