Skip to content

Commit 73e3729

Browse files
committed
feat(model/omni):support session.audio.input/output
1 parent f974f10 commit 73e3729

2 files changed

Lines changed: 145 additions & 4 deletions

File tree

dashscope/audio/qwen_omni/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
from .omni_realtime import (
55
AudioFormat,
6+
AudioFormatConfig,
7+
AudioFormatType,
8+
AudioSampleRate,
69
MultiModality,
710
OmniRealtimeCallback,
811
OmniRealtimeConversation,
@@ -11,6 +14,9 @@
1114
__all__ = [
1215
"OmniRealtimeCallback",
1316
"AudioFormat",
17+
"AudioFormatConfig",
18+
"AudioFormatType",
19+
"AudioSampleRate",
1420
"MultiModality",
1521
"OmniRealtimeConversation",
1622
]

dashscope/audio/qwen_omni/omni_realtime.py

Lines changed: 139 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,92 @@ def __str__(self):
8787
return f"{self.format.upper()} with {self.sample_rate}Hz sample rate, {self.channels} channel, {self.bit_rate} bit rate: {self.format_str}" # noqa: E501 # pylint: disable=line-too-long
8888

8989

90+
class AudioFormatType(Enum):
91+
"""
92+
Preset audio format types for omni realtime input/output audio.
93+
94+
These are provided for convenient reference only. ``AudioFormatConfig``
95+
also accepts any raw string value (e.g. ``"mp3"``) without validation,
96+
so new formats can be used without upgrading the SDK.
97+
"""
98+
99+
PCM = "pcm"
100+
WAV = "wav"
101+
102+
def __str__(self):
103+
return self.value
104+
105+
106+
@unique
107+
class AudioSampleRate(Enum):
108+
"""
109+
Preset audio sample rates(Hz) for omni realtime input/output audio.
110+
111+
These are provided for convenient reference only. ``AudioFormatConfig``
112+
also accepts any raw int value without validation.
113+
"""
114+
115+
SAMPLE_RATE_8K = 8000
116+
SAMPLE_RATE_16K = 16000
117+
SAMPLE_RATE_24K = 24000
118+
SAMPLE_RATE_48K = 48000
119+
120+
def __int__(self):
121+
return self.value
122+
123+
124+
@dataclass
125+
class AudioFormatConfig:
126+
"""
127+
Audio format config for input(uplink) / output(downlink) audio in a
128+
omni realtime session.
129+
130+
No strict validation is performed: the preset enums are only for
131+
convenient reference, while any raw value is also accepted so that new
132+
formats or sample rates can be used without upgrading the SDK.
133+
134+
Parameters
135+
----------
136+
type: str
137+
audio format type. Presets ``AudioFormatType.PCM`` / ``.WAV`` are
138+
provided for convenience; accepts an ``AudioFormatType`` enum or any
139+
raw string such as ``"pcm"`` / ``"wav"`` / ``"mp3"``.
140+
sample_rate: int
141+
audio sample rate in Hz. Presets ``AudioSampleRate`` (8000 / 16000 /
142+
24000 / 48000) are provided for convenience; accepts an
143+
``AudioSampleRate`` enum or any raw int value.
144+
extra_params: Dict[str, Any]
145+
free extension parameters that will be merged into the ``format``
146+
dict. Reserved for future parameters such as speech rate, e.g.
147+
``{"speech_rate": 1.2}``.
148+
"""
149+
150+
type: Any = AudioFormatType.PCM.value
151+
sample_rate: Any = AudioSampleRate.SAMPLE_RATE_16K.value
152+
extra_params: Dict[str, Any] = field(default_factory=dict)
153+
154+
def to_dict(self) -> Dict[str, Any]:
155+
"""
156+
convert to the ``format`` dict used in the session.update request.
157+
158+
Preset enums are unwrapped to their underlying value; any raw value
159+
is passed through as-is without validation.
160+
"""
161+
format_type = self.type
162+
if isinstance(format_type, AudioFormatType):
163+
format_type = format_type.value
164+
sample_rate = self.sample_rate
165+
if isinstance(sample_rate, AudioSampleRate):
166+
sample_rate = sample_rate.value
167+
result: Dict[str, Any] = {
168+
"type": format_type,
169+
"sample_rate": sample_rate,
170+
}
171+
if self.extra_params:
172+
result.update(self.extra_params)
173+
return result
174+
175+
90176
class MultiModality(Enum):
91177
"""
92178
MultiModality
@@ -232,6 +318,35 @@ def create_item(self, item: dict):
232318
enable_log=True,
233319
)
234320

321+
def _apply_audio_format(
322+
self,
323+
input_audio_format: AudioFormat,
324+
output_audio_format: AudioFormat,
325+
input_audio_config: AudioFormatConfig,
326+
output_audio_config: AudioFormatConfig,
327+
) -> None:
328+
"""
329+
apply audio format config into ``self.config``.
330+
331+
Prefer the new-style ``session.audio.{input,output}.format`` structure
332+
when ``input_audio_config`` / ``output_audio_config`` is provided,
333+
otherwise keep the old-style top-level fields for backward
334+
compatibility.
335+
"""
336+
if input_audio_config is None and output_audio_config is None:
337+
# old-style: keep backward compatibility
338+
self.config["input_audio_format"] = input_audio_format.format_str
339+
self.config["output_audio_format"] = output_audio_format.format_str
340+
return
341+
# new-style: separate audio format type and sample rate under
342+
# session.audio.{input,output}.format
343+
audio: Dict[str, Any] = {}
344+
if input_audio_config is not None:
345+
audio["input"] = {"format": input_audio_config.to_dict()}
346+
if output_audio_config is not None:
347+
audio["output"] = {"format": output_audio_config.to_dict()}
348+
self.config["audio"] = audio
349+
235350
def update_session(
236351
self,
237352
output_modalities: List[MultiModality],
@@ -248,6 +363,8 @@ def update_session(
248363
turn_detection_param: dict = None,
249364
translation_params: TranslationParams = None,
250365
transcription_params: TranscriptionParams = None,
366+
input_audio_config: AudioFormatConfig = None,
367+
output_audio_config: AudioFormatConfig = None,
251368
**kwargs,
252369
) -> None:
253370
"""
@@ -260,9 +377,13 @@ def update_session(
260377
voice: str
261378
voice to be used in session
262379
input_audio_format: AudioFormat
263-
input audio format
380+
input audio format. Deprecated, kept for backward compatibility.
381+
Prefer ``input_audio_config`` which supports separate audio
382+
format type and sample rate.
264383
output_audio_format: AudioFormat
265-
output audio format
384+
output audio format. Deprecated, kept for backward compatibility.
385+
Prefer ``output_audio_config`` which supports separate audio
386+
format type and sample rate.
266387
enable_turn_detection: bool
267388
enable turn detection
268389
turn_detection_threshold: float
@@ -278,13 +399,27 @@ def update_session(
278399
transcription params, include language, sample_rate, input_audio_format, corpus. # noqa: E501 # pylint: disable=line-too-long
279400
Only effective with qwen3-asr-flash-realtime model or
280401
further models. Do not set this parameter for other models.
402+
input_audio_config: AudioFormatConfig
403+
input(uplink) audio format config. Supports separate format type
404+
(pcm/wav) and sample rate (8000/16000/24000/48000), as well as
405+
free extension parameters via ``extra_params``. When provided,
406+
the request emits the ``session.audio.input.format`` structure.
407+
output_audio_config: AudioFormatConfig
408+
output(downlink) audio format config. Supports separate format
409+
type (pcm/wav) and sample rate (8000/16000/24000/48000), as well
410+
as free extension parameters via ``extra_params``. When provided,
411+
the request emits the ``session.audio.output.format`` structure.
281412
"""
282413
self.config = {
283414
"modalities": [m.value for m in output_modalities],
284415
"voice": voice,
285-
"input_audio_format": input_audio_format.format_str,
286-
"output_audio_format": output_audio_format.format_str,
287416
}
417+
self._apply_audio_format(
418+
input_audio_format,
419+
output_audio_format,
420+
input_audio_config,
421+
output_audio_config,
422+
)
288423
if enable_input_audio_transcription:
289424
self.config["input_audio_transcription"] = {
290425
"model": input_audio_transcription_model,

0 commit comments

Comments
 (0)