Text Control and Pronunciation
On this page
Course updated November 3, 2026 for Voxtral TTS 3, based on the Migrate from Voxtral 2 guide and Mistral’s Text to Speech pages:
voxtral-mini-tts-2603, deprecated October 31, 2026 and retired April 30, 2027, is replaced in examples byvoxtral-mini-tts-3-0. Voxtral 2 predefined voices (gb_jane_neutral…) remain supported; Voxtral 3 adds[emotion=…]and[pace=…]tags in text, theexpressivenesssetting, custom pronunciation (phoneme_hints), and 35 languages. Mistral recommends re-measuring latency after migration. Sources: Migrate from Voxtral 2 · Speech generation.
Mastering What Voxtral Pronounces
Voxtral generates natural speech from raw text, which works perfectly for standard narratives or dialogue. Challenges arise with non-prose elements: phone numbers, acronyms, dates, and percentages. Your input text becomes your only control mechanism—there is no markup to add. How you write dictates the vocal output. This lesson covers the techniques that separate a professional message from an approximate reading.
Writing Numbers as They Are Spoken
The model interprets digits inconsistently, making results hard to predict. The rule is simple: in text destined for synthesis, write numbers out exactly as a radio presenter would read them.
| Write | Do Not Write | Why |
|---|---|---|
| ”two thousand twenty-six" | "2026” | The model might say “twenty twenty-six" |
| "zero one, forty-two, thirty-seven" | "01 42 37” | Phone number mispronounced |
| ”fifteen point five percent" | "15.5%” | % symbol not interpreted |
| ”three forty-five" | "3:45” | Ambiguous abbreviated format |
Note the phone number treatment: commas are not decorative. They enforce two-digit grouping and the staccato rhythm humans naturally use when dictating a number.
Acronyms and Abbreviations
Abbreviations pose similar issues, with a nuance: sometimes you want them expanded, other times spelled out. A raw acronym may be pronounced as a word, creating awkward results in customer-facing messages.
# Bad: model might pronounce "sarl" as a word
input_bad = "Our SARL is based in Paris."
# Good: explicit pronunciation
input_good = "Our Société à Responsabilité Limitée is based in Paris."
# Alternative for letter-by-letter acronyms
input_acronym = "Our S.A.R.L. is based in Paris."
The third form is the key takeaway: inserting a period between each letter forces letter-by-letter reading. Use this for reservation codes, license plates, or identifiers listeners need to note down.
Punctuating for Breath
Without dedicated markup, punctuation controls silence. A comma creates a short pause (~200 ms); a period, a medium pause (~500 ms); ellipses, a long breath (~800 ms); and an em dash sets a dramatic pause, the kind you place before a revelation.
# Text with controlled pauses
text = (
"Ladies and gentlemen... "
"welcome to this conference. "
"Today, we will discuss — "
"a topic that will change how you work."
)
Speech rate comes primarily from the reference sample: a fast source voice yields a fast synthetic voice. However, you can influence it through text. Adding punctuation slows the rate and airs out the content; removing commas and shortening sentences speeds it up. To emphasize a word, write it in ALL CAPS—“This is ABSOLUTELY essential”—and you get emphasis without touching the audio.
Splitting Long Texts
Voxtral 2 documentation recommended staying under 300 words per request for best results. Voxtral TTS 3 documentation sets no hard limit but warns that an emotion tag placed before a long sentence may truncate audio at a comma. Splitting remains best practice.
The solution is to split into 200–300 word segments, never mid-sentence. A cut at an unnatural boundary is immediately audible. The following function only closes a segment after a word ending in a period.
def split_text(text, max_words=250):
"""Splits text into segments of max_words words."""
words = text.split()
segments = []
current_segment = []
for word in words:
current_segment.append(word)
# Split at sentences (after a period)
if len(current_segment) >= max_words and word.endswith("."):
segments.append(" ".join(current_segment))
current_segment = []
if current_segment:
segments.append(" ".join(current_segment))
return segments
# Usage
long_text = "..." # Your full text
segments = split_text(long_text)
for i, segment in enumerate(segments):
print(f"Segment {i + 1}: {len(segment.split())} words")
response = client.audio.speech.complete(
model="voxtral-mini-tts-3-0",
input=segment,
voice_id=voice_id,
response_format="wav",
)
# Save each segment
What to Remove from Text
Certain characters severely disrupt generation. Emojis are unsupported: the model ignores them or interprets them randomly. HTML tags and Markdown are pronounced as text, turning CMS-copied content into gibberish. URLs are spelled character by character, including slashes and dots. Programming symbols—braces, brackets, arrows—are misinterpreted. The solution is reformulation in natural language:
# Bad
input_bad = "Visit https://mistral.ai to learn more 🎉"
# Good
input_good = "Visit mistral dot ai to learn more."
Make it a habit to run any content from a database or website through a cleaning function before the API call. It costs less than listening to hours of audio to spot a forgotten emoji.
Multilingual Texts
One case resolves itself: language mixing. Voxtral detects changes and adapts pronunciation without requiring annotation.
mixed_text = (
"Welcome to our presentation. "
"As we say in English, the sky is the limit. "
"Willkommen bei unserer Vorstellung."
)
Quality is optimal as long as the languages used are among Voxtral TTS 3’s 35 supported languages. Beyond that, pronunciation remains plausible but the accent drifts, which a native listener spots immediately.
Directing the Voice with Voxtral TTS 3
Voxtral TTS 3 adds three control levers, written directly in the request.
Emotion and pace tags go in input, in brackets, before the text they affect: [emotion=calm], [emotion=happy], [pace=slow], or [pace=fast]. They are not spoken, apply until the next tag, and combine ([emotion=calm][pace=slow]). Thirty-four emotions are documented, from amused to wistful. With Voxtral 2, emotion came via voice variant selection (gb_jane_sad); these variants remain supported.
expressiveness, from 1.0 to 5.0, sets how strongly speech follows your request: higher values bring out more emotion at the cost of reduced voice resemblance. Start with the default, increase if emotion doesn’t come through, decrease if delivery sounds forced.
phoneme_hints fixes a word’s pronunciation—a brand name, an acronym—via a list of phonemes from a closed set of 50 (an unknown phoneme returns a 422 error).
import base64
from pathlib import Path
response = client.audio.speech.complete(
model="voxtral-mini-tts-3-0",
input="[emotion=calm][pace=slow]I like tomato soup.",
voice_id="gb_jane_neutral",
phoneme_hints={"tomato": ["t", "ə", "m", "ɑ", "t", "oʊ"]},
response_format="wav",
)
Path("soup.wav").write_bytes(base64.b64decode(response.audio_data))
Two precautions from the documentation: a tag placed before a long sentence may truncate audio at a comma—keep tagged sentences short—and natural language style instructions (instruction) are unavailable at Voxtral TTS 3 launch.
Key Takeaways
- Spell out numbers and abbreviations for correct pronunciation
- Use punctuation to control pauses (comma, period, ellipses)
- Split long texts into segments ending on complete sentences
- Avoid emojis, HTML, URLs, and code in input text
- Voxtral TTS 3 handles multilingual text across its 35 languages; language is carried by the voice
[emotion=…]and[pace=…]tags,expressiveness, andphoneme_hintsdirect the voice in Voxtral TTS 3