fix(llm): Modelle mit anderer Quantisierung laden (Gemma 4 von unsloth)
Laden von unsloth/gemma-4-12B-it-qat-GGUF scheiterte mit "500": der Katalog
trug pauschal Q4_K_M ein, das Repo hat aber nur UD-Q4_K_XL. llama-server fand
die Datei nicht und beendete sich sofort; llama-swap reicht den Grund nicht
weiter ("upstream command exited prematurely"), es kam nur "500" an.
llm-adapter: fragt vor dem Laden die Dateiliste des Repos ab. Gibt es die
gewuenschte Quantisierung nicht, nimmt er die naechstbeste aus einer festen
Reihenfolge (Q4_K_M, UD-Q4_K_XL, Q4_K_XL, Q4_K_S, IQ4_XS, …) und sagt das im
Download-Fenster an. Kein ladbares GGUF im Repo → sofortige Absage, die Karte
bleibt unberuehrt. Bild-Projektor (mmproj), MTP-Zusatzdateien und imatrix
zaehlen nicht als Modell. Endet llama-server trotzdem sofort, nennt die
Meldung die haeufigsten Gruende statt nur "500".
Diagnostic: "Von HuggingFace aktualisieren" traegt pro HF-Repo die tatsaechlich
vorhandene Quantisierung und die echte Groesse ein (bisher 0 GB) — auch bei
schon vorhandenen HF-Eintraegen. Repos ohne ladbares Modell kommen nicht mehr
in den Katalog bzw. werden als "nicht ladbar" markiert. Katalog zeigt die
Quantisierung pro Modell.
Gemma 4 selbst: llama.cpp kann es seit Juni (#24077), der Stand auf der Box ist
vom 14.08. — es lag nur an der Datei.
Getestet gegen echte HF-Repos (Gemma → UD-Q4_K_XL 6,7 GB, Qwen/Mistral bleiben
Q4_K_M) in Adapter und Diagnostic identisch, und gegen llama-swap: Ausweichen
angesagt + geladen; Repo ohne GGUF → Absage ohne Download.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8980,7 +8980,10 @@
|
|||||||
: '<option value="">(keine Box online)</option>';
|
: '<option value="">(keine Box online)</option>';
|
||||||
return '<tr style="border-bottom:1px solid #1E1E2E;">' +
|
return '<tr style="border-bottom:1px solid #1E1E2E;">' +
|
||||||
'<td ' + td + 'white-space:nowrap;"><b>' + escapeHtml(m.id) + '</b></td>' +
|
'<td ' + td + 'white-space:nowrap;"><b>' + escapeHtml(m.id) + '</b></td>' +
|
||||||
'<td ' + td + 'color:#9a9ab5;min-width:220px;">' + escapeHtml(m.description || m.hfRepo || '') + '</td>' +
|
'<td ' + td + 'color:#9a9ab5;min-width:220px;">' + escapeHtml(m.description || m.hfRepo || '')
|
||||||
|
+ (m.quant ? ' <span style="color:#555570;" title="Quantisierung, die geladen wird' + (m.quants ? ' — vorhanden: ' + escapeHtml(m.quants.join(', ')) : '') + '">· ' + escapeHtml(m.quant) + '</span>' : '')
|
||||||
|
+ (m.unusable ? ' <span style="color:#FF6B6B;" title="Im Repo liegt keine ladbare GGUF-Modelldatei mehr">· nicht ladbar</span>' : '')
|
||||||
|
+ '</td>' +
|
||||||
'<td ' + td + vramStyle + 'white-space:nowrap;">' + vram + '</td>' +
|
'<td ' + td + vramStyle + 'white-space:nowrap;">' + vram + '</td>' +
|
||||||
'<td ' + td + 'white-space:nowrap;">' + haveTxt + '</td>' +
|
'<td ' + td + 'white-space:nowrap;">' + haveTxt + '</td>' +
|
||||||
'<td ' + td + '"><select id="llm-cat-box-' + i + '" style="background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:3px 6px;color:#E0E0F0;font-size:11px;">' + opts + '</select></td>' +
|
'<td ' + td + '"><select id="llm-cat-box-' + i + '" style="background:#1E1E2E;border:1px solid #333;border-radius:4px;padding:3px 6px;color:#E0E0F0;font-size:11px;">' + opts + '</select></td>' +
|
||||||
@@ -9076,6 +9079,7 @@
|
|||||||
</div>${bar}
|
</div>${bar}
|
||||||
<div style="color:${color === '#0096FF' ? '#E0E0F0' : color};font-size:12px;">${line}</div>
|
<div style="color:${color === '#0096FF' ? '#E0E0F0' : color};font-size:12px;">${line}</div>
|
||||||
${sub ? `<div style="color:#6a6a88;font-size:11px;margin-top:2px;">${sub}</div>` : ''}
|
${sub ? `<div style="color:#6a6a88;font-size:11px;margin-top:2px;">${sub}</div>` : ''}
|
||||||
|
${j.note && j.phase !== 'error' ? `<div style="color:#FFD60A;font-size:11px;margin-top:2px;">ℹ ${escapeHtml(j.note)}</div>` : ''}
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|||||||
+60
-3
@@ -473,8 +473,50 @@ function saveLlmCatalog(arr) {
|
|||||||
function slugModelId(repo) {
|
function slugModelId(repo) {
|
||||||
return String(repo).toLowerCase().replace(/^.*\//, "").replace(/-gguf$/,"").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "model";
|
return String(repo).toLowerCase().replace(/^.*\//, "").replace(/-gguf$/,"").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "model";
|
||||||
}
|
}
|
||||||
|
// ── Quantisierung pro Repo ──────────────────────────────────────────
|
||||||
|
// Nicht jedes Repo hat eine Q4_K_M-Datei (unsloth z.B. "UD-Q4_K_XL"). Steht
|
||||||
|
// eine Quantisierung im Katalog, die es nicht gibt, beendet sich llama-server
|
||||||
|
// sofort und die Box meldet nur "500". Darum fragen wir pro Repo die Dateiliste
|
||||||
|
// ab und nehmen die beste vorhandene — dieselbe Reihenfolge wie im llm-adapter.
|
||||||
|
const QUANT_PREFERENCE = ["Q4_K_M", "UD-Q4_K_XL", "Q4_K_XL", "Q4_K_S", "IQ4_XS", "IQ4_NL", "Q4_0",
|
||||||
|
"Q5_K_M", "UD-Q5_K_XL", "Q6_K", "Q8_0"];
|
||||||
|
const QUANT_RE = /((?:UD-)?(?:IQ[1-4]_(?:XXS|XS|S|M|NL)|Q[2-8]_K(?:_(?:XL|L|M|S))?|Q[4-8]_[01]|BF16|F16|F32))/gi;
|
||||||
|
const SPLIT_RE = /-(\d{5})-of-(\d{5})\.gguf$/i;
|
||||||
|
function ggufQuant(p) {
|
||||||
|
const base = String(p).split("/").pop().replace(SPLIT_RE, ".gguf").replace(/\.gguf$/i, "");
|
||||||
|
const m = base.match(QUANT_RE);
|
||||||
|
return m ? m[m.length - 1].toUpperCase() : "";
|
||||||
|
}
|
||||||
|
function isMainGguf(p) {
|
||||||
|
const low = String(p).toLowerCase();
|
||||||
|
const base = low.split("/").pop();
|
||||||
|
return low.endsWith(".gguf") && !base.includes("mmproj") && !base.startsWith("mtp")
|
||||||
|
&& !("/" + low).includes("/mtp/") && !base.includes("imatrix");
|
||||||
|
}
|
||||||
|
// → { quant, sizeGB, quants } oder null (Repo nicht lesbar / kein Modell darin)
|
||||||
|
async function hfRepoQuant(repo, wanted = "Q4_K_M") {
|
||||||
|
try {
|
||||||
|
const r = await fetch(`https://huggingface.co/api/models/${repo}/tree/main?recursive=1`,
|
||||||
|
{ headers: { "User-Agent": "aria-diagnostic" } });
|
||||||
|
if (!r.ok) return null;
|
||||||
|
const files = (await r.json()).filter(e => e.type === "file" && isMainGguf(e.path))
|
||||||
|
.map(e => ({ path: e.path, size: (e.lfs && e.lfs.size) || e.size || 0, quant: ggufQuant(e.path) }));
|
||||||
|
const have = new Set(files.map(f => f.quant).filter(Boolean));
|
||||||
|
const quant = have.has(String(wanted).toUpperCase()) ? String(wanted).toUpperCase()
|
||||||
|
: QUANT_PREFERENCE.find(q => have.has(q)) || "";
|
||||||
|
if (!quant) return null;
|
||||||
|
const match = files.filter(f => f.quant === quant);
|
||||||
|
const parts = match.some(f => SPLIT_RE.test(f.path)) ? match.filter(f => SPLIT_RE.test(f.path))
|
||||||
|
: [match.reduce((a, b) => (a.path.length <= b.path.length ? a : b))];
|
||||||
|
const bytes = parts.reduce((n, f) => n + f.size, 0);
|
||||||
|
return { quant, sizeGB: Math.round(bytes / 1e8) / 10, quants: [...have].sort() };
|
||||||
|
} catch { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
// Holt populaere GGUF-Modelle von der HuggingFace-API und merged sie in den
|
// Holt populaere GGUF-Modelle von der HuggingFace-API und merged sie in den
|
||||||
// Katalog (kuratierte Eintraege + Beschreibungen bleiben erhalten).
|
// Katalog (kuratierte Eintraege + Beschreibungen bleiben erhalten). Fuer jedes
|
||||||
|
// HF-Repo wird die TATSAECHLICH vorhandene Quantisierung und Groesse
|
||||||
|
// eingetragen — auch bei schon vorhandenen HF-Eintraegen.
|
||||||
async function refreshLlmCatalogFromHF() {
|
async function refreshLlmCatalogFromHF() {
|
||||||
const url = "https://huggingface.co/api/models?search=GGUF&sort=downloads&direction=-1&limit=40";
|
const url = "https://huggingface.co/api/models?search=GGUF&sort=downloads&direction=-1&limit=40";
|
||||||
const r = await fetch(url, { headers: { "User-Agent": "aria-diagnostic" } });
|
const r = await fetch(url, { headers: { "User-Agent": "aria-diagnostic" } });
|
||||||
@@ -489,9 +531,24 @@ async function refreshLlmCatalogFromHF() {
|
|||||||
const id = slugModelId(repo);
|
const id = slugModelId(repo);
|
||||||
if (byId.has(id)) continue; // kuratierte/vorhandene nicht ueberschreiben
|
if (byId.has(id)) continue; // kuratierte/vorhandene nicht ueberschreiben
|
||||||
const entry = { id, hfRepo: repo, quant: "Q4_K_M", ctx: 8192, sizeGB: 0,
|
const entry = { id, hfRepo: repo, quant: "Q4_K_M", ctx: 8192, sizeGB: 0,
|
||||||
description: `HuggingFace · ${(m.downloads || 0).toLocaleString("de")} Downloads`, source: "hf" };
|
description: `HuggingFace · ${(m.downloads || 0).toLocaleString("de")} Downloads`, source: "hf", _new: true };
|
||||||
byId.set(id, entry); added++;
|
byId.set(id, entry);
|
||||||
}
|
}
|
||||||
|
// Quantisierung + Groesse pruefen: alle HF-Eintraege (kuratierte haben
|
||||||
|
// gepflegte Werte). Je 6 gleichzeitig, damit HF nicht drosselt.
|
||||||
|
const toCheck = [...byId.values()].filter(e => e.source === "hf");
|
||||||
|
for (let i = 0; i < toCheck.length; i += 6) {
|
||||||
|
await Promise.all(toCheck.slice(i, i + 6).map(async e => {
|
||||||
|
const q = await hfRepoQuant(e.hfRepo, e.quant || "Q4_K_M");
|
||||||
|
if (!q) {
|
||||||
|
// Kein ladbares Modell im Repo: neue nicht aufnehmen, alte markieren.
|
||||||
|
if (e._new) byId.delete(e.id); else e.unusable = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.quant = q.quant; e.sizeGB = q.sizeGB; e.quants = q.quants; delete e.unusable;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
for (const e of byId.values()) { if (e._new) { added++; delete e._new; } }
|
||||||
const merged = Array.from(byId.values());
|
const merged = Array.from(byId.values());
|
||||||
saveLlmCatalog(merged);
|
saveLlmCatalog(merged);
|
||||||
return { models: merged, added };
|
return { models: merged, added };
|
||||||
|
|||||||
+92
-22
@@ -645,8 +645,33 @@ _INPROGRESS = ".downloadInProgress"
|
|||||||
_SPLIT_RE = re.compile(r"-(\d{5})-of-(\d{5})\.gguf$", re.IGNORECASE)
|
_SPLIT_RE = re.compile(r"-(\d{5})-of-(\d{5})\.gguf$", re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
async def _hf_expected_files(repo: str, quant: str) -> list:
|
# Quantisierung aus einem Dateinamen: "gemma-4-12B-it-qat-UD-Q4_K_XL.gguf" → "UD-Q4_K_XL"
|
||||||
"""Welche GGUF-Dateien zieht 'repo:quant'? [{path, oid, size}]. Fail-soft: []."""
|
_QUANT_RE = re.compile(r"(?i)((?:UD-)?(?:IQ[1-4]_(?:XXS|XS|S|M|NL)|Q[2-8]_K(?:_(?:XL|L|M|S))?|Q[4-8]_[01]|BF16|F16|F32))")
|
||||||
|
# Wenn die gewuenschte fehlt: die erste vorhandene aus dieser Liste. 4-Bit zuerst
|
||||||
|
# (beste Groesse/Qualitaet fuer 12-GB-Karten), dann groessere.
|
||||||
|
QUANT_PREFERENCE = ["Q4_K_M", "UD-Q4_K_XL", "Q4_K_XL", "Q4_K_S", "IQ4_XS", "IQ4_NL", "Q4_0",
|
||||||
|
"Q5_K_M", "UD-Q5_K_XL", "Q6_K", "Q8_0"]
|
||||||
|
|
||||||
|
|
||||||
|
def _quant_of(path: str) -> str:
|
||||||
|
base = os.path.basename(path)
|
||||||
|
base = _SPLIT_RE.sub(".gguf", base)
|
||||||
|
m = _QUANT_RE.findall(base[:-5] if base.lower().endswith(".gguf") else base)
|
||||||
|
return m[-1].upper() if m else ""
|
||||||
|
|
||||||
|
|
||||||
|
def _is_main_gguf(path: str) -> bool:
|
||||||
|
"""Das eigentliche Modell — nicht Bild-Projektor (mmproj), nicht die
|
||||||
|
Zusatzdatei fuers spekulative Dekodieren (mtp), keine imatrix."""
|
||||||
|
low = path.lower()
|
||||||
|
base = os.path.basename(low)
|
||||||
|
return (low.endswith(".gguf") and "mmproj" not in base and not base.startswith("mtp")
|
||||||
|
and "/mtp/" not in ("/" + low) and "imatrix" not in base)
|
||||||
|
|
||||||
|
|
||||||
|
async def _hf_repo_files(repo: str):
|
||||||
|
"""Alle Modell-GGUFs eines Repos: [{path, oid, size, quant}] — oder None,
|
||||||
|
wenn Hugging Face nicht erreichbar ist (dann pruefen wir eben nicht)."""
|
||||||
url = f"https://huggingface.co/api/models/{repo}/tree/main?recursive=1"
|
url = f"https://huggingface.co/api/models/{repo}/tree/main?recursive=1"
|
||||||
headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
|
headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
|
||||||
try:
|
try:
|
||||||
@@ -655,28 +680,42 @@ async def _hf_expected_files(repo: str, quant: str) -> list:
|
|||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
entries = r.json()
|
entries = r.json()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("HF-Dateiliste fuer %s nicht abrufbar (%s) — Fortschritt ohne Gesamtgroesse", repo, e)
|
logger.warning("HF-Dateiliste fuer %s nicht abrufbar (%s)", repo, e)
|
||||||
return []
|
return None
|
||||||
q = (quant or "").lower()
|
out = []
|
||||||
files = []
|
|
||||||
for e in entries if isinstance(entries, list) else []:
|
for e in entries if isinstance(entries, list) else []:
|
||||||
path = e.get("path") or ""
|
path = e.get("path") or ""
|
||||||
low = path.lower()
|
if e.get("type") != "file" or not _is_main_gguf(path):
|
||||||
if e.get("type") != "file" or not low.endswith(".gguf") or "mmproj" in low:
|
|
||||||
continue
|
|
||||||
if q and q not in low:
|
|
||||||
continue
|
continue
|
||||||
lfs = e.get("lfs") or {}
|
lfs = e.get("lfs") or {}
|
||||||
files.append({"path": path, "oid": lfs.get("oid") or e.get("oid") or "",
|
out.append({"path": path, "oid": lfs.get("oid") or e.get("oid") or "",
|
||||||
"size": int(lfs.get("size") or e.get("size") or 0)})
|
"size": int(lfs.get("size") or e.get("size") or 0), "quant": _quant_of(path)})
|
||||||
if not files:
|
return out
|
||||||
return []
|
|
||||||
# Gesplittetes Modell → alle Teile; sonst die eine passende Datei (bei
|
|
||||||
# mehreren Treffern die mit dem kuerzesten Namen, z.B. ohne "-imat").
|
def _pick_quant(files: list, wanted: str) -> str:
|
||||||
split = [f for f in files if _SPLIT_RE.search(f["path"])]
|
"""Die gewuenschte Quantisierung, wenn es sie gibt — sonst die erste aus
|
||||||
|
QUANT_PREFERENCE, die das Repo hat. "" wenn gar nichts Brauchbares da ist."""
|
||||||
|
have = {f["quant"] for f in files if f["quant"]}
|
||||||
|
if wanted and wanted.upper() in have:
|
||||||
|
return wanted.upper()
|
||||||
|
return next((q for q in QUANT_PREFERENCE if q in have), "")
|
||||||
|
|
||||||
|
|
||||||
|
def _files_for_quant(files: list, quant: str) -> list:
|
||||||
|
"""Die Datei(en), die llama.cpp fuer repo:quant zieht. Gesplittet → alle
|
||||||
|
Teile; sonst die eine (bei mehreren die mit dem kuerzesten Namen)."""
|
||||||
|
match = [f for f in files if f["quant"] == quant.upper()]
|
||||||
|
split = [f for f in match if _SPLIT_RE.search(f["path"])]
|
||||||
if split:
|
if split:
|
||||||
return split
|
return split
|
||||||
return [min(files, key=lambda f: len(f["path"]))]
|
return [min(match, key=lambda f: len(f["path"]))] if match else []
|
||||||
|
|
||||||
|
|
||||||
|
async def _hf_expected_files(repo: str, quant: str) -> list:
|
||||||
|
"""Welche GGUF-Dateien zieht 'repo:quant'? [{path, oid, size}]. Fail-soft: []."""
|
||||||
|
files = await _hf_repo_files(repo)
|
||||||
|
return _files_for_quant(files, quant) if files else []
|
||||||
|
|
||||||
|
|
||||||
def _scan_download(oids: set) -> tuple:
|
def _scan_download(oids: set) -> tuple:
|
||||||
@@ -792,10 +831,32 @@ async def _handle_provision(ws, payload: dict) -> None:
|
|||||||
return await _provision_result(
|
return await _provision_result(
|
||||||
ws, key, False, gpu=card,
|
ws, key, False, gpu=card,
|
||||||
error=f"{key} liegt schon auf Karte {elsewhere} dieser Box — ein Modell pro Box nur einmal.")
|
error=f"{key} liegt schon auf Karte {elsewhere} dieser Box — ein Modell pro Box nur einmal.")
|
||||||
|
quant_note = ""
|
||||||
|
repo_files = None
|
||||||
if repo:
|
if repo:
|
||||||
|
wanted = (payload.get("quant") or "Q4_K_M").strip()
|
||||||
|
quant = wanted
|
||||||
|
# Gibt es die Datei ueberhaupt? Fehlt sie, beendet sich llama-server
|
||||||
|
# sofort und llama-swap meldet nur "500" — der Grund geht verloren.
|
||||||
|
# Lieber vorher pruefen und ggf. die naechstbeste Quantisierung nehmen
|
||||||
|
# (unsloth z.B. hat statt Q4_K_M ein UD-Q4_K_XL).
|
||||||
|
repo_files = await _hf_repo_files(repo)
|
||||||
|
if repo_files is not None:
|
||||||
|
if not repo_files:
|
||||||
|
return await _provision_result(
|
||||||
|
ws, key, False, gpu=card,
|
||||||
|
error=f"In {repo} gibt es keine GGUF-Modelldatei.")
|
||||||
|
quant = _pick_quant(repo_files, wanted)
|
||||||
|
if not quant:
|
||||||
|
have = sorted({f["quant"] for f in repo_files if f["quant"]}) or ["?"]
|
||||||
|
return await _provision_result(
|
||||||
|
ws, key, False, gpu=card,
|
||||||
|
error=f"{repo}: keine brauchbare Quantisierung. Vorhanden: {', '.join(have)}")
|
||||||
|
if quant != wanted.upper():
|
||||||
|
quant_note = f"{wanted} gibt es in {repo} nicht — nehme {quant}"
|
||||||
|
logger.info("Karte %s: %s", card, quant_note)
|
||||||
entry = {
|
entry = {
|
||||||
"key": key, "hfRepo": repo,
|
"key": key, "hfRepo": repo, "quant": quant,
|
||||||
"quant": (payload.get("quant") or "Q4_K_M").strip(),
|
|
||||||
"ctx": int(payload.get("ctx") or 8192),
|
"ctx": int(payload.get("ctx") or 8192),
|
||||||
"ngl": int(payload.get("ngl") or 99),
|
"ngl": int(payload.get("ngl") or 99),
|
||||||
}
|
}
|
||||||
@@ -809,9 +870,10 @@ async def _handle_provision(ws, payload: dict) -> None:
|
|||||||
_generate_config()
|
_generate_config()
|
||||||
|
|
||||||
quant = next((e.get("quant") for e in _load_registry() if e.get("key") == key), "") or "Q4_K_M"
|
quant = next((e.get("quant") for e in _load_registry() if e.get("key") == key), "") or "Q4_K_M"
|
||||||
files = await _hf_expected_files(repo, quant) if repo else []
|
files = _files_for_quant(repo_files, quant) if repo_files else []
|
||||||
await _emit_progress(ws, key, "start", total=sum(f["size"] for f in files),
|
await _emit_progress(ws, key, "start", total=sum(f["size"] for f in files),
|
||||||
files=len(files), gpu=card, replaces=previous)
|
files=len(files), gpu=card, replaces=previous, quant=quant,
|
||||||
|
note=quant_note)
|
||||||
await _reload_llama()
|
await _reload_llama()
|
||||||
await _announce(ws)
|
await _announce(ws)
|
||||||
stop = asyncio.Event()
|
stop = asyncio.Event()
|
||||||
@@ -842,6 +904,14 @@ async def _handle_provision(ws, payload: dict) -> None:
|
|||||||
# ein kaputtes Modell in der Config, und jedes Neuladen von llama-swap
|
# ein kaputtes Modell in der Config, und jedes Neuladen von llama-swap
|
||||||
# risse die anderen Karten mit.
|
# risse die anderen Karten mit.
|
||||||
err = (res.get("error") or "Laden fehlgeschlagen")[:200]
|
err = (res.get("error") or "Laden fehlgeschlagen")[:200]
|
||||||
|
if "500" in err and dt < 120:
|
||||||
|
# llama-swap reicht den Grund nicht weiter ("upstream command exited
|
||||||
|
# prematurely"). Kam der Abbruch schnell, lief kein Download — dann ist
|
||||||
|
# es fast immer eins von dreien.
|
||||||
|
err = ("llama.cpp hat sich beim Start sofort beendet. Haeufigste Gruende: "
|
||||||
|
"die Modell-Architektur ist neuer als die llama.cpp-Version der Box, "
|
||||||
|
"zu wenig (V)RAM, oder die Datei passt nicht. (llama-swap gibt den "
|
||||||
|
"genauen Grund nicht weiter.)")
|
||||||
slots = _load_slots()
|
slots = _load_slots()
|
||||||
if previous:
|
if previous:
|
||||||
slots[card] = previous
|
slots[card] = previous
|
||||||
|
|||||||
Reference in New Issue
Block a user