Signed-off-by: reidliu41 <reid201711@gmail.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
86 lines
3.1 KiB
Python
86 lines
3.1 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from vllm_omni.lora.request import LoRARequest
|
|
from vllm_omni.lora.utils import stable_lora_int_id
|
|
|
|
|
|
def get_stage_type(stage_cfg: Any) -> str:
|
|
"""Best-effort stage type resolver across dict/omegaconf/object configs."""
|
|
if isinstance(stage_cfg, dict):
|
|
return stage_cfg.get("stage_type", "llm")
|
|
if hasattr(stage_cfg, "get"):
|
|
try:
|
|
return stage_cfg.get("stage_type", "llm")
|
|
except Exception:
|
|
pass
|
|
return getattr(stage_cfg, "stage_type", "llm")
|
|
|
|
|
|
def parse_lora_request(lora_body: Any) -> tuple[LoRARequest | None, float | None]:
|
|
"""Parse a request-level LoRA object into a LoRARequest and optional scale.
|
|
|
|
Raises:
|
|
ValueError: If the object shape is invalid or required fields are missing.
|
|
"""
|
|
if lora_body is None:
|
|
return None, None
|
|
|
|
if not isinstance(lora_body, dict):
|
|
raise ValueError("Invalid lora field: expected an object.")
|
|
|
|
lora_name = lora_body.get("name") or lora_body.get("lora_name") or lora_body.get("adapter")
|
|
lora_path = (
|
|
lora_body.get("local_path")
|
|
or lora_body.get("path")
|
|
or lora_body.get("lora_path")
|
|
or lora_body.get("lora_local_path")
|
|
)
|
|
lora_scale = lora_body.get("scale")
|
|
if lora_scale is None:
|
|
lora_scale = lora_body.get("lora_scale")
|
|
lora_int_id = lora_body.get("int_id")
|
|
if lora_int_id is None:
|
|
lora_int_id = lora_body.get("lora_int_id")
|
|
if lora_int_id is None and lora_path:
|
|
lora_int_id = stable_lora_int_id(str(lora_path))
|
|
|
|
if not lora_name or not lora_path:
|
|
raise ValueError("Invalid lora object: both name and path are required.")
|
|
|
|
scale = float(lora_scale) if lora_scale is not None else None
|
|
return LoRARequest(str(lora_name), int(lora_int_id), str(lora_path)), scale
|
|
|
|
|
|
def get_supported_speakers_from_hf_config(hf_config: Any) -> set[str]:
|
|
"""Extract supported speaker names from a model hf_config."""
|
|
config = (
|
|
hf_config.get("talker_config") if isinstance(hf_config, dict) else getattr(hf_config, "talker_config", None)
|
|
)
|
|
if config is None:
|
|
return set()
|
|
|
|
for spk_attr in ("speaker_id", "spk_id"):
|
|
speakers_dict = config.get(spk_attr) if isinstance(config, dict) else getattr(config, spk_attr, None)
|
|
if speakers_dict and isinstance(speakers_dict, dict):
|
|
return {speaker.lower() for speaker in speakers_dict}
|
|
return set()
|
|
|
|
|
|
def validate_requested_speaker(speaker: str | None, supported_speakers: set[str]) -> str | None:
|
|
"""Normalize and validate an optional speaker value.
|
|
|
|
Returns the normalized speaker string when provided, otherwise ``None``.
|
|
Raises ``ValueError`` when the speaker is not in the supported list.
|
|
"""
|
|
if not isinstance(speaker, str) or not speaker.strip():
|
|
return None
|
|
|
|
normalized = speaker.lower().strip()
|
|
if supported_speakers and normalized not in supported_speakers:
|
|
raise ValueError(f"Invalid speaker '{speaker}'. Supported: {', '.join(sorted(supported_speakers))}")
|
|
return normalized
|