174 lines
6.1 KiB
Python
174 lines
6.1 KiB
Python
# ============================================================
|
||
# master.query + 机加工知识库黄金测试
|
||
# ============================================================
|
||
from __future__ import annotations
|
||
|
||
from server.aps_domain.kangni_intake import DEFAULT_ROUTE_XLSX, load_site_into_world
|
||
from server.aps_domain.master_query import format_master_query, run_master_query
|
||
from server.aps_domain.workflow import handle_intent
|
||
from server.contracts import IntentResult
|
||
from server.knowledge import get_knowledge
|
||
from server.state.seed import seed_world
|
||
from pathlib import Path
|
||
|
||
|
||
class _Mem:
|
||
def __init__(self, data):
|
||
self.data = data
|
||
|
||
def next_id(self, kind: str) -> int:
|
||
self.data[f"_c_{kind}"] = self.data.get(f"_c_{kind}", 100) + 1
|
||
return self.data[f"_c_{kind}"]
|
||
|
||
def save(self):
|
||
pass
|
||
|
||
|
||
def _world_site():
|
||
w = seed_world()
|
||
if Path(DEFAULT_ROUTE_XLSX).exists():
|
||
load_site_into_world(w, route_path=DEFAULT_ROUTE_XLSX, include_sibling_orders=False)
|
||
return w
|
||
|
||
|
||
def test_master_query_on_site_order():
|
||
w = _world_site()
|
||
if not Path(DEFAULT_ROUTE_XLSX).exists():
|
||
return
|
||
q = run_master_query(w, entity="order", code="102285668")
|
||
assert q["count"] >= 1
|
||
assert any(r["orderNo"] == "102285668" for r in q["rows"])
|
||
text = format_master_query(q)
|
||
assert "102285668" in text
|
||
|
||
bom = run_master_query(w, entity="bom", code="28200003654300")
|
||
assert bom["count"] >= 15
|
||
|
||
rt = run_master_query(w, entity="routing", code="28200003654300")
|
||
assert rt["count"] == 10
|
||
|
||
|
||
def test_master_query_requires_pi_structured_parameters():
|
||
w = _world_site()
|
||
missing_entity = run_master_query(w, text="帮我看看这个")
|
||
assert missing_entity["ok"] is False
|
||
assert "主数据类型" in missing_entity["error"]
|
||
|
||
missing_code = run_master_query(w, entity="order", text="查订单 102285668")
|
||
assert missing_code["ok"] is False
|
||
assert "编码" in missing_code["error"]
|
||
|
||
missing_aspect = run_master_query(w, entity="mrp", code="102285668")
|
||
assert missing_aspect["ok"] is False
|
||
assert "aspect" in missing_aspect["error"]
|
||
|
||
|
||
def test_machining_seed_assets_present():
|
||
kb = get_knowledge()
|
||
n = kb.ensure_seed_assets()
|
||
titles = {a["title"] for a in kb.assets}
|
||
assert "机加工工艺路线生成总则" in titles
|
||
assert "车削工艺路线模式" in titles
|
||
assert "机械装配工艺模式" in titles
|
||
assert "城轨机构装配路线模板" in titles
|
||
assert sum(1 for a in kb.assets if a.get("kind") == "process") >= 10
|
||
|
||
|
||
def test_chat_master_query_and_kb_catalog():
|
||
import asyncio
|
||
|
||
w = _world_site()
|
||
store = _Mem(w)
|
||
|
||
async def _run():
|
||
reply = await handle_intent(
|
||
store, "t",
|
||
IntentResult(intent="master.query", params={"entity": "overview", "query": "主数据概览"},
|
||
confidence=0.95, source="LLM"),
|
||
actor="test",
|
||
)
|
||
assert "主数据概览" in reply.text or "工厂" in reply.text
|
||
|
||
reply2 = await handle_intent(
|
||
store, "t",
|
||
IntentResult(intent="knowledge.query", params={"mode": "catalog", "query": "知识清单"},
|
||
confidence=0.95, source="LLM"),
|
||
actor="test",
|
||
)
|
||
assert "机加工工艺路线生成总则" in reply2.text
|
||
assert "知识库共" in reply2.text
|
||
|
||
asyncio.run(_run())
|
||
|
||
|
||
def test_schedule_this_order_deixis():
|
||
"""查完订单后带 orderRef=last 的 flex.schedule 请求应解析到会话焦点订单。"""
|
||
import asyncio
|
||
|
||
from server.agent_core.session_focus import get_last_order_no
|
||
|
||
w = _world_site()
|
||
if not Path(DEFAULT_ROUTE_XLSX).exists() or not w.get("flexOrders"):
|
||
return
|
||
store = _Mem(w)
|
||
sid = "deixis-sched"
|
||
|
||
r = IntentResult(intent="flex.schedule", params={"orderRef": "last"},
|
||
confidence=1.0, source="LLM")
|
||
|
||
async def _run():
|
||
q = IntentResult(intent="master.query",
|
||
params={"entity": "order", "code": "102285668"},
|
||
confidence=1.0, source="LLM")
|
||
await handle_intent(store, sid, q, actor="test")
|
||
assert get_last_order_no(sid) == "102285668"
|
||
reply = await handle_intent(store, sid, r, actor="test")
|
||
assert "闭环排产被阻断" in reply.text
|
||
assert "102285668" in reply.text
|
||
|
||
asyncio.run(_run())
|
||
|
||
|
||
def test_outsource_qa_and_plan_report():
|
||
"""委外查询(entity=mrp + orderRef=last)可答;排产方案报告可下载。"""
|
||
import asyncio
|
||
|
||
from server.agent_core.session_focus import set_focus
|
||
from server.aps_domain.flex import run_flex_schedule
|
||
from server.aps_domain.reports import build_plan_report
|
||
|
||
w = _world_site()
|
||
if not Path(DEFAULT_ROUTE_XLSX).exists() or not w.get("flexOrders"):
|
||
return
|
||
store = _Mem(w)
|
||
sid = "qa-report"
|
||
|
||
r = IntentResult(intent="master.query",
|
||
params={"entity": "mrp", "code": "102285668", "aspect": "outsource"},
|
||
confidence=1.0, source="LLM")
|
||
|
||
r_plan = IntentResult(intent="report.generate", params={"reportType": "plan"},
|
||
confidence=1.0, source="LLM")
|
||
|
||
run_flex_schedule(store, sort_mode="BOTTLENECK", actor="test")
|
||
plan = build_plan_report(w, order_no="102285668")
|
||
assert plan["reportId"]
|
||
assert plan.get("xlsxBytes")
|
||
assert plan["xlsxBytes"][:2] == b"PK" # zip/xlsx magic
|
||
assert "工作计划" in plan["markdown"] or "Excel" in plan["markdown"]
|
||
assert plan["snapshot"]["woCount"] == 0
|
||
assert plan["blocked"] is True
|
||
|
||
async def _run():
|
||
set_focus(sid, orderNo="102285668")
|
||
reply = await handle_intent(store, sid, r, actor="test")
|
||
assert "委外" in reply.text
|
||
assert "102285668" in reply.text
|
||
reply2 = await handle_intent(store, sid, r_plan, actor="test")
|
||
assert reply2.blocks and reply2.blocks[0].type == "report"
|
||
assert "排产阻断分析报告" in reply2.blocks[0].props["title"]
|
||
assert reply2.blocks[0].props.get("format") == "xlsx"
|
||
assert reply2.blocks[0].props.get("downloadUrl")
|
||
|
||
asyncio.run(_run())
|