Add assistent-personas support and enhance model merging functionality
- Introduced `assistent-personas.yaml` to the project and updated the `.gitignore` accordingly. - Implemented functions to seed and merge assistent personas from local files to the VM. - Enhanced the model capture process to include merging of wanted models from the VM into `models.yaml`. - Updated documentation to reflect changes in the assistent personas and model management processes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -710,9 +710,139 @@ def seed_swarmui_api_keys(cfg: Config, host: str, log: Log) -> None:
|
||||
run_ssh(cfg, host, "rm -f /tmp/gpu-rent-swarm-api-keys.json", check=False)
|
||||
|
||||
|
||||
def seed_assistent_personas(cfg: Config, host: str, log: Log) -> None:
|
||||
"""Push local assistent-personas.yaml → VM Assistent/personas.yaml + personas.json."""
|
||||
from gpu_rent.paths import assistent_personas_example_path, assistent_personas_manifest_path
|
||||
|
||||
local = Path(
|
||||
(getattr(cfg, "assistent_personas_manifest", None) or assistent_personas_manifest_path())
|
||||
)
|
||||
if not local.is_file():
|
||||
example = assistent_personas_example_path()
|
||||
if example.is_file():
|
||||
local = example
|
||||
else:
|
||||
log("assistent-personas: нет yaml — skip")
|
||||
return
|
||||
text = local.read_text(encoding="utf-8")
|
||||
if not text.strip():
|
||||
log("assistent-personas: пустой файл — skip")
|
||||
return
|
||||
remote_dir = f"{DATA}/Assistent"
|
||||
remote_yaml = f"{remote_dir}/personas.yaml"
|
||||
remote_json = f"{remote_dir}/personas.json"
|
||||
run_ssh(cfg, host, f"mkdir -p {shlex.quote(remote_dir)}", check=False)
|
||||
put_text(cfg, host, remote_yaml, text if text.endswith("\n") else text + "\n")
|
||||
try:
|
||||
import yaml
|
||||
|
||||
data = yaml.safe_load(text) or {}
|
||||
put_text(
|
||||
cfg,
|
||||
host,
|
||||
remote_json,
|
||||
json.dumps(data, ensure_ascii=False, indent=2) + "\n",
|
||||
)
|
||||
except Exception as exc:
|
||||
log(f"assistent-personas: json convert — {exc}")
|
||||
log(f"assistent-personas → {remote_yaml}")
|
||||
|
||||
|
||||
def merge_wanted_models_from_vm(cfg: Config, host: str, log: Log) -> int:
|
||||
"""Pull VM wanted queue into local models.yaml. Returns count of new urls merged."""
|
||||
from gpu_rent.capture import ModelCaptureItem, merge_models_yaml
|
||||
|
||||
remote = f"{DATA}/.gpu-rent-wanted-models.yaml"
|
||||
raw = run_ssh(
|
||||
cfg,
|
||||
host,
|
||||
f"test -f {shlex.quote(remote)} && cat {shlex.quote(remote)} || true",
|
||||
check=False,
|
||||
timeout=20,
|
||||
).strip()
|
||||
if not raw:
|
||||
return 0
|
||||
try:
|
||||
import yaml
|
||||
|
||||
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] = []
|
||||
for kind, rows in data.items():
|
||||
if kind not in MODEL_DIRS or not isinstance(rows, list):
|
||||
continue
|
||||
for row in rows:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
url = str(row.get("url") or "").strip()
|
||||
if not url:
|
||||
continue
|
||||
vid = row.get("version_id")
|
||||
try:
|
||||
vid_i = int(vid) if vid not in (None, "", 0, "0") else extract_version_id(url)
|
||||
except (TypeError, ValueError):
|
||||
vid_i = extract_version_id(url)
|
||||
items.append(
|
||||
ModelCaptureItem(
|
||||
kind=kind,
|
||||
url=url,
|
||||
title=str(row.get("title") or Path(url).name),
|
||||
version_id=vid_i,
|
||||
source="wanted",
|
||||
)
|
||||
)
|
||||
if not items:
|
||||
return 0
|
||||
added, skipped = merge_models_yaml(Path(cfg.models_manifest), items, dry_run=False)
|
||||
if added:
|
||||
log(f"wanted→models.yaml: +{len(added)} (skip {len(skipped)})")
|
||||
elif skipped:
|
||||
log(f"wanted→models.yaml: уже есть ({len(skipped)})")
|
||||
return len(added)
|
||||
|
||||
|
||||
def _place_wanted_cards(cfg: Config, host: str, jobs: list[dict], log: Log) -> None:
|
||||
"""Copy drafted .assistent.json from wanted-cards next to freshly seeded weights."""
|
||||
cards_dir = f"{DATA}/.gpu-rent-wanted-cards"
|
||||
exists = run_ssh(
|
||||
cfg, host, f"test -d {shlex.quote(cards_dir)} && echo YES || true", check=False
|
||||
).strip()
|
||||
if "YES" not in exists:
|
||||
return
|
||||
placed = 0
|
||||
for job in jobs:
|
||||
dest = str(job.get("dest") or "")
|
||||
vid = job.get("version_id")
|
||||
if not dest or vid in (None, "", 0, "0"):
|
||||
continue
|
||||
stem = Path(dest).stem
|
||||
card_src = f"{cards_dir}/{vid}.assistent.json"
|
||||
card_dst = str(Path(dest).with_name(f"{stem}.assistent.json"))
|
||||
out = run_ssh(
|
||||
cfg,
|
||||
host,
|
||||
f"if test -f {shlex.quote(card_src)} && test -f {shlex.quote(dest)}; then "
|
||||
f"cp -n {shlex.quote(card_src)} {shlex.quote(card_dst)} && echo PLACED; fi",
|
||||
check=False,
|
||||
).strip()
|
||||
if "PLACED" in out:
|
||||
placed += 1
|
||||
if placed:
|
||||
log(f"wanted-cards: положил {placed} .assistent.json рядом с весами")
|
||||
|
||||
|
||||
def seed_civitai(cfg: Config, host: str, log: Log) -> None:
|
||||
from gpu_rent.huggingface import is_huggingface_url
|
||||
|
||||
try:
|
||||
merge_wanted_models_from_vm(cfg, host, log)
|
||||
except Exception as exc:
|
||||
log(f"wanted-models merge: {exc}")
|
||||
|
||||
entries = parse_models(cfg.models_manifest)
|
||||
if not entries:
|
||||
log("model-seed пропущен: манифест пуст — дефолт SwarmUI")
|
||||
@@ -775,6 +905,7 @@ def seed_civitai(cfg: Config, host: str, log: Log) -> None:
|
||||
"url": url,
|
||||
"sha256": "",
|
||||
"auth": "hf",
|
||||
"version_id": None,
|
||||
"sidecars": {
|
||||
f"{stem}.swarm.json": json.dumps(swarm, ensure_ascii=False, indent=2),
|
||||
},
|
||||
@@ -825,6 +956,7 @@ def seed_civitai(cfg: Config, host: str, log: Log) -> None:
|
||||
"url": _download_url(api_host, vid, info),
|
||||
"sha256": sha,
|
||||
"auth": "civitai",
|
||||
"version_id": int(vid),
|
||||
"sidecars": {
|
||||
f"{stem}.civitai.json": civitai_json,
|
||||
f"{stem}.swarm.json": json.dumps(swarm, ensure_ascii=False, indent=2),
|
||||
@@ -903,6 +1035,10 @@ def seed_civitai(cfg: Config, host: str, log: Log) -> None:
|
||||
timeout=7200,
|
||||
log=log,
|
||||
)
|
||||
try:
|
||||
_place_wanted_cards(cfg, host, jobs, log)
|
||||
except Exception as exc:
|
||||
log(f"wanted-cards: {exc}")
|
||||
put_text(
|
||||
cfg,
|
||||
host,
|
||||
@@ -1159,6 +1295,10 @@ def provision_vm(
|
||||
except GpuRentError as exc:
|
||||
log(f"autocomplete: {exc}")
|
||||
seed_civitai(cfg, host, log)
|
||||
try:
|
||||
seed_assistent_personas(cfg, host, log)
|
||||
except Exception as exc:
|
||||
log(f"assistent-personas: {exc}")
|
||||
push_tree(cfg, host, cfg.local_models_dir, f"{DATA}/Models", log, models=True)
|
||||
push_tree(
|
||||
cfg, host, cfg.local_wildcards_dir, f"{DATA}/Data/Wildcards", log, models=False
|
||||
|
||||
Reference in New Issue
Block a user