Add capture wanted and harden Assistent wanted-queue merge.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -79,6 +79,7 @@ gpu-rent up --yes --ollama
|
||||
| `gpu-rent pull-output` | VM `Output/` → `./Output` |
|
||||
| `gpu-rent capture` / `capture all` | Инвентарь VM → merge **ссылок** в `models.yaml` + `extensions.yaml` (веса не качать) |
|
||||
| `gpu-rent capture models` / `--kind lora` | Только модели (фильтр по типу) |
|
||||
| `gpu-rent capture wanted` | Очередь Assistent Cards → `models.yaml` |
|
||||
| `gpu-rent capture extensions` | Только git Extensions / DLNodes |
|
||||
| `gpu-rent capture --dry-run` | Отчёт без записи файлов |
|
||||
| `gpu-rent resize-data --gb 400` | Data volume **только вверх** |
|
||||
|
||||
+2
-1
@@ -23,11 +23,12 @@ copy models.example.yaml models.yaml
|
||||
```powershell
|
||||
.\gpu-rent.ps1 capture models # merge Civitai url → models.yaml
|
||||
.\gpu-rent.ps1 capture models --kind lora
|
||||
.\gpu-rent.ps1 capture wanted # только очередь Assistent Cards → models.yaml
|
||||
.\gpu-rent.ps1 capture --dry-run # models + extensions, без записи
|
||||
.\gpu-rent.ps1 capture all
|
||||
```
|
||||
|
||||
Берёт `{stem}.civitai.json` или SHA256 → Civitai `by-hash`. Также мержит очередь Assistent `/mnt/swarm_data/.gpu-rent-wanted-models.yaml` (модели, добавленные из вкладки Cards). Дубли `modelVersionId` не дублируются. Перед записью — `models.yaml.bak`. Неизвестные файлы (нет в Civitai) — только в отчёте.
|
||||
Берёт `{stem}.civitai.json` или SHA256 → Civitai `by-hash`. Также мержит очередь Assistent `/mnt/swarm_data/.gpu-rent-wanted-models.yaml` (модели, добавленные из вкладки Cards / Enqueue wanted) — на `capture models|wanted|all` и перед `seed-models` / `up`. Дубли `modelVersionId` не дублируются. Перед записью — `models.yaml.bak`. Неизвестные файлы (нет в Civitai) — только в отчёте.
|
||||
|
||||
Локальный SwarmUI на `7801` не зеркалируем. Только дерево `./Models` приложения.
|
||||
|
||||
|
||||
+59
-7
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import shutil
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass, field
|
||||
@@ -420,14 +421,15 @@ def merge_wanted_models_from_vm(cfg: Config, host: str, log: Log) -> int:
|
||||
).strip()
|
||||
if not raw:
|
||||
return 0
|
||||
try:
|
||||
data = yaml.safe_load(raw) or {}
|
||||
except Exception as exc:
|
||||
log(f"wanted-models: bad yaml — {exc}")
|
||||
return 0
|
||||
if not isinstance(data, dict):
|
||||
return 0
|
||||
items: list[ModelCaptureItem] = []
|
||||
data: dict = {}
|
||||
try:
|
||||
parsed = yaml.safe_load(raw) or {}
|
||||
if isinstance(parsed, dict):
|
||||
data = parsed
|
||||
except Exception as exc:
|
||||
log(f"wanted-models: yaml parse — {exc}; fallback line scan")
|
||||
|
||||
for kind, rows in data.items():
|
||||
if kind not in MODEL_DIRS or not isinstance(rows, list):
|
||||
continue
|
||||
@@ -451,6 +453,56 @@ def merge_wanted_models_from_vm(cfg: Config, host: str, log: Log) -> int:
|
||||
source="wanted",
|
||||
)
|
||||
)
|
||||
|
||||
# Recover entries lost to duplicate YAML keys (old Assistent writers appended
|
||||
# a fresh `lora:` block each time; PyYAML keeps only the last).
|
||||
kind = "lora"
|
||||
pending_url = None
|
||||
pending_title = None
|
||||
pending_vid = None
|
||||
seen_urls = {i.url for i in items}
|
||||
|
||||
def flush_pending() -> None:
|
||||
nonlocal pending_url, pending_title, pending_vid
|
||||
if not pending_url or pending_url in seen_urls:
|
||||
pending_url = pending_title = pending_vid = None
|
||||
return
|
||||
vid_i = pending_vid or extract_version_id(pending_url)
|
||||
items.append(
|
||||
ModelCaptureItem(
|
||||
kind=kind if kind in MODEL_DIRS else "lora",
|
||||
url=pending_url,
|
||||
title=str(pending_title or Path(pending_url).name),
|
||||
version_id=vid_i,
|
||||
source="wanted",
|
||||
)
|
||||
)
|
||||
seen_urls.add(pending_url)
|
||||
pending_url = pending_title = pending_vid = None
|
||||
|
||||
for line in raw.splitlines():
|
||||
t = line.strip()
|
||||
m_kind = re.match(r"^([A-Za-z0-9_-]+):\s*$", t)
|
||||
if m_kind and not t.startswith("-"):
|
||||
flush_pending()
|
||||
kind = m_kind.group(1).strip().lower()
|
||||
continue
|
||||
m_url = re.match(r"^-\s*url:\s*[\"']?(.+?)[\"']?\s*$", t)
|
||||
if m_url:
|
||||
flush_pending()
|
||||
pending_url = m_url.group(1).strip()
|
||||
continue
|
||||
if not pending_url:
|
||||
continue
|
||||
m_title = re.match(r"^title:\s*[\"']?(.+?)[\"']?\s*$", t)
|
||||
if m_title:
|
||||
pending_title = m_title.group(1).strip()
|
||||
continue
|
||||
m_vid = re.match(r"^version_id:\s*(\d+)\s*$", t)
|
||||
if m_vid:
|
||||
pending_vid = int(m_vid.group(1))
|
||||
flush_pending()
|
||||
|
||||
if not items:
|
||||
return 0
|
||||
added, skipped = merge_models_yaml(Path(cfg.models_manifest), items, dry_run=False)
|
||||
|
||||
@@ -986,6 +986,22 @@ def capture_models_cmd(
|
||||
_die(exc)
|
||||
|
||||
|
||||
@capture_app.command("wanted")
|
||||
def capture_wanted_cmd() -> None:
|
||||
"""Только очередь Assistent (.gpu-rent-wanted-models.yaml) → models.yaml."""
|
||||
try:
|
||||
from gpu_rent.capture import merge_wanted_models_from_vm
|
||||
|
||||
cfg, host = _live()
|
||||
n = merge_wanted_models_from_vm(cfg, host, log)
|
||||
if n:
|
||||
log(f"wanted→models.yaml: +{n}")
|
||||
else:
|
||||
log("wanted→models.yaml: пусто или уже есть")
|
||||
except GpuRentError as exc:
|
||||
_die(exc)
|
||||
|
||||
|
||||
@capture_app.command("extensions")
|
||||
def capture_extensions_cmd(
|
||||
dry_run: bool = typer.Option(False, "--dry-run"),
|
||||
|
||||
Reference in New Issue
Block a user