c48e583790
Engine-Cutover ROCm/HIP -> Vulkan/RADV (gfx1151): +12-22% tg auf MoE (llama-bench
verifiziert, fast 53->65 t/s). ROCm-Build bleibt als Rollback unter /opt/llamacpp.
- Backend: vocab-aware Speculative Decoding. services/gguf_meta.py liest den
Tokenizer-Fingerprint (model/pre/n_vocab) direkt aus dem GGUF-Header (ohne Modell-Load);
register_model + migrate_config haengen nur VOCAB-KOMPATIBLE Drafts an (inkl. --spec-type,
das in dieser llama.cpp-Generation noetig ist). Neue Endpoints /api/models/drafts + /{id}/draft.
- Frontend: idiotensichere Spec-Draft-UI (SpecDraftModal) - nur kompatible Drafts waehlbar,
inkompatible gesperrt mit Begruendung; SPEC/SPEC?-Badge nach echtem Aktiv-Status; Rolle in AddModel.
- maintenance.py: Engine-Update-Quelle -> ggml-org/llama.cpp (Build-Nummer-Vergleich),
ENGINE_PATH=/opt/llamacpp-vulkan.
- Startup-Warmup der brains (deploy/warmup.sh, self-detaching ExecStartPost) + deploy/provision-engine.sh.
- Cleanup: tote LiteLLM gateway/config.yaml + alle Referenzen (config.py/backup.py/backup.sh) entfernt;
README + docs/memory aktualisiert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
"""
|
|
Backup der „Verfassung" (Shared-Memory-SQLite) + aller Configs.
|
|
Snapshot in einen Zeitstempel-Ordner; die letzten N bleiben erhalten.
|
|
"""
|
|
|
|
import shutil
|
|
import time
|
|
from pathlib import Path
|
|
|
|
from config import CONFIG_PATH, MEMORY_DB, MODELS_DIR
|
|
|
|
BACKUP_DIR = Path(MODELS_DIR) / "mc2-backups"
|
|
RETAIN = 7
|
|
|
|
|
|
def _safe_copy(src: Path, dst_dir: Path) -> str | None:
|
|
try:
|
|
if src and src.exists():
|
|
shutil.copy2(src, dst_dir / src.name)
|
|
return src.name
|
|
except Exception:
|
|
pass
|
|
return None
|
|
|
|
|
|
def backup_now() -> dict:
|
|
"""Erstellt einen Snapshot (Memory-DB inkl. WAL/SHM + Configs). Alte Snapshots
|
|
über RETAIN hinaus werden entfernt."""
|
|
ts = time.strftime("%Y%m%d-%H%M%S")
|
|
dst = BACKUP_DIR / ts
|
|
dst.mkdir(parents=True, exist_ok=True)
|
|
saved = []
|
|
for src in (MEMORY_DB, Path(str(MEMORY_DB) + "-wal"), Path(str(MEMORY_DB) + "-shm"),
|
|
CONFIG_PATH):
|
|
if (name := _safe_copy(src, dst)):
|
|
saved.append(name)
|
|
# Aufräumen: nur die letzten RETAIN Snapshots behalten.
|
|
snaps = sorted([p for p in BACKUP_DIR.iterdir() if p.is_dir()], reverse=True)
|
|
for old in snaps[RETAIN:]:
|
|
shutil.rmtree(old, ignore_errors=True)
|
|
return {"ok": bool(saved), "snapshot": ts, "files": saved, "dir": str(dst)}
|
|
|
|
|
|
def list_backups() -> list[dict]:
|
|
if not BACKUP_DIR.exists():
|
|
return []
|
|
out = []
|
|
for p in sorted([d for d in BACKUP_DIR.iterdir() if d.is_dir()], reverse=True):
|
|
files = [f.name for f in p.iterdir() if f.is_file()]
|
|
out.append({"snapshot": p.name, "files": files})
|
|
return out
|