aps-agent/tests/golden/test_drawing_process.py

128 lines
6.8 KiB
Python
Raw Normal View History

# ============================================================
# 图纸工艺/工序/细节识别黄金测试(R71.2 增强)
# 覆盖:合成文本识别、真实图纸标题栏/零件名、不误判比例、候选门禁。
# ============================================================
from __future__ import annotations
from pathlib import Path
from server.aps_domain.drawing_dxf import build_drawing_master_candidates, inspect_dxf
from server.aps_domain.drawing_process import (
recognize_process_candidates,
recognize_process_text,
)
from server.aps_domain.drawing_understanding import build_drawing_understanding
_DEFAULT_SAMPLE = Path(r"D:\ItemSpace\14.工业智核\锐扬\5060102101-001-e(1).dxf")
_SAMPLE_003 = Path(r"D:\ItemSpace\14.工业智核\锐扬\5060102101-003-e(1).dxf")
def _sample(path: Path) -> Path:
if not path.is_file():
import pytest
pytest.skip(f"real DXF fixture not available: {path}")
return path
def test_synthetic_process_and_detail_recognition():
parsed = {
"asset": {"sha256": "0" * 64},
"texts": [
{"text": "DREHEN Ø20 TOLERANZ ±0.01", "evidence": {"source": "drawingText", "page": 1}},
{"text": "OBERFLÄCHE Ra 3.2", "evidence": {"source": "drawingText", "page": 1}},
{"text": "M30x1.5 16 TIEF", "evidence": {"source": "drawingText", "page": 1}},
{"text": "MONTAGE", "evidence": {"source": "drawingText", "page": 1}},
{"text": "SCALE 1:5", "evidence": {"source": "drawingText", "page": 1}},
],
}
process = recognize_process_candidates(parsed)
codes = {row["processCode"] for row in process["operations"]}
assert {"TURNING", "ASSEMBLY", "THREADING"} <= codes
assert "SURFACE_TREATMENT" in codes
details = {row["field"]: row["value"] for row in process["details"]}
assert details["tolerance"] == "±0.01"
assert details["surfaceRoughness"] == "Ra 3.2"
assert details["threadSpecification"] == "M30x1.5"
assert details["depthMm"] == "16 TIEF"
assert "M1" not in [row["value"] for row in process["details"]]
def test_real_dxf_recognizes_process_and_details():
parsed = inspect_dxf(_sample(_DEFAULT_SAMPLE))
fields = {row["field"]: row["value"] for row in parsed["fieldCandidates"]}
assert fields.get("threadSpecification") in {"M10", "M12", "M6", "M18x1.5"}
assert "M1" not in [row["value"] for row in parsed["fieldCandidates"]]
change_set = build_drawing_master_candidates(parsed)
ops = change_set["routingOperations"]
assert any(row["operationCode"] != "ENGINEERING_REVIEW" for row in ops)
assert change_set["processDetails"]
assert "processBlocks" in change_set
assert "processAssemblies" in change_set
assert "processLocations" in change_set
assert "processSequenceSteps" in change_set
for row in ops:
assert row["reviewRequired"] is True
assert row["standardTime"] is None
assert row["resourceCode"] is None
assert row["evidence"]
def test_real_parts_list_extracts_assembly_thread_and_depth():
understanding = build_drawing_understanding(inspect_dxf(_sample(_SAMPLE_003)))
assert understanding["processCandidates"]
assert understanding["routingOperations"]
details = {row["field"]: row["value"] for row in understanding["processDetails"]}
assert details.get("threadSpecification")
assert details.get("depthMm")
assert any(row["processCode"] == "ASSEMBLY" for row in understanding["processCandidates"])
assert any(row["processCode"] == "THREADING" for row in understanding["processCandidates"])
_CHINESE_PROCESS_TEXT = """
烟囱(9005)分段分为首面围壁组立、尾面围壁组立、侧壁组立、顶板组立等。
2.1首、尾围壁组立、侧壁组立、顶板组立在上建场地平胎位制作完成。
2.2烟囱分段在经托架改造的胎架上以首面围壁为胎,依次装配顶板组立、侧壁组立和尾面围壁组立,根据《9004分段建造工艺》要求穿插进行管系、舾装作业。
上建主体分段(9011、9012、9013、9014、9015、9016、9017分段)主要分为甲板组立、围堰双壳组立、外围壁组立、内部隔舱壁组立、伙食吊筒壁(仅9016分段)等组立。
3.1外围壁组立、内部隔舱壁组立在平胎位拼板,装焊骨材,形成平面组立。甲板板在分片制作场地拼板,然后甲板板上大组胎架进行拼板(单面焊)、划线、装焊骨材、横梁、纵桁等形成甲板组立。伙食吊筒壁在联合厂房进行下料、卷制、焊接。
3.2围堰双壳组立内的板片、隔板、顶板、骨材、筋板肘板等在联合厂房下料送至上建场地。在上建场地以一侧围板为胎装焊内部构件,翻身与另一侧围板装焊形成完整的围堰双壳组立。
9212/9312围堰分段的建造流程与3.2项类似。
9211/9311/9411/9412/9512分段在上建场地以甲板为胎反造。
9216/9316分段在上建场地制作成型。分段主要包含驾驶甲板平台组立、FR46横壁组立、箱形立柱和斜纵壁等组立。
6.2驾驶甲板平台中组立先以驾驶甲板为基装配隔板组立,完成焊接后翻身装配到驾驶甲板平台组立上,再装配FR46舷墙组立。
"""
def test_chinese_process_text_extracts_rich_key_information():
result = recognize_process_text(_CHINESE_PROCESS_TEXT)
codes = {row["blockCode"] for row in result["blocks"]}
assert "9005" in codes
assert any("9011" in code for code in codes)
assert any("9212/9312" in code or "9212" in code for code in codes)
assert any("9211/9311/9411/9412/9512" in code or "9211" in code for code in codes)
assert any("9216/9316" in code or "9216" in code for code in codes)
assert any("FR46" in code for code in codes)
assemblies = {row["assemblyName"] for row in result["assemblies"]}
assert {"首面围壁组立", "尾面围壁组立", "侧壁组立", "顶板组立", "甲板组立",
"围堰双壳组立", "外围壁组立", "内部隔舱壁组立", "驾驶甲板平台组立"} <= assemblies
assert any("FR46横壁组立" in name for name in assemblies)
ops = {row["processName"] for row in result["operations"]}
assert {"拼板", "装焊", "下料", "卷制", "翻身", "反造", "舾装", "管系", "焊接", "划线"} <= ops
locations = {row["location"] for row in result["locations"]}
assert {"上建场地", "联合厂房", "平胎位", "大组胎架"} <= locations
assert result["sequenceSteps"]
assert result["status"] == "PENDING_REVIEW"
def test_process_candidates_stay_pending_with_evidence():
understanding = build_drawing_understanding(inspect_dxf(_sample(_SAMPLE_003)))
for row in understanding["processCandidates"] + understanding["processDetails"]:
assert row["status"] == "PENDING_REVIEW"
assert row["reviewRequired"] is True
assert 0 < row["confidence"] <= 1
assert row["evidence"]