ai newsMo., 2. Nov.
EilmeldungGoogle, Microsoft, OpenAI and Anthropic Back a Shared AI Training Opt-Out Signal

I recorded 1,180 TTS clips to find out what voices misread in LLM output

Every voice agent has the same seam: a language model writes text for a reader, and a text-to-speech model reads it for a listener. The two were never designed for each other. The model writes **Step 1:** run `npm install` and the voice says "asterisk asterisk step one". It writes 1,250 units and s

dev.toMontag 22:18 · 02.11.3 Min. Lesezeit
Bild: dev.to

Every voice agent has the same seam: a language model writes text for a reader, and a text-to-speech model reads it for a listener. The two were never designed for each other. The model writes **Step 1:** run `npm install` and the voice says "asterisk asterisk step one". It writes 1,250 units and some voices say "one two five zero". It writes a Turkish phone number as 0532 123 45 67 and the voice reads it as a single number with the wrong suffix.

I kept patching these one at a time in prompts and regexes until I decided to do it properly. This post is about the result, and more about how I measured it, because the measuring turned out to be the hard part.

speechready runs between the LLM and the TTS. Four stages:

There is a Python package and a TypeScript package. Both pass the same 217 YAML fixtures and produce the same output for every one of them.

A text preprocessor is easy to make look good: pick an ugly input, show the tidy output. I wanted to know whether voices actually read the processed text correctly more often, so I built a loop that could tell me.

145 lines of English and Turkish: assistant answers with markdown, dates, phone numbers, prices, URLs, identifiers, and control prose that should pass through untouched. 16 voices across 7 providers. Each line synthesized twice, as written and after speechready. Both recordings transcribed back with gpt-4o-transcribe and scored against the intended words.

The scorer forgives the ways a transcription engine writes speech down: digits for spoken numbers, "21st" for "twenty-first", "NPM" for "en pi em". It only ever lowers the error, and it applies to both sides equally. A line counts as misread when more than a fifth of the words are wrong. Most of the 145 lines are the fixture inputs the rules were developed against, plus control prose and a handful of real assistant answers, so this is a go/no-go measurement on curated cases, not a held-out production sample.

Every voice improved. Control prose did not regress. The weakest result is Cartesia's Turkish, where the voice speaks with an English accent and the transcription model misses words that were rendered correctly.

Because most of those lines are the library's own test inputs, I also ran a held-out check: 60 answers that gpt-4.1-mini gave to typical voice-agent questions, generated after the rules were written, scored against a narration the same model wrote independently, on four voices. Misreads went from 10% to 8% and mean word error rate did not move. Concise assistant answers simply contain few of the things the library fixes; when they do contain markdown, prices, phone numbers or code, that is where the gain is. The held-out run also found two bugs, a dotted Turkish time with a suffix and a spaced minus read as a range, which is what held-out data is for.

You can listen to the pairs, with what the STT heard under each: https://berkerbatur.github.io/speechready/

pip install speechready # Python 3.10+ npm install speechready # Node 20+, 35 kB, no dependencies Enter fullscreen mode Exit fullscreen mode from speechready import prepare prepare ( " **Step 1:** run `npm install`. [pause 1s] ", provider = " elevenlabs ", model = " eleven_multilingual_v2 " ). text # 'Step 1: run npm install. <break time="1s" />' Enter fullscreen mode Exit fullscreen mode For LiveKit Agents, speechready.integrations.livekit.text_transform goes in tts_text_transforms. For Pipecat, speechready.integrations.pipecat.text_transform goes in a TTS service's text_transforms. Neither imports the framework.

Playground, in the browser: https://berkerbatur.github.io/speechready/play/

English and Turkish for now. If you want another language, the fixtures show exactly what a locale has to cover, and the eval harness will tell you whether it worked.

Quelle: dev.to (dev.to). Original öffnen