Transcription en temps réel
Envoyez du PCM en continu via le WebSocket Muse Voice Transcribe et recevez les événements de transcription en temps réel.
Muse Voice Transcribe reçoit de l’audio PCM brut via un WebSocket persistant et renvoie en continu des événements de progression, de tours de parole et de transcription. Cette interface produit uniquement du texte, pas de réponse vocale.
wss://api.agtcloud.cn/v1/asr/realtimeAuthentification et connexion
Après l’établissement du WebSocket, envoyez la première trame texte JSON dans les 10 secondes. La clé API Bearer se trouve dans authorization.accessToken, et non dans un Header de la négociation WebSocket.
| Élément | Valeur |
|---|---|
| URL de connexion | wss://api.agtcloud.cn/v1/asr/realtime |
| Emplacement de l’authentification | authorization.accessToken dans la première trame texte JSON |
| Modèle | muse-voice-transcribe-1.0 |
| Paramètre de requête facultatif | sessionId, transmis uniquement comme identifiant de session ; il n’implique pas la prise en charge de la reprise après déconnexion ou de la consultation de sessions historiques |
La première trame ne contient pas de type et ne doit pas dépasser 64 KiB. Attendez une réponse de réussite contenant sessionId avant d’envoyer l’audio ; la réussite de la mise à niveau WebSocket ne signifie pas que l’authentification de la première trame a réussi.
Déroulement de la session
- Établissez la connexion WebSocket.
- Envoyez la première trame contenant l’authentification, le modèle et la configuration audio.
- Attendez que le serveur renvoie
sessionId. - Envoyez les trames binaires PCM brutes à la vitesse du temps réel tout en continuant à recevoir les événements.
- À la fin de l’audio, envoyez
{"type":"endStream"}. - Continuez à recevoir la transcription finale et les messages de fermeture.
speechComplete indique uniquement la fin d’un tour de parole, pas celle de toute la session. Après l’envoi de endStream, continuez à lire les événements du serveur jusqu’à la fermeture de la connexion.
Paramètres de la première trame
| Champ | Type | Description |
|---|---|---|
authorization.accessToken | string | Obligatoire, au format Bearer your-api-key |
model | string | Obligatoire, utilisez muse-voice-transcribe-1.0 |
audioEncoding | string | Obligatoire, utilisez PCM_16KHZ ou PCM_24KHZ pour l’audio en temps réel |
mode | string | Facultatif : PUSH_TO_TALK, ENDPOINTING, DIARIZATION |
partialMode | string | Facultatif : CUMULATIVE renvoie le texte cumulé ; DELTA renvoie le nouveau texte |
keywords | string[] | Facultatif, indique des termes ou des noms propres |
languageBias | string[] | Facultatif, indique la langue attendue |
emitAudioProgress | boolean | Facultatif, indique s’il faut renvoyer les événements de progression du traitement audio |
zdrOverride | boolean | Option de traitement des données facultative ; son effet dépend du service actuel et des autorisations du compte |
Entrée audio
L’audio doit être du PCM16 little-endian mono sans en-tête de fichier WAV, avec la même fréquence d’échantillonnage de 16 kHz ou 24 kHz que celle déclarée dans la première trame. Chaque trame audio ne doit pas dépasser 1 MiB, et son nombre d’octets doit être pair.
Il est recommandé d’envoyer des blocs audio de 100 ms à la vitesse du temps réel : 4800 octets à 24 kHz, ou 3200 octets à 16 kHz. Pour maintenir une chronologie continue pendant les silences, envoyez aussi des données PCM silencieuses au même format.
# Générer de l’audio PCM16 brut mono à 24 kHz
ffmpeg -i input.mp3 -ac 1 -ar 24000 -c:a pcm_s16le -f s16le audio.pcmExemple Python
Installez le client WebSocket et préparez audio.pcm avant d’exécuter l’exemple. L’envoi et la réception utilisent des threads distincts pour éviter que le téléversement audio ne bloque le traitement des événements du serveur.
python -m pip install websocket-clientimport json
import sys
import threading
import websocket
url = "wss://api.agtcloud.cn/v1/asr/realtime"
stop = threading.Event()
sender = None
ws = websocket.create_connection(url, timeout=40, enable_multithread=True)
def send_audio():
try:
with open(sys.argv[1], "rb") as audio:
while not stop.is_set():
chunk = audio.read(4800)
if not chunk:
break
if len(chunk) % 2:
raise ValueError("Le nombre d’octets PCM doit être pair")
ws.send_binary(chunk)
if stop.wait(len(chunk) / 48000):
return
if not stop.is_set():
silence = bytes(4800)
for _ in range(10):
ws.send_binary(silence)
if stop.wait(0.1):
return
ws.send(json.dumps({"type": "endStream"}))
except Exception as exc:
print("Envoi interrompu :", exc)
stop.set()
ws.close()
try:
ws.send(json.dumps({
"authorization": {"accessToken": "Bearer your-api-key"},
"model": "muse-voice-transcribe-1.0",
"audioEncoding": "PCM_24KHZ",
"mode": "ENDPOINTING",
"partialMode": "CUMULATIVE",
"languageBias": ["Mandarin Chinese"],
"emitAudioProgress": True
}))
ack = json.loads(ws.recv())
if ack.get("type") == "error" or not ack.get("sessionId"):
raise RuntimeError("Échec de l’initialisation de la connexion : " + json.dumps(ack, ensure_ascii=False))
print("sessionId:", ack["sessionId"])
sender = threading.Thread(target=send_audio, daemon=True)
sender.start()
while not stop.is_set():
message = ws.recv()
if not message:
break
event = json.loads(message)
print(json.dumps(event, ensure_ascii=False))
if event.get("type") == "error":
break
finally:
stop.set()
ws.close()
if sender is not None:
sender.join(timeout=2)Référence des événements
audioProcessedMs représente la progression cumulée du traitement ; n’additionnez pas les valeurs de plusieurs événements. Avec CUMULATIVE, le nouveau texte partiel remplace le résultat cumulé précédent ; avec DELTA, ajoutez le texte de manière incrémentale.
audioProgress
Renvoie la progression cumulée actuelle du traitement audio.
| Champ | Type | Obligatoire | Description | Exemple |
|---|---|---|---|---|
type | string | Oui | Toujours `audioProgress`. | audioProgress |
audioProcessedMs | integer | Oui | Durée cumulée de l’audio traité, en millisecondes. | 1600 |
{
"type": "audioProgress",
"audioProcessedMs": 1600
}speechComplete.transcript contient la transcription complète du tour de parole actuel. Lors de la clôture de la session, un événement transcript avec final: true peut ne pas contenir de texte ; le client ne doit pas remplacer le texte cumulé déjà enregistré ou speechComplete.transcript par une chaîne vide.
Limites de session et gestion des erreurs
Une session dure environ 60 minutes au maximum. Une absence de messages du client pendant 15 secondes peut déclencher la clôture de l’entrée ; le réseau ou l’état du serveur peuvent aussi fermer la connexion plus tôt. Le client doit prévoir une durée totale maximale, un délai de lecture et un nombre limité de tentatives.
| Code de fermeture | Signification | Traitement recommandé |
|---|---|---|
1008 | Erreur de politique ou de protocole | Vérifiez la structure de la première trame, l’authentification, les paramètres et les messages de contrôle suivants |
1011 | Interruption du serveur ou du service en amont | Enregistrez sessionId, l’événement d’erreur et le motif de fermeture avant de décider de réessayer |
1013 | Service temporairement indisponible ou limitation de débit | Effectuez un nombre limité de tentatives avec une stratégie de backoff |
Facturation
La transcription en temps réel est facturée selon la durée de l’audio traité. Consultez les tarifs actuels dans le catalogue des modèles du site. Les valeurs en millisecondes des événements de progression représentent la chronologie du traitement ; ne les additionnez pas comme des éléments de facturation indépendants.