@ai_kit/core inclut une transcription temps réel full-duplex : vous poussez des chunks audio au fil de l’eau (micro, flux live) sur une connexion WebSocket et recevez les deltas de transcription à mesure qu’ils arrivent. C’est compatible avec l’API realtime de Mistral (modèle Voxtral).
À ne pas confondre avec
createTranscriptionStreamingModel (voir Transcription audio), qui streame la sortie d’un fichier complet déjà envoyé. Ici, c’est l’entrée qui est poussée en continu — idéal pour un micro.Pourquoi un client WebSocket natif ?
Le SDK Vercel AI (ai) ne propose aucune primitive de transcription temps réel : experimental_transcribe / transcribe et l’interface TranscriptionModelV3 sont batch uniquement. @ai_kit/core fournit donc un petit client WebSocket direct — sans dépendance runtime supplémentaire (le WebSocket global de Node ≥ 22 envoie l’en-tête Authorization: Bearer via undici).
Deux primitives publiques
| Export | Rôle |
|---|---|
createRealtimeTranscription(config) | Factory générique, config-driven (compatible Mistral par défaut, réutilisable pour tout endpoint WebSocket compatible) |
mistralRealtimeTranscription(opts?) | Raccourci Mistral-first : applique le modèle, la base URL et le fallback MISTRAL_API_KEY |
Format audio
Mistral attend du PCM brutpcm_s16le, 16 000 Hz, mono. Aucune conversion n’est embarquée. Pour convertir un fichier avec ffmpeg :
Démarrage rapide — transcribeStream (haut niveau)
Idéal pour transcrire un fichier ou un flux que vous pouvez itérer. Vous passez un AsyncIterable<Uint8Array> de PCM et recevez les événements jusqu’à done.
transcribeStream ouvre la connexion, pompe l’audio en tâche de fond (puis envoie flush + end), et s’arrête automatiquement après l’événement done ou error.
Micro / source poussée — connect (bas niveau)
Quand l’audio arrive via des callbacks (micro, WebSocket entrant), ouvrez une session et poussez les chunks vous-même.
Méthodes de session
| Méthode | Rôle |
|---|---|
sendAudio(chunk) | Encode en base64 et envoie le PCM (découpe automatiquement les chunks > 262144 octets) |
flush() | Demande au provider de vider son buffer et d’émettre la transcription en attente |
end() | Signale la fin du flux audio |
close(code?, reason?) | Ferme le WebSocket et termine le flux d’événements |
events() | Itérateur async sur les événements normalisés (équivalent à for await ... of session) |
Événements normalisés
{ type: "unknown", raw } (jamais d’exception) pour la compatibilité ascendante.
Configuration
Options de connexion
| Option | Rôle |
|---|---|
audioFormat | { encoding, sampleRate } envoyé via session.update avant l’audio |
targetStreamingDelayMs | Réglage latence/précision (ex. 240 pour la réactivité, 2400 pour la précision) |
timeoutMs | Timeout du handshake (défaut 30000) |
signal | AbortSignal pour interrompre la connexion |
headers | En-têtes additionnels sur la requête d’upgrade |
Gestion des erreurs
- Échec de connexion, timeout de handshake ou abort → lève une
RealtimeTranscriptionError. - Un événement serveur
errorest remonté en{ type: "error", error };transcribeStreams’arrête après l’avoir émis (en bas niveau, c’est l’appelant qui décide).