Comment créer des sous-titres SRT d’une vidéo avec une API

Envoyez votre vidéo à POST /transcribe en passant output_format à srt et word_timestamps à false. Une fois la tâche terminée, enregistrez le texte reçu dans un fichier .srt. Si vous voulez traduire les sous-titres, ajoutez simplement translate_to. Voici la requête exacte à envoyer, à quoi ressemble le SRT obtenu, comment découper des lignes propres à partir du minutage par mot, et comment convertir en WebVTT ou incruster le texte dans la vidéo.

Obtenir une clé API Démarrage rapide Langues prises en charge

Dernière mise à jour: · Markdown

La requête

Deux appels : lancer la tâche, puis l’interroger. Le result d’une tâche srt terminée est une chaîne, pas du JSON. Cette version n’exige que curl et 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

Vous pouvez aussi envoyer une vidéo : l’API en lit directement la piste audio. Si le fichier est en local, passez d’abord par POST /upload (jusqu’à 100 MiB). Au-delà, extrayez l’audio avec ffmpeg pour les vidéos plus longues. La fonction présentée dans le guide du montage vidéo gère ces deux étapes en Python.

Contenu du fichier SRT

Si vous passez "word_timestamps": false, vous récupérez une seule ligne par segment de parole, comme dans la plupart des fichiers de sous-titres :

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.

Par défaut, l’horodatage mot à mot est activé et l’API génère une ligne par mot. Chaque ligne reprend tout le segment en entourant le mot prononcé d’une balise <font> jaune, pour surligner le texte au fil de la lecture plutôt que d’afficher de simples sous-titres :

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.

Pour obtenir des sous-titres classiques, passez "word_timestamps": false ou découpez vous-même vos lignes à partir des mots du JSON, comme dans l’exemple qui suit.

Découper ses propres sous-titres à partir de l’horodatage des mots

Demandez le format output_format: "json" et regroupez les mots vous-même : comptez au maximum 42 caractères et 6 secondes par sous-titre, en coupant après chaque pause. Vous gardez ainsi la main sur la longueur des lignes, ce qui est bien utile avant d’incruster des sous-titres dans la vidéo.

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 fonction cues_from_result(result) renvoie des triplets (start, end, text) pour tout le résultat, et se replie sur les temps du segment si le modèle ne fournit pas le détail par mot. Il suffit ensuite d’appeler write_srt(cues, "talk.srt") pour écrire le fichier.

Sous-titres traduits

Ajoutez le paramètre translate_to avec le code de la langue voulue et choisissez un modèle Oracle (oracle_mini est le plus économique qui prenne en charge la traduction). Les sous-titres reviennent directement traduits ; pensez à laisser word_timestamps à false pour avoir une entrée par segment.

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

Si vous voulez sous-titrer la vidéo en plusieurs langues, lancez une tâche par langue cible. Relisez toujours les noms propres, les chiffres et le vocabulaire métier avant de publier : la traduction automatique reste un premier jet.

WebVTT, ASS et autres formats

L’API exporte uniquement en json, txt ou srt. Pour intégrer les sous-titres dans une balise <video> HTML5, convertissez le SRT en WebVTT avec ffmpeg :

ffmpeg -i video.srt video.vtt

La même commande ffmpeg permet de convertir vers la plupart des formats de sous-titres : il suffit de changer l’extension du fichier de sortie.

Incruster les sous-titres ou ajouter une piste

Incrustés directement dans l’image :

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

En tant que piste de sous-titres séparée dans un MP4 (désactivable dans le lecteur) :

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

YouTube Studio ainsi que la plupart des lecteurs vidéo et des logiciels de montage acceptent directement les fichiers .srt.

Sous-titres en hébreu et en arabe

  • L’API renvoie du texte Unicode standard. C’est le lecteur vidéo ou le moteur de rendu de ffmpeg qui se charge de l’affichage de droite à gauche, et tous deux gèrent bien l’hébreu et l’arabe dès lors que la police choisie contient les bons caractères.
  • Spécifiez une police compatible avec l’alphabet voulu et vérifiez le rendu sur une image fixe avant d’encoder toute la vidéo. Lors de nos tests avec la police Arial, l’hébreu passait sans problème, mais il manquait un glyphe dans un mot en arabe : prévoyez une autre police pour l’arabe.
ffmpeg -i video.mp4 -vf "subtitles=video.he.srt:force_style='FontName=Arial,FontSize=24'" -c:a copy burned.mp4
  • Si une ligne se termine par de la ponctuation ou par des caractères latins (un nombre, un nom de marque), l’ordre d’affichage peut sauter dans les lecteurs qui gèrent mal le texte bidirectionnel. Faites un essai sur les lecteurs utilisés par votre public.

Combien ça coûte

TâcheModèleCoût
Cours de 45 minutes, sous-titréoracle1,08 US$
Le même cours, avec sous-titres traduitsoracle_mini0,72 US$
Une heure d’audio clair, sous-titrébase0,48 US$

Facturation à la seconde, sans minimum. Voir la grille complète : /llms/pricing.md.

Questions et réponses

Comment extraire un fichier SRT à partir d’une vidéo ?

Envoyez l’URL de la vidéo à POST /transcribe avec output_format: "srt" et word_timestamps: false. Une fois la tâche terminée, récupérez la chaîne result et enregistrez-la dans un fichier .srt.

L’API peut-elle renvoyer du WebVTT ?

Non, uniquement du json, du txt ou du srt. Vous pouvez convertir le fichier SRT en WebVTT avec la commande ffmpeg -i video.srt video.vtt.

Pourquoi mon fichier SRT contient-il une ligne par mot ?

Parce que l’horodatage mot à mot est activé par défaut : le SRT génère alors un sous-titre par mot en surlignant le mot prononcé. Passez word_timestamps: false pour avoir un sous-titre par segment de parole, ou découpez vos propres lignes à partir de la sortie JSON.

Peut-on générer des sous-titres traduits dans une autre langue ?

Oui. Passez le code de la langue voulue dans translate_to et choisissez un modèle de la gamme Oracle. Le texte des sous-titres sera directement traduit.

Quelle est la différence entre des sous-titres classiques et le sous-titrage pour sourds et malentendants ?

Les sous-titres classiques transcrivent ou traduisent les dialogues pour un public qui entend la bande-son, tandis que le sous-titrage pour sourds et malentendants indique aussi les bruits et la musique. L’API fournit la transcription horodatée des paroles ; à vous d’y ajouter les indications sonores nécessaires.