Enhance SwarmUI integration and GPU environment verification
- Updated CLI documentation to reflect the new handling of `CIVITAI_API_TOKEN`, which is now automatically passed to SwarmUI user settings during startup. - Improved the `render_access_panel` function to include additional warnings for idle-killer failures and stack errors, enhancing user feedback. - Introduced a new function `seed_swarmui_api_keys` to manage API key injection into SwarmUI, ensuring seamless integration with the Model Downloader. - Enhanced GPU environment verification logic to include fail-fast checks for critical components like CUDA, improving error handling and user notifications. - Updated tests to validate the new API key handling and access panel behavior, ensuring robustness in the integration process.
This commit is contained in:
@@ -77,9 +77,21 @@ ensure_bind() {
|
||||
}
|
||||
|
||||
log "пакеты (без upgrade ядра)"
|
||||
if [[ "${GPU_RENT_BOOTSTRAP_LIGHT:-0}" == "1" && -f "$MARKER_BOOT" ]]; then
|
||||
log "light bootstrap — пропускаем apt-get"
|
||||
# Light: skip apt when Swarm already bootstrapped, or llm-only data disk already ready.
|
||||
_light_ok=0
|
||||
if [[ "${GPU_RENT_BOOTSTRAP_LIGHT:-0}" == "1" ]]; then
|
||||
if [[ -f "$MARKER_BOOT" ]]; then
|
||||
_light_ok=1
|
||||
elif [[ "${GPU_RENT_SKIP_SWARMUI:-0}" == "1" && -f "$MARKER_DATA" ]]; then
|
||||
_light_ok=1
|
||||
fi
|
||||
fi
|
||||
if [[ "$_light_ok" == "1" ]]; then
|
||||
log "light bootstrap — пропускаем apt-get (маркер уже есть)"
|
||||
else
|
||||
if [[ "${GPU_RENT_BOOTSTRAP_LIGHT:-0}" == "1" ]]; then
|
||||
log "light запрошен, но маркера нет — полный apt"
|
||||
fi
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq git python3 python3-venv python3-pip python3-full curl ca-certificates
|
||||
fi
|
||||
|
||||
@@ -179,14 +179,16 @@ def main() -> int:
|
||||
token = TOKEN_PATH.read_text(encoding="utf-8").strip() if TOKEN_PATH.is_file() else ""
|
||||
jobs = json.loads(JOBS_PATH.read_text(encoding="utf-8"))
|
||||
update = do_update()
|
||||
print(f"extensions update={'on' if update else 'off'}")
|
||||
print(f"extensions update={'on' if update else 'off'} jobs={len(jobs)}")
|
||||
failed = 0
|
||||
known: set[str] = set()
|
||||
try:
|
||||
for job in jobs:
|
||||
total = len(jobs)
|
||||
for i, job in enumerate(jobs, start=1):
|
||||
try:
|
||||
dest = str(Path(job["dest"]))
|
||||
known.add(dest)
|
||||
print(f"extensions [{i}/{total}] {dest}")
|
||||
clone_one(job, token, update)
|
||||
except Exception as exc:
|
||||
failed += 1
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Push upstream API keys into SwarmUI (user GenericData via SetAPIKey).
|
||||
|
||||
Stdlib only. Keys file: /tmp/gpu-rent-swarm-api-keys.json (mode 600), shape:
|
||||
{"civitai_api": "...", "huggingface_api": "..."} # omit empty
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
KEYS_PATH = Path("/tmp/gpu-rent-swarm-api-keys.json")
|
||||
SWARM = "http://127.0.0.1:7801"
|
||||
ACCEPTED = ("civitai_api", "huggingface_api", "stability_api")
|
||||
|
||||
|
||||
def post(path: str, payload: dict, timeout: float = 15.0) -> dict:
|
||||
body = json.dumps(payload).encode("utf-8")
|
||||
req = urllib.request.Request(
|
||||
f"{SWARM}{path}",
|
||||
data=body,
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
|
||||
def wait_session(deadline: float) -> str:
|
||||
last = ""
|
||||
while time.time() < deadline:
|
||||
try:
|
||||
data = post("/API/GetNewSession", {})
|
||||
sid = str(data.get("session_id") or "")
|
||||
if sid:
|
||||
return sid
|
||||
last = "no session_id"
|
||||
except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, OSError, json.JSONDecodeError) as exc:
|
||||
last = str(exc)[:160]
|
||||
time.sleep(2)
|
||||
raise SystemExit(f"SwarmUI session unavailable: {last}")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not KEYS_PATH.is_file():
|
||||
print("no keys file — skip")
|
||||
return 0
|
||||
try:
|
||||
raw = json.loads(KEYS_PATH.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError) as exc:
|
||||
print(f"bad keys file: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
finally:
|
||||
try:
|
||||
KEYS_PATH.unlink(missing_ok=True)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
keys = {k: str(v).strip() for k, v in (raw or {}).items() if k in ACCEPTED and str(v).strip()}
|
||||
if not keys:
|
||||
print("no api keys to set")
|
||||
return 0
|
||||
|
||||
sid = wait_session(time.time() + 120)
|
||||
for key_type, value in keys.items():
|
||||
try:
|
||||
resp = post(
|
||||
"/API/SetAPIKey",
|
||||
{"session_id": sid, "keyType": key_type, "key": value},
|
||||
)
|
||||
except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError, OSError, json.JSONDecodeError) as exc:
|
||||
print(f"SetAPIKey {key_type} failed: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
if resp.get("error"):
|
||||
print(f"SetAPIKey {key_type}: {resp['error']}", file=sys.stderr)
|
||||
return 1
|
||||
if not resp.get("success"):
|
||||
print(f"SetAPIKey {key_type}: unexpected {resp}", file=sys.stderr)
|
||||
return 1
|
||||
print(f"SetAPIKey {key_type}=ok")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -129,11 +129,15 @@ def main() -> int:
|
||||
prev = json.loads(MARKER.read_text(encoding="utf-8"))
|
||||
except json.JSONDecodeError:
|
||||
prev = {}
|
||||
if prev.get("uuid") and prev.get("uuid") == plan["uuid"] and prev.get("extra_args") == plan["extra_args"]:
|
||||
same_gpu = bool(prev.get("uuid") and prev.get("uuid") == plan["uuid"])
|
||||
if same_gpu and prev.get("extra_args") == plan["extra_args"]:
|
||||
if prev.get("pip_ok") or not plan["use_sage"]:
|
||||
print(f"perf tune already applied for {plan['name']} ({plan['tier']})")
|
||||
return 0
|
||||
|
||||
if same_gpu and plan["use_sage"] and prev.get("pip_ok") is False:
|
||||
print("perf tune: retry (previous pip_ok=false — sage/triton ещё не встали)")
|
||||
|
||||
print(f"perf tune: {plan['name']} tier={plan['tier']} sage={plan['use_sage']}")
|
||||
pip_ok = not plan["use_sage"]
|
||||
restarted_needed = False
|
||||
|
||||
Reference in New Issue
Block a user