[Bugfix][CI] Vendor Qwen3-TTS and CosyVoice3 reference audio fixtures (#3267)
Signed-off-by: Yueqian Lin <linyueqian@outlook.com>
This commit is contained in:
1 parent
b9789091e9
commit
b1ff695029
10 files changed
+53
-11
No files matched your search
@@ -27,6 +27,7 @@
|
|||||||
*.mov binary
|
*.mov binary
|
||||||
*.mp4 binary
|
*.mp4 binary
|
||||||
*.mp3 binary
|
*.mp3 binary
|
||||||
|
*.wav binary
|
||||||
*.flv binary
|
*.flv binary
|
||||||
*.fla binary
|
*.fla binary
|
||||||
*.swf binary
|
*.swf binary
|
||||||
|
|||||||
@@ -264,6 +264,8 @@ tmp_test
|
|||||||
vllm_omni/_version.py
|
vllm_omni/_version.py
|
||||||
# output files
|
# output files
|
||||||
*.wav
|
*.wav
|
||||||
|
# Vendored test reference audio (small, intentionally checked in)
|
||||||
|
!tests/assets/**/*.wav
|
||||||
.worktrees/
|
.worktrees/
|
||||||
# CI overlay yamls materialized from tests/utils.py:_CI_OVERLAYS at test time
|
# CI overlay yamls materialized from tests/utils.py:_CI_OVERLAYS at test time
|
||||||
tests/.ci_generated/
|
tests/.ci_generated/
|
||||||
Binary file not shown.
Binary file not shown.
@@ -13,10 +13,8 @@ verifies a stable reference recipe:
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import io
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib.request import urlopen
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pytest
|
import pytest
|
||||||
@@ -25,6 +23,7 @@ from huggingface_hub import snapshot_download
|
|||||||
from vllm.sampling_params import SamplingParams
|
from vllm.sampling_params import SamplingParams
|
||||||
|
|
||||||
from tests.helpers.mark import hardware_test
|
from tests.helpers.mark import hardware_test
|
||||||
|
from tests.helpers.media import test_asset_path
|
||||||
from tests.helpers.runtime import OmniRunner
|
from tests.helpers.runtime import OmniRunner
|
||||||
from tests.helpers.stage_config import get_deploy_config_path
|
from tests.helpers.stage_config import get_deploy_config_path
|
||||||
from vllm_omni.model_executor.models.cosyvoice3.config import CosyVoice3Config
|
from vllm_omni.model_executor.models.cosyvoice3.config import CosyVoice3Config
|
||||||
@@ -33,7 +32,9 @@ from vllm_omni.model_executor.models.cosyvoice3.tokenizer import get_qwen_tokeni
|
|||||||
MODEL = "FunAudioLLM/Fun-CosyVoice3-0.5B-2512"
|
MODEL = "FunAudioLLM/Fun-CosyVoice3-0.5B-2512"
|
||||||
MODEL_DIR_ENV = "VLLM_OMNI_COSYVOICE3_MODEL_DIR"
|
MODEL_DIR_ENV = "VLLM_OMNI_COSYVOICE3_MODEL_DIR"
|
||||||
|
|
||||||
REFERENCE_PROMPT_WAV_URL = "https://raw.githubusercontent.com/FunAudioLLM/CosyVoice/main/asset/zero_shot_prompt.wav"
|
# Vendored under tests/assets/cosyvoice3/ so the test does not depend on
|
||||||
|
# raw.githubusercontent.com being reachable from CI runners.
|
||||||
|
REFERENCE_PROMPT_WAV_PATH = test_asset_path("cosyvoice3/zero_shot_prompt.wav")
|
||||||
REFERENCE_PROMPT_TEXT = "You are a helpful assistant.<|endofprompt|>希望你以后能够做的比我还好呦。"
|
REFERENCE_PROMPT_TEXT = "You are a helpful assistant.<|endofprompt|>希望你以后能够做的比我还好呦。"
|
||||||
REFERENCE_SYNTH_TEXT = (
|
REFERENCE_SYNTH_TEXT = (
|
||||||
"CosyVoice is undergoing a comprehensive upgrade, providing more accurate, "
|
"CosyVoice is undergoing a comprehensive upgrade, providing more accurate, "
|
||||||
@@ -51,9 +52,7 @@ ASYNC_CHUNK_MODES = [
|
|||||||
|
|
||||||
@functools.lru_cache(maxsize=1)
|
@functools.lru_cache(maxsize=1)
|
||||||
def _load_reference_prompt_wav() -> tuple[np.ndarray, int]:
|
def _load_reference_prompt_wav() -> tuple[np.ndarray, int]:
|
||||||
with urlopen(REFERENCE_PROMPT_WAV_URL, timeout=30) as resp:
|
audio, sr = sf.read(str(REFERENCE_PROMPT_WAV_PATH), dtype="float32", always_2d=False)
|
||||||
data = resp.read()
|
|
||||||
audio, sr = sf.read(io.BytesIO(data), dtype="float32", always_2d=False)
|
|
||||||
if isinstance(audio, np.ndarray) and audio.ndim > 1:
|
if isinstance(audio, np.ndarray) and audio.ndim > 1:
|
||||||
audio = np.mean(audio, axis=-1)
|
audio = np.mean(audio, axis=-1)
|
||||||
return np.asarray(audio, dtype=np.float32), int(sr)
|
return np.asarray(audio, dtype=np.float32), int(sr)
|
||||||
|
|||||||
@@ -16,10 +16,12 @@ os.environ["VLLM_TEST_CLEAN_GPU_MEMORY"] = "0"
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tests.helpers.mark import hardware_test
|
from tests.helpers.mark import hardware_test
|
||||||
|
from tests.helpers.media import load_test_audio_data_url
|
||||||
from tests.helpers.stage_config import get_deploy_config_path, modify_stage_config
|
from tests.helpers.stage_config import get_deploy_config_path, modify_stage_config
|
||||||
|
|
||||||
MODEL = "Qwen/Qwen3-TTS-12Hz-0.6B-Base"
|
MODEL = "Qwen/Qwen3-TTS-12Hz-0.6B-Base"
|
||||||
REF_AUDIO_URL = "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-TTS-Repo/clone_2.wav"
|
# See tests/e2e/online_serving/test_qwen3_tts_base.py for the vendored-asset rationale.
|
||||||
|
REF_AUDIO_URL = load_test_audio_data_url("qwen3_tts/clone_2.wav")
|
||||||
REF_TEXT = "Okay. Yeah. I resent you. I love you. I respect you. But you know what? You blew it! And thanks to you."
|
REF_TEXT = "Okay. Yeah. I resent you. I love you. I respect you. But you know what? You blew it! And thanks to you."
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,16 @@ os.environ["VLLM_TEST_CLEAN_GPU_MEMORY"] = "0"
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tests.helpers.mark import hardware_test
|
from tests.helpers.mark import hardware_test
|
||||||
|
from tests.helpers.media import load_test_audio_data_url
|
||||||
from tests.helpers.runtime import OmniServerParams
|
from tests.helpers.runtime import OmniServerParams
|
||||||
from tests.helpers.stage_config import get_deploy_config_path
|
from tests.helpers.stage_config import get_deploy_config_path
|
||||||
|
|
||||||
MODEL = "FunAudioLLM/Fun-CosyVoice3-0.5B-2512"
|
MODEL = "FunAudioLLM/Fun-CosyVoice3-0.5B-2512"
|
||||||
|
|
||||||
# Official CosyVoice zero-shot prompt audio and its transcript
|
# Official CosyVoice zero-shot prompt audio and its transcript. Vendored under
|
||||||
REF_AUDIO_URL = "https://raw.githubusercontent.com/FunAudioLLM/CosyVoice/main/asset/zero_shot_prompt.wav"
|
# tests/assets/ so the server does not depend on raw.githubusercontent.com being
|
||||||
|
# reachable at request time (same rationale as issue #3263 for Qwen3-TTS).
|
||||||
|
REF_AUDIO_URL = load_test_audio_data_url("cosyvoice3/zero_shot_prompt.wav")
|
||||||
REF_TEXT = "希望你以后能够做的比我还好呦。"
|
REF_TEXT = "希望你以后能够做的比我还好呦。"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,16 @@ os.environ["VLLM_TEST_CLEAN_GPU_MEMORY"] = "0"
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tests.helpers.mark import hardware_test
|
from tests.helpers.mark import hardware_test
|
||||||
|
from tests.helpers.media import load_test_audio_data_url
|
||||||
from tests.helpers.runtime import OmniServerParams
|
from tests.helpers.runtime import OmniServerParams
|
||||||
from tests.helpers.stage_config import get_deploy_config_path
|
from tests.helpers.stage_config import get_deploy_config_path
|
||||||
|
|
||||||
MODEL = "Qwen/Qwen3-TTS-12Hz-0.6B-Base"
|
MODEL = "Qwen/Qwen3-TTS-12Hz-0.6B-Base"
|
||||||
|
|
||||||
REF_AUDIO_URL = "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-TTS-Repo/clone_2.wav"
|
# Vendored under tests/assets/qwen3_tts/clone_2.wav so the server does not need
|
||||||
|
# to fetch the reference audio over HTTPS at request time (CI runners in some
|
||||||
|
# regions cannot reach the original Aliyun OSS host; see issue #3263).
|
||||||
|
REF_AUDIO_URL = load_test_audio_data_url("qwen3_tts/clone_2.wav")
|
||||||
REF_TEXT = "Okay. Yeah. I resent you. I love you. I respect you. But you know what? You blew it! And thanks to you."
|
REF_TEXT = "Okay. Yeah. I resent you. I love you. I respect you. But you know what? You blew it! And thanks to you."
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import os
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from tests.helpers.mark import hardware_test
|
from tests.helpers.mark import hardware_test
|
||||||
|
from tests.helpers.media import load_test_audio_data_url
|
||||||
from tests.helpers.runtime import OmniServerParams
|
from tests.helpers.runtime import OmniServerParams
|
||||||
from tests.helpers.stage_config import get_deploy_config_path
|
from tests.helpers.stage_config import get_deploy_config_path
|
||||||
|
|
||||||
@@ -22,7 +23,8 @@ os.environ["VLLM_TEST_CLEAN_GPU_MEMORY"] = "0"
|
|||||||
|
|
||||||
MODEL = "Qwen/Qwen3-TTS-12Hz-0.6B-Base"
|
MODEL = "Qwen/Qwen3-TTS-12Hz-0.6B-Base"
|
||||||
|
|
||||||
REF_AUDIO_URL = "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-TTS-Repo/clone_2.wav"
|
# See tests/e2e/online_serving/test_qwen3_tts_base.py for the vendored-asset rationale.
|
||||||
|
REF_AUDIO_URL = load_test_audio_data_url("qwen3_tts/clone_2.wav")
|
||||||
REF_TEXT = "Okay. Yeah. I resent you. I love you. I respect you. But you know what? You blew it! And thanks to you."
|
REF_TEXT = "Okay. Yeah. I resent you. I love you. I respect you. But you know what? You blew it! And thanks to you."
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -496,6 +496,33 @@ def generate_synthetic_image(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_TEST_ASSETS_ROOT = Path(__file__).resolve().parents[1] / "assets"
|
||||||
|
|
||||||
|
_AUDIO_MIME_BY_SUFFIX = {
|
||||||
|
".wav": "audio/wav",
|
||||||
|
".mp3": "audio/mpeg",
|
||||||
|
".flac": "audio/flac",
|
||||||
|
".ogg": "audio/ogg",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_asset_path(relative_path: str | os.PathLike) -> Path:
|
||||||
|
"""Resolve a path under ``tests/assets/`` to its absolute on-disk location."""
|
||||||
|
return _TEST_ASSETS_ROOT / Path(relative_path)
|
||||||
|
|
||||||
|
|
||||||
|
def load_test_audio_data_url(relative_path: str | os.PathLike) -> str:
|
||||||
|
"""Load a vendored test audio file under ``tests/assets/`` as a base64 data URL.
|
||||||
|
|
||||||
|
Used by tests that need real reference audio (e.g. voice cloning) without
|
||||||
|
relying on the server's ability to fetch external URLs at request time.
|
||||||
|
"""
|
||||||
|
path = test_asset_path(relative_path)
|
||||||
|
mime = _AUDIO_MIME_BY_SUFFIX.get(path.suffix.lower(), "application/octet-stream")
|
||||||
|
encoded = base64.b64encode(path.read_bytes()).decode("ascii")
|
||||||
|
return f"data:{mime};base64,{encoded}"
|
||||||
|
|
||||||
|
|
||||||
def decode_b64_image(b64: str):
|
def decode_b64_image(b64: str):
|
||||||
img = Image.open(io.BytesIO(base64.b64decode(b64)))
|
img = Image.open(io.BytesIO(base64.b64decode(b64)))
|
||||||
img.load()
|
img.load()
|
||||||
@@ -653,5 +680,7 @@ __all__ = [
|
|||||||
"generate_synthetic_audio",
|
"generate_synthetic_audio",
|
||||||
"generate_synthetic_image",
|
"generate_synthetic_image",
|
||||||
"generate_synthetic_video",
|
"generate_synthetic_video",
|
||||||
|
"load_test_audio_data_url",
|
||||||
"preprocess_text",
|
"preprocess_text",
|
||||||
|
"test_asset_path",
|
||||||
]
|
]
|
||||||
Reference in new issue
Block a user