Cas d'Usage de la Transcription Temps Réel
Mis à jour le 29 juillet 2026
Quatre applications concrètes du streaming
Vous disposez maintenant de toutes les briques : le flux, le microphone, le réglage de latence. Cette leçon les assemble en quatre applications complètes — sous-titrage en direct, assistant vocal, dictée et transcription de conférence — que vous pouvez reprendre telles quelles comme point de départ. Chacune illustre un problème que le mode offline ne sait pas résoudre, et chacune adopte une latence différente, ce qui vous donnera une intuition concrète du réglage vu précédemment.
Sous-titrage en direct
Le sous-titrage est le cas le plus visible du temps réel, et aussi le plus exigeant côté présentation. Transcrire ne suffit pas : il faut découper le texte en lignes courtes, n’en afficher que deux à la fois et faire défiler l’ensemble, sans jamais couper un mot en deux. C’est exactement ce que fait la classe suivante. Quand la ligne courante atteint la longueur maximale, elle cherche le dernier espace avant cette limite et coupe là ; si aucun espace n’est trouvé — un mot très long, une URL dictée — elle tranche à la longueur maximale plutôt que de laisser la ligne déborder. Le réglage à 800 millisecondes reflète la priorité de ce cas d’usage : un texte lisible vaut mieux qu’un texte instantané mais bancal, et le public ne perçoit pas ce léger décalage.
import asyncio
import os
from mistralai import Mistral
from mistralai.models import (
AudioFormat,
TranscriptionStreamTextDelta,
TranscriptionStreamDone
)
class SousTitrageDirect:
"""Système de sous-titrage en direct avec gestion des lignes."""
def __init__(self, max_chars_par_ligne=50, max_lignes=2):
self.max_chars = max_chars_par_ligne
self.max_lignes = max_lignes
self.ligne_courante = ""
self.lignes = []
async def lancer(self, source_audio):
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
audio_format = AudioFormat(encoding="pcm_s16le", sample_rate=16000)
async for event in client.audio.realtime.transcribe_stream(
audio_stream=source_audio,
model="voxtral-mini-transcribe-realtime-2602",
audio_format=audio_format,
target_streaming_delay_ms=800,
):
if isinstance(event, TranscriptionStreamTextDelta):
self._ajouter_texte(event.text)
elif isinstance(event, TranscriptionStreamDone):
self._afficher_final()
def _ajouter_texte(self, texte):
self.ligne_courante += texte
if len(self.ligne_courante) >= self.max_chars:
pos = self.ligne_courante.rfind(" ", 0, self.max_chars)
if pos > 0:
self.lignes.append(self.ligne_courante[:pos])
self.ligne_courante = self.ligne_courante[pos + 1:]
else:
self.lignes.append(self.ligne_courante[:self.max_chars])
self.ligne_courante = self.ligne_courante[self.max_chars:]
if len(self.lignes) > self.max_lignes:
self.lignes = self.lignes[-self.max_lignes:]
self._afficher()
def _afficher(self):
for ligne in self.lignes:
print(f" {ligne}")
print(f" {self.ligne_courante}", end="", flush=True)
def _afficher_final(self):
print("\n\n[Sous-titrage terminé]")
Assistant vocal interactif
Un assistant vocal n’a pas le droit au silence. Il doit comprendre l’utilisateur pendant qu’il parle, sous peine de laisser après chaque question un blanc qui trahit immédiatement la machine. La transcription temps réel constitue le premier maillon d’une chaîne en trois temps : Speech-to-Text, puis LLM, puis Text-to-Speech. Ici, la latence descend à 300 millisecondes, la valeur la plus agressive de toute la leçon, et le texte s’affiche en écrasant la ligne courante grâce au retour chariot, ce qui donne l’impression d’une phrase qui se complète sous les yeux.
La seconde moitié de la fonction bascule sur le LLM. La réponse est elle-même demandée en streaming, si bien que les premiers mots arrivent avant que le modèle n’ait terminé sa phrase : la réactivité obtenue à la transcription n’est pas gaspillée à l’étape suivante. Le prompt système impose la concision, un détail décisif à l’oral où une réponse de dix lignes devient inécoutable.
async def assistant_vocal(source_audio):
"""Transcrit puis répond via un LLM."""
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
audio_format = AudioFormat(encoding="pcm_s16le", sample_rate=16000)
# Étape 1 : Transcrire la question
question_parts = []
async for event in client.audio.realtime.transcribe_stream(
audio_stream=source_audio,
model="voxtral-mini-transcribe-realtime-2602",
audio_format=audio_format,
target_streaming_delay_ms=300,
):
if isinstance(event, TranscriptionStreamTextDelta):
question_parts.append(event.text)
texte_en_cours = "".join(question_parts)
print(f"\rVous : {texte_en_cours}", end="", flush=True)
elif isinstance(event, TranscriptionStreamDone):
break
question = "".join(question_parts).strip()
print()
if not question:
print("Aucune question détectée.")
return
# Étape 2 : Envoyer au LLM pour obtenir une réponse
print("Assistant : ", end="", flush=True)
reponse_stream = client.chat.stream(
model="mistral-large-latest",
messages=[
{
"role": "system",
"content": "Vous êtes un assistant vocal concis. "
"Répondez en 2-3 phrases maximum."
},
{"role": "user", "content": question}
]
)
for chunk in reponse_stream:
texte = chunk.data.choices[0].delta.content
if texte:
print(texte, end="", flush=True)
print("\n")
Dictée vocale avec sauvegarde
La dictée pose un problème que les deux cas précédents ignorent : la durée. Une session peut s’étendre sur une heure, et perdre le texte à cause d’un plantage ou d’une coupure serait inacceptable. D’où la sauvegarde automatique, déclenchée environ tous les cent mots, qui réécrit le fichier de sortie au fil de l’eau. Le compteur nb_mots sert aussi de retour d’usage : il vous dit combien vous avez produit, information attendue par quiconque dicte un compte rendu. La latence de 600 millisecondes place le curseur du côté de la précision, puisque celui qui dicte relit son texte et préfère un mot juste à un mot instantané.
class DicteeVocale:
"""Dictée vocale avec sauvegarde automatique."""
def __init__(self, fichier_sortie="dictee.txt"):
self.fichier_sortie = fichier_sortie
self.texte = []
self.nb_mots = 0
async def lancer(self, source_audio):
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
audio_format = AudioFormat(encoding="pcm_s16le", sample_rate=16000)
print("Dictée en cours... (Ctrl+C pour arrêter)\n")
async for event in client.audio.realtime.transcribe_stream(
audio_stream=source_audio,
model="voxtral-mini-transcribe-realtime-2602",
audio_format=audio_format,
target_streaming_delay_ms=600,
):
if isinstance(event, TranscriptionStreamTextDelta):
self.texte.append(event.text)
self.nb_mots += len(event.text.split())
print(event.text, end="", flush=True)
# Sauvegarde automatique tous les 100 mots
if self.nb_mots % 100 < 5:
self._sauvegarder()
elif isinstance(event, TranscriptionStreamDone):
break
self._sauvegarder()
print(f"\n\nDictée terminée : {self.nb_mots} mots")
print(f"Fichier : {self.fichier_sortie}")
def _sauvegarder(self):
contenu = "".join(self.texte)
with open(self.fichier_sortie, "w", encoding="utf-8") as f:
f.write(contenu)
Transcription de conférence avec métadonnées
Sur une conférence longue, le texte brut ne vaut pas grand-chose s’il n’est pas identifiable. Six mois plus tard, personne ne saura de quelle session ni de quel intervenant provient un fichier nommé transcription.txt. La fonction suivante emballe donc la transcription dans une structure documentée — nom de la conférence, orateur, horodatage de début et de fin, nombre de mots — puis l’exporte en JSON sous un nom horodaté, immédiatement exploitable par un moteur de recherche interne ou un pipeline d’archivage. La latence de 1 500 millisecondes est ici parfaitement confortable : le public écoute l’orateur, l’affichage n’est qu’un complément, et la précision prime.
import json
from datetime import datetime
async def transcrire_conference(
source_audio,
nom_conference: str,
orateur: str = "Inconnu"
):
"""Transcrit une session de conférence avec métadonnées."""
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
audio_format = AudioFormat(encoding="pcm_s16le", sample_rate=16000)
session = {
"conference": nom_conference,
"orateur": orateur,
"debut": datetime.now().isoformat(),
"texte": [],
}
print(f"Transcription : {nom_conference}")
print(f"Orateur : {orateur}")
print("-" * 50)
async for event in client.audio.realtime.transcribe_stream(
audio_stream=source_audio,
model="voxtral-mini-transcribe-realtime-2602",
audio_format=audio_format,
target_streaming_delay_ms=1500,
):
if isinstance(event, TranscriptionStreamTextDelta):
session["texte"].append(event.text)
print(event.text, end="", flush=True)
elif isinstance(event, TranscriptionStreamDone):
break
session["fin"] = datetime.now().isoformat()
session["texte"] = "".join(session["texte"])
session["nb_mots"] = len(session["texte"].split())
nom_fichier = f"session_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(nom_fichier, "w", encoding="utf-8") as f:
json.dump(session, f, ensure_ascii=False, indent=2)
print(f"\n\nSession sauvegardée : {nom_fichier}")
return session
Relisez les quatre latences dans l’ordre — 300, 600, 800 puis 1 500 millisecondes — et notez qu’elles suivent une logique unique : plus l’utilisateur attend une réaction de la machine, plus le délai doit être court ; plus il attend un document exploitable, plus il peut s’allonger. Reprenez l’une de ces applications et branchez-la sur le générateur microphone de la leçon précédente : vous obtiendrez en quelques minutes un outil réellement utilisable.
Points clés à retenir
- Le sous-titrage en direct utilise une latence de 800 ms et gère l’affichage ligne par ligne
- L’assistant vocal chaîne transcription temps réel et LLM pour répondre aux questions
- La dictée vocale sauvegarde automatiquement le texte au fil de l’eau
- La transcription de conférence ajoute des métadonnées et exporte en JSON
- Chaque cas d’usage a sa latence optimale : 300 ms (assistant) à 1500 ms (conférence)