Skip to content

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.

Uma transcrição apresentada como balões de falante coloridos, cada um com o seu botão de reprodução, marcas temporais e uma pergunta de etiquetagem por turno.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

FormatoDetetado porFalantesTempos por palavra
Whisper JSONArray segmentsNãoSim, com --word_timestamps
WhisperX / JSON diarizadosegments com speakerSimSim
whisper.cpp JSONArray transcriptionNãoNão
Whisper TSVCabeçalho start/end/textNãoNão
AWS Transcriberesults.items ou results.audio_segmentsSimSim
Deepgramresults.channels ou results.utterancesSim, com diarize=trueSim
AssemblyAItext mais words/utterancesSim, com speaker_labelsSim
Rev.aiArray monologuesSimSim
SPoRCLinhas turn_text/turnTextSim, inferidosNão

Legendas

FormatoDetetado porFalantes
SubRip (.srt)Setas de bloco, separador ,mmmPor um prefixo Name:
WebVTT (.vtt)Cabeçalho WEBVTTPor etiquetas <v Name> ou um prefixo Name:
SubStation Alpha (.ass, .ssa)[Script Info] / Dialogue:Pelo campo Name
TTML / DFXPElemento raiz <tt>Por um atributo speaker/agent
YouTube srv1/srv2/srv3XML <transcript><text>Por um prefixo Name:
YouTube json3Array eventsNenhum; 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

FormatoDetetado porFalantes
NIST CTMColunas separadas por espaços, início e duração numéricosPelo campo de canal
Praat TextGridFile type = "ooTextFile"Uma camada por falante
ELAN EAFRaiz ANNOTATION_DOCUMENTPor 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.

Um Praat TextGrid apresentado como dois falantes chamados fieldworker e speaker, um por camada, com os intervalos de silêncio omitidos.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_json da 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:

json
{
  "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.

Três turnos de transcrição com fundo cinzento tracejado, cada um etiquetado como Unassigned com uma seta de menu, porque o formato de origem não trazia etiquetas de falante.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:

json
{
  "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:

yaml
display_options:
  transcript_is_path: auto   # auto (default) | true | false

Configuraçã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.

yaml
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çãoPredefiniçãoO que faz
audio_keyaudioSubchave do valor do campo que contém o URL ou caminho do áudio.
turns_keyturnsSubchave que contém a lista de turnos. Aceita também segments.
speaker_key / text_keyspeaker / textChaves por turno.
speakers[]Lista de {id, name, color, side}. Falantes não listados recebem uma cor determinística e um lado alternado.
allow_speaker_assignmentautoauto liga a atribuição por clique quando há turnos não diarizados ou uma lista a corrigir. true força, false desliga.
transcript_is_pathautoSe o valor do campo deve ser lido como caminho para um ficheiro adjacente.
show_timestampstrueMostra mm:ss–mm:ss em cada turno.
scroll_height480pxAltura 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.

yaml
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: turns

A 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:

yaml
  - 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:

bash
# 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:

text
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çãoPara que serve
-o, --outputOnde escrever. Obrigatório exceto com --dry-run.
--formatjson (predefinição) ou jsonl.
--media-dirPasta de conteúdos a emparelhar por nome base.
--media-url-prefixURL base dos conteúdos em vez de ficheiros locais.
--fieldCampo do item onde vai a transcrição. Predefinição conversation.
--id-prefixCadeia acrescentada antes de cada id gerado.
--speaker-keyChave de origem que contém a etiqueta de falante.
-r, --recursivePercorre subpastas.
--dry-runRelata o formato detetado e o número de turnos por ficheiro.
--emit-configImprime também um fragmento de config.yaml correspondente.
-q, --quietSuprime 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.

bash
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

SintomaO que aconteceu
Tudo aparece como um único balão grandeO 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 UnassignedA 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 erradosSegundos 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 textoO 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 ficheiroPonha 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.

bash
python potato/flask_server.py start examples/audio/transcript-formats/config.yaml -p 8000

A 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