Thin HTTP client for the resident oMLX server on :8020 (launchd party.monster.deepseek-v4, repo monster/deepseek_v4_flash_0731_mrp_mlx). gpu lane so the queue serializes LLM calls against mesh/image gen on this node. Kickstarts the service if down. Primary-only — ~150GB wired warm. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
92 lines
3.2 KiB
Python
92 lines
3.2 KiB
Python
import argparse
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import urllib.error
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
# DeepSeek-V4-Flash-0731 via the oMLX server (repo: monster/deepseek_v4_flash_0731_mrp_mlx).
|
|
# The server is a resident service (launchd party.monster.deepseek-v4) holding ~150GB
|
|
# wired when warm; this operator is a thin HTTP client. It runs on the gpu lane so the
|
|
# queue serializes it against trellis/flux on this node — that serialization, not this
|
|
# script, is what stops the LLM and mesh gen fighting over Metal.
|
|
BASE = "http://127.0.0.1:8020"
|
|
MODEL = "DeepSeek-V4-Flash-0731-MXFP4-MLX"
|
|
LAUNCHD_LABEL = "party.monster.deepseek-v4"
|
|
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--input", action="append", default=[])
|
|
ap.add_argument("--outdir", required=True)
|
|
ap.add_argument("--params", default="{}")
|
|
a = ap.parse_args()
|
|
p = json.loads(a.params)
|
|
|
|
prompt = (p.get("prompt") or "").strip()
|
|
if not prompt:
|
|
print("ERROR: prompt is required")
|
|
sys.exit(1)
|
|
|
|
|
|
def server_up() -> bool:
|
|
try:
|
|
with urllib.request.urlopen(f"{BASE}/health", timeout=5) as r:
|
|
return r.status == 200
|
|
except (urllib.error.URLError, OSError):
|
|
return False
|
|
|
|
|
|
if not server_up():
|
|
# Cold path: ask launchd to (re)start the service, then wait for readiness.
|
|
# First token after a cold start also pays the ~30s weight load.
|
|
print("oMLX server down — kickstarting launchd service", flush=True)
|
|
uid = subprocess.run(["id", "-u"], capture_output=True, text=True).stdout.strip()
|
|
subprocess.run(["launchctl", "kickstart", f"gui/{uid}/{LAUNCHD_LABEL}"],
|
|
capture_output=True)
|
|
deadline = time.time() + 180
|
|
while time.time() < deadline and not server_up():
|
|
time.sleep(3)
|
|
if not server_up():
|
|
print("ERROR: oMLX server did not come up on :8020. Install the service with "
|
|
"~/Documents/deepseek_v4_flash_0731_mrp_mlx/scripts/install_launchagent.sh")
|
|
sys.exit(1)
|
|
|
|
messages = []
|
|
if (p.get("system") or "").strip():
|
|
messages.append({"role": "system", "content": p["system"].strip()})
|
|
messages.append({"role": "user", "content": prompt})
|
|
|
|
body = json.dumps({
|
|
"model": MODEL,
|
|
"messages": messages,
|
|
"max_tokens": int(p.get("max_tokens", 1024)),
|
|
"temperature": float(p.get("temperature", 0.7)),
|
|
}).encode()
|
|
|
|
t0 = time.time()
|
|
req = urllib.request.Request(f"{BASE}/v1/chat/completions", data=body,
|
|
headers={"Content-Type": "application/json"})
|
|
try:
|
|
# generous timeout: cold start pays ~30s model load before first token
|
|
with urllib.request.urlopen(req, timeout=600) as r:
|
|
d = json.loads(r.read())
|
|
except (urllib.error.URLError, OSError) as e:
|
|
print(f"ERROR: request failed: {e}")
|
|
sys.exit(1)
|
|
|
|
if "error" in d:
|
|
print(f"ERROR: {d['error']}")
|
|
sys.exit(1)
|
|
|
|
msg = d["choices"][0]["message"]
|
|
text = (msg.get("content") or "").strip()
|
|
usage = d.get("usage", {})
|
|
el = time.time() - t0
|
|
ct = usage.get("completion_tokens") or 0
|
|
|
|
out = Path(a.outdir) / "llm_output.txt"
|
|
out.write_text(text + "\n")
|
|
tps = f", {ct / el:.1f} tok/s" if ct and el > 0 else ""
|
|
print(f"done in {el:.1f}s ({ct} tokens{tps}), {len(text)} chars:\n{text[:400]}", flush=True)
|