[Higgs-Audio] bosonai/higgs-audio-v2-generation-3B-base TTS model support (#3762)

Signed-off-by: Yuekai Zhang <zhangyuekai@foxmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Yueqian Lin <70319226+linyueqian@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-05-25 23:16:07 +08:00
1 parent 80dea88007
commit 8f45e68bcd
25 files changed
+4835 -2

No files matched your search

@@ -100,6 +100,50 @@ class OpenAICreateSpeechRequest(BaseModel):
raise ValueError("'speaker_embedding' values must be finite (no NaN or Inf)")
return v
@model_validator(mode="before")
@classmethod
def reject_higgs_audio_v2_unsupported_aliases(cls, data):
"""Reject unsupported rich-input aliases for higgs_audio_v2 BEFORE pydantic strips them.
OpenAICreateSpeechRequest is a permissive schema (it accepts any extra
field that the OpenAI Speech API didn't promise to ban) but several
of those aliases pull a request out of the v1 higgs_audio_v2 scope.
Catching them at parse time lets the API return a deterministic 4xx
with a model-specific error message instead of silently dropping the
field and proceeding with a degraded request.
"""
# Keys that are silently dropped by pydantic when posted to /v1/audio/speech
# (the schema doesn't declare them) but which a model-specific
# validator MUST be able to reject. Kept inline to avoid clashing
# with pydantic's ModelPrivateAttr discovery for class-level
# underscore-prefixed attributes.
higgs_audio_v2_reserved_keys = (
"messages", # ChatML rich content (out of scope for v1)
"reference_audio", # voice-cloning alias 1
"voice_prompt", # voice-cloning alias 2
"speaker_audio", # voice-cloning alias 3
"speakers", # multi-speaker dialogue
)
if not isinstance(data, dict):
return data
model_id = data.get("model")
if not isinstance(model_id, str):
return data
# Match the "higgs_audio_v2" model_type label, the HF architecture id
# in pipeline_registry.hf_architectures, and the hyphenated HF repo id
# (e.g. "bosonai/higgs-audio-v2-generation-3B-base") by normalizing
# both underscores and hyphens out of the id before substring matching.
normalized = model_id.lower().replace("-", "").replace("_", "")
if "higgsaudiov2" not in normalized:
return data
offending = sorted(k for k in higgs_audio_v2_reserved_keys if k in data)
if offending:
raise ValueError(
"higgs_audio_v2 v1 does not support these rich-input fields: "
f"{offending}. Supply plain text via the 'input' field instead."
)
return data
@model_validator(mode="after")
def validate_embedding_constraints(self) -> "OpenAICreateSpeechRequest":
if self.speaker_embedding is not None: