engines: detect Riva/NIM model from /metadata, show placeholder on empty fetch
- stt.list_models(): fall back to /metadata (NVIDIA Riva/NIM) when /models returns nothing — extracts shortName and strips the version tag suffix - Settings: show "type model name manually" placeholder when fetch returns empty and no model is currently set Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
06167a1e6d
commit
101bb1e796
@ -1445,6 +1445,8 @@ notebook.bt-nb tab:checked label {
|
||||
def apply():
|
||||
cur = _combo_text(combo)
|
||||
_fill_combo(combo, models, cur)
|
||||
if not models and not cur:
|
||||
combo.entry.set_placeholder_text("type model name manually")
|
||||
return False
|
||||
GLib.idle_add(apply)
|
||||
threading.Thread(target=work, daemon=True).start()
|
||||
|
||||
@ -62,29 +62,46 @@ def status(engine: STTEngine, timeout: float = 2.0) -> bool:
|
||||
|
||||
|
||||
def list_models(base_url: str, api_key_env: str = "", timeout: float = 5.0) -> list[str]:
|
||||
"""Fetch model ids from an OpenAI-compatible (or Ollama-style) /models endpoint."""
|
||||
"""Fetch model ids from an OpenAI-compatible, Ollama-style, or Riva/NIM /models endpoint."""
|
||||
import os
|
||||
|
||||
if not base_url:
|
||||
return []
|
||||
url = base_url.rstrip("/") + "/models"
|
||||
headers = {}
|
||||
base = base_url.rstrip("/")
|
||||
headers: dict[str, str] = {}
|
||||
key = os.environ.get(api_key_env) if api_key_env else None
|
||||
if key:
|
||||
headers["Authorization"] = f"Bearer {key}"
|
||||
try:
|
||||
req = urllib.request.Request(url, headers=headers)
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||
data = json.loads(resp.read().decode("utf-8"))
|
||||
except (urllib.error.URLError, json.JSONDecodeError, OSError):
|
||||
return []
|
||||
|
||||
items = data.get("data") if isinstance(data, dict) else None
|
||||
if isinstance(items, list): # OpenAI shape: {"data":[{"id":...}]}
|
||||
return [m["id"] for m in items if isinstance(m, dict) and m.get("id")]
|
||||
items = data.get("models") if isinstance(data, dict) else None
|
||||
if isinstance(items, list): # Ollama shape: {"models":[{"name"/"model":...}]}
|
||||
return [m.get("name") or m.get("model") for m in items if (m.get("name") or m.get("model"))]
|
||||
def _get(url: str) -> dict | None:
|
||||
try:
|
||||
req = urllib.request.Request(url, headers=headers)
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
except (urllib.error.URLError, json.JSONDecodeError, OSError):
|
||||
return None
|
||||
|
||||
# 1. Standard OpenAI /models
|
||||
data = _get(base + "/models")
|
||||
if isinstance(data, dict):
|
||||
items = data.get("data")
|
||||
if isinstance(items, list): # OpenAI shape: {"data":[{"id":...}]}
|
||||
return [m["id"] for m in items if isinstance(m, dict) and m.get("id")]
|
||||
items = data.get("models")
|
||||
if isinstance(items, list): # Ollama shape: {"models":[{"name"/"model":...}]}
|
||||
return [m.get("name") or m.get("model") for m in items
|
||||
if (m.get("name") or m.get("model"))]
|
||||
|
||||
# 2. NVIDIA Riva / NIM — exposes model info at /metadata
|
||||
data = _get(base + "/metadata")
|
||||
if isinstance(data, dict):
|
||||
for info in data.get("modelInfo") or []:
|
||||
name = info.get("shortName") or info.get("modelUrl") or ""
|
||||
if name:
|
||||
# Strip the long tag suffix: keep everything before the first ':'
|
||||
short = name.split(":")[0]
|
||||
return [short]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user