איך יוצרים כתוביות SRT מסרטון עם API

שולחים את הסרטון ל־POST /transcribe עם output_format שמוגדר ל־srt ו־word_timestamps שמוגדר ל־false, מחכים שהמשימה תסתיים ושומרים את הטקסט שחזר בתור קובץ .srt. אם רוצים כתוביות מתורגמות, מוסיפים את הפרמטר translate_to. במדריך הזה תראו את הבקשה המדויקת, איך בנוי קובץ ה־SRT שחוזר, איך מרכיבים שורות נוחות לקריאה מתוך זמני המילים, איך ממירים ל־WebVTT ואיך צורבים את הכתוביות על הווידאו.

קבלת מפתח API התחלה מהירה שפות נתמכות

עודכן לאחרונה: · Markdown

הבקשה

שתי קריאות: פותחים משימה ואז בודקים אותה. ה־result של משימת srt שהסתיימה הוא מחרוזת ולא JSON. הגרסה הזו צריכה רק curl ו־jq:

# 1. Start the job. "word_timestamps": false gives one cue per segment.
JOB=$(curl -s https://app.kolwrite.com/transcribe \
  -H "x-api-key: $KOLWRITE_API_KEY" -H "Content-Type: application/json" \
  -d '{"audio_url": "https://example.com/talk.mp3", "model": "oracle", "output_format": "srt", "word_timestamps": false}' \
  | jq -r .jobId)

# 2. Poll until it is done and save the result string as a .srt file.
while true; do
  REPLY=$(curl -s "https://app.kolwrite.com/transcribe/$JOB" -H "x-api-key: $KOLWRITE_API_KEY")
  STATUS=$(echo "$REPLY" | jq -r .status)
  if [ "$STATUS" = "COMPLETED" ]; then echo "$REPLY" | jq -r .result > talk.srt; break; fi
  if [ "$STATUS" = "FAILED" ]; then echo "$REPLY" | jq -r .error; break; fi
  sleep 5
done

אפשר לשלוח גם קובץ וידאו, וה־API יקרא את ערוץ האודיו שלו. קובץ מקומי מעלים קודם ל־POST /upload (עד 100 MiB), ומסרטונים ארוכים כדאי לחלץ את האודיו מראש עם ffmpeg. פונקציית העזר במדריך עריכת הווידאו מטפלת בשני השלבים האלה ב־Python.

מה יש בקובץ ה־SRT

כשמגדירים "word_timestamps": false מקבלים בלוק כתובית אחד לכל מקטע, כמו ברוב קובצי הכתוביות:

1
00:00:01,000 --> 00:00:03,750
Hello everyone and welcome to the show.

2
00:00:05,000 --> 00:00:07,750
Today we talk about editing video from a transcript.

כברירת מחדל, חותמות הזמן למילים פועלות וה־API מחזיר בלוק נפרד לכל מילה. בכל בלוק מופיע הטקסט המלא של המקטע, והמילה הנוכחית מודגשת בצהוב עם תגית <font>. זה מיועד למעקב מילה־מילה בזמן הדיבור, לא לכתוביות רגילות:

1
00:00:01,000 --> 00:00:01,350
<font color="yellow">Hello</font> everyone and welcome to the show.

2
00:00:01,400 --> 00:00:01,750
Hello <font color="yellow">everyone</font> and welcome to the show.

אם אתם צריכים כתוביות רגילות, שלחו "word_timestamps": false, או הרכיבו את השורות בעצמכם מתוך ה־JSON כמו בדוגמה הבאה.

הרכבת שורות מסודרות מזמני המילים

בקשו output_format: "json" וקבצו את המילים לשורות בעצמכם: עד 42 תווים ועד 6 שניות לשורה, ושבירת שורה אחרי הפסקה בדיבור. ככה אתם שולטים באורך השורה, וזה נוח במיוחד כשצורבים כתוביות על הווידאו.

srt_tools.py

# srt_tools.py — neat subtitle cues from word timings
def srt_time(seconds):
    ms = round(seconds * 1000)
    h, ms = divmod(ms, 3_600_000)
    m, ms = divmod(ms, 60_000)
    s, ms = divmod(ms, 1000)
    return f"{h:02}:{m:02}:{s:02},{ms:03}"


def cues_from_words(words, max_chars=42, max_seconds=6.0, max_gap=0.8):
    """Group timed words into subtitle cues: (start, end, text)."""
    cues, line = [], []
    for word in words:
        text = word["word"].strip()
        if not text:
            continue
        if line:
            length = sum(len(w["word"]) + 1 for w in line) + len(text)
            if (length > max_chars
                    or word["end"] - line[0]["start"] > max_seconds
                    or word["start"] - line[-1]["end"] > max_gap):
                cues.append(line)
                line = []
        line.append({"start": word["start"], "end": word["end"], "word": text})
    if line:
        cues.append(line)
    return [(c[0]["start"], c[-1]["end"], " ".join(w["word"] for w in c)) for c in cues]


def cues_from_result(result):
    """Cues for a whole JSON result; a segment without word times becomes one cue."""
    cues = []
    for segment in result["segments"]:
        if segment.get("words"):
            cues += cues_from_words(segment["words"])
        elif segment["text"].strip():
            cues.append((segment["start"], segment["end"], segment["text"].strip()))
    return cues


def write_srt(cues, path):
    with open(path, "w", encoding="utf-8") as out:
        for number, (start, end, text) in enumerate(cues, 1):
            out.write(f"{number}\n{srt_time(start)} --> {srt_time(end)}\n{text}\n\n")

הפונקציה cues_from_result(result) מחזירה שלשות (start, end, text) לכל התמליל, ואם המודל לא החזיר זמנים ברמת מילה היא נעזרת בזמני המקטעים. הפונקציה write_srt(cues, "talk.srt") שומרת את התוצאה לקובץ.

כתוביות מתורגמות

מוסיפים את translate_to עם קוד השפה ובוחרים במודל ממשפחת Oracle (oracle_mini הוא הזול ביותר שתומך בתרגום). הטקסט של כל שורה יחזור בשפת היעד. השאירו את word_timestamps על false כדי שכל שורה תייצג מקטע שלם.

{
  "audio_url": "https://example.com/lecture-he.mp4",
  "model": "oracle_mini",
  "language": "he",
  "translate_to": "en",
  "output_format": "srt",
  "word_timestamps": false
}

אם צריך לתרגם סרטון לכמה שפות, מריצים משימה נפרדת לכל שפה. תרגום מכונה הוא רק טיוטה, אז תעברו על שמות, מספרים ומונחים מקצועיים לפני הפרסום.

WebVTT,‏ ASS ופורמטים אחרים

ה־API מחזיר רק json,‏ txt או srt. כדי להמיר קובץ SRT ל־WebVTT (למשל בשביל תגית <video> ב־HTML5), מריצים ב־ffmpeg:

ffmpeg -i video.srt video.vtt

באותה צורה ffmpeg יודע להמיר בין רוב פורמטי הכתוביות, פשוט מחליפים את הסיומת של קובץ הפלט.

צריבה או צירוף של הכתוביות לסרטון

צרובות בתמונה:

ffmpeg -i edited.mp4 -vf "subtitles=edited.srt" -c:a copy burned.mp4

הוספה כערוץ כתוביות נפרד בתוך קובץ ה־MP4 (כך שהצופה יכול להדליק ולכבות בנגן):

ffmpeg -i edited.mp4 -i edited.srt -c copy -c:s mov_text -metadata:s:s:0 language=eng soft.mp4

YouTube Studio, רוב נגני הווידאו ורוב תוכנות העריכה מקבלים קובצי .srt ישירות.

כתוביות בעברית ובערבית

  • ה־API מחזיר טקסט Unicode רגיל. מי שמסדר את הכיוון מימין לשמאל הוא הנגן או מנוע הכתוביות של ffmpeg, שמסתדר עם עברית וערבית כל עוד הגופן מכיל את האותיות המתאימות.
  • תנו לו גופן שתומך בשפה, ובדקו פריים אחד מרונדר לפני שאתם מריצים עיבוד על סרטון שלם. בבדיקות שלנו עברית נראתה מצוין עם Arial, אבל בערבית הייתה מילה אחת עם תו חסר באותו גופן, כך שלערבית עדיף לבחור גופן אחר.
ffmpeg -i video.mp4 -vf "subtitles=video.he.srt:force_style='FontName=Arial,FontSize=24'" -c:a copy burned.mp4
  • בנגנים שלא תומכים בטקסט דו־כיווני, שורה שמסתיימת בסימן פיסוק או במילה באותיות לטיניות (כמו שם מותג או מספר) עלולה להתהפך ולהופיע בסדר לא צפוי. בדקו מראש איך זה נראה בנגנים שבהם הקהל שלכם משתמש.

כמה זה עולה

משימהמודלעלות
הרצאה של 45 דקות, כתוביותoracle1.08 דולר
אותה הרצאה, כתוביות מתורגמותoracle_mini0.72 דולר
שעה של אודיו נקי, כתוביותbase0.48 דולר

החיוב הוא לפי שנייה, בלי מינימום. לכל התעריפים: /llms/pricing.md.

שאלות ותשובות

איך מפיקים קובץ SRT מסרטון?

שולחים בקשה ל־POST /transcribe עם כתובת הסרטון, output_format: "srt" ו־word_timestamps: false. מחכים שהמשימה תסתיים ושומרים את הטקסט שחזר בשדה result כקובץ .srt.

האם ה־API מחזיר WebVTT?

לא, הפלט הוא json,‏ txt או srt. אפשר להמיר SRT ל־WebVTT בפקודה אחת: ffmpeg -i video.srt video.vtt.

למה בקובץ ה־SRT שלי יש כתובית נפרדת לכל מילה?

כי חותמות זמן למילים פועלות כברירת מחדל, ובמצב הזה קובץ ה־SRT מציג בלוק נפרד לכל מילה כשהמילה הנוכחית מודגשת. כדי לקבל שורה אחת לכל מקטע שלחו word_timestamps: false, או שתבנו את השורות בעצמכם מפלט ה־JSON.

אפשר לקבל כתוביות מתורגמות לשפה אחרת?

כן. מוסיפים את הפרמטר translate_to עם קוד השפה הרצויה ובוחרים במודל ממשפחת Oracle. הכתוביות יחזרו מתורגמות לשפת היעד.

מה ההבדל בין כתוביות לכתוביות מותאמות לכבדי שמיעה?

כתוביות רגילות מציגות או מתרגמות את מה שנאמר עבור צופים ששומעים את פס הקול. כתוביות מותאמות לכבדי שמיעה כוללות גם תיאור של צלילים ורעשי רקע. ה־API מתמלל את הדיבור עם חותמות זמן, ואת תיאורי הצלילים תוכלו להוסיף בעצמכם במקומות הרלוונטיים.