Ton assistant, ton agent ou ton bot de support a appris à réfléchir, à écrire et même à raisonner. Mais tant qu'il ne peut pas parler, il reste confiné à l'écrit, et l'expérience en pâtit. La synthèse vocale (TTS, pour text-to-speech) est le chaînon qui transforme un modèle de langage silencieux en produit vivant : assistant vocal, audiobook, répondeur téléphonique, tutoriel narré, lecteur d'articles pour les longs trajets. Le problème, c'est que les grandes API de TTS coûtent de l'argent, imposent une clé d'accès et envoient tes données dans un cloud que tu ne contrôles pas.
Il existe pourtant une voie souvent méconnue : edge-tts, une bibliothèque Python qui exploite gratuitement le moteur de synthèse neurale de Microsoft Edge. Pas de compte à créer, pas de clé API, pas de facture en fin de mois. Tu récupères les mêmes voix haute qualité que celles de Windows et de la lecture immersive du navigateur Edge, directement depuis ton script, dans la langue de ton choix.
Dans ce tutoriel, tu vas faire parler une machine en français, explorer le catalogue des voix, régler le débit et la hauteur, générer un fichier MP3, et brancher le tout sur un chatbot. À la fin, tu auras une fonction réutilisable de synthèse vocale, prête à l'emploi dans n'importe quel projet Python, du simple script au service web.
Prérequis
edge-tts est très peu exigeant. Il te faut Python 3.8 ou plus récent, et une connexion internet, car le texte est envoyé au service en ligne de Microsoft pour être synthétisé, puis renvoyé sous forme de flux audio. La bibliothèque est asynchrone sous le capot, mais rien ne t'oblige à maîtriser asyncio en profondeur : quelques lignes suffisent. Un éditeur et un terminal font l'affaire. Installe le paquet :
pip install edge-ttsVérifie que tout est en place en affichant la version installée. Au moment où ces lignes sont écrites, on tourne autour de la série 7.x, mais l'API présentée ici est stable depuis plusieurs versions majeures.
edge-tts --versionComment ça marche sous le capot
Comprendre le mécanisme t'évitera bien des surprises. edge-tts n'embarque aucun modèle de synthèse : il reproduit le protocole qu'utilise la page de lecture immersive d'Edge pour communiquer avec les serveurs de synthèse de Microsoft. Concrètement, ta bibliothèque ouvre une connexion WebSocket chiffrée vers le service, envoie le texte avec les paramètres de voix, puis reçoit un flux de fragments : des morceaux d'audio MP3, et des métadonnées qui marquent les frontières de mots et de phrases.
Deux conséquences pratiques en découlent. D'abord, tu dépends de la disponibilité d'un service tiers : sans réseau, pas de voix. Ensuite, ton texte transite par les serveurs de Microsoft, ce qui impose de ne jamais y envoyer de données sensibles. Pour un usage interne ou un prototype, c'est un excellent compromis entre qualité, coût et simplicité.
Ta première phrase parlée
Le cœur de la bibliothèque, c'est la classe Communicate. Tu lui donnes un texte et un nom de voix, elle dialogue avec le service Microsoft et te restitue le flux audio. La méthode save écrit directement le résultat dans un fichier. Trois lignes de code suffisent pour faire prononcer une phrase à ta machine :
import asyncio
import edge_tts
async def parler():
voix = "fr-FR-HenriNeural"
texte = "Bonjour, je suis une machine qui parle français."
communicate = edge_tts.Communicate(texte, voix)
await communicate.save("bonjour.mp3")
# Point d'entree asynchrone
asyncio.run(parler())Lance ce script, puis ouvre bonjour.mp3 dans ton lecteur audio : tu entends une voix masculine française, naturelle et expressive. Le passage par asyncio.run est obligatoire car edge-tts est construit sur des coroutines. Note que le texte peut contenir des accents, des apostrophes et de la ponctuation : ils sont pris en compte dans la prosodie, c'est ce qui rend le rendu si naturel.
Choisir la bonne voix
Il existe des centaines de voix, réparties par langue et par région. Pour une synthèse crédible en français, tu ne veux pas la première venue : une voix canadienne ou suisse a des intonations différentes d'une voix de France métropolitaine, et une voix mal choisie peut trahir un contenu destiné à un public précis. La fonction list_voices récupère le catalogue complet :
import asyncio
import edge_tts
async def lister_voix():
voix = await edge_tts.list_voices()
for v in voix:
if v["Locale"].startswith("fr"):
print(v["ShortName"], "-", v["Gender"], "-", v["Locale"])
asyncio.run(lister_voix())Le résultat filtre les locales qui commencent par fr : fr-FR (France), fr-CA (Canada), fr-BE (Belgique) et fr-CH (Suisse). Chaque entrée expose un ShortName à passer à Communicate, ainsi qu'un genre et quelques métadonnées. Voici une sélection représentative des voix françaises les plus utiles :
- fr-FR-DeniseNeural — femme, France, ton chaleureux et posé
- fr-FR-HenriNeural — homme, France, voix grave et claire
- fr-FR-VivienneMultilingualNeural — femme, France, bascule d'une langue à l'autre en cours de phrase
- fr-FR-RemyMultilingualNeural — homme, France, multilingue
- fr-FR-EloiseNeural — voix enfantine, France
- fr-CA-AntoineNeural et fr-CA-SylvieNeural — homme et femme, Canada
- fr-BE-CharlineNeural — femme, Belgique
- fr-CH-ArianeNeural — femme, Suisse
Le meilleur moyen de trancher, c'est d'écouter : génère la même phrase avec trois ou quatre voix candidates, puis compare. Ce test d'une minute t'évitera de découvrir en production qu'une voix paraît robotique ou trop enjouée pour ton usage. Les voix marquées Multilingual, on y revient juste après, sont souvent le choix le plus sûr pour du contenu technique.
Pourquoi edge-tts plutôt qu'une autre option
Le paysage de la synthèse vocale en Python est vaste, et chaque outil a sa place. Mettre edge-tts en perspective t'aidera à défendre ce choix (ou à en sortir quand il le faut) :
- gTTS s'appuie sur Google Translate : gratuit et très simple, mais les voix sont datées et clairement robotiques. À réserver aux prototypes jetables.
- pyttsx3 fonctionne entièrement hors ligne en pilotant le moteur du système d'exploitation : idéal pour un Raspberry Pi sans réseau, mais la qualité française est très en retrait.
- Les API payantes (OpenAI TTS, ElevenLabs, Google Cloud TTS) offrent un rendu professionnel et un contrôle fin, avec un coût par caractère et une clé à gérer.
- edge-tts occupe le point d'équilibre : voix neuronales de qualité quasi professionnelle, gratuit, sans clé, accessible en deux lignes de code.
En résumé, pour un assistant vocal, un audiobook ou un service web qui a besoin d'une voix française agréable sans budget, edge-tts est difficile à battre. Si tu dois garantir une disponibilité stricte ou traiter des données sensibles, oriente-toi vers une synthèse locale ou une API payante.
Régler le débit, le volume et la hauteur
Une voix neutre, c'est bien ; une voix qui s'adapte au contexte, c'est mieux. Le constructeur de Communicate accepte trois paramètres optionnels : rate (le débit, en pourcentage), volume (en pourcentage) et pitch (la hauteur, en hertz). Ils se passent sous forme de chaînes de caractères :
import asyncio
import edge_tts
async def parler_ajuste():
texte = "Alerte : votre vol est retardé de deux heures."
# debit : de -50% a +100% ; hauteur : environ +/- 50 Hz
c = edge_tts.Communicate(
texte,
"fr-FR-DeniseNeural",
rate="-10%", # legerement plus lent
volume="+20%", # un peu plus fort
pitch="+5Hz", # legerement plus aigu
)
await c.save("alerte.mp3")
asyncio.run(parler_ajuste())Le débit est sans doute le réglage le plus utile : un texte lu trop vite devient illisible, trop lent il endort. Pour un audiobook, vise -10% à -20% ; pour une alerte d'urgence, reste à 0% ou accélère légèrement. La hauteur, elle, te permet de nuancer une même voix sans avoir à en changer, par exemple pour distinguer deux personnages dans un dialogue.
Changer de langue au milieu d'une phrase
Les termes techniques pullulent en anglais dans nos textes : API, machine learning, backend, token. Une voix française classique les prononcera à la française, ce qui sonne faux. Les voix Multilingual, elles, basculent de prononciation automatiquement. Compare les deux approches :
import asyncio
import edge_tts
async def demo_multilingue():
texte = ("Nous utilisons une API de machine learning, "
"avec un backend en Python et des tokens.")
# Voix francaise classique : l'anglais sera mal prononce
await edge_tts.Communicate(texte, "fr-FR-DeniseNeural").save("fr_pur.mp3")
# Voix multilingue : bascule automatique de prononciation
await edge_tts.Communicate(texte, "fr-FR-RemyMultilingualNeural").save("fr_multi.mp3")
asyncio.run(demo_multilingue())Écoute les deux fichiers : la différence est flagrante. Pour tout contenu technique ou marketing qui mêle les langues, une voix Multilingual est presque toujours le meilleur choix, et c'est la raison pour laquelle on la recommande comme valeur par défaut dans les exemples qui suivent.
Synthèse en streaming et gros textes
La méthode save est pratique, mais elle garde tout en mémoire avant d'écrire. Pour un très long texte, ou si tu veux traiter l'audio au fil de l'eau (diffusion en direct, traitement par morceaux), utilise stream, qui te renvoie des fragments audio un par un :
import asyncio
import edge_tts
async def streamer():
texte = "Ceci est une demonstration de synthese en streaming."
c = edge_tts.Communicate(texte, "fr-FR-DeniseNeural")
with open("stream.mp3", "wb") as f:
async for chunk in c.stream():
if chunk["type"] == "audio":
f.write(chunk["data"])
asyncio.run(streamer())Chaque chunk porte un champ type : audio pour les données sonores, WordBoundary pour les frontières de mots, et SentenceBoundary pour celles de phrases. Ce découpage te permet par exemple d'afficher le mot en cours de prononciation dans une interface, ou de commencer la lecture avant la fin de la génération.
Générer des sous-titres synchronisés
Si tu produis une vidéo ou un audiobook, des sous-titres alignés sur l'audio valent de l'or. La classe SubMaker capte les frontières de mots et génère un fichier SRT standard, lisible par tous les lecteurs et logiciels de montage :
import asyncio
import edge_tts
from edge_tts import SubMaker
async def sous_titres():
texte = "Les sous-titres apparaissent au bon moment."
c = edge_tts.Communicate(texte, "fr-FR-DeniseNeural")
maker = SubMaker()
with open("voix.mp3", "wb") as f:
async for chunk in c.stream():
if chunk["type"] == "audio":
f.write(chunk["data"])
elif chunk["type"] == "WordBoundary":
maker.create_sub(
(chunk["offset"], chunk["duration"]),
chunk["text"],
)
with open("voix.srt", "w", encoding="utf-8") as srt:
srt.write(maker.generate_subs())
asyncio.run(sous_titres())Le fichier voix.srt contient des lignes horodatées que tu peux importer dans n'importe quel logiciel de montage ou lecteur vidéo. C'est la brique de base d'un pipeline de doublage automatique : tu génères l'audio, tu récupères les sous-titres, et tu as une narration prête à être montée.
La ligne de commande, pour les scripts shell
edge-tts s'installe aussi en outil de ligne de commande, idéal pour les tests rapides ou l'intégration dans des scripts shell sans écrire de Python. La syntaxe est immédiate :
edge-tts --voice fr-FR-DeniseNeural --text "Bonjour le monde" --write-media bonjour.mp3Pour explorer le catalogue directement depuis le terminal, combine avec grep. Tu peux même enchaîner plusieurs générations dans une boucle shell pour narrer une liste d'articles :
edge-tts --list-voices | grep fr-FRBrancher la synthèse sur ton chatbot
Assemblage final : une fonction propre qui prend la réponse d'un modèle et la transforme en fichier audio, prête à être jouée ou envoyée. Voici un exemple minimaliste mais complet :
import asyncio
import edge_tts
# Voix par defaut : feminine, France, multilingue pour les termes anglais
VOIX_DEFAUT = "fr-FR-VivienneMultilingualNeural"
async def synthetiser(texte, voix=VOIX_DEFAUT, fichier="reponse.mp3"):
"""Transforme un texte en fichier audio. Renvoie le chemin du fichier."""
c = edge_tts.Communicate(texte, voix, rate="+0%", volume="+0%", pitch="+0Hz")
await c.save(fichier)
return fichier
async def main():
reponse_llm = "Bien sûr ! Voici comment configurer ton assistant vocal."
chemin = await synthetiser(reponse_llm)
print("Audio genere :", chemin)
asyncio.run(main())Pour aller plus loin, tu peux découper les réponses longues en phrases, générer un MP3 par phrase et les enchaîner à la lecture, ou encore poster le flux audio directement vers un client via WebSocket. La brique de synthèse, elle, ne change plus.
Gérer les erreurs et la robustesse
Comme tout service en ligne, la synthèse peut échouer : coupure réseau, limite atteinte, voix retirée du catalogue. Un script de production doit encaisser ces incidents sans tomber. Voici un exemple avec nouvelle tentative et voix de repli :
import asyncio
import edge_tts
async def synthetiser_robuste(texte, voix, fichier, essais=3):
dernier = None
for tentative in range(1, essais + 1):
try:
c = edge_tts.Communicate(texte, voix)
await c.save(fichier)
return fichier
except Exception as e:
dernier = e
print(f"Tentative {tentative} echouee : {e}")
await asyncio.sleep(2 * tentative) # attente progressive
# Repli sur une voix sure si la voix demandee pose probleme
c = edge_tts.Communicate(texte, "fr-FR-DeniseNeural")
await c.save(fichier)
print(f"Repli apres echec ({dernier})")
return fichier
asyncio.run(synthetiser_robuste("Test de robustesse.", "fr-FR-HenriNeural", "robuste.mp3"))L'idée est simple : réessayer avec un délai croissant, puis basculer sur une voix de secours. Tu peux aussi ajouter un timeout global pour ne jamais bloquer une requête web indéfiniment. Ces quelques lignes transforment un script fragile en brique fiable.
Bonnes pratiques et limites à connaître
edge-tts est gratuit parce qu'il repose sur un service public de Microsoft, et cette gratuité vient avec des règles implicites de bon sens. Garde en tête les points suivants avant de l'intégrer en production :
- C'est un service en ligne : ton texte transite par les serveurs de Microsoft. N'envoie jamais de données sensibles, de secrets ou de données personnelles.
- Respecte un usage raisonnable : pas de rafale de milliers de requêtes, ajoute un délai entre les appels, et mets en cache les résultats identiques.
- L'API peut évoluer sans préavis : le nom des voix, les limites de taille ou le format de réponse peuvent changer. Enveloppe tes appels dans un try/except et prévois une voix de repli.
- Il n'y a pas de garantie de disponibilité : pour un produit critique, prévois un fournisseur de secours (une API payante, ou une synthèse locale avec un modèle open source).
- La longueur du texte est bornée : pour un très long document, découpe en segments et concatène les fichiers audio.
Pour un projet sérieux, encapsule toute la logique dans une fonction unique (comme synthetiser ci-dessus), ajoute de la journalisation, et garde la voix et le débit configurables. Tu pourras ainsi migrer vers un autre moteur sans toucher au reste du code.
Conclusion
Tu sais désormais donner une voix française à n'importe quel texte en quelques lignes de Python, sans clé ni abonnement. On a couvert la synthèse de base, le choix des voix, les réglages de débit et de hauteur, les voix multilingues, le streaming, les sous-titres, la ligne de commande, la gestion des erreurs et l'intégration dans un chatbot.
Les pistes d'approfondissement ne manquent pas : combine edge-tts avec un modèle de reconnaissance vocale comme Whisper pour construire un assistant vocal conversationnel complet, génère des audiobooks à partir de tes articles, ou ajoute une voix narrative à tes tutoriels vidéo. La brique de synthèse est gratuite et fonctionnelle : à toi de lui trouver une voix.
Pour aller plus loin
Le dépôt officiel du projet : github.com/rany2/edge-tts, avec la documentation complète de l'API.
Le catalogue des voix est documenté sur la page des langues de Microsoft Speech.






