From ade0ee910421951e335d5223f9b4d41b7b5442be Mon Sep 17 00:00:00 2001 From: Joao Victor Cardoso dos Santos <57873270+jvcss@users.noreply.github.com> Date: Sat, 18 Jul 2026 07:38:35 -0300 Subject: [PATCH] feat(openai-realtime): allow pinning input transcription language (#557) The OpenAI realtime factory already reads `language` from the realtime config, but builds `InputAudioTranscription()` without it, so the language is silently dropped and the model auto-detects on every utterance. On 8kHz telephony audio this misfires badly: in our production tests a Brazilian Portuguese speaker was transcribed as English, French and Chinese within a single call, which then corrupted downstream extraction. Every other STT branch in `create_stt_service` already honours `language` (Deepgram, Google, Cartesia, Dograh, Sarvam), and `GoogleRealtimeLLMConfiguration` already exposes a `language` field for Gemini Live. This brings the OpenAI realtime provider in line with both. - expose `language` on `OpenAIRealtimeLLMConfiguration` (optional, defaults to None -> unchanged auto-detect behaviour) - pass it through to `InputAudioTranscription`, which already accepts it Verified against pipecat: the session now carries `{"transcription": {"model": "gpt-realtime-whisper", "language": "pt"}}`. Co-authored-by: Liberty Card --- api/services/configuration/registry.py | 25 +++++++++++++++++++++++++ api/services/pipecat/service_factory.py | 11 ++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/api/services/configuration/registry.py b/api/services/configuration/registry.py index c74b0116..aba0b7c7 100644 --- a/api/services/configuration/registry.py +++ b/api/services/configuration/registry.py @@ -584,6 +584,20 @@ class SarvamLLMConfiguration(BaseLLMConfiguration): OPENAI_REALTIME_MODELS = ["gpt-realtime-2"] +# ISO 639-1 codes accepted by the Realtime API's input_audio_transcription. +# Not exhaustive — the field allows custom input. +OPENAI_REALTIME_LANGUAGES = [ + "en", + "es", + "pt", + "fr", + "de", + "it", + "hi", + "ja", + "ko", + "zh", +] OPENAI_REALTIME_VOICES = [ "alloy", "ash", @@ -618,6 +632,17 @@ class OpenAIRealtimeLLMConfiguration(BaseLLMConfiguration): "allow_custom_input": True, }, ) + language: str | None = Field( + default=None, + description=( + "ISO 639-1 language code for input audio transcription (e.g. 'pt', 'es'). " + "Improves transcription accuracy and latency. Leave unset to auto-detect." + ), + json_schema_extra={ + "examples": OPENAI_REALTIME_LANGUAGES, + "allow_custom_input": True, + }, + ) GROK_REALTIME_MODELS = ["grok-voice-think-fast-1.0"] diff --git a/api/services/pipecat/service_factory.py b/api/services/pipecat/service_factory.py index e8a357a1..d34abd48 100644 --- a/api/services/pipecat/service_factory.py +++ b/api/services/pipecat/service_factory.py @@ -1008,6 +1008,13 @@ def create_realtime_llm_service(user_config, audio_config: "AudioConfig"): SessionProperties, ) + # Pin the transcription language when configured. Without it the model + # auto-detects per utterance, which misfires on short/noisy telephony + # audio (e.g. Portuguese transcribed as English or Chinese). + transcription_kwargs = {} + if language: + transcription_kwargs["language"] = language + return DograhOpenAIRealtimeLLMService( api_key=api_key, settings=DograhOpenAIRealtimeLLMService.Settings( @@ -1015,7 +1022,9 @@ def create_realtime_llm_service(user_config, audio_config: "AudioConfig"): session_properties=SessionProperties( audio=AudioConfiguration( input=AudioInput( - transcription=InputAudioTranscription(), + transcription=InputAudioTranscription( + **transcription_kwargs + ), ), output=AudioOutput( voice=voice or "alloy",