Studio: tag MLX loaded models as MLX instead of Base in chat (#6067)
* Studio: tag MLX loaded models as MLX instead of Base in chat * Studio: tag MLX named hub defaults via name heuristic
This commit is contained in:
parent
1b588cd141
commit
1e811acd62
7 changed files with 36 additions and 2 deletions
|
|
@ -705,6 +705,7 @@ class InferenceOrchestrator:
|
|||
self.models[self.active_model_name] = {
|
||||
"is_vision": model_info.get("is_vision", False),
|
||||
"is_lora": model_info.get("is_lora", False),
|
||||
"is_mlx": model_info.get("is_mlx", False),
|
||||
"display_name": model_info.get("display_name", model_name),
|
||||
"is_audio": model_info.get("is_audio", False),
|
||||
"audio_type": model_info.get("audio_type"),
|
||||
|
|
|
|||
|
|
@ -342,6 +342,8 @@ def _handle_load(backend, config: dict, resp_queue: Any) -> None:
|
|||
"is_vision": mc.is_vision,
|
||||
"is_lora": mc.is_lora,
|
||||
"is_gguf": False,
|
||||
# MLX backend sets device="mlx"; lets the UI tag MLX models.
|
||||
"is_mlx": getattr(backend, "device", None) == "mlx",
|
||||
"is_audio": getattr(mc, "is_audio", False),
|
||||
"audio_type": getattr(mc, "audio_type", None),
|
||||
"has_audio_input": getattr(mc, "has_audio_input", False),
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ class ModelDetails(BaseModel):
|
|||
is_gguf: bool = Field(
|
||||
False, description = "Whether model is a GGUF model (llama.cpp format)"
|
||||
)
|
||||
is_mlx: bool = Field(
|
||||
False, description = "Whether model is served via the MLX backend (Apple Silicon)"
|
||||
)
|
||||
is_audio: bool = Field(False, description = "Whether model is a TTS audio model")
|
||||
audio_type: Optional[str] = Field(
|
||||
None, description = "Audio codec type: snac, csm, bicodec, dac"
|
||||
|
|
|
|||
|
|
@ -1446,6 +1446,15 @@ async def browse_folders(
|
|||
)
|
||||
|
||||
|
||||
def _looks_like_mlx_repo(model_id: str) -> bool:
|
||||
"""Name heuristic for unloaded models, mirrors the -GGUF suffix check.
|
||||
Tokenized so MLX only matches as a whole name segment."""
|
||||
if model_id.lower().startswith("mlx-community/"):
|
||||
return True
|
||||
tail = model_id.split("/")[-1]
|
||||
return "MLX" in _re.split(r"[-_.]", tail.upper())
|
||||
|
||||
|
||||
@router.get("/list")
|
||||
async def list_models(
|
||||
current_subject: str = Depends(get_current_subject),
|
||||
|
|
@ -1471,6 +1480,7 @@ async def list_models(
|
|||
name = model_name.split("/")[-1] if "/" in model_name else model_name,
|
||||
is_vision = _is_vision,
|
||||
is_lora = model_data.get("is_lora", False),
|
||||
is_mlx = model_data.get("is_mlx", False),
|
||||
is_audio = model_data.get("is_audio", False),
|
||||
audio_type = _audio_type,
|
||||
has_audio_input = model_data.get("has_audio_input", False),
|
||||
|
|
@ -1498,13 +1508,18 @@ async def list_models(
|
|||
all_models = []
|
||||
seen_ids = set()
|
||||
|
||||
# Prefer loaded entries for duplicate ids so runtime flags
|
||||
# (is_mlx, is_vision, is_audio, ...) are not lost.
|
||||
loaded_by_id = {model_info.id: model_info for model_info in loaded_models}
|
||||
|
||||
# Add default models
|
||||
for model_id in default_models:
|
||||
if model_id not in seen_ids:
|
||||
model_info = ModelDetails(
|
||||
model_info = loaded_by_id.get(model_id) or ModelDetails(
|
||||
id = model_id,
|
||||
name = model_id.split("/")[-1] if "/" in model_id else model_id,
|
||||
is_gguf = model_id.upper().endswith("-GGUF"),
|
||||
is_mlx = _looks_like_mlx_repo(model_id),
|
||||
)
|
||||
all_models.append(model_info)
|
||||
seen_ids.add(model_id)
|
||||
|
|
|
|||
|
|
@ -94,16 +94,25 @@ function describeModel(model: {
|
|||
is_lora?: boolean;
|
||||
is_vision?: boolean;
|
||||
is_gguf?: boolean;
|
||||
is_mlx?: boolean;
|
||||
is_audio?: boolean;
|
||||
has_audio_input?: boolean;
|
||||
}): string | undefined {
|
||||
const tags: string[] = [];
|
||||
if (model.is_gguf) tags.push("GGUF");
|
||||
if (model.is_mlx) tags.push("MLX");
|
||||
if (model.is_lora) tags.push("LoRA");
|
||||
if (model.is_vision) tags.push("Vision");
|
||||
if (model.is_audio) tags.push("Audio");
|
||||
if (model.has_audio_input) tags.push("Audio Input");
|
||||
if (!model.is_lora && !model.is_vision && !model.is_gguf && !model.is_audio && !model.has_audio_input)
|
||||
if (
|
||||
!model.is_lora &&
|
||||
!model.is_vision &&
|
||||
!model.is_gguf &&
|
||||
!model.is_mlx &&
|
||||
!model.is_audio &&
|
||||
!model.has_audio_input
|
||||
)
|
||||
tags.push("Base");
|
||||
return tags.join(" · ");
|
||||
}
|
||||
|
|
@ -114,6 +123,7 @@ function toChatModelSummary(model: {
|
|||
is_lora?: boolean;
|
||||
is_vision?: boolean;
|
||||
is_gguf?: boolean;
|
||||
is_mlx?: boolean;
|
||||
is_audio?: boolean;
|
||||
audio_type?: string | null;
|
||||
has_audio_input?: boolean;
|
||||
|
|
@ -125,6 +135,7 @@ function toChatModelSummary(model: {
|
|||
isLora: Boolean(model.is_lora),
|
||||
isVision: Boolean(model.is_vision),
|
||||
isGguf: Boolean(model.is_gguf),
|
||||
isMlx: Boolean(model.is_mlx),
|
||||
isAudio: Boolean(model.is_audio),
|
||||
audioType: model.audio_type ?? null,
|
||||
hasAudioInput: Boolean(model.has_audio_input),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export interface BackendModelDetails {
|
|||
is_vision?: boolean;
|
||||
is_lora?: boolean;
|
||||
is_gguf?: boolean;
|
||||
is_mlx?: boolean;
|
||||
is_audio?: boolean;
|
||||
audio_type?: string | null;
|
||||
has_audio_input?: boolean;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ export interface ChatModelSummary {
|
|||
isVision: boolean;
|
||||
isLora: boolean;
|
||||
isGguf?: boolean;
|
||||
isMlx?: boolean;
|
||||
isAudio?: boolean;
|
||||
audioType?: string | null;
|
||||
hasAudioInput?: boolean;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue