Spoken language identification
VoiceThere can identify the language the caller is speaking and deliver a user_language speech event to your agent. Use it to switch prompts, pick a TTS voice, or keep session state in the caller’s language. Detection uses Whisper tiny on VoiceThere (ISO 639-1 codes such as en, de, es).
How it works
- At the start of each new user utterance, the voice pipeline buffers inbound speech and runs spoken-language identification once enough audio is buffered. On VoiceThere Cloud the window is 1500 ms (1.5 seconds) by default and identification runs while the caller is still talking; the SDK and self-hosted runners default to 1000 ms when unset.
- The confident ISO code is emitted as
user_language. The event is re-emitted only if the detected language changes later in the session. - Both
event.languageandevent.textcarry the ISO code. - Detection alone does not change STT or TTS unless you enable LID auto-switch or call
setVoiceLanguagefrom your agent (see the request shape). - When conversation history is on, each stored utterance can include an ISO
languageon turn metadata (not a separateuser_languagerow).
Agent handler
Handle every speech event with onSpeechEvent, or use the convenience hook onUserLanguage in @voicethere/agent:
import { defineAgent, agentLog } from "@voicethere/agent";
export default defineAgent({
onUserLanguage({ sessionId, language }) {
agentLog("info", `detected language ${language} for ${sessionId}`);
// Route system prompts or TTS voice from the ISO 639-1 code.
},
});The voice-starter template logs user_language. See Agent templates.
Identification timing
On VoiceThere Cloud, languageId.timing decides when identification runs (runner SHERPA_LID_TIMING):
early(default): once per utterance, as soon aslanguageId.minSpeechMsof speech is buffered, while the caller is still talking.end_of_utterance: once per utterance, after the caller stops talking.continuous: repeated passes while the caller keeps talking. In your own SDK app the same behavior islanguageId.continuous: trueinVoiceAgentConfig.
CPU trade-off of continuous: it runs Whisper more often. On a busy runner that can slow Piper TTS and stretch the gap between spoken sentences (a brief first TTS burst such as an echo. prefix is the first thing listeners lose). If agent audio gets choppy, go back to voicethere projects voice-advanced set languageId.timing early. See Switching language mid-conversation for how timing changes the language check hold on finals.
TTS voice ids
These are the VoiceThere text-to-speech voices. Pass one as ttsVendor.voice in setVoiceLanguage (see the request shape), or as the project tts_model_id.
| voice | Language | Label |
|---|---|---|
| en | en | English (Amy, Piper medium) |
| en-amy-low | en | English (Amy, Piper low) |
| en-lessac | en | English (Lessac, Piper medium) |
| en-lessac-high | en | English (Lessac, Piper high) |
| en-lessac-low | en | English (Lessac, Piper low) |
| en-glados | en | English (GLaDOS) |
| en-glados-high | en | English (GLaDOS high) |
| en-ryan | en | English (Ryan, Piper medium) |
| en-ryan-high | en | English (Ryan, Piper high) |
| en-ryan-low | en | English (Ryan, Piper low) |
| en-joe | en | English (Joe, Piper medium) |
| en-bryce | en | English (Bryce, Piper medium) |
| en-john | en | English (John, Piper medium) |
| en-kristin | en | English (Kristin, Piper medium) |
| en-norman | en | English (Norman, Piper medium) |
| en-danny-low | en | English (Danny, Piper low) |
| en-kathleen-low | en | English (Kathleen, Piper low) |
| en-ljspeech | en | English (LJSpeech, Piper medium) |
| en-ljspeech-high | en | English (LJSpeech, Piper high) |
| en-arctic | en | English (Arctic multi-speaker, Piper medium) |
| en-hfc-female | en | English (HFC female, Piper medium) |
| en-hfc-male | en | English (HFC male, Piper medium) |
| en-gb-alan | en | English GB (Alan, Piper medium) |
| en-gb-cori | en | English GB (Cori, Piper medium) |
| en-gb-jenny | en | English GB (Jenny, Piper medium) |
| es | es | Spanish (GLaDOS medium) |
| de | de | German (Thorsten medium) |
| de-thorsten-high | de | German (Thorsten high) |
| de-glados | de | German (GLaDOS medium) |
| fr | fr | French (Siwis, Piper medium) |
| it | it | Italian (Paola, Piper medium) |
| pt | pt | Portuguese BR (Faber, Piper medium) |
| nl | nl | Dutch (Pim, Piper medium) |
| pl | pl | Polish (Gosia, Piper medium) |
| ru | ru | Russian (Irina, Piper medium) |
| hi | hi | Hindi (Priyamvada, Piper medium) |
| zh | zh | Chinese + English (Melo TTS) |
STT model ids
These are the VoiceThere speech-to-text models. Pass one as sttVendor.model in setVoiceLanguage, or as the project stt_model_id. When you omit the model on a switch, the language code is used if a model with that id exists. Whisper tiny is only the language detector. It is not an STT id.
| stt | Language | Label |
|---|---|---|
| en | en | English (Kroko) |
| en-legacy | en | English (2023 baseline) |
| en-small | en | English (20M, small) |
| es | es | Spanish |
| fr | fr | French |
| de | de | German |
| zh | zh | Chinese (Mandarin) |
| zh-en | zh | Chinese + English (bilingual) |
| ja | ja | Japanese |
| ar | ar | Arabic |
| id | id | Indonesian |
| th | th | Thai |
| vi | vi | Vietnamese |
| ko | ko | Korean |
| ru | ru | Russian |
| fr-legacy | fr | French (2023 baseline) |
| en-2023-02 | en | English (2023-02 LibriSpeech) |
| bn | bn | Bengali (South Asia) |
Cloud runners
Voice and Voice+Data cloud deploys enable spoken-language identification automatically using Whisper tiny on VoiceThere, with early identification by default.
Tune identification from the dashboard or CLI under Advanced voice pipeline:
languageId.enabled— turn off to skip LID while keeping the model on the runner (SHERPA_LID_ENABLED=0).languageId.minSpeechMs— integer 1000–5000, cloud default 1500. Lower values emituser_languagesooner but Whisper tiny may mis-guess on short or ambiguous audio. Higher values wait for more inbound PCM for a more confident code. An utterance shorter than the window skips identification (language_id_skipped) and its final is released immediately.languageId.timing—early(default),end_of_utteranceorcontinuous(SHERPA_LID_TIMING).
See also Advanced voice settings.
Whisper tiny is not an STT picker option. Choose a Zipformer language in STT & TTS vendors as usual; language ID runs alongside that model.
Local development
From a node-webrtc-rust checkout:
npm run download-lid --workspace=@node-webrtc-rust/example-voice-agent-local-sherpa export SHERPA_LID_MODEL_PATH=.models/sherpa-onnx-whisper-tiny npm run start:roundtrip-language-id --workspace=@node-webrtc-rust/example-voice-agent-local-sherpa
Local runner: set SHERPA_LID_MODEL_PATH in .env.local (see the runner .env.example).