aps-agent/scripts/demo_ruiyang_e2e.py

148 lines
5.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ============================================================
# 锐扬 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())