Whisper 전사를 주석하는 방법
Whisper나 WhisperX 출력을 그대로 주석 프로젝트로 만드는 방법. 어떤 출력 파일을 남겨야 하는지, 화자 분리가 필요한 시점, 화자를 배정하는 방법, 시간 정보를 유지한 채 내보내는 방법.
Whisper는 시간이 붙은 세그먼트를 주므로, 주석 도구는 그것을 그대로 읽어야 합니다. .txt 대신 .json 출력을 남기고, 화자 표시가 필요하면 WhisperX를 실행한 다음, Potato를 그 폴더로 향하게 하세요. 변환 스크립트도 재포맷 단계도 필요 없습니다. 형식별 상세 내용은 전사 형식을 보세요.
Whisper는 OpenAI의 오픈소스 음성 인식 모델로, 처리할 음성이 잔뜩 있는 사람에게 사실상 기본 첫 단계가 되었습니다. 나오는 결과는 시간이 붙은 세그먼트 묶음이고, 주석 프로젝트에 필요한 것의 대부분이 거기에 있습니다. 빠진 것은 "전사는 있다"와 "주석자가 라벨을 붙이고 있다" 사이의 모든 과정입니다.
Note: Potato는 전사하지 않습니다. 음성 인식은 앞단에서 실행되고 Potato는 그 결과를 받아들입니다. 이 문서는 앞단의 어떤 선택이 중요한지를 다루지만, 전사 자체는 Potato가 무엇을 보기도 전에 끝나 있습니다.
Whisper의 어떤 출력 파일을 남겨야 하나요?
Whisper는 여러 파일을 쓰는데, 그 선택이 보기보다 중요합니다.
whisper interview_01.mp3 --model medium --output_format json --word_timestamps True| 파일 | 내용 | 쓸 만한가 |
|---|---|---|
.json | 시작·종료 시각이 붙은 세그먼트, 필요하면 단어별 시간까지 | 이것을 쓰세요 |
.srt / .vtt | 시간이 붙은 세그먼트, 메타데이터 없음 | 예, 문제없이 동작합니다 |
.tsv | 밀리초 단위 시작·종료와 텍스트 | 예 |
.txt | 텍스트만, 시간 정보 없음 | 아니요, 음성과 맞출 근거가 없습니다 |
.txt만 남았다면 정렬 정보는 사라진 것이고, 모델을 다시 돌리지 않는 한 복원할 수 없습니다. 전사가 Potato에서 구분 없는 하나의 텍스트 덩어리로 보이는 이유는 거의 이것입니다.
Whisper가 화자를 표시하나요?
아니요. 이 점에 놀라는 사람이 정말 많습니다. Whisper는 전사만 하고 누가 말하는지는 알려주지 않습니다. 모든 발화 차례가 배정되지 않은 상태로 도착합니다. 내용 주석에는 문제가 없지만 화자와 관련된 작업에는 곤란합니다.
화자 분리는 별도의 단계입니다. 처리 방법은 세 가지입니다.
WhisperX를 실행하세요. Whisper를 pyannote 화자 분리로 감싼 도구입니다.
whisperx interview_01.mp3 --model medium --diarize --output_format json출력에는 세그먼트마다 speaker 필드(SPEAKER_00, SPEAKER_01 등)가 들어 있고 Potato가 그대로 읽습니다.
화자 분리를 켠 클라우드 API를 쓰세요. diarize=true의 Deepgram, speaker_labels의 AssemblyAI, AWS Transcribe, Rev.ai 모두 화자 표시를 만들어 내고, Potato는 네 가지를 모두 기본으로 읽습니다.
화자 분리가 되지 않은 차례는 화자 선택기와 함께 Unassigned로 표시됩니다
주석자에게 맡기세요. 화자 분리가 되지 않은 차례는 각 말풍선이 선택기와 함께 Unassigned로 표시됩니다. 음질이 나쁘거나 발화가 겹치거나 배경 소음이 있는 상황에서는, 듣는 사람이 자동 화자 분리보다 더 정확한 경우가 많습니다. 규모가 작은 말뭉치라면 이것은 임시방편이 아니라 합리적인 선택입니다.
데이터 파일은 어떻게 만드나요?
변환 도구를 Whisper 출력 폴더로 향하게 하세요.
potato transcripts ./whisper_out --media-dir ./audio -o data/interviews.json전사는 파일 기본 이름으로 음성과 짝지어지므로 interview_01.json이 interview_01.mp3를 찾습니다. 항목 ID는 파일 이름에서 나오고, Whisper의 이중 확장자 interview_01.mp3.json도 interview_01.mp3 같은 ID가 되지 않도록 처리됩니다.
진행하기 전에 무엇을 어떻게 읽었는지 확인하세요.
potato transcripts ./whisper_out --dry-runScanned 3 file(s):
interview_01.json Whisper JSON 42 turns 891.4s undiarized
interview_02.json WhisperX JSON 51 turns 1120.8s 2 speaker(s): SPEAKER_00, SPEAKER_01
interview_03.json Whisper JSON 38 turns 754.2s undiarized
3 item(s), 131 turn(s).
plain text나 차례 0으로 보고되는 파일이 문제의 파일입니다. 거의 언제나 .json 출력에 섞여 들어간 .txt입니다.
변환 단계를 건너뛸 수 있나요?
가능합니다. 데이터 파일이 디스크의 전사 파일을 곧바로 가리킬 수 있습니다.
{"id": "int_001", "conversation": {"audio": "media/int_001.mp3",
"transcript": "media/int_001.srt"}}Potato가 파일을 읽고 내용으로 형식을 판별해 인스턴스를 그릴 때 정규화합니다. 전사는 비교하고 다시 내보낼 수 있는 파일로 남고, 데이터 덩어리 안에 묻히지 않습니다.
설정은 어떻게 생겼나요?
생성된 데이터 파일은 이런 모양입니다.
{
"id": "interview_01",
"conversation": {
"audio": "audio/interview_01.mp3",
"turns": [
{"turn_id": "t0", "speaker": "SPEAKER_00", "start": 0.0, "end": 6.5,
"text": "Welcome back."}
]
}
}그리고 이에 맞는 설정은 potato transcripts --emit-config가 출력해 줍니다.
annotation_task_name: "Interview Annotation"
task_dir: .
data_files:
- data/interviews.json
item_properties:
id_key: id
text_key: conversation
instance_display:
fields:
- key: conversation
type: audio_dialogue
label: "Transcript"
span_target: true
display_options:
show_timestamps: true
allow_speaker_assignment: auto
annotation_schemes:
- annotation_type: span
name: topics
description: "Highlight topic mentions"
target_field: conversation
labels:
- name: policy
- name: personal
audio_dialogue 표시. 차례마다 질문이 붙습니다
audio_dialogue 표시는 발화 차례를 음성과 동기화된 화자 말풍선으로 그리고, 각 차례에는 그 차례만 재생하는 버튼이 붙습니다. span_target: true로 두면 스팬이 차례 경계를 넘을 수 있고, 화자를 다시 배정해도 오프셋은 그대로 유지됩니다.
내용에 라벨을 붙이는 대신 전사 자체를 검토하게 하고 싶다면, speech_transcript가 오류 태그와 수정 상자가 있는 세그먼트 카드를 제공합니다. 발화 겹침과 끼어들기를 다룬다면 voice_interaction이 이중 트랙 타임라인을 제공합니다. 둘 다 같은 파일을 읽습니다.
주석자는 화자를 어떻게 배정하나요?
화자 목록을 정의하면 이름과 색, 좌우 위치가 일관되게 유지됩니다.
display_options:
allow_speaker_assignment: auto
speakers:
- id: interviewer
name: "Interviewer"
color: "#7c3aed"
side: left
- id: participant
name: "Participant"
color: "#059669"
side: rightauto는 배정할 미분리 차례가 있을 때 선택기를 켭니다. 원본에 화자 표시가 있어도 다시 배정할 수 있게 하려면 true로 두세요. 빈칸을 채우는 게 아니라 화자 분리 오류를 고치는 경우에 필요합니다.
배정 결과는 안정적인 차례 ID에 묶여 주석과 함께 저장되므로 새로고침해도 남습니다.
주석은 어떻게 다시 꺼내나요?
JSON, JSONL, CSV 내보내기는 평소와 같습니다. 시간 정렬이 유지되어야 한다면 계층 주석을 ELAN EAF나 Praat TextGrid로 내보내세요.
python -m potato.export --config config.yaml --format eaf --output ./out/
python -m potato.export --config config.yaml --format textgrid --output ./out/둘 다 왕복이 됩니다. Potato는 EAF와 TextGrid를 입력으로도 읽으므로, Potato에서 주석하고 ELAN이나 Praat에서 다듬은 뒤 그 결과를 다시 읽어올 수 있습니다.
더 읽을거리
- 전사 형식, 지원하는 모든 형식과 판별 방식
- YouTube 자막을 주석하는 방법, 자막 파일 버전의 같은 흐름
- 오디오 주석, 전사에서 시작하지 않는 파형 작업
- Transcript Format Ingestion, 여섯 형식을 나란히 보여 주는 실행 가능한 쇼케이스
- 주석자 간 일치도, 차례 단위 라벨의 일치도를 재기 위해