Timestamps et Segmentation Temporelle
Structurer la transcription dans le temps
Une transcription brute est utile, mais une transcription horodatée ouvre des possibilités bien plus riches : sous-titrage, navigation temporelle, synchronisation avec la vidéo, extraction de passages précis. Le paramètre timestamp_granularities de Voxtral vous donne ce pouvoir.
Les deux niveaux de granularité
Voxtral propose deux niveaux de timestamps, utilisables séparément ou ensemble :
Granularité segment
Un segment est un bloc de parole continu — typiquement une phrase ou un groupe de phrases prononcées sans pause significative.
import os
from mistralai import Mistral
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
with open("conference.mp3", "rb") as f:
response = client.audio.transcriptions.complete(
model="voxtral-mini-latest",
file={"content": f, "file_name": "conference.mp3"},
timestamp_granularities=["segment"]
)
# Parcourir les segments
for seg in response.segments:
debut = f"{seg.start:.1f}s"
fin = f"{seg.end:.1f}s"
print(f"[{debut} → {fin}] {seg.text}")
Résultat typique :
[0.0s → 4.2s] Bonjour à tous, merci d'être présents aujourd'hui.
[4.5s → 11.8s] Nous allons aborder les résultats du trimestre et les perspectives pour la suite.
[12.1s → 18.3s] Commençons par le chiffre d'affaires qui a progressé de douze pour cent.
Les segments sont idéaux pour : la navigation dans un enregistrement long, l’affichage de blocs de sous-titres, l’indexation par passage.
Granularité mot
Chaque mot est horodaté individuellement avec son début et sa fin.
with open("discours.mp3", "rb") as f:
response = client.audio.transcriptions.complete(
model="voxtral-mini-latest",
file={"content": f, "file_name": "discours.mp3"},
timestamp_granularities=["word"]
)
# Parcourir les mots
for mot in response.words:
print(f"[{mot.start:.2f}s → {mot.end:.2f}s] {mot.text}")
Résultat typique :
[0.00s → 0.45s] Bonjour
[0.48s → 0.62s] à
[0.63s → 0.98s] tous
Les timestamps mot par mot sont idéaux pour : le sous-titrage précis (karaoké), la mise en surbrillance du mot actuel pendant la lecture, l’analyse prosodique.
Combiner les deux
Vous pouvez demander les deux granularités dans le même appel :
response = client.audio.transcriptions.complete(
model="voxtral-mini-latest",
file={"content": f, "file_name": "audio.mp3"},
timestamp_granularities=["segment", "word"]
)
# Segments disponibles
print(f"Nombre de segments : {len(response.segments)}")
# Mots disponibles
print(f"Nombre de mots : {len(response.words)}")
Générer des sous-titres SRT
Les timestamps permettent de générer directement des fichiers de sous-titres au format SRT :
def generer_srt_depuis_segments(segments, max_chars=60):
"""Génère un fichier SRT à partir des segments Voxtral."""
lignes_srt = []
compteur = 1
for seg in segments:
texte = seg.text.strip()
if not texte:
continue
# Découper les segments trop longs
mots = texte.split()
sous_texte = ""
for mot in mots:
if len(sous_texte) + len(mot) + 1 > max_chars and sous_texte:
lignes_srt.append(str(compteur))
lignes_srt.append(
f"{formater_temps_srt(seg.start)} --> "
f"{formater_temps_srt(seg.end)}"
)
lignes_srt.append(sous_texte.strip())
lignes_srt.append("")
compteur += 1
sous_texte = mot
else:
sous_texte += " " + mot
if sous_texte.strip():
lignes_srt.append(str(compteur))
lignes_srt.append(
f"{formater_temps_srt(seg.start)} --> "
f"{formater_temps_srt(seg.end)}"
)
lignes_srt.append(sous_texte.strip())
lignes_srt.append("")
compteur += 1
return "\n".join(lignes_srt)
def formater_temps_srt(secondes):
"""Convertit des secondes en format SRT (HH:MM:SS,mmm)."""
h = int(secondes // 3600)
m = int((secondes % 3600) // 60)
s = int(secondes % 60)
ms = int((secondes % 1) * 1000)
return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
# Utilisation
srt_contenu = generer_srt_depuis_segments(response.segments)
with open("sous_titres.srt", "w", encoding="utf-8") as f:
f.write(srt_contenu)
print("Fichier SRT généré avec succès")
Naviguer dans un enregistrement long
Les segments horodatés permettent de créer un index navigable pour un enregistrement long :
def creer_index_temporel(segments, intervalle_minutes=5):
"""Crée un index toutes les N minutes."""
index = []
prochain_jalon = 0
for seg in segments:
if seg.start >= prochain_jalon * 60:
minutes = int(seg.start // 60)
secondes = int(seg.start % 60)
apercu = seg.text[:80] + "..." if len(seg.text) > 80 else seg.text
index.append(f"[{minutes:02d}:{secondes:02d}] {apercu}")
prochain_jalon = minutes + intervalle_minutes
return index
# Utilisation
for entree in creer_index_temporel(response.segments, intervalle_minutes=5):
print(entree)
Contrainte importante
Le paramètre timestamp_granularities est incompatible avec le paramètre language. Si vous avez besoin de forcer la langue ET d’obtenir des timestamps, vous devrez faire deux appels séparés ou laisser la détection automatique de langue (qui fonctionne très bien pour le français).
Points clés à retenir
- Deux granularités :
"segment"(phrases/blocs) et"word"(mot par mot) - Les deux peuvent être combinées dans un même appel
- Les timestamps sont en secondes (float) avec une précision au centième
- Idéal pour le sous-titrage SRT/VTT, la navigation temporelle, l’indexation
- Incompatible avec le paramètre
language— utilisez la détection automatique