Apprendre

Synthèse vocale JavaScript avec SpeechSynthesis

Rene, Kabir Goel 
Synthèse vocale JavaScript avec SpeechSynthesis

Pour convertir du texte en parole en JavaScript, créez un SpeechSynthesisUtterance et transmettez-le à window.speechSynthesis.speak(). Le navigateur gère la lecture. Vous n’avez besoin ni de clé API, ni de serveur, ni de paquet JavaScript.

Cela convient à un prototype ou à une commande de lecture à voix haute si les voix de l’appareil suffisent. Pour un agent qui doit conserver la même voix sur tous les appareils ou diffuser l’audio dans un appel, préférez une API de synthèse vocale hébergée. SpeechSynthesis et l’API Cartesia sont deux méthodes distinctes.

Fonctionnement de la synthèse du navigateur

window.speechSynthesis est le contrôleur de parole synthétique de la Web Speech API. Un énoncé contient le texte et les réglages d’une requête. speak() l’ajoute à une file d’attente sans renvoyer de fichier audio.1

Le navigateur expose les voix de l’appareil via getVoices(). La liste peut se charger après votre script : lisez-la immédiatement, puis actualisez-la à l’événement voiceschanged.2 Ne codez pas en dur une voix de votre ordinateur en supposant qu’elle existe sur le téléphone d’un client.

1. Enregistrer une démonstration fonctionnelle

Enregistrez le code suivant dans speech.html et ouvrez-le dans un navigateur. Saisissez une phrase courte, choisissez une voix si une liste apparaît, puis appuyez sur Speak. Utilisez du texte non sensible : certaines voix passent par des services distants.3

<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<title>JavaScript text-to-speech demo</title>
	</head>
	<body>
		<h1>Read text aloud</h1>
		<p>
			<label for="text">Text to speak</label><br />
			<textarea id="text" rows="4" cols="30" maxlength="500">
Hello from your browser.</textarea
			>
		</p>
		<p>
			<label for="voice">Voice</label>
			<select id="voice"></select>
		</p>
		<button id="speak" type="button">Speak</button>
		<button id="stop" type="button">Stop</button>
		<p id="status" role="status" aria-live="polite">Ready.</p>

		<script>
			const text = document.querySelector("#text");
			const voiceSelect = document.querySelector("#voice");
			const speakButton = document.querySelector("#speak");
			const stopButton = document.querySelector("#stop");
			const status = document.querySelector("#status");
			let voices = [];
			let currentUtterance = null;

			if (
				!("speechSynthesis" in window) ||
				!("SpeechSynthesisUtterance" in window)
			) {
				status.textContent = "This browser does not support speech synthesis.";
				speakButton.disabled = true;
				stopButton.disabled = true;
			} else {
				const synth = window.speechSynthesis;

				function loadVoices() {
					const previousVoice = voiceSelect.value;
					voices = synth.getVoices();
					voiceSelect.replaceChildren(new Option("Browser default", ""));
					for (const voice of voices) {
						voiceSelect.add(
							new Option(`${voice.name} (${voice.lang})`, voice.voiceURI),
						);
					}
					if (voices.some((voice) => voice.voiceURI === previousVoice)) {
						voiceSelect.value = previousVoice;
					}
				}

				loadVoices();
				synth.addEventListener("voiceschanged", loadVoices);

				speakButton.addEventListener("click", () => {
					const transcript = text.value.trim();
					if (!transcript) {
						status.textContent = "Enter some text first.";
						return;
					}

					// Ignore callbacks from the utterance being replaced.
					currentUtterance = null;
					synth.cancel();
					const utterance = new SpeechSynthesisUtterance(transcript);
					const voice = voices.find(
						(item) => item.voiceURI === voiceSelect.value,
					);
					if (voice) {
						utterance.voice = voice;
						utterance.lang = voice.lang;
					} else {
						utterance.lang = document.documentElement.lang;
					}
					utterance.rate = 1;
					currentUtterance = utterance;
					status.textContent = "Starting speech...";
					utterance.onstart = () => {
						if (currentUtterance === utterance)
							status.textContent = "Speaking...";
					};
					utterance.onend = () => {
						if (currentUtterance !== utterance) return;
						currentUtterance = null;
						status.textContent = "Finished.";
					};
					utterance.onerror = (event) => {
						if (currentUtterance !== utterance) return;
						currentUtterance = null;
						status.textContent = `Speech failed: ${event.error}`;
					};
					synth.speak(utterance);
				});

				stopButton.addEventListener("click", () => {
					currentUtterance = null;
					synth.cancel();
					status.textContent = "Stopped.";
				});
			}
		</script>
	</body>
</html>

La démonstration limite le texte à 500 caractères pour garder le premier test court. C’est sa propre limite, pas celle de la Web Speech API. Testez séparément les passages longs sur chaque navigateur pris en charge.

2. Vérifier le choix de voix et la lecture

Le sélecteur affiche le nom et la langue des voix disponibles. Choisissez celle qui correspond au texte : définir utterance.lang ne traduit pas les mots.

Speak s’exécute après un clic plutôt qu’au chargement. L’auditeur garde ainsi le contrôle et vous ne dépendez pas de la lecture automatique. Un nouveau clic annule la requête en cours avant d’en lancer une autre, au lieu d’accumuler les clics dans la file. Stop appelle cancel(), qui vide les énoncés en attente et arrête la parole en cours.4

La vérification de currentUtterance empêche le rappel tardif d’une requête annulée de remplacer l’état d’une requête plus récente. Si vous adaptez le code en composant, retirez l’écouteur voiceschanged au démontage. N’annulez la lecture à ce moment que si ce composant possède la file vocale de la page.

3. Résoudre les problèmes de silence ou d’incohérence

SymptômeVérifications
Le sélecteur n’affiche que Browser defaultAttendez voiceschanged. Si la liste reste vide, vérifiez le navigateur et les voix système installées. La démonstration peut encore demander une voix par défaut.
Aucun son après SpeakVérifiez volume et sortie audio, essayez une phrase courte dans la bonne langue et lisez le message d’état pour repérer une erreur.
Une voix existe sur ordinateur mais pas sur mobileLes listes dépendent de l’appareil. Gardez un choix par défaut et testez les systèmes réellement pris en charge.
Des clics répétés retardent la parolespeak() met les requêtes en attente. Annulez l’ancienne si le nouveau texte doit la remplacer.
La parole échoue sans InternetLa voix choisie peut dépendre d’un service distant. Examinez voice.localService et testez hors ligne au lieu de supposer une synthèse locale.

Pour une lecture à voix haute, gardez le texte original visible et rendez Stop accessible au clavier. Ne démarrez pas automatiquement et ne traitez pas la synthèse comme un remplacement de la compatibilité avec les lecteurs d’écran.

Quand utiliser une API TTS hébergée

Choisissez la synthèse du navigateur si les voix disponibles suffisent et si la lecture reste sur cet appareil. Choisissez une API hébergée pour obtenir des octets audio, une identité vocale gérée par le fournisseur ou une diffusion hors navigateur.

BesoinSpeechSynthesis du navigateurAPI TTS hébergée comme Cartesia
IdentifiantsPas de clé API applicativeIdentifiants API et compte autorisé
Choix des voixListe du navigateur et du systèmeBibliothèque du fournisseur ou voix personnalisée autorisée
Destination audioLecture dans le navigateurAudio reçu par l’application pour lecture, stockage ou transport
Hors ligneDépend de la voix et de l’appareilLes requêtes API Cartesia nécessitent le réseau
Traitement du texteLocal ou distant selon la voixTexte envoyé au fournisseur ; vérifiez les exigences de données avant intégration

Pour la synthèse vocale Cartesia, appelez l’API depuis votre serveur. Gardez-y la clé, hors d’un fichier HTML public ou d’un bundle client. Le navigateur peut envoyer le texte à votre serveur authentifié, qui applique les limites d’entrée et renvoie l’audio. Limitez le débit de ce point de terminaison pour empêcher une consommation illimitée de vos crédits.

Commencez par générer un WAV avec le SDK Python Cartesia. Ce guide teste la génération hébergée ; ce n’est pas un lecteur de navigateur en continu. Une application conversationnelle demande aussi mémoire tampon et gestion des interruptions. Comparez ce travail à Cartesia Managed Agents avant de construire toute la chaîne vous-même.

Références associées

Notes de bas de page

  1. MDN, SpeechSynthesis. ↩

  2. MDN, SpeechSynthesis.getVoices(). ↩

  3. MDN, SpeechSynthesisVoice.localService. ↩

  4. MDN, SpeechSynthesis.cancel(). ↩

FAQ

JavaScript peut-il convertir du texte en parole sans clé API ?

Oui. Dans les navigateurs compatibles, window.speechSynthesis lit le texte avec les voix disponibles sur l'appareil. Cet exemple ne nécessite ni compte Cartesia ni clé API. La disponibilité et le comportement des voix varient selon le navigateur et le système.

Pourquoi speechSynthesis.getVoices() renvoie-t-il un tableau vide ?

Le navigateur n'a peut-être pas encore chargé les voix. Appelez getVoices au démarrage et écoutez voiceschanged pour actualiser la liste. Si elle reste vide, vérifiez la prise en charge du navigateur et les voix installées sur le système.

SpeechSynthesis peut-il enregistrer un MP3 ou un WAV ?

SpeechSynthesis lit la parole dans le navigateur ; son API ne renvoie pas l'audio généré sous forme de fichier ou de flux d'octets. Utilisez un service vocal avec sortie audio si vous devez enregistrer ou transmettre le résultat.

La synthèse vocale du navigateur fonctionne-t-elle hors ligne ?

Cela dépend de la voix. SpeechSynthesisVoice.localService indique si elle provient d'un service local ou distant. Ne supposez pas que toutes les voix fonctionnent hors ligne ou gardent le texte sur l'appareil. Vérifiez la voix choisie sur vos appareils cibles.