feat(diagnostic): pro LLM-Karte ein Dropdown — und Kontextfenster an Clients melden
Einstellungen → Modelle & KI → "LLM-Karten": fuer jede Karte, die auf einer Box fuers LLM vorgesehen ist, ein Dropdown mit den Katalog-Modellen und "— leer —" (entlaedt die Karte). Nur echte LLM-Karten erscheinen. Modelle, die auf derselben Box schon auf einer anderen Karte liegen, werden nicht angeboten; zu grosse (Katalog-Groesse > VRAM der Karte) sind als "passt nicht" markiert. Waehrend eines Ladevorgangs ist das Dropdown gesperrt und zeigt den Fortschritt. Box meldet dafuer pro Karte den VRAM (nvidia-smi memory.total) und das Kontextfenster, mit dem llama-server das Modell startet (-c). Kontext an Clients: llm_models enthaelt jetzt "ctx". Anlass: die Software- Schmiede rechnete mit 32768 Tokens, die Box startet die Modelle mit 8192 — lange Auftraege waeren gescheitert oder falsch gekuerzt worden, und der Client konnte es nicht wissen. Doku entsprechend ergaenzt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -417,23 +417,33 @@ _gpu_name_cache: dict = {}
|
||||
|
||||
|
||||
async def _gpu_names() -> dict:
|
||||
"""{index: name} aller Karten, einmal per nvidia-smi geholt."""
|
||||
"""{index: {"name", "vramMB"}} aller Karten, einmal per nvidia-smi geholt.
|
||||
Der VRAM steht fest — die Diagnostic warnt damit vor Modellen, die nicht
|
||||
auf die Karte passen."""
|
||||
if _gpu_name_cache:
|
||||
return _gpu_name_cache
|
||||
try:
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
"nvidia-smi", "--query-gpu=index,name", "--format=csv,noheader",
|
||||
"nvidia-smi", "--query-gpu=index,name,memory.total", "--format=csv,noheader,nounits",
|
||||
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL)
|
||||
out, _ = await asyncio.wait_for(proc.communicate(), 10)
|
||||
for line in out.decode().splitlines():
|
||||
if "," in line:
|
||||
i, n = line.split(",", 1)
|
||||
_gpu_name_cache[i.strip()] = n.strip()
|
||||
parts = [x.strip() for x in line.split(",")]
|
||||
if len(parts) >= 3:
|
||||
_gpu_name_cache[parts[0]] = {"name": parts[1], "vramMB": int(float(parts[2]))}
|
||||
except Exception:
|
||||
pass
|
||||
return _gpu_name_cache
|
||||
|
||||
|
||||
def _model_ctx(key: str) -> int:
|
||||
"""Kontextfenster, mit dem llama-server das Modell startet (-c). Clients
|
||||
MUESSEN das wissen: rechnen sie mit mehr, scheitern lange Auftraege oder
|
||||
werden falsch gekuerzt."""
|
||||
m = re.search(r"(?:^|\s)(?:-c|--ctx-size)\s+(\d+)", _model_cmd(key) or "")
|
||||
return int(m.group(1)) if m else 0
|
||||
|
||||
|
||||
async def _slots_info() -> list:
|
||||
"""Pro LLM-Karte: [{gpu, gpuName, model, state}]. state aus llama-swap
|
||||
/running: ready | starting | stopping | stopped; "unknown", wenn llama-swap
|
||||
@@ -441,12 +451,14 @@ async def _slots_info() -> list:
|
||||
slots = _load_slots()
|
||||
running = await _fetch_loaded()
|
||||
rmap = {r["model"]: r["state"] for r in running} if running is not None else None
|
||||
names = await _gpu_names()
|
||||
gpus = await _gpu_names()
|
||||
out = []
|
||||
for card in _llm_cards():
|
||||
m = slots.get(card, "")
|
||||
state = "" if not m else ("unknown" if rmap is None else rmap.get(m, "stopped"))
|
||||
out.append({"gpu": card, "gpuName": names.get(card, ""), "model": m, "state": state})
|
||||
g = gpus.get(card) or {}
|
||||
out.append({"gpu": card, "gpuName": g.get("name", ""), "vramMB": g.get("vramMB", 0),
|
||||
"model": m, "state": state, "ctx": _model_ctx(m) if m else 0})
|
||||
return out
|
||||
|
||||
|
||||
@@ -973,7 +985,7 @@ async def _handle_models_request(ws, payload: dict) -> None:
|
||||
await _send(ws, "llm_models", {
|
||||
"requestId": payload.get("requestId", ""),
|
||||
"instanceId": INSTANCE_ID, "node": NODE_NAME,
|
||||
"models": [{"model": x["model"], "gpu": x["gpu"], "gpuName": x["gpuName"],
|
||||
"models": [{"model": x["model"], "gpu": x["gpu"], "gpuName": x["gpuName"], "ctx": x["ctx"],
|
||||
"state": x["state"]} for x in info if x["model"] in sel],
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user