Whisper ट्रांसक्रिप्ट को एनोटेट कैसे करें
Whisper या WhisperX के आउटपुट को चालू एनोटेशन प्रोजेक्ट में कैसे बदलें: कौन सी आउटपुट फ़ाइल रखें, diarization कब ज़रूरी है, स्पीकर कैसे सौंपे जाएँ, और टाइमिंग बरकरार रखते हुए एक्सपोर्ट कैसे करें।
Whisper आपको समय के साथ बँटे सेगमेंट देता है, और एनोटेशन टूल को उन्हें जैसा है वैसा ही पढ़ लेना चाहिए। .txt के बजाय .json आउटपुट रखें, स्पीकर लेबल चाहिए तो WhisperX चलाएँ, फिर Potato को उस फ़ोल्डर की ओर इशारा कर दें। कोई कन्वर्ज़न स्क्रिप्ट नहीं, कोई फिर से फ़ॉर्मैट करने का चरण नहीं। हर फ़ॉर्मैट का ब्योरा ट्रांसक्रिप्ट फ़ॉर्मैट में है।
Whisper OpenAI का ओपन-सोर्स speech recognition मॉडल है, और जिसके पास भी निपटाने के लिए ऑडियो का ढेर हो, उसके लिए यह पहला कदम बन चुका है। यह जो बनाता है वह समय के साथ बँटे सेगमेंट का एक समूह होता है, जो एनोटेशन प्रोजेक्ट की लगभग सारी ज़रूरत पूरी कर देता है। कमी वहाँ रह जाती है जो “मेरे पास ट्रांसक्रिप्ट हैं” और “एनोटेटर उन्हें लेबल कर रहे हैं” के बीच पड़ता है।
ध्यान दें: Potato ट्रांसक्राइब नहीं करता। ASR उससे पहले चलता है और 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 ट्रांसक्राइब करता है, यह नहीं बताता कि बोल कौन रहा है। हर टर्न बिना किसी के नाम के आता है, जो कंटेंट एनोटेशन के लिए ठीक है और स्पीकर से जुड़े किसी भी काम के लिए तकलीफ़देह।
Speaker diarization एक अलग चरण है। इसे सँभालने के तीन तरीके:
WhisperX चलाएँ, जो Whisper के साथ pyannote diarization जोड़ देता है:
whisperx interview_01.mp3 --model medium --diarize --output_format jsonइसके आउटपुट में हर सेगमेंट पर एक speaker फ़ील्ड होती है (SPEAKER_00, SPEAKER_01, वग़ैरह) और Potato उसे सीधे पढ़ लेता है।
diarization चालू करके कोई क्लाउड API इस्तेमाल करें। diarize=true के साथ Deepgram, speaker_labels के साथ AssemblyAI, AWS Transcribe, और Rev.ai, चारों स्पीकर लेबल देते हैं और Potato चारों को सीधे पढ़ता है।
बिना diarization वाले टर्न Unassigned के रूप में दिखते हैं, साथ में स्पीकर चुनने का विकल्प
एनोटेटरों से करवाएँ। जब टर्न बिना diarization के आते हैं, तो हर बबल Unassigned के रूप में एक पिकर के साथ दिखता है। गड़बड़ ऑडियो, एक-दूसरे पर चढ़ती आवाज़ों, या पीछे शोर वाले कमरे में सुनकर बताने वाला इंसान अक्सर अपने आप होने वाले diarization से ज़्यादा सही निकलता है। छोटे संग्रह के लिए यह मजबूरी नहीं, एक वाजिब सौदा है।
डेटा फ़ाइल कैसे बनाएँ?
कन्वर्टर को अपने Whisper आउटपुट फ़ोल्डर पर लगाएँ:
potato transcripts ./whisper_out --media-dir ./audio -o data/interviews.jsonट्रांसक्रिप्ट अपने मीडिया से basename के आधार पर जुड़ते हैं, इसलिए interview_01.json को interview_01.mp3 मिल जाती है। आइटम id फ़ाइल के नाम से बनते हैं, और Whisper का दोहरा एक्सटेंशन interview_01.mp3.json ऐसे सँभाला जाता है कि id interview_01.mp3 न बन जाए।
इस पर टिकने से पहले देख लें कि उसने क्या समझा:
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 या शून्य टर्न बताए, वही आपकी गड़बड़ फ़ाइल है। लगभग हमेशा यह कोई .txt होती है जो .json आउटपुट के बीच आ मिली है।
क्या कन्वर्ज़न वाला चरण छोड़ा जा सकता है?
हाँ। डेटा फ़ाइल सीधे डिस्क पर पड़ी ट्रांसक्रिप्ट फ़ाइलों की ओर इशारा कर सकती है:
{"id": "int_001", "conversation": {"audio": "media/int_001.mp3",
"transcript": "media/int_001.srt"}}Potato फ़ाइल पढ़ता है, उसकी सामग्री से फ़ॉर्मैट पहचानता है, और इंस्टेंस दिखाते समय उसे सामान्य रूप में ढाल देता है। आपके ट्रांसक्रिप्ट किसी डेटा ब्लॉब में पक जाने के बजाय ऐसी फ़ाइलें बने रहते हैं जिनका diff लिया जा सके और जिन्हें दोबारा एक्सपोर्ट किया जा सके।
कॉन्फ़िग कैसा दिखता है?
बनी हुई डेटा फ़ाइल की शक्ल ऐसी होती है:
{
"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"
labels:
- name: policy
- name: personal
audio_dialogue डिस्प्ले, जिसमें हर टर्न से एक प्रश्न जुड़ा है
audio_dialogue डिस्प्ले टर्न को ऑडियो से सिंक स्पीकर बबल के रूप में दिखाता है, और हर टर्न पर एक प्ले बटन होता है जो सिर्फ़ वही टर्न बजाता है। span_target: true से span टर्न की सीमाओं के आर-पार जा सकते हैं, और स्पीकर बदलने पर भी offset स्थिर रहते हैं।
अगर आप चाहते हैं कि एनोटेटर कंटेंट लेबल करने के बजाय ट्रांसक्रिप्शन की जाँच करें, तो 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 पिकर तभी चालू करता है जब लेबल करने के लिए बिना diarization वाले टर्न मौजूद हों। इसे true कर दें तो स्पीकर तब भी बदले जा सकते हैं जब स्रोत ने लेबल दे रखे हों, यानी जब आप खाली जगह भरने के बजाय diarization की ग़लतियाँ सुधार रहे हों।
सौंपे गए स्पीकर एनोटेशन के साथ, एक स्थिर turn id से जुड़कर सहेजे जाते हैं, इसलिए पेज दोबारा लोड होने पर भी बने रहते हैं।
एनोटेशन वापस कैसे निकालें?
JSON, JSONL और CSV एक्सपोर्ट हमेशा की तरह चलते हैं। जब समय का मिलान बचाए रखना हो, तो tiered एनोटेशन को 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 सबटाइटल एनोटेट करना, इसी वर्कफ़्लो का कैप्शन-फ़ाइल वाला रूप
- ऑडियो एनोटेशन, उस waveform काम के लिए जो ट्रांसक्रिप्ट से शुरू नहीं होता
- ट्रांसक्रिप्ट फ़ॉर्मैट इंजेशन, छह फ़ॉर्मैट साथ-साथ दिखाता एक चलाने लायक showcase डिज़ाइन
- Speaker Diarization, एक चलाने लायक showcase डिज़ाइन
- इंटर-एनोटेटर सहमति, टर्न-स्तर के लेबल पर सहमति मापने के लिए