Quand une transcription audio échoue, beaucoup pensent d'abord à changer de modèle ou doutent de la reconnaissance. Pourtant, la plupart des pannes se situent à quatre niveaux : fichier, authentification, réseau et limitation de débit. L'interface de transcription reçoit un upload multipart/form-data ; sa chaîne est plus longue que celle d'une interface texte, et l'ordre de diagnostic doit l'être aussi : d'abord le code HTTP et le type d'erreur, ensuite la requête elle-même, enfin seulement l'audio et le prompt.
Cet article détaille les cas 401, 400 format non pris en charge, 413 fichier trop volumineux, 429 limitation, timeouts, puis texte vide ou illisible. Il fournit un chemin de diagnostic et un code de traitement réutilisable. Les limites de fichier, noms de modèles et formats d'erreur peuvent changer selon les versions ; la documentation officielle et celle du site font foi, et les prix figurent sur la page Tarifs des modèles.
Remarque : OpenAI et Whisper sont des marques de leurs détenteurs respectifs ; cet article est purement technique. Les limites d'interface, formats pris en charge et noms de modèles peuvent évoluer ; la documentation officielle et celle du site font foi.
1. Établir d'abord l'ordre de diagnostic
| Symptôme | Codes fréquents | Cause probable | Piste de traitement |
|---|---|---|---|
| Échec d'authentification | 401, 403 | Clé erronée, Bearer absent, droits audio absents | Corriger les identifiants, ne pas réessayer |
| Format non pris en charge | 400 | Encodage hors liste, extension différente du codage réel | Transcoder puis renvoyer |
| Fichier trop volumineux | 413 ou 400 | Dépassement de la taille maximale par fichier | Compresser ou découper |
| Requêtes trop fréquentes | 429 | Requêtes/minute, concurrence ou quota dépassés | Backoff, file d'attente, séparer les clés |
| Erreur serveur | 500, 502, 503 | Anomalie ou surcharge amont | Backoff puis reprises limitées |
| Timeout | Aucune réponse ou connexion interrompue | Fichier gros, upload lent, traitement long | Découper, ajuster les timeouts |
| Texte vide | 200 | Silence, volume faible, langue mal détectée, encodage anormal | Vérifier l'audio, pas réessayer |
Si l'en-tête de réponse ou le corps d'erreur contient un request-id, conservez-le. Pour un diagnostic auprès du fournisseur, un ID de requête et un audio minimal reproductible valent mieux que dix captures d'écran.
2. 401 : vérifier d'abord l'en-tête, puis la clé
Un 401 signifie que l'authentification a échoué ; le solde et les capacités du modèle n'y sont généralement pour rien. Procédez dans cet ordre :
- L'en-tête est-il
Authorization: Bearer <key>, sans oublierBearerni l'espace ? - La clé contient-elle des espaces, retours à la ligne ou guillemets en début ou fin ? La copie depuis une fenêtre de chat est la cause la plus fréquente.
- La variable d'environnement est-elle réellement chargée ? Affichez seulement le préfixe, jamais la clé complète dans les journaux.
- La clé est-elle révoquée, rattachée au bon projet, et le compte dispose-t-il des droits sur l'interface audio ?
- L'URL de base est-elle
https://ai.zhongshangqihang.com/v1, et le chemin/v1/audio/transcriptions? - S'il s'agit d'une passerelle, vérifiez que cette entrée ouvre bien la transcription audio : ne supposez pas que l'interface texte disponible implique l'audio.
Autre erreur fréquente : placer le fichier dans un corps JSON. L'interface de transcription exige multipart/form-data ; en ligne de commande, utilisez curl -F "file=@meeting.mp3", pas -d. Un corps au mauvais format peut produire un 400, ou un 401 si aucun identifiant valide n'a été lu.
3. 400 et 413 : format et taille
Le 400 le plus courant concerne un format non pris en charge. La documentation officielle liste notamment mp3, mp4, mpeg, mpga, m4a, wav et webm ; la liste complète et les exigences d'encodage suivent la documentation en vigueur. Renommer une extension ne transcode pas : un .amr renommé en .mp3 reste lu dans son encodage d'origine et échoue de la même manière.
Un 413 indique généralement un dépassement de la taille maximale par fichier, souvent 25 Mo selon la documentation. Deux traitements :
- Compresser : convertir en 16 kHz mono, un usage vocal n'exige pas un haut débit. Exemple :
ffmpeg -i input.mp3 -ac 1 -ar 16000 -b:a 64k output.mp3. - Découper : segments de 10 minutes, transcription puis fusion. Coupez de préférence aux silences et gardez un léger chevauchement pour ne pas séparer un mot en deux.
Ne comptez pas uniquement sur la compression pour caser un long audio. Plus le fichier est gros, plus l'upload est lent, plus le timeout est probable et plus un renvoi coûte cher. Le découpage parallèle est plus stable, mais limitez la concurrence, sinon le 413 devient un 429.
4. 429 : limitation ne rime pas avec solde insuffisant
Un 429 signifie que la requête dépasse une limite de débit, de concurrence ou de quota. Le type d'erreur peut différer : fréquence excessive ou quota épuisé. Lisez le type avant de décider s'il faut attendre, réduire la concurrence ou recharger.
Scénarios fréquents : trop de concurrence dans un lot ; plusieurs services partagent une clé ; reprise immédiate après échec formant une tempête ; long audio occupant une connexion trop longtemps ; quota par minute faible sur un compte gratuit ou d'entrée de gamme.
Ordre de traitement : vérifier Retry-After dans la réponse, puis réessayer avec backoff exponentiel et jitter ; placer les lots dans une file et limiter les requêtes simultanées ; séparer les clés par projet pour éviter la contention ; fixer un plafond et une alerte de reprise, sans boucle infinie. La transcription se facture à la durée audio ; une soumission répétée peut aussi être facturée deux fois. Avant de réessayer, confirmez que la tentative précédente n'a pas déjà réussi.
5. Timeout : upload lent ou traitement lent ?
Le timeout peut survenir à trois étapes : établissement de connexion, upload du fichier, traitement serveur. Si même les petits fichiers expirent, vérifiez d'abord réseau, proxy et URL de base ; si les gros fichiers expirent régulièrement, privilégiez découpage et compression.
Le client doit fixer explicitement ses timeouts, sans dépendre des valeurs par défaut. La durée de transcription dépend de l'audio, de la taille du fichier et de la file ; choisissez une limite généreuse mais bornée, par exemple deux à trois minutes, et distinguez par tâche « soumis sans réponse » et « jamais envoyé ». La reprise automatique après timeout demande de la prudence : si le serveur a déjà terminé, elle produit une seconde facturation et un doublon.
6. 200 mais texte vide ou illisible
Ces deux cas n'ont pas d'erreur HTTP et leurs causes diffèrent totalement.
Texte vide : silence ou volume trop faible sur tout l'extrait ; paramètre de langue incompatible avec l'audio ; canal anormal, canal principal muet ; encodage accepté à l'upload mais décodage défaillant. Mesurez d'abord le volume, passez explicitement language=fr, puis testez après conversion en 16 kHz mono.
Texte illisible ou fautes massives : langue mal détectée, accent dialectal marqué, musique de fond mêlée à la voix, interruptions entre locuteurs, prise de son trop lointaine. Utilisez prompt pour fournir noms de personnes, produits et termes techniques, puis appliquez un glossaire après transcription. Si l'audio lui-même est inexploitable, changer de modèle ne le sauvera pas : revenez à l'enregistrement et au prétraitement.
7. Reprises et découpage : un code réutilisable
La reprise ne vaut que pour les erreurs transitoires. Pour un 401, 400 ou 413, il faut modifier la requête ; réessayer à l'aveugle aggrave le problème.
import os
import random
import time
from openai import (
OpenAI,
APIConnectionError,
APIStatusError,
APITimeoutError,
RateLimitError,
)
client = OpenAI(
api_key=os.environ["WHISPER_API_KEY"],
base_url="https://ai.zhongshangqihang.com/v1",
timeout=180,
)
def transcribe(path: str, model: str = "whisper-1", retries: int = 4) -> str:
for attempt in range(retries):
try:
with open(path, "rb") as f:
result = client.audio.transcriptions.create(
model=model,
file=f,
language="fr",
response_format="verbose_json",
)
text = (result.text or "").strip()
if not text:
raise ValueError("transcription vide : vérifier volume, langue et canal")
return text
except RateLimitError:
wait = min(2 ** attempt, 30) + random.random()
print(f"429, nouvelle tentative dans {wait:.1f}s")
time.sleep(wait)
except (APITimeoutError, APIConnectionError):
time.sleep(min(2 ** attempt, 30) + random.random())
except APIStatusError as exc:
if exc.status_code >= 500:
time.sleep(min(2 ** attempt, 30) + random.random())
else:
raise # 400/401/413 : corriger la requête, ne pas réessayer
raise RuntimeError("nombre de tentatives épuisé")
print(transcribe("meeting.mp3"))
Les noms de modèles suivent la documentation du site ; whisper-1 n'est qu'un exemple courant. Pour un audio dépassant la limite, découpez-le d'abord avec ffmpeg, appelez cette fonction sur chaque segment, puis ajoutez l'heure de début de chaque segment lors de la fusion.
8. Journalisation et liste pour le diagnostic fournisseur
- Noter l'heure, le fuseau, le code HTTP et le type d'erreur.
- Noter le
request-idet l'entrée utilisée : officielle ou passerelle. - Noter le nom du fichier, l'encodage réel, la durée, la taille, le taux d'échantillonnage et le nombre de canaux.
- Noter les paramètres clés :
model,language,response_format. - Noter le nombre de reprises, chaque durée d'attente et le résultat final.
- Préciser si la clé est partagée, la concurrence au moment des faits et la taille du lot.
- Préparer un audio minimal reproductible de 10 à 30 secondes, diffusable et expurgé des données personnelles.
Lors de l'envoi au fournisseur, ne transmettez jamais la clé complète ni un enregistrement client sans autorisation. Un échantillon minimal reproductible est bien plus utile qu'un « ça échoue parfois ».
Questions fréquentes
413 et 400 viennent tous deux du fichier : comment les distinguer ?
Le 413 indique généralement un dépassement de volume, à traiter par compression ou découpage ; le 400 relève plutôt du format, des paramètres ou de l'encodage, à traiter par transcodage et vérification des champs. Lisez le type et le message, pas seulement le code.
Que faire si le 429 ne se résorbe pas ?
Vérifiez d'abord s'il s'agit d'une limite de fréquence ou d'un quota épuisé. Pour la fréquence : réduire la concurrence, mettre en file, séparer les clés. Pour le quota : recharger ou changer d'entrée. Ne continuez pas à réessayer de plus en plus vite, cela prolonge la panne.
Faut-il réessayer immédiatement après un timeout ?
Déterminez d'abord si la requête a pu aboutir côté serveur. La transcription peut déjà être facturée ; une reprise directe produit un doublon et un second coût. Vérifiez l'état via un journal de tâches ou une conception idempotente avant de renvoyer.
Une transcription vide signifie-t-elle que le modèle est défaillant ?
Le plus souvent non. Vérifiez le volume, les silences, le paramètre de langue, les canaux et l'encodage réel. Tester le même audio sur une autre entrée distingue rapidement un problème d'audio d'un problème de service.
Comment distinguer une erreur de passerelle d'une erreur officielle ?
Conservez request-id et le type d'erreur, puis envoyez la même requête aux deux entrées. Si l'entrée officielle fonctionne et la passerelle échoue, le problème vient probablement de la configuration ou du transfert ; si les deux échouent, vérifiez clé, réseau et fichier audio.
Pour aller plus loin
Commencez par créer un compte sur la passerelle ZSQH AI Gateway, puis exercez successivement un 401, un 413, un 429 et un timeout avec un audio d'une minute avant de brancher la supervision de production. Disponibilité des modèles et tarifs font foi sur la page Tarifs des modèles.
Articles liés :
