[Feature][TTS] Add Speech API streaming metrics (#6853)

Signed-off-by: XIN GAO <1037396230@qq.com>
Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
This commit is contained in:
GXINandHongsheng Liu authored and GitHub committed 2026-09-11 21:22:15 +08:00
1 parent 02aaa34059
commit 33fff2155e
10 files changed
+895 -92

No files matched your search

@@ -48,7 +48,14 @@ def _build_test_app(
speech_service.forced_aligner_enabled = False
async def mock_generate_pcm_chunks(
_generator, _request_id, *, include_sample_rate=False, tts_params=None, collect=None
_generator,
_request_id,
*,
request_start_s=None,
request_arrival_ts=None,
include_sample_rate=False,
tts_params=None,
collect=None,
):
for chunk in (b"\x01\x02", b"\x03\x04\x05"):
yield (chunk, 24000) if include_sample_rate else chunk
@@ -249,6 +256,7 @@ class TestStreamingSpeechWebSocket:
def test_streaming_multiple_binary_frames(self, mocker: MockerFixture):
captured_requests = []
captured_timing = {}
captured_tts_params = []
speech_service = mocker.MagicMock(spec=OmniOpenAIServingSpeech)
@@ -257,13 +265,27 @@ class TestStreamingSpeechWebSocket:
speech_service.engine_client.abort = mocker.AsyncMock()
speech_service.forced_aligner_enabled = False
async def mock_prepare_speech_generation(request):
async def mock_prepare_speech_generation(request, *, arrival_time=None):
captured_requests.append(request)
assert arrival_time is not None
captured_timing["prepare_arrival"] = arrival_time
return "req-stream", object(), {"_qwen3_tts_effective_max_tokens": [192]}
speech_service._prepare_speech_generation = mock_prepare_speech_generation
async def mock_generate_pcm_chunks(_generator, _request_id, *, include_sample_rate=False, tts_params=None):
async def mock_generate_pcm_chunks(
_generator,
_request_id,
*,
request_start_s=None,
request_arrival_ts=None,
include_sample_rate=False,
tts_params=None,
):
assert request_start_s is not None
assert request_arrival_ts is not None
captured_timing["chunk_start"] = request_start_s
captured_timing["chunk_arrival"] = request_arrival_ts
captured_tts_params.append(tts_params)
for chunk in (b"\x01\x02", b"\x03\x04\x05", b"\x06"):
yield (chunk, 24000) if include_sample_rate else chunk
@@ -309,6 +331,8 @@ class TestStreamingSpeechWebSocket:
assert captured_requests[0].stream is True
assert captured_requests[0].response_format == "pcm"
assert captured_requests[0].initial_codec_chunk_frames == 12
assert captured_timing["prepare_arrival"] == captured_timing["chunk_arrival"]
assert captured_timing["chunk_start"] > 0
assert captured_tts_params == [{"_qwen3_tts_effective_max_tokens": [192]}]
assert speech_service._generate_audio_bytes.await_count == 0
@@ -341,8 +365,9 @@ class TestStreamingSpeechWebSocket:
speech_service.engine_client.abort = mocker.AsyncMock()
speech_service.forced_aligner_enabled = True
async def mock_prepare_speech_generation(request):
async def mock_prepare_speech_generation(request, *, arrival_time=None):
captured_requests.append(request)
assert arrival_time is not None
return "req-stream", object(), {}
speech_service._prepare_speech_generation = mock_prepare_speech_generation
@@ -353,8 +378,17 @@ class TestStreamingSpeechWebSocket:
# The forced-aligner stage rides the same generator: its pooling output
# is surfaced via the ``collect`` channel once the audio has streamed.
async def mock_generate_pcm_chunks(
_generator, _request_id, *, include_sample_rate=False, tts_params=None, collect=None
_generator,
_request_id,
*,
request_start_s=None,
request_arrival_ts=None,
include_sample_rate=False,
tts_params=None,
collect=None,
):
assert request_start_s is not None
assert request_arrival_ts is not None
for chunk in (first_chunk, second_chunk):
yield (chunk, 1000) if include_sample_rate else chunk
if collect is not None:
@@ -438,7 +472,14 @@ class TestStreamingSpeechWebSocket:
speech_service._prepare_speech_generation = mocker.AsyncMock(return_value=("req", object(), {}))
async def mock_generate_pcm_chunks(
_generator, _request_id, *, include_sample_rate=False, tts_params=None, collect=None
_generator,
_request_id,
*,
request_start_s=None,
request_arrival_ts=None,
include_sample_rate=False,
tts_params=None,
collect=None,
):
chunk = b"\x01" * 1000
yield (chunk, 1000) if include_sample_rate else chunk
@@ -620,7 +661,15 @@ class TestStreamingSpeechWebSocket:
speech_service.engine_client.abort = mocker.AsyncMock()
speech_service.forced_aligner_enabled = False
async def mock_generate_pcm_chunks(_generator, _request_id, *, include_sample_rate=False, tts_params=None):
async def mock_generate_pcm_chunks(
_generator,
_request_id,
*,
request_start_s=None,
request_arrival_ts=None,
include_sample_rate=False,
tts_params=None,
):
yield b"\x01\x02"
raise RuntimeError("stream boom")
@@ -716,7 +765,15 @@ class TestStreamingSpeechWebSocket:
speech_service.engine_client.abort = mocker.AsyncMock()
speech_service.forced_aligner_enabled = False
async def mock_generate_pcm_chunks(_generator, _request_id, *, include_sample_rate=False, tts_params=None):
async def mock_generate_pcm_chunks(
_generator,
_request_id,
*,
request_start_s=None,
request_arrival_ts=None,
include_sample_rate=False,
tts_params=None,
):
yield b"\x01\x02"
speech_service._generate_pcm_chunks = mock_generate_pcm_chunks