Files
vllm-omni/tests/e2e/online_serving/test_audex_tta.py
T
5014fea4a0 [New Model] support nemotron Audex (#4976)
Signed-off-by: Yuekai Zhang <zhangyuekai@foxmail.com>
Signed-off-by: Yueqian Lin <linyueqian@outlook.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Yueqian Lin <linyueqian@outlook.com>
Co-authored-by: Yueqian Lin <70319226+linyueqian@users.noreply.github.com>
2026-07-28 03:58:22 +00:00

85 lines
3.0 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""E2E online tests for Audex (Nemotron-Labs-Audex-2B) text-to-audio.
Covers /v1/audio/speech through the ``audex_tta`` deployment:
the ``audex_tta`` adapter builds the caption prompt and the serving layer
injects the RVQ phase contract plus the official default guidance
(cfg_scale 3.0) server-side.
"""
import os
os.environ["VLLM_WORKER_MULTIPROC_METHOD"] = "spawn"
import pytest
from tests.helpers.mark import hardware_test
from tests.helpers.runtime import OmniServerParams
from tests.helpers.stage_config import get_deploy_config_path
pytestmark = [pytest.mark.slow, pytest.mark.tts]
MODEL = "nvidia/Nemotron-Labs-Audex-2B"
CAPTION = "Heavy rain falling on a tin roof."
SAMPLE_RATE = 16_000
audex_tta_server_params = [
pytest.param(
OmniServerParams(
model=MODEL,
stage_config_path=get_deploy_config_path("audex_tta.yaml"),
server_args=["--trust-remote-code"],
),
id="audex_tta",
)
]
# 30B-A3B variant: opt-in (pulls ~60 GB); enable with AUDEX_E2E_30B=1.
_AUDEX_30B_MODEL = os.environ.get("VLLM_OMNI_AUDEX_30B_MODEL_DIR") or "nvidia/Nemotron-Labs-Audex-30B-A3B"
if os.environ.get("AUDEX_E2E_30B") == "1":
audex_tta_server_params.append(
pytest.param(
OmniServerParams(
model=_AUDEX_30B_MODEL,
stage_config_path=get_deploy_config_path("audex_tta_30b.yaml"),
server_args=["--trust-remote-code"],
),
id="online_tta_30b",
)
)
@hardware_test(res={"cuda": "H100"}, num_cards=1)
@pytest.mark.parametrize("omni_server", audex_tta_server_params, indirect=True)
def test_audex_tta_online_smoke(omni_server, openai_client, run_level) -> None:
"""A caption returns a valid finite non-silent WAV at the default cfg 3.0."""
import io
import wave
import numpy as np
import requests
url = f"{openai_client.base_url.rstrip('/')}/v1/audio/speech"
resp = requests.post(
url,
json={"model": omni_server.model, "input": CAPTION, "response_format": "wav"},
timeout=600,
)
assert resp.status_code == 200, resp.text[:200]
assert resp.content[:4] == b"RIFF", "not a WAV response"
with wave.open(io.BytesIO(resp.content)) as wav:
assert wav.getframerate() == SAMPLE_RATE, f"unexpected sample rate {wav.getframerate()}"
frames = wav.readframes(wav.getnframes())
duration_s = wav.getnframes() / wav.getframerate()
audio = np.frombuffer(frames, dtype=np.int16).astype(np.float32) / 32768.0
assert audio.size > 0, "empty audio body"
assert np.isfinite(audio).all(), "audio contains NaN/Inf"
if run_level in {"advanced_model", "full_model"}:
# The decode cap is 500 frames = 10 s at 50 fps.
assert 0.1 <= duration_s <= 10.5, f"unexpected duration={duration_s:.3f}s"
rms = float(np.sqrt(np.mean(np.square(audio))))
assert rms > 1e-4, f"audio is near-silent (rms={rms})"