2026-03-30 13:02:28 +08:00
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""
E2E Online tests for Qwen3-TTS model with text input and audio output.
These tests verify the /v1/audio/speech endpoint works correctly with
actual model inference, not mocks.
"""
import os
os . environ [ "VLLM_WORKER_MULTIPROC_METHOD" ] = "spawn"
import pytest
2026-04-20 14:23:42 +08:00
from tests.helpers.mark import hardware_test
from tests.helpers.runtime import OmniServerParams
2026-07-25 16:09:19 +08:00
from tests.helpers.stage_config import (
get_deploy_config_path ,
get_deploy_config_stage ,
modify_stage_config ,
)
2026-03-30 13:02:28 +08:00
MODEL = "Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice"
2026-07-25 16:09:19 +08:00
_DEFAULT_STAGE_CONFIG = get_deploy_config_path ( "qwen3_tts.yaml" )
2026-06-29 13:17:57 +08:00
_STAGE_CONFIG = modify_stage_config (
2026-07-25 16:09:19 +08:00
_DEFAULT_STAGE_CONFIG ,
2026-06-29 13:17:57 +08:00
updates = { "stages" : { 0 : { "default_sampling_params.max_tokens" : 500 }}},
)
2026-03-30 13:02:28 +08:00
def get_prompt ( prompt_type = "text" ):
"""Text prompt for text-to-audio tests (same as test_qwen3_omni - beijing test case)."""
prompts = {
"text" : "Beijing, China's capital, blends ancient wonders like the Great Wall with modern marvels. This vibrant metropolis offers rich culture, delicious Peking duck, and endless exploration opportunities." ,
}
return prompts . get ( prompt_type , prompts [ "text" ])
def get_max_batch_size ( size_type = "few" ):
"""Batch size for concurrent requests (same as test_qwen3_omni)."""
batch_sizes = { "few" : 5 , "medium" : 100 , "large" : 256 }
return batch_sizes . get ( size_type , 5 )
tts_server_params = [
pytest . param (
OmniServerParams (
model = MODEL ,
2026-06-29 13:17:57 +08:00
stage_config_path = _STAGE_CONFIG ,
2026-05-12 10:23:56 +08:00
server_args = [ "--trust-remote-code" ],
2026-03-30 13:02:28 +08:00
),
id = "async_chunk" ,
)
]
2026-07-25 16:09:19 +08:00
default_tts_server_params = [
pytest . param (
OmniServerParams (
model = MODEL ,
stage_config_path = _DEFAULT_STAGE_CONFIG ,
server_args = [ "--trust-remote-code" ],
),
id = "async_chunk" ,
)
]
@pytest.mark.core_model
@pytest.mark.advanced_model
@pytest.mark.tts
@hardware_test ( res = { "cuda" : "L4" }, num_cards = 1 )
@pytest.mark.parametrize ( "omni_server" , default_tts_server_params , indirect = True )
def test_default_cuda_graph_startup ( omni_server ) -> None :
"""Verify both stages start with the shipped CUDA Graph configuration.
The fixture reaching this test is the smoke assertion: it waits for the
server to become ready after both stages finish model initialization and
CUDA Graph capture. The regression covered here exited during stage 1
capture, before fixture setup could complete.
"""
for stage_id in ( 0 , 1 ):
stage = get_deploy_config_stage ( "qwen3_tts.yaml" , stage_id = stage_id )
assert stage . get ( "enforce_eager" , False ) is False
assert omni_server . proc is not None
assert omni_server . proc . poll () is None
2026-03-30 13:02:28 +08:00
@pytest.mark.core_model
@pytest.mark.advanced_model
2026-05-08 14:12:23 +08:00
@pytest.mark.tts
2026-07-28 15:26:36 +08:00
@hardware_test ( res = { "cuda" : "L4" , "npu" : "A3" }, num_cards = 1 )
2026-03-30 13:02:28 +08:00
@pytest.mark.parametrize ( "omni_server" , tts_server_params , indirect = True )
def test_text_to_audio_001 ( omni_server , openai_client ) -> None :
"""
Test text input processing and audio output via OpenAI API.
Deploy Setting: default yaml
Input Modal: text
Output Modal: audio
Input Setting: stream=False
Datasets: few requests
"""
request_config = {
"model" : omni_server . model ,
"input" : get_prompt (),
"stream" : False ,
"response_format" : "wav" ,
"task_type" : "CustomVoice" ,
"voice" : "vivian" ,
}
openai_client . send_audio_speech_request ( request_config , request_num = get_max_batch_size ())
@pytest.mark.core_model
@pytest.mark.advanced_model
2026-05-08 14:12:23 +08:00
@pytest.mark.tts
2026-07-28 15:26:36 +08:00
@hardware_test ( res = { "cuda" : "L4" , "npu" : "A3" }, num_cards = 1 )
2026-03-30 13:02:28 +08:00
@pytest.mark.parametrize ( "omni_server" , tts_server_params , indirect = True )
def test_text_to_audio_002 ( omni_server , openai_client ) -> None :
"""
Test text input processing and audio output via OpenAI API.
Deploy Setting: default yaml
Input Modal: text
Output Modal: audio
Input Setting: stream=True
Datasets: single request
"""
request_config = {
"model" : omni_server . model ,
"input" : get_prompt (),
"stream" : True ,
2026-06-30 10:17:24 +08:00
"stream_format" : "audio" ,
2026-03-30 13:02:28 +08:00
"response_format" : "wav" ,
"task_type" : "CustomVoice" ,
"voice" : "vivian" ,
}
openai_client . send_audio_speech_request ( request_config )