Add capture wanted and harden Assistent wanted-queue merge.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-21 21:29:00 +03:00
co-authored by Cursor
parent 08120194f9
commit 6c45a7560e
4 changed files with 78 additions and 8 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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)
+16
View File
@@ -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"),