aps-agent/scripts/demo_ruiyang_e2e.py

148 lines
5.7 KiB
Python
Raw Normal View History

# ============================================================
# 锐扬 APS 演示全流程 E2E 驱动(开发/诊断用)
# 解析文件夹 → 导入试排 → MRP 分解 → 下达 → 柔性排产 → 验证订单页数据
# ============================================================
from __future__ import annotations
import json
import os
import sys
import urllib.request
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
BASE = (os.environ.get("APS_DEMO_API_URL") or "http://127.0.0.1:8000").rstrip("/")
WORKDIR = str(Path(
os.environ.get("RUIYANG_DEMO_DIR")
or (REPO_ROOT / "demo-data" / "锐扬APS演示数据")
).resolve())
PROJECT_NAME = "锐扬演示-E2E"
def req(method: str, path: str, body: dict | None = None, timeout: int = 300) -> dict:
data = json.dumps(body).encode("utf-8") if body is not None else None
r = urllib.request.Request(
BASE + path, data=data, method=method,
headers={"Content-Type": "application/json"},
)
with urllib.request.urlopen(r, timeout=timeout) as resp:
return json.loads(resp.read().decode("utf-8"))
def chat(session_id: str, project_id: str, text: str) -> dict:
"""POST /api/chat(SSE),聚合 token 文本 / intent / blocks。"""
body = json.dumps({"sessionId": session_id, "projectId": project_id, "text": text, "history": []}).encode("utf-8")
r = urllib.request.Request(BASE + "/api/chat", data=body, method="POST",
headers={"Content-Type": "application/json"})
out = {"text": "", "intents": [], "blocks": [], "errors": []}
with urllib.request.urlopen(r, timeout=600) as resp:
for raw in resp:
line = raw.decode("utf-8", "ignore").strip()
if not line.startswith("data:"):
continue
try:
ev = json.loads(line[5:].strip())
except json.JSONDecodeError:
continue
t = ev.get("type")
if t == "token":
out["text"] += ev.get("text") or ""
elif t == "intent":
out["intents"].append((ev.get("intent") or {}).get("intent"))
elif t == "block":
out["blocks"].append(ev.get("block") or {})
elif t == "error":
out["errors"].append(ev.get("message"))
return out
def confirm(session_id: str, confirm_id: str) -> dict:
return req("POST", "/api/actions/confirm",
{"sessionId": session_id, "confirmId": confirm_id, "approve": True})
def show(title: str, payload: dict, keys: list[str]) -> None:
print(f"\n--- {title} ---")
for k in keys:
v = payload.get(k)
if isinstance(v, list):
print(f" {k}: {len(v)} 条")
else:
print(f" {k}: {v}")
def main() -> None:
# 1) 建项目 + 会话
proj = req("POST", "/api/projects", {
"name": PROJECT_NAME, "scopeLabel": "锐扬 APS 文件夹演示", "workDir": WORKDIR,
})
pid = proj["project"]["id"]
print(f"[1] 项目已建: {pid} workDir={WORKDIR}")
sess = req("POST", "/api/sessions", {"projectId": pid, "title": "锐扬全流程演示"})
sid = sess["session"]["id"]
print(f"[1] 会话已建: {sid}")
# 2) 激活工作区(切换世界);服务端只接受选择字段与消息体
ws = req("PUT", "/api/workspace", {
"activeProjectId": pid, "activeSessionId": sid, "messages": {},
})
print(f"[2] 工作区已激活 worldKey={ws.get('worldKey')}")
# 3) 解析文件夹
r = chat(sid, pid, "分析一下数据文件")
print(f"\n[3] folder.analyze intents={r['intents']}\n{r['text'][:1200]}")
if r["errors"]:
print(" ERRORS:", r["errors"])
# 4) 导入目录数据并试排(P2 → 确认卡)
r = chat(sid, pid, "根据这个文件夹的数据导入并试排")
print(f"\n[4] folder.schedule intents={r['intents']}\n{r['text'][:800]}")
for b in r["blocks"]:
cid = (b.get("props") or {}).get("confirmId")
if cid:
res = confirm(sid, cid)
print(f" 确认 {cid[:12]}… → {json.dumps(res, ensure_ascii=False)[:400]}")
# 5) MRP 分解
r = chat(sid, pid, "执行MRP分解")
print(f"\n[5] order.decompose intents={r['intents']}\n{r['text'][:800]}")
if r["errors"]:
print(" ERRORS:", r["errors"])
mrp = req("GET", "/api/mrp")
show("MRP 分解后 /api/mrp", mrp, ["make", "purchaseOrders", "outsourceOrders"])
# 6) 下达 MRP 建议单(P2 → 确认卡)
r = chat(sid, pid, "下达MRP建议单")
print(f"\n[6] mrp.release intents={r['intents']}\n{r['text'][:600]}")
for b in r["blocks"]:
cid = (b.get("props") or {}).get("confirmId")
if cid:
res = confirm(sid, cid)
print(f" 确认 {cid[:12]}… → {json.dumps(res, ensure_ascii=False)[:400]}")
# 7) 柔性排产
r = chat(sid, pid, "跑一版柔性排产")
print(f"\n[7] flex.schedule intents={r['intents']}\n{r['text'][:800]}")
for b in r["blocks"]:
cid = (b.get("props") or {}).get("confirmId")
if cid:
res = confirm(sid, cid)
print(f" 确认 {cid[:12]}… → {json.dumps(res, ensure_ascii=False)[:400]}")
if r["errors"]:
print(" ERRORS:", r["errors"])
# 8) 验证订单页各 Tab 数据
od = req("GET", "/api/orders")
show("订单页 /api/orders", od,
["orders", "productionOrders", "purchaseOrders", "outsourceOrders", "make", "hasSchedule"])
g = req("GET", "/api/flex/gantt")
rows = g.get("rows") or g.get("lines") or []
print(f"\n[8] /api/flex/gantt keys={list(g.keys())[:8]} rows={len(rows)}")
print(f"\nDONE project={pid} session={sid}")
if __name__ == "__main__":
sys.exit(main())