Files
vllm-omni/vllm_omni/model_executor/models/audex/prompt.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

84 lines
3.8 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Audex TTS/TTA prompt construction.
The Audex thinker consumes the exact ChatML prompt used by the official
inference script (``inference_scripts_vllm/audiogen_scripts/run_audio_gen_vllm.py``
in the nvidia/Nemotron-Labs-Audex-2B repo). The checkpoint's bundled chat
template opens a thinking block (``<think>\\n``) instead of the closed
``<think></think>`` + ``<speechgen_start>`` priming that TTS generation
requires, so the prompt is built from a literal template here; a unit test
pins it byte-for-byte against the official format.
``build_null_prompt`` is the unconditional-prompt counterpart used by
classifier-free guidance: the transcription is replaced with repeated
``<unk>`` tokens, iteratively adjusted so the tokenized null prompt is
exactly as long as the conditional prompt (the CFG pair must decode the
same positions).
"""
AUDEX_SYSTEM_PROMPT = "You are a helpful and harmless assistant.\n\nYou are not allowed to use any tools."
# ``{text}`` carries its own leading whitespace: the conditional prompt uses
# " {transcription}" (matching the official script byte-for-byte), while the
# CFG null prompt inserts the bare ``<unk>`` run. ``<unk>`` is a special
# token, so a leading space would tokenize as a standalone space token and
# make some conditional lengths unreachable by whole-``<unk>`` steps.
_TTS_PROMPT_TEMPLATE = (
"<|im_start|>system\n{system_prompt}<|im_end|>\n"
"<|im_start|>user\n<|text to speech|> Generate speech for this transcription.{text}<|im_end|>\n"
"<|im_start|>assistant\n<think></think><speechgen_start>"
)
_TTA_PROMPT_TEMPLATE = (
"<|im_start|>system\n{system_prompt}<|im_end|>\n"
"<|im_start|>user\n<|text to audio|> Generate audio for this caption.{text}<|im_end|>\n"
"<|im_start|>assistant\n<think></think><audiogen_start>"
)
def build_cond_prompt(text: str) -> str:
"""Build the conditional TTS prompt for one transcription."""
text = text.strip()
if not text:
raise ValueError("Audex TTS requires non-empty input text")
return _TTS_PROMPT_TEMPLATE.format(system_prompt=AUDEX_SYSTEM_PROMPT, text=f" {text}")
def build_tta_cond_prompt(caption: str) -> str:
"""Build the conditional TTA prompt for one audio caption."""
caption = caption.strip()
if not caption:
raise ValueError("Audex TTA requires a non-empty caption")
return _TTA_PROMPT_TEMPLATE.format(system_prompt=AUDEX_SYSTEM_PROMPT, text=f" {caption}")
def _length_matched_null(cond_prompt: str, tokenizer, template: str, max_iters: int) -> str:
target_len = len(tokenizer.encode(cond_prompt))
n_unk = 1
for _ in range(max_iters):
prompt = template.format(system_prompt=AUDEX_SYSTEM_PROMPT, text="<unk>" * n_unk)
diff = target_len - len(tokenizer.encode(prompt))
if diff == 0:
return prompt
n_unk = max(1, n_unk + diff)
if diff < 0 and n_unk == 1:
break
raise ValueError(f"Could not length-match the CFG null prompt to {target_len} tokens")
def build_null_prompt(cond_prompt: str, tokenizer, max_iters: int = 64) -> str:
"""Unconditional TTS prompt for CFG (length-matched ``<unk>`` padding).
Replaces the transcription with ``<unk>`` repeated, adjusting the count
until ``tokenizer.encode`` yields exactly the conditional prompt's
length. Raises when no count matches so callers can fail the request
instead of submitting a misaligned pair.
"""
return _length_matched_null(cond_prompt, tokenizer, _TTS_PROMPT_TEMPLATE, max_iters)
def build_tta_null_prompt(cond_prompt: str, tokenizer, max_iters: int = 64) -> str:
"""Unconditional TTA prompt for CFG (length-matched ``<unk>`` padding)."""
return _length_matched_null(cond_prompt, tokenizer, _TTA_PROMPT_TEMPLATE, max_iters)