صيغ النصوص التفريغية
كل صيغ النصوص التفريغية والترجمات التي يقرأها Potato: Whisper وWhisperX وDeepgram وAssemblyAI وAWS Transcribe وSRT وWebVTT وTTML وترجمات YouTube وCTM وPraat TextGrid وELAN EAF، إضافة إلى الملفات المرافقة ونموذج الأدوار الموحّد.
يقرأ Potato 21 نوعًا من مدخلات النصوص التفريغية والترجمات، ويحوّلها جميعًا إلى نموذج الأدوار نفسه قبل عرض أي شيء. مهما كان ما أنتجه مسار التعرّف على الكلام لديك أو أداة الترجمة، يمكنك توجيه Potato إليه دون كتابة برنامج تحويل. هذه الصفحة مرجع لما يعمل، ولكيفية استنتاج كل صيغة، ولما تقدّمه كل واحدة منها. وللشرح خطوة بخطوة انظر كيفية شرح نصوص Whisper التفريغية وكيفية شرح ترجمات YouTube.
ملف SRT مرافق معروض كفقاعات متحدثين، مع سؤال مرفق بكل دور
Potato لا يقوم بالتفريغ
يجري التعرّف على الكلام وفصل المتحدثين قبل أن يرى Potato أي شيء. شغّل أولًا Whisper أو WhisperX أو pyannote أو واجهة برمجية سحابية؛ وPotato يستقبل النتيجة. لا شيء في هذه الصفحة يشغّل أي نموذج.
Note: يشغّل وضع Think-Aloud بالفعل نموذج Whisper محليًا، لكن لغرض مختلف: فهو يسجّل المشاركين في الشرح وهم يفكّرون بصوت عالٍ أثناء العمل. تلك ميزة تسجيل، لا استقبالًا لنصوص تفريغية.
الاستنتاج يتم من المحتوى لا من الامتداد
ينظر Potato فيما بداخل الملف بدل الاعتماد على اسمه. فملف WebVTT اسمه captions.txt يظل يُحلَّل كـ WebVTT. والنتيجة العملية أن النص التفريغي نفسه يعمل سواء كان مضمّنًا في ملف بياناتك أو مقروءًا من ملف مرافق على القرص، دون تغيير في الإعدادات.
الصيغ المدعومة
مخرجات التعرّف على الكلام
| الصيغة | يُستنتج من | المتحدثون | توقيتات الكلمات |
|---|---|---|---|
| Whisper JSON | مصفوفة segments | لا | نعم، مع --word_timestamps |
| WhisperX / JSON مفصول المتحدثين | segments تحتوي speaker | نعم | نعم |
| whisper.cpp JSON | مصفوفة transcription | لا | لا |
| Whisper TSV | ترويسة start/end/text | لا | لا |
| AWS Transcribe | results.items أو results.audio_segments | نعم | نعم |
| Deepgram | results.channels أو results.utterances | نعم، مع diarize=true | نعم |
| AssemblyAI | text مع words/utterances | نعم، مع speaker_labels | نعم |
| Rev.ai | مصفوفة monologues | نعم | نعم |
| SPoRC | صفوف turn_text/turnText | نعم، مستنتجة | لا |
الترجمات والتعليقات النصية
| الصيغة | يُستنتج من | المتحدثون |
|---|---|---|
SubRip (.srt) | أسهم المقاطع، الفاصل ,mmm | من بادئة Name: |
WebVTT (.vtt) | ترويسة WEBVTT | من وسوم <v Name> أو بادئة Name: |
SubStation Alpha (.ass، .ssa) | [Script Info] / Dialogue: | من حقل Name |
| TTML / DFXP | العنصر الجذر <tt> | من السمة speaker/agent |
| YouTube srv1/srv2/srv3 | XML على شكل <transcript><text> | من بادئة Name: |
| YouTube json3 | مصفوفة events | لا شيء؛ الترجمات التلقائية بلا متحدثين |
يغطي SubRip وWebVTT معظم ما ستصادفه. ويظهر TTML في أرشيفات البث وفي الملفات المصدَّرة من أدوات الترجمة الاحترافية.
المحاذاة والشرح اللغوي
| الصيغة | يُستنتج من | المتحدثون |
|---|---|---|
| NIST CTM | أعمدة مفصولة بمسافات، بداية ومدة رقميتان | من حقل القناة |
| Praat TextGrid | File type = "ooTextFile" | طبقة لكل متحدث |
| ELAN EAF | الجذر ANNOTATION_DOCUMENT | من PARTICIPANT، وإلا معرّف الطبقة |
تُحلَّل صيغتا TextGrid الطويلة والقصيرة معًا. وفي ملفات ELAN، يحلّ Potato عنصري ALIGNABLE_ANNOTATION وREF_ANNOTATION مقابل جدول TIME_ORDER ويقرأ مرجع الوسائط من الترويسة.
تصبح كل طبقة في TextGrid متحدثًا، وتُتخطّى الفترات الفارغة بينها
ما تبقّى
ثلاثة أشكال عامة تكمل العدد إلى 21:
- قائمة بسيطة من قواميس
{speaker, start, end, text}. - كائن
{"audio": ..., "turns": [...]}. - فقرة نصية بلا أي توقيتات، تُعرض كفقاعة واحدة.
غير مدعومة
لا يوجد محلّل لهذه. حوّلها أولًا.
- SAMI (
.smi)، MicroDVD (.sub)، SubViewer (.sbv) - Transcriber (
.trs)، EXMARaLDA، CHAT/CHILDES (.cha) - المخرجات الأصلية لـ Montreal Forced Aligner وGentle. صدّر منها CTM أو TextGrid بدلًا من ذلك.
- Azure Speech وGoogle Speech-to-Text و
verbose_jsonمن واجهة Whisper داخل أغلفة غير معتادة - ملفات فصل المتحدثين RTTM بمفردها
تُحلَّل درجة الثقة على مستوى الكلمة وتُحفظ في نموذج البيانات حيثما وفّرها المصدر، لكن لا توجد حاليًا واجهة لعرضها.
نموذج الأدوار الموحّد
كل الصيغ أعلاه تتحوّل إلى هذا:
{
"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 وconfidence إلا إذا كان المصدر يحملهما. وspeaker يكون null في الأدوار غير المفصولة، فتُعرض على أنها Unassigned مع أداة اختيار ليكملها المشاركون في الشرح.
تصل ترجمات YouTube التلقائية بلا متحدثين، فيبقى كل دور Unassigned حتى يختار أحد المشاركين
turn_id هو مفتاح حفظ الشروح على مستوى الدور وإسنادات المتحدثين. يأتي من سلسلة turn_id أو step_id صريحة في المصدر إن وُجدت، وإلا من t{الفهرس}. والملف نفسه ينتج المعرّفات نفسها دائمًا، فتبقى الشروح بعد إعادة التحميل.
Warning: تختلف وحدات الوقت بين الأدوات. يستخدم Whisper وDeepgram ثوانيَ عشرية؛ بينما يستخدم AssemblyAI وإزاحات whisper.cpp ومخرجات Whisper بصيغة TSV ميلي ثوانٍ صحيحة. يحوّل Potato عند الحدّ كي يكون كل ما بعده بالثواني. وإن خلطت معالجتك السابقة بينهما، خرجت التوقيتات خاطئة بمقدار ألف ضعف.
الملفات المرافقة
قيمة الحقل التي تكون مسارًا قصيرًا في سطر واحد وينتهي بامتداد نص تفريغي معروف تُقرأ من القرص بدل أن تُعامَل كنص. وبذلك يعمل التنظيم الذي أنتجته أداة التعرّف على الكلام أصلًا، بوجود ملفات الوسائط إلى جانب ملف .srt أو .json الخاص بها، دون أي خطوة معالجة مسبقة:
{
"id": "int_001",
"conversation": {
"audio": "media/int_001.mp3",
"transcript": "media/int_001.srt"
}
}تُحلّ المسارات نسبةً إلى task_dir وتمرّ بالتحقق الأمني نفسه الذي يمرّ به أي مسار مُعدّ آخر، فلا يستطيع ملف بيانات أن يقرأ خارج المشروع.
الامتدادات المعروفة: .srt .vtt .webvtt .json .json3 .srv1 .srv2 .srv3 .ttml .dfxp .xml .ass .ssa .tsv .ctm .TextGrid .eaf .txt
إن كانت بياناتك تحتوي فعلًا نصوصًا تفريغية من سطر واحد تشبه أسماء الملفات، فعطّل هذا الاستنتاج:
display_options:
transcript_is_path: auto # auto (default) | true | falseالإعدادات
العرض: audio_dialogue
يعرض عرض الحوار الصوتي الأدوار كفقاعات متحدثين متزامنة مع الصوت، مع زر تشغيل على كل دور.
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| الخيار | الافتراضي | ما يفعله |
|---|---|---|
audio_key | audio | المفتاح الفرعي داخل قيمة الحقل الذي يحمل رابط الصوت أو مساره. |
turns_key | turns | المفتاح الفرعي الذي يحمل قائمة الأدوار. ويقبل segments أيضًا. |
speaker_key / text_key | speaker / text | مفاتيح على مستوى الدور. |
speakers | [] | قائمة من {id, name, color, side}. المتحدثون غير المدرجين يحصلون على لون محدّد بشكل ثابت وجهة متناوبة. |
allow_speaker_assignment | auto | يفعّل auto الإسناد بالنقر عند وجود أدوار غير مفصولة أو قائمة تحتاج تصحيحًا. وtrue يفرضه وfalse يعطّله. |
transcript_is_path | auto | هل تُقرأ قيمة الحقل كمسار إلى ملف مرافق. |
show_timestamps | true | يعرض mm:ss–mm:ss على كل دور. |
scroll_height | 480px | ارتفاع لوحة النص التفريغي القابلة للتمرير. |
playback_rates | [1, 1.25, 1.5, 2] | خيارات محدّد السرعة. |
المخططات
منذ الإصدار 2.7.1، يقرأ كلٌّ من speech_transcript وvoice_interaction وtiered_annotation النص التفريغي مباشرة من سجل العنصر، ويقبل كل الصيغ المذكورة في هذه الصفحة. وقبل ذلك كان عرض audio_dialogue وحده يفعل ذلك.
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يمكن للشرح الطبقي أن يملأ طبقة مسبقًا من النص التفريغي، فيصحّح المشاركون محاذاة موجودة بدل إعادة تقطيع الكلام يدويًا:
- 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"لا تُكتب الشروح المملوءة مسبقًا حتى يجري المشارك تعديلًا فعليًا، فلا يُنسب شيء إلى من اكتفى بفتح العنصر.
بناء ملف بيانات باستخدام potato transcripts
وجّه أداة التحويل إلى مجلد فيه مخرجات تعرّف على الكلام، فتكتب ملف بيانات جاهزًا للشرح:
# 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 عما وجده دون أن يكتب شيئًا، وهو أسرع طريقة لاكتشاف مجلد فيه ملف مخرجات Whisper الخاطئ:
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.
| الخيار | الغرض |
|---|---|
-o، --output | أين يُكتب الناتج. إلزامي إلا مع --dry-run. |
--format | json (الافتراضي) أو jsonl. |
--media-dir | مجلد الوسائط الذي تُزاوَج ملفاته بالاسم الأساسي. |
--media-url-prefix | رابط أساسي للوسائط بدل الملفات المحلية. |
--field | حقل العنصر الذي يوضع فيه النص التفريغي. الافتراضي conversation. |
--id-prefix | نص يُضاف قبل كل معرّف مُولَّد. |
--speaker-key | مفتاح المصدر الذي يحمل تسمية المتحدث. |
-r، --recursive | يشمل المجلدات الفرعية. |
--dry-run | يُبلغ عن الصيغة المستنتَجة وعدد الأدوار لكل ملف. |
--emit-config | يطبع أيضًا مقتطف config.yaml مطابقًا. |
-q، --quiet | يكتم التقرير الخاص بكل ملف. |
تُشتق معرّفات العناصر من اسم الملف بعد إزالة امتداد وسائط في نهايته، فيصبح ملف interview_01.mp3.json من Whisper هو interview_01 لا interview_01.mp3.
التصدير إلى الخارج
تُصدَّر الشروح الطبقية إلى ELAN EAF وPraat TextGrid، فيستطيع النص التفريغي أن يكمل دورة كاملة: تستقبله، وتشرحه في Potato، وتصدّره، وتنقّحه في ELAN أو Praat، ثم تعيد قراءة النتيجة.
python -m potato.export --config config.yaml --format eaf --output ./out/
python -m potato.export --config config.yaml --format textgrid --output ./out/يعمل كلا المُصدِّرَين انطلاقًا من مخرجات tiered_annotation. أما المخططات الأخرى فتُصدَّر عبر الصيغ القياسية.
معالجة المشكلات
| العَرَض | ما الذي حدث |
|---|---|
| يظهر كل شيء كفقاعة واحدة كبيرة | لم تُستنتج الصيغة فسقط الملف على البديل النصي البسيط. شغّل potato transcripts <file> --dry-run؛ فإن أبلغ عن plain text فالتوقيتات لم تُقرأ أصلًا. وغالبًا يكون الملف .txt من Whisper، وهو بلا أي توقيتات، بدل .json أو .srt. |
| لا متحدثين، والكل Unassigned | المصدر لا يحمل تسميات متحدثين. Whisper وحده لا يفصل المتحدثين، وكذلك ترجمات YouTube التلقائية. شغّل فصل المتحدثين قبل ذلك أو دع المشاركين يُسنِدون المتحدثين في الواجهة. |
| التوقيتات خاطئة بمقدار ألف ضعف | خُلطت الثواني والميلي ثواني في مرحلة سابقة. فإزاحات whisper.cpp وAssemblyAI وملف TSV من Whisper كلها بالميلي ثانية. |
| مسار النص التفريغي يظهر بوصفه النص نفسه | تعذّرت قراءة الملف المرافق، فعُرض المسار كمحتوى. تحقق من أنه يُحلّ داخل task_dir. وتسجّل سجلات الخادم السبب المحدّد. |
| نص تفريغي من سطر واحد يُقرأ كاسم ملف | اضبط transcript_is_path: false على حقل العرض. |
مشروع مثال
يعرض examples/audio/transcript-formats/ في مستودع Potato ست صيغ جنبًا إلى جنب، كل منها محمّلة من ملف مرافق: SubRip وWebVTT وWhisper JSON وYouTube json3 وPraat TextGrid وDeepgram. وتنتج الست جميعها فقاعات المتحدثين نفسها.
python potato/flask_server.py start examples/audio/transcript-formats/config.yaml -p 8000المهمة نفسها متاحة كتصميم قابل للتنزيل: Transcript Format Ingestion.
لتفاصيل التنفيذ، انظر الوثائق المصدرية.
قراءات إضافية
- كيفية شرح نصوص Whisper التفريغية، الشرح الكامل من البداية إلى النهاية
- كيفية شرح ترجمات YouTube، للترجمات وحدودها
- شرح الحوار، عرض فقاعات المتحدثين
- شرح الصوت، تقطيع الموجة الصوتية من الصفر
- تصميم صيغ البيانات للشرح