Come creare sottotitoli SRT da un video con un'API

Manda il video a POST /transcribe impostando output_format su srt e word_timestamps su false, aspetta che il lavoro finisca e salva il testo restituito in un file .srt. Se vuoi i sottotitoli tradotti in un’altra lingua, aggiungi translate_to. In questa guida vediamo come fare la richiesta esatta, cosa c’è dentro l’SRT, come creare righe ordinate partendo dai tempi delle singole parole, come passare a WebVTT e come incorporare i sottotitoli nel video.

Ottieni una chiave API Guida rapida Lingue supportate

Ultimo aggiornamento: · Markdown

La richiesta

Due chiamate: avviare il lavoro e poi interrogarlo. Il result di un lavoro srt completato è una stringa, non JSON. Questa versione richiede solo curl e 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

Puoi usare direttamente un file video, perché l'API ne legge la traccia audio. Se il file è in locale, passa prima da POST /upload (massimo 100 MiB); per i video lunghi estrai prima l'audio con ffmpeg. Nella guida al montaggio video trovi una funzione di supporto che fa entrambe le cose in Python.

Cosa c’è dentro l’SRT

Impostando "word_timestamps": false si ottiene una riga per ogni segmento, come avviene nella maggior parte dei file di sottotitoli:

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.

Se lasci attivi i timestamp per parola (l'impostazione predefinita), l'API genera invece una riga per ogni singola parola. Ogni riga ripete l'intero testo del segmento racchiudendo la parola pronunciata in quel momento in un tag <font> giallo. Serve a evidenziare il testo mentre si legge, quindi non è un sottotitolo tradizionale:

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.

Se ti servono sottotitoli standard, passa "word_timestamps": false oppure componi tu le righe partendo dalle parole nel JSON, come vediamo qui sotto.

Comporre righe su misura dai timestamp delle parole

Richiedi output_format: "json" e raggruppa le parole via codice: fissa un tetto di 42 caratteri e 6 secondi per riga, andando a capo dopo le pause. In questo modo hai il pieno controllo sulla lunghezza delle righe, un aspetto molto utile quando imprimi i sottotitoli direttamente nel video.

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")

La funzione cues_from_result(result) restituisce delle tuple (start, end, text) per l'intero risultato e, se un modello non fornisce i tempi delle singole parole, usa come ripiego i tempi del segmento. Poi write_srt(cues, "talk.srt") scrive il file vero e proprio.

Sottotitoli tradotti in un'altra lingua

Aggiungi il parametro translate_to con il codice della lingua desiderata e scegli un modello Oracle (oracle_mini è il più economico tra quelli che traducono). Il testo ti arriverà già tradotto; ricorda di lasciare word_timestamps su false per avere un segmento intero su ogni riga.

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

Se devi tradurre un video in più lingue, avvia un lavoro separato per ciascuna lingua. Prima di pubblicare, però, rileggi sempre nomi, numeri e termini specifici: considera la traduzione automatica come una prima bozza.

WebVTT, ASS e altri formati

L’API restituisce soltanto i formati json, txt o srt. Se ti serve un file WebVTT per un tag <video> in HTML5, puoi convertire l’SRT con ffmpeg:

ffmpeg -i video.srt video.vtt

Con lo stesso comando ffmpeg puoi convertire quasi tutti i formati di sottotitoli: ti basta cambiare l'estensione del file di output.

Incorporare o allegare i sottotitoli al video

Incorporati nell’immagine:

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

Per aggiungerli come traccia separata dentro un file MP4 (così chi guarda può attivarli o disattivarli):

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

YouTube Studio e la maggior parte dei lettori e dei programmi di montaggio accettano direttamente il file .srt.

Sottotitoli in ebraico e arabo

  • L’API restituisce semplice testo Unicode. L’impaginazione da destra a sinistra dipende poi dal lettore video o dal renderer dei sottotitoli di ffmpeg, che gestisce senza problemi l’ebraico e l’arabo se il font usato contiene quelle lettere.
  • Specifica un font che supporti quell'alfabeto e fai una prova su un singolo fotogramma prima di elaborare tutto il video. Nei nostri test, ad esempio, con Arial l'ebraico si vedeva bene, mentre in una parola araba mancava un glifo. Per l'arabo conviene quindi scegliere un altro font.
ffmpeg -i video.mp4 -vf "subtitles=video.he.srt:force_style='FontName=Arial,FontSize=24'" -c:a copy burned.mp4
  • Se una riga finisce con un segno di punteggiatura o con caratteri latini (come un marchio o un numero), i lettori che non gestiscono bene il testo bidirezionale potrebbero mostrare gli elementi in un ordine strano. Fai sempre qualche prova sui lettori che usa il tuo pubblico.

Quanto costa

LavoroModelloCosto
Lezione di 45 minuti, sottotitolioracle1,08 US$
La stessa lezione, sottotitoli tradottioracle_mini0,72 US$
Un'ora di audio pulito, sottotitolibase0,48 US$

Paghi al secondo, senza costi minimi. Trovi le tariffe in /llms/pricing.md.

Domande e risposte

Come ottengo un file SRT da un video?

Chiama POST /transcribe passando l'URL del video, output_format: "srt" e word_timestamps: false. Interroga lo stato del lavoro e, una volta pronto, salva la stringa result in un file .srt.

L’API può restituire WebVTT?

No, restituisce solo json, txt o srt. Puoi però convertire l'SRT in WebVTT con il comando ffmpeg -i video.srt video.vtt.

Perché il mio SRT ha una riga per ogni parola?

Perché i timestamp per parola sono attivi per impostazione predefinita: nell’SRT trovi quindi una riga per ogni parola, con il termine corrente evidenziato. Passa word_timestamps: false per avere una riga per ogni segmento, oppure componi tu le righe partendo dal JSON.

Posso ottenere sottotitoli in un'altra lingua?

Sì. Ti basta aggiungere translate_to con il codice della lingua e scegliere un modello Oracle. Il testo delle righe ti arriverà già tradotto.

Che differenza c'è tra sottotitoli normali e sottotitoli per non udenti?

I sottotitoli normali trascrivono o traducono i dialoghi per chi sente l’audio, mentre quelli per non udenti descrivono anche i suoni. L’API genera il testo del parlato con i relativi tempi; le indicazioni sui suoni puoi aggiungerle tu dove servono.