Intelligence Artificielle angularforall.com

- Text-to-Speech IA : voix naturelles avec ElevenLabs

Text-To-Speech Elevenlabs Synthese-Vocale Tts Voice-Ai Ia-Generative Node-Js Javascript Streaming Accessibilite Whisper Assistant-Vocal Audio-Ia Api
Text-to-Speech IA : voix naturelles avec ElevenLabs

Generez des voix naturelles avec ElevenLabs : API Text-to-Speech, reglages stability et similarity, streaming faible latence, pipeline vocal LLM, couts et ethique du clonage.

Le TTS moderne en bref

La synthese vocale a fait un bond spectaculaire. Les voix robotiques d'antan ont cede la place a des voix naturelles, capables de respirer, d'accentuer, de transmettre une emotion. ElevenLabs s'est impose comme la reference, avec un rendu multilingue convaincant et une API simple.

Le TTS est le pendant de Whisper : la ou Whisper transcrit la voix en texte, le TTS genere de la voix a partir de texte. Ensemble, ils forment la base des assistants vocaux, des livres audio automatises et de l'accessibilite.

Cas d'usage : narration de contenu (articles, newsletters), assistants vocaux, doublage, accessibilite (lecture pour malvoyants), notifications vocales, formation et e-learning. Combine au TTS streaming, on atteint une experience conversationnelle fluide.

Prerequis et cle API

Avant de commencer :
  • Compte ElevenLabs et cle API
  • Node.js 18+ (support natif de fetch et streams)
  • Cle stockee dans ELEVENLABS_API_KEY
# Installer le SDK officiel
npm install @elevenlabs/elevenlabs-js

# Stocker la cle (jamais commitee)
echo "ELEVENLABS_API_KEY=..." >> .env

Premiere generation audio

Generons un fichier audio a partir d'un texte. L'API renvoie un flux audio que l'on ecrit sur disque.

// tts-first.js — generer un MP3 a partir de texte
import 'dotenv/config';
import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';
import { writeFile } from 'node:fs/promises';

const client = new ElevenLabsClient({ apiKey: process.env.ELEVENLABS_API_KEY });

// Generer l'audio (renvoie un flux de chunks)
const audioStream = await client.textToSpeech.convert('voice-id-ici', {
  text: 'Bonjour et bienvenue sur AngularForAll, votre ressource technique.',
  modelId: 'eleven_multilingual_v2',     // modele multilingue (gere le francais)
  outputFormat: 'mp3_44100_128',          // qualite MP3 44.1kHz 128kbps
});

// Accumuler les chunks et ecrire le fichier
const chunks = [];
for await (const chunk of audioStream) chunks.push(chunk);
await writeFile('bienvenue.mp3', Buffer.concat(chunks));

console.log('Audio genere : bienvenue.mp3');
Le modele eleven_multilingual_v2 gere de nombreuses langues dont le francais, avec detection automatique. Pour de l'anglais pur a faible latence, des modeles « turbo » plus rapides existent.

Regler la voix : stability et similarity

ElevenLabs expose des reglages qui modulent le rendu. Les deux principaux sont stability (constance vs expressivite) et similarity_boost (fidelite a la voix d'origine).

// Affiner les parametres de voix
const audioStream = await client.textToSpeech.convert('voice-id-ici', {
  text: 'Cette phrase sera lue avec une intonation expressive.',
  modelId: 'eleven_multilingual_v2',
  voiceSettings: {
    stability: 0.35,          // bas = plus expressif/variable ; haut = monotone/stable
    similarityBoost: 0.8,     // fidelite a la voix de reference
    style: 0.4,               // intensite stylistique (selon le modele)
    useSpeakerBoost: true,    // renforce la presence de la voix
  },
});
ParametreValeur basseValeur haute
stabilityExpressif, variableStable, monotone
similarity_boostPlus libreFidele a la reference
styleNeutreMarque, theatral
Conseil pratique : pour une narration d'article, une stability moyenne (0.4 a 0.6) evite les variations excessives. Pour un personnage expressif, descendez plus bas. Testez sur une phrase representative avant de generer un long contenu.

Streaming audio faible latence

Attendre la generation complete d'un long texte introduit une latence penible. Le streaming renvoie l'audio des les premiers mots — indispensable pour un assistant vocal.

// tts-stream.js — relayer l'audio en streaming vers le navigateur
import express from 'express';
import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';

const app = express();
const client = new ElevenLabsClient({ apiKey: process.env.ELEVENLABS_API_KEY });

app.get('/speak', async (req, res) => {
  res.setHeader('Content-Type', 'audio/mpeg');

  // stream() renvoie les chunks au fur et a mesure de la generation
  const audioStream = await client.textToSpeech.stream('voice-id-ici', {
    text: req.query.text,
    modelId: 'eleven_turbo_v2_5',     // modele turbo = latence reduite
    outputFormat: 'mp3_44100_128',
  });

  // Pipe direct vers la reponse HTTP : le navigateur joue en streaming
  for await (const chunk of audioStream) {
    res.write(chunk);
  }
  res.end();
});

app.listen(3000);
// Cote navigateur : jouer le flux audio
const audio = new Audio('/speak?text=' + encodeURIComponent('Bonjour !'));
audio.play();   // commence des reception des premiers chunks
Les modeles « turbo » sacrifient une part de qualite pour une latence minimale. Pour un assistant conversationnel, c'est le bon choix ; pour un livre audio, privilegiez la qualite maximale.

Lister et choisir les voix

ElevenLabs fournit une bibliotheque de voix pretes a l'emploi. Recuperez la liste pour choisir le voice_id adapte a votre cas.

// Lister les voix disponibles et leurs metadonnees
const voices = await client.voices.getAll();

voices.voices.forEach((v) => {
  console.log(`${v.name} (${v.voiceId})`);
  console.log(`  Langue/style : ${v.labels?.accent ?? '-'}, ${v.labels?.gender ?? '-'}`);
});

// Choisir programmatiquement une voix selon des criteres
function pickVoice(voices, { gender, accent }) {
  return voices.find((v) =>
    v.labels?.gender === gender && v.labels?.accent === accent
  ) ?? voices[0];
}
Coherence de marque : fixez une voix unique pour votre produit afin de creer une identite sonore reconnaissable. Stockez le voice_id en configuration plutot qu'en dur dans le code.

Pipeline vocal complet avec un LLM

Le TTS prend tout son sens combine a un LLM : l'utilisateur parle, on transcrit (Whisper), le LLM repond, et le TTS vocalise. Voici l'orchestration cote serveur.

// voice-pipeline.js — STT (Whisper) -> LLM -> TTS (ElevenLabs)
import OpenAI from 'openai';
import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const tts = new ElevenLabsClient({ apiKey: process.env.ELEVENLABS_API_KEY });

async function voiceTurn(audioFile) {
  // 1. Transcrire l'audio entrant (speech-to-text)
  const transcription = await openai.audio.transcriptions.create({
    file: audioFile,
    model: 'whisper-1',
  });

  // 2. Generer une reponse textuelle avec le LLM
  const completion = await openai.chat.completions.create({
    model: 'gpt-4o-mini',
    messages: [
      { role: 'system', content: 'Reponds en une a deux phrases concises.' },
      { role: 'user', content: transcription.text },
    ],
  });
  const answer = completion.choices[0].message.content;

  // 3. Vocaliser la reponse (text-to-speech)
  const audioStream = await tts.textToSpeech.stream('voice-id-ici', {
    text: answer,
    modelId: 'eleven_turbo_v2_5',
  });

  return { userSaid: transcription.text, assistantSaid: answer, audioStream };
}
Alternative tout-en-un : pour une latence minimale, l'OpenAI Realtime API realise ce pipeline en speech-to-speech direct. Le pipeline STT+LLM+TTS reste pertinent quand vous voulez choisir la voix (ElevenLabs) ou un LLM specifique.

Ajouter un lecteur "Ecouter l'article"

Le cas d'usage le plus immediat pour un site de contenu : offrir une version audio de chaque article. On expose un endpoint qui genere (et met en cache) l'audio d'un texte, puis un petit composant front qui pilote la lecture avec une barre de progression.

// server : endpoint qui renvoie l'audio cache d'un article
import express from 'express';
const app = express();

app.get('/api/article-audio/:slug', async (req, res) => {
  const article = await loadArticle(req.params.slug);   // votre source de contenu
  if (!article) return res.status(404).end();

  // getSpeech() reutilise le cache vu plus bas : zero cout si deja genere
  const buffer = await getSpeech(article.plainText, process.env.BRAND_VOICE_ID);

  res.setHeader('Content-Type', 'audio/mpeg');
  res.setHeader('Cache-Control', 'public, max-age=86400');   // cache navigateur 24h
  res.send(buffer);
});
// player.ts — composant "Ecouter l'article" avec progression (TypeScript)
export function initArticlePlayer(slug: string, btn: HTMLButtonElement, bar: HTMLElement) {
  const audio = new Audio(`/api/article-audio/${slug}`);

  btn.addEventListener('click', () => {
    if (audio.paused) {
      audio.play();
      btn.textContent = 'Pause';
    } else {
      audio.pause();
      btn.textContent = 'Ecouter l\'article';
    }
  });

  // Mettre a jour la barre de progression au fil de la lecture
  audio.addEventListener('timeupdate', () => {
    const pct = (audio.currentTime / audio.duration) * 100;
    bar.style.inlineSize = `${pct}%`;
  });

  audio.addEventListener('ended', () => { btn.textContent = 'Reecouter'; });
}
Bonus SEO & accessibilite : une version audio augmente le temps passe sur la page et sert les utilisateurs malvoyants ou en mobilite. Generez l'audio a la publication (pas a chaque visite) et servez-le depuis un cache/CDN pour ne payer le TTS qu'une seule fois par article.

Surlignage synchronise pour l'accessibilite

Pour une lecture vraiment accessible (karaoke / read-along), on synchronise le surlignage du texte avec l'audio. L'API d'ElevenLabs peut renvoyer des timestamps par caractere : on les exploite pour surligner le mot en cours de lecture.

// server : recuperer l'audio AVEC les timestamps de caracteres
const result = await client.textToSpeech.convertWithTimestamps('voice-id-ici', {
  text: article.plainText,
  modelId: 'eleven_multilingual_v2',
});

// result.alignment.characters / .characterStartTimesSeconds
res.json({
  audioBase64: result.audioBase64,
  chars: result.alignment.characters,
  starts: result.alignment.characterStartTimesSeconds,   // debut de chaque char (s)
});
// front : surligner le caractere lu en suivant audio.currentTime
function attachReadAlong(audio, starts) {
  let idx = 0;
  audio.addEventListener('timeupdate', () => {
    const t = audio.currentTime;
    // Avancer le curseur jusqu'au caractere correspondant au temps courant
    while (idx < starts.length && starts[idx] <= t) idx++;
    highlightUpTo(idx);   // applique une classe .lu sur les caracteres deja lus
  });
}
Cette technique transforme un simple lecteur en outil d'apprentissage (langues, lecture assistee) et coche des criteres WCAG. Cote performance, generez l'alignement une fois et stockez-le en JSON a cote du MP3 mis en cache.

Couts, quotas et alternatives

ElevenLabs facture au caractere genere, avec des quotas mensuels selon le plan. Un long contenu se chiffre vite : mettez en cache l'audio des textes statiques.

// Cache d'audio pour les textes recurrents (evite de regenerer)
import { createHash } from 'node:crypto';
import { existsSync } from 'node:fs';
import { readFile, writeFile } from 'node:fs/promises';

async function getSpeech(text, voiceId) {
  // Cle de cache = hash du texte + voix
  const key = createHash('sha256').update(text + voiceId).digest('hex');
  const path = `./cache/${key}.mp3`;

  if (existsSync(path)) {
    return readFile(path);              // deja genere : zero cout API
  }

  const stream = await client.textToSpeech.convert(voiceId, { text });
  const chunks = [];
  for await (const c of stream) chunks.push(c);
  const buffer = Buffer.concat(chunks);
  await writeFile(path, buffer);        // mise en cache pour la prochaine fois
  return buffer;
}
SolutionQualiteModele
ElevenLabsExcellente, expressivePayant a l'usage
OpenAI TTSTres bonnePayant, integre au SDK
Web Speech APIBasique, gratuiteNavigateur, hors ligne
Coqui / PiperVariableOpen source, self-hosted

Ethique et clonage de voix

Le clonage de voix est techniquement accessible, mais juridiquement et ethiquement sensible. Cloner la voix de quelqu'un sans son consentement explicite est illegal dans de nombreuses juridictions et viole les conditions d'usage des plateformes.

Regles a respecter :
  • Consentement ecrit explicite avant tout clonage de voix
  • Privilegier les voix de synthese fournies ou sa propre voix
  • Mentionner que l'audio est genere par IA quand c'est trompeur autrement
  • Ne jamais imiter une personne pour la desinformation ou la fraude
  • Respecter les watermarks audio anti-deepfake des plateformes

Erreurs frequentes a l'integration

La premiere erreur, couteuse au sens propre, est de regenerer l'audio a chaque requete. Pour un contenu statique (un article, une notification type, un message d'accueil), le texte ne change pas : son audio doit etre genere une seule fois puis servi depuis un cache ou un CDN. Sans cela, vous payez le TTS au caractere a chaque visiteur, pour un resultat strictement identique. Le pattern de cache par hash vu plus haut est la parade.

Deuxieme piege technique cote navigateur : l'autoplay bloque. Les navigateurs interdisent la lecture audio automatique sans interaction utilisateur prealable. Un audio.play() declenche au chargement de la page echoue silencieusement. Liez toujours le demarrage de la lecture a un clic explicite (le bouton « Ecouter l'article »), et gerez la promesse renvoyee par play() pour detecter un rejet.

Troisieme source de frustration : negliger la nettoyage du texte avant synthese. Du HTML, des emojis ou des URL brutes envoyes au TTS produisent une lecture parasitee (« inferieur p superieur »...). Extrayez le texte propre, developpez les abreviations ambigues et supprimez le balisage avant l'appel. Enfin, choisissez le bon outputFormat selon le canal : un format leger pour le streaming web, une qualite superieure pour un livre audio telecharge — envoyer du sans-perte sur mobile gaspille de la bande passante sans gain percu.

Quand un texte long doit etre decoupe en plusieurs requetes, attention a la coherence de voix entre les fragments. Si vous generez chaque paragraphe avec des voiceSettings legerement differents (ou en laissant le modele varier), l'auditeur percoit des ruptures de ton genantes. Figez les memes parametres de voix sur tout un document, et coupez le texte sur des frontieres naturelles (fin de phrase, fin de paragraphe) plutot qu'a un nombre de caracteres arbitraire qui tronquerait une intonation en plein milieu.

Cote serveur, surveillez enfin les limites de concurrence de votre plan. Generer en masse l'audio de centaines d'articles d'un coup peut saturer le quota et renvoyer des erreurs 429. Une file de jobs avec un nombre de workers plafonne, plus un backoff sur les erreurs de debit, evite de perdre des generations et lisse la charge — exactement comme pour n'importe quelle API LLM facturee a l'usage.

Pensez aussi a l'invalidation du cache : si vous mettez en cache l'audio d'un article et que son texte est corrige, l'ancien audio reste servi tant que la cle de cache (le hash du texte) n'a pas change. En indexant le cache sur le hash du contenu, une modification du texte genere automatiquement une nouvelle cle, donc une nouvelle synthese — sans intervention manuelle. C'est le meme principe que le cache-busting des assets statiques, applique a la voix : aucune purge manuelle, aucune incoherence entre le texte affiche et l'audio lu, et la regeneration ne se declenche que pour les contenus reellement modifies.

Conclusion

Le Text-to-Speech IA a atteint un niveau de naturel qui le rend exploitable en production : narration de contenu, assistants vocaux, accessibilite, e-learning. ElevenLabs offre une API simple, multilingue et expressive, avec un streaming faible latence indispensable aux usages conversationnels.

Combine a Whisper et a un LLM, le TTS complete le pipeline vocal complet. Pensez a mettre en cache les textes statiques pour maitriser les couts factures au caractere, choisissez le modele selon le compromis qualite/latence, et respectez scrupuleusement l'ethique autour du clonage de voix. La voix devient une interface a part entiere de vos applications.

A retenir :
  • TTS = generer de la voix naturelle a partir de texte
  • stability et similarity_boost modulent l'expressivite
  • Streaming + modeles turbo pour la faible latence
  • Cacher l'audio des textes recurrents pour reduire les couts
  • Consentement obligatoire pour tout clonage de voix

Partager