Gå till innehåll

Text to Speech API-integration: streaming, batchning, omförsök

Publicerad

LyssnaLyssna på den här artikeln

Att integrera ett Text to Speech API är enkelt… efter några viktiga beslut: vilket överföringsläge du ska använda, hur du väljer modell och utdataformat, hur du streamar, hur du hanterar hög volym utan att överskrida din samtidighetsgräns, hur du cachar och gör omförsök så du aldrig betalar för att rendera samma ljud två gånger, och hur du jämför time-to-first-byte mot en annan leverantör.

För att hjälpa dig med Text to Speech API-integrationen har vi brutit ner varje arkitekturbeslut och vad du ska göra. Den här guiden hjälper dig att integrera ElevenLabs Text to Speech API och skala upp, med kodexempel du kan klistra in direkt i produktion för att komma igång.

För en djupare bakgrund till de begrepp som nämns här, se våra guider om förstå ljudstreaming, optimera latens, och översikt av ElevenLabs-modeller.

Sammanfattning

  • Det finns ett ElevenLabs Text to Speech API-endpoint som du kan använda på tre sätt: batchkonvertering, HTTP-streaming och stream-input via WebSocket.
  • Över HTTP räknas varje pågående förfrågan mot din samtidighetsgräns, medan det över WebSocket bara är aktiv generering som räknas.
  • Håll din parallellism strax under din plan-gräns och cacha en hash av varje parameter som påverkar ljudet så att du aldrig debiteras för samma text två gånger.
  • Gör omförsök på 429 och 5xx med exponentiell backoff och full jitter för att undvika att slå i samtidighetsväggen.

Tre sätt att integrera Text to Speech API

Det finns ett Text to Speech-endpoint, men hur du integrerar det påverkar latens, komplexitet och kostnad.

Samma POST /v1/text-to-speech/{voice_id}-anrop fungerar på tre sätt, där varje passar för lite olika behov. Här är en översikt över alla tre sätten att integrera Text to Speech API:

  • Batch (konvertering) är den enklaste integrationen: Du skickar en förfrågan och får ett ljudsvar tillbaka. Det är det minst komplexa alternativet och har längst time-to-first-audio, eftersom hela klippet syntetiseras innan några bytes skickas tillbaka.
  • HTTP-streaming (stream) behåller samma förfrågan men delar upp svaret: Du lägger till /stream i sökvägen, anropar stream-metoden och ljudet returneras i delar. Koden är nästan identisk och upplevd latens är mycket lägre.
  • WebSocket (stream-input) håller en öppen anslutning: Du skickar text stegvis och får tillbaka ljuddelar medan du går. Det är byggt för interaktiva agenter och för att koppla LLM-utdata till tal i realtid, innan meningen är klar.

Streaming gör inte att modellen genererar ljud snabbare; inferenstiden är densamma. Det streaming ändrar är när du får första delen: den skickas innan hela klippet är klart, så väntetiden för användaren blir kortare även om det totala arbetet är lika stort.

Batch vs. streaming vs. WebSocket – jämförelsetabell

När du väljer mellan dessa tre metoder finns det flera faktorer att ta hänsyn till.

Snabbguide: välj batch för offline-rendering, HTTP-streaming för känd text som en användare väntar på, och WebSocket för agenter och live LLM till tal.

Tabellen nedan visar för- och nackdelar för varje metod i stor skala.

Batch (convert)
Time-to-first-audio
Highest (wait for full clip)
Implementation complexity
Lowest
Text known up front?
Required
Streaming LLM output into TTS
Awkward
Concurrency cost
Each request counts fully
Best for
Offline rendering, audiobooks, caching
HTTP streaming
Time-to-first-audio
Low
Implementation complexity
Low
Text known up front?
Required
Streaming LLM output into TTS
Awkward
Concurrency cost
Each request counts fully
Best for
Web/app playback of known text
WebSocket (stream-input)
Time-to-first-audio
Lowest
Implementation complexity
Highest (connection lifecycle, framing)
Text known up front?
Not required - send incrementally
Streaming LLM output into TTS
Native fit
Concurrency cost
Only active generation counts
Best for
Voice agents, live LLM to speech

Över HTTP, oavsett batch eller streaming, räknas varje pågående förfrågan mot din plan-gräns under hela tiden den körs. Över WebSocket räknas bara tiden då modellen faktiskt genererar ljud; en öppen men inaktiv socket kostar i princip inget.

För en kaskad röstagent som håller anslutningen öppen under hela samtalet men bara genererar ljud under agentens turer, är skillnaden stor, och det är huvudskälet att använda WebSockets för agenter. Hela protokollet finns dokumenterat i guiden för realtids-Text to Speech via WebSocket.

Välja modell och utdataformat

Två val avgör vilket ljud du får tillbaka från din TTS API-integration. Först modellen, som styr kvalitet och hastighet. Sedan utdataformatet, som styr container, bitrate och samplingsfrekvens.

Om du får till båda rätt från början fungerar allt nedströms, som latens och telefoni-kompatibilitet, direkt.

Modeller

Vi erbjuder flera Text to Speech-modeller. De är inte rankade bäst till sämst; varje gör olika avvägningar.

Best for
eleven_flash_v2_5
Real-time, agents, bulk throughput (~75ms model inference)
eleven_flash_v2
Real-time, English only (~75ms)
eleven_multilingual_v2
Highest stable fidelity, narration
eleven_v3
Most expressive, widest language range
Languages
eleven_flash_v2_5
32
eleven_flash_v2
English
eleven_multilingual_v2
29
eleven_v3
70+
Character limit
eleven_flash_v2_5
40,000
eleven_flash_v2
30,000
eleven_multilingual_v2
10,000
eleven_v3
5,000

Notera att ~75 ms är modellens inferenstid under typiska förhållanden, exklusive nätverks- och applikationslatens. Den ökar med längre indata och vid hög belastning. Mät alltid från din applikation, inte från ett benchmark.

Flash-modeller är mindre och använder mer aggressiva approximationer för att minska inferenstiden. Eleven v3 och Multilingual v2 är större modeller som lägger mer tid per tecken för att skapa rikare ljud. Det finns ingen inställning som ger dig Eleven v3-kvalitet i Flash-hastighet, eftersom kvaliteten kräver mer beräkning.

För realtids- eller agentanvändning, använd eleven_flash_v2_5; det är det snabbaste flerspråkiga alternativet. För berättarröst, ljudböcker eller marknadsföringsvoice-over, använd eleven_multilingual_v2 när du vill ha stabil hög kvalitet, eller eleven_v3 när du behöver maximal uttrycksfullhet och känsla.

När uttal är viktigt, till exempel för telefonnummer, datum eller valuta, normalisera siffror själv i din applikation innan texten skickas till API:et. Skriv ut det du vill att rösten ska säga.

Att normalisera själv gör uttalet förutsägbart mellan modeller och undviker att förlita sig på modell-specifika standarder som kan ändras.

Utdataformat

Parametern output_format styr container, samplingsfrekvens och bitrate för ljudet du får tillbaka. De vanligaste värdena:

Use case
mp3_44100_128
General playback, downloads, highest mp3 quality shown here
mp3_22050_32
Lower-bandwidth playback, smaller files
pcm_24000 / pcm_16000
Raw PCM for your own audio pipeline or further processing
ulaw_8000
Telephony - the format used with Twilio and similar systems
Languages
mp3_44100_128
32
mp3_22050_32
English
pcm_24000 / pcm_16000
29
ulaw_8000
70+
Character limit
mp3_44100_128
40,000
mp3_22050_32
30,000
pcm_24000 / pcm_16000
10,000
ulaw_8000
5,000

Röstinställningar

Följande inställningar styr hur det genererade talet levereras:

  • Stability: Styr balans mellan konsekvens och uttrycksfullhet. Lägre värden ger mer varierat och uttrycksfullt tal, högre värden ger jämnare och mer förutsägbart resultat.
  • SimilarityBoost: Styr hur nära resultatet följer referensrösten.
  • Style: Förstärker röstens naturliga talstil när värdet höjs.
  • useSpeakerBoost: Förbättrar likheten med originalrösten till en liten latenskostnad.
  • Speed: Justerar talhastigheten kring standardvärdet 1.0.

Av dessa inställningar påverkar Stability oftast upplevd kvalitet mest. Lägre värden ger mer uttrycksfullt men mindre konsekvent resultat, högre värden prioriterar jämnhet och förutsägbarhet.

När du väljer röst är den snabbaste kombinationen Flash ihop med en Instant Voice Clone eller en standardröst; Professionella Voice Clones låter utmärkt men ger extra fördröjning per generering som du bör räkna med.

I den här guiden används röst-id JBFqnCBsd6RMkjVDRZzb (George) som exempel.

Streaming-integration (HTTP och WebSocket)

I det här avsnittet går vi igenom det praktiska med Text to Speech API-integration. Vi visar hur du installerar SDK, öppnar en stream och tar emot ljudet när det kommer. HTTP-vägen täcker de flesta webb- och appuppspelningar, medan WebSocket-vägen täcker agenter och live LLM-utdata.

Båda dessa vägar förutsätter att du har initierat ElevenLabs-klienten enligt nedan.

npm install @elevenlabs/elevenlabs-js
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

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

Streaming-vägen öppnar en stream och tar emot ljuddelar när de kommer. voiceId är första argumentet, följt av ett options-objekt med camelCase-nycklar (modelId, outputFormat, voiceSettings):

const stream = await elevenlabs.textToSpeech.stream("JBFqnCBsd6RMkjVDRZzb", {
  text,
  modelId: "eleven_flash_v2_5",
  outputFormat: "mp3_44100_128",
  voiceSettings: { stability: 0, similarityBoost: 1.0, style: 0, useSpeakerBoost: true, speed: 1.0 },
});

for await (const chunk of stream) {
  // chunk is a Buffer; feed it to the player as it arrives
}

För WebSocket-varianten, anslut till wss://api.elevenlabs.io/v1/text-to-speech/{voice_id}/stream-input, skicka ett första meddelande med dina röstinställningar och ett inledande mellanslag, skicka sedan textmeddelanden när de finns tillgängliga och läs tillbaka JSON-ramar där audio-fältet innehåller base64-kodade ljuddelar.

Batchning och samtidighetsgränser för hög kapacitet

Integration med hög kapacitet styrs av samtidighet, alltså hur många förfrågningar som genererar ljud samtidigt. Varje plan har en gräns per modellfamilj.

Varje plan har en specifik samtidighetsgräns:

  • Gratis: 4 samtidiga Flash-förfrågningar.
  • Starter: 6 samtidiga Flash-förfrågningar.
  • Creator: 10 samtidiga Flash-förfrågningar.
  • Pro: 20 samtidiga Flash-förfrågningar.
  • Scale och Business: 30 samtidiga Flash-förfrågningar, med anpassade gränser för Enterprise.

Gränserna för Multilingual v2 är ungefär hälften av ovanstående.

En begränsad pool löser detta genom att sätta tak på hur många förfrågningar som körs samtidigt:

// Set MAX_CONCURRENCY at or below your plan's Flash concurrency limit.
const MAX_CONCURRENCY = 8;

async function synthMany(texts: string[]): Promise<Buffer[]> {
  const results: Buffer[] = [];
  for (let i = 0; i < texts.length; i += MAX_CONCURRENCY) {
    const batch = texts.slice(i, i + MAX_CONCURRENCY);
    results.push(...(await Promise.all(batch.map(eachSingleRequest)))); // never more than MAX_CONCURRENCY in flight
  }
  return results;

Sätt MAX_CONCURRENCY lite under din plan-gräns istället för exakt på den. Det ger utrymme för annan trafik på samma nyckel och håller dig under gränsen där du får 429.

Teckengränser och uppdelning av lång text

Varje modell har ett tak för hur många tecken den accepterar per förfrågan. All långformad integration måste dela upp texten och sätta ihop ljudet igen.

Här är teckengränserna per förfrågan för varje modell:

  • Flash v2.5: Accepterar upp till 40 000 tecken per förfrågan.
  • Flash v2: Accepterar upp till 30 000 tecken per förfrågan.
  • Multilingual v2: Accepterar upp till 10 000 tecken per förfrågan.
  • Eleven v3: Accepterar upp till 5 000 tecken per förfrågan.

Allt längre måste delas upp i flera förfrågningar. Försök dela på meningsgränser så prosodin bevaras mellan delarna.

function splitText(text: string, maxChars: number): string[] {
  const sentences = text.trim().split(/(?<=[.!?])\s+/);
  const chunks: string[] = [];
  let current = "";
  for (let sentence of sentences) {
    if (current.length + sentence.length + 1 > maxChars) {
      if (current) chunks.push(current.trim());
      // A single sentence longer than the limit is hard-split.
      while (sentence.length > maxChars) {
        chunks.push(sentence.slice(0, maxChars));
        sentence = sentence.slice(maxChars);
      }
      current = sentence;
    } else {
      current = `${current} ${sentence}`.trim();
    }
  }
  if (current) chunks.push(current.trim());
  return chunks;
}

Rendera delarna i ordning och slå ihop ljudet. För långformad uppläsning där varje del är oberoende, kan du direkt mata splitText-utdata till poolen ovan och låta den sköta resten.

Caching och idempotens

Text to Speech-utdata är tillräckligt deterministisk för att det är slöseri att rendera samma text med samma röst, modell och inställningar flera gånger. Cacha resultatet med en hash av alla indata som påverkar ljudet, och använd samma nyckel som idempotens-token vid omförsök.

Så här gör du båda delarna.

import { createHash } from "node:crypto";

function cacheKey(text: string, voiceId: string, modelId: string,
                  outputFormat: string, settings: object): string {
  // Every parameter that changes the audio must be in the key.
  const payload = JSON.stringify({ text, voiceId, modelId, outputFormat, settings });
  return createHash("sha256").update(payload).digest("hex");
}

async function cachedSynth(text: string, voiceId: string, modelId: string,
                           outputFormat: string, settings: object): Promise<Buffer> {
  const key = cacheKey(text, voiceId, modelId, outputFormat, settings);
  const cached = await cacheGet(key);          // e.g. read from disk or S3
  if (cached) return cached;

  const audio = await elevenlabs.textToSpeech.convert(voiceId, { text, modelId, outputFormat });
  await cachePut(key, audio);                   // store the bytes under the key
  return audio;
}

Regeln som gör detta möjligt är att varje parameter som ändrar ljudet måste ingå i nyckeln, inklusive outputFormat och röstinställningar. Om det görs rätt fungerar samma nyckel som idempotens-token. När en klient gör omförsök på en redan lyckad förfrågan returnerar du de cachade byten istället för att generera igen.

Felsökning och rate limits (429:or)

En produktionsklient behöver omförsök med backoff och jitter, samt hantering som varierar beroende på statuskod, eftersom vissa fel är värda att försöka igen och andra inte.

Tabellen nedan visar rätt åtgärd för varje status, och avsnittet förklarar varför en 429 är en mjuk gräns snarare än en hård vägg.

Meaning
401
Authentication failed
422
Invalid request
429
Concurrency exceeded
5xx
Transient server error
Action
401
Do not retry. Check the xi-api-key header and key validity.
422
Do not retry. Fix the payload (bad voice id, unsupported format, text over limit).
429
Retry with exponential backoff and jitter.
5xx
Retry with backoff.
Character limit
401
40,000
422
30,000
429
10,000
5xx
5,000

En 429 är inte en hård vägg, och det är bra att förstå mekanismen. När du går över samtidighetsgränsen köas förfrågningar först efter prioritet, vilket oftast lägger till ca 50 ms. Först om du fortfarande är över kapacitet får du en 429.

Svaret innehåller också headers för current-concurrent-requests och maximum-concurrent-requests som visar ditt aktuella utrymme, så du kan läsa av och backa innan du når gränsen.

const RETRYABLE = new Set([429, 500, 502, 503, 504]);

async function synthWithRetry(text: string, voiceId: string, maxRetries = 5): Promise<Buffer> {
  let delay = 500; // ms, base for exponential backoff
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await elevenlabs.textToSpeech.convert(voiceId, {
        text, modelId: "eleven_flash_v2_5", outputFormat: "mp3_44100_128",
      });
    } catch (err: any) {
      const status = err.statusCode;
      // 401/422 and exhausted retries are not recoverable here.
      if (!RETRYABLE.has(status) || attempt === maxRetries) throw err;
      // Exponential backoff with full jitter.
      await new Promise((r) => setTimeout(r, Math.random() * delay));
      delay = Math.min(delay * 2, 8000);
    }
  }
  throw new Error("unreachable");
}

När du behöver mer utrymme snarare än bättre omförsök, uppgradera din plan. Enterprise-kunder kan begära högre gränser via sin account manager.

Benchmarking av latens och time-to-first-byte

Latens beror på din region, din indata och aktuell belastning, vilket betyder att det enda latensvärde du kan lita på är det du själv mäter i din miljö.

Det här avsnittet ger dig time-to-first-byte (TTFB) för Flash streaming-endpoint, och är upplagt så att du kan testa mot en annan leverantör under identiska förhållanden.

Se detta som en metod, inte ett publicerat resultat. Ingen enskild körning garanterar något.

Här är några saker att tänka på när du benchmarkar latensen för en Text to Speech API-integration:

  • Ta med nätverksrundan: TTFB beror på din geografi och leverantörens närmaste kluster, så kör testet där dina servrar normalt körs.
  • Kasta bort en uppvärmningskörning: Första förfrågan till en kall anslutning är långsammare och kan snedvrida siffrorna.
  • Håll indata fasta: Indatalängd, röst, modell och belastning påverkar resultatet, så håll dem identiska mellan leverantörer.
  • Rapportera en fördelning: Siffror varierar mellan körningar, så publicera median och p95 istället för ett enskilt värde.

Med detta i åtanke är du redo att benchmarka.

const TEXT = "This is a fixed benchmark sentence used for every provider.";

async function measureElevenLabs(): Promise<number> {
  const start = performance.now();
  const res = await fetch(
    "https://api.elevenlabs.io/v1/text-to-speech/JBFqnCBsd6RMkjVDRZzb/stream?output_format=mp3_44100_128",
    {
      method: "POST",
      headers: { "xi-api-key": process.env.ELEVENLABS_API_KEY!, "Content-Type": "application/json" },
      body: JSON.stringify({ text: TEXT, model_id: "eleven_flash_v2_5" }),
    },
  );
  for await (const _ of res.body!) {
    return performance.now() - start; // first chunk received
  }
  throw new Error("no audio returned");
}

För att jämföra mot en annan leverantör, skriv en funktion med samma struktur. Kör båda genom en liten runner som kastar bort en uppvärmningskörning, tar ca 20 tidsmätta prover med mellanrum så de inte krockar, och rapporterar median och p95 i millisekunder.

En rättvis jämförelse handlar om att kontrollera variablerna.

Kör båda leverantörerna från samma maskin och nätverk, helst en server i den region du faktiskt använder och inte en laptop på hemmabredband. Använd samma indata, och håll ljudet kort så att modellens inferenstid dominerar siffran istället för längden på genereringen. Rapportera median och p95 över många körningar, eftersom en enskild mätning är brus.

Kom ihåg att TTFB över publika internet inkluderar 20–200 ms nätverksrunda som inte har med modellen att göra. Vi serverar från kluster i Nordamerika, Europa och Sydostasien och dirigerar till närmaste, så placera din testklient därefter – annars mäter du mest avståndet till datacentret.

Viktiga saker att ta med för din Text to Speech API-integration

En produktionsintegration av Text to Speech API handlar om några avgörande beslut.

Om du får till dessa rätt faller allt annat på plats:

  • Välj modell efter uppgift: Använd Flash v2.5 för allt interaktivt och en högupplöst modell som Multilingual v2 eller Eleven v3 för offline-rendering där latens inte är lika viktigt.
  • Streama när en användare väntar: Använd HTTP-streaming för känd text och WebSocket för agenter, så att inaktiv tid inte tar av din samtidighetsbudget.
  • Håll parallellismen inom din plan-gräns: Begränsa samtidiga förfrågningar strax under din plan-gräns och cacha på en hash av varje parameter som påverkar ljudet så att samma ljud aldrig debiteras två gånger.
  • Gör omförsök på 429 och 5xx med exponentiell backoff och full jitter: Backa på 429 och 5xx med full jitter och håll koll på concurrency-headers för att se hur nära gränsen du är.
  • Dela lång text på meningsgränser: Dela på meningsgränser inom varje modells teckengräns så prosodin bevaras.

Vill du fördjupa dig ännu mer? Kolla in streaming-guiden, ljudstreaming-konceptet, autentisering, och engångstokens för klientanvändning.

Bygg din Text to Speech-integration med ElevenAPI

Efter att ha läst den här guiden har du alla mönster du behöver för en produktionsklar Text to Speech API-integration. Oavsett om det gäller streaming, batchning, caching, omförsök eller till och med benchmarking är du redo att köra igång.

Börja med att läsa mer om Text to Speech API eller registrera dig för att göra ditt första anrop med ElevenAPI idag.

Vanliga frågor om Text to Speech API-integration

Liknande artiklar

Skapa med AI-ljud av högsta kvalitet