支持直接审查 PDF 与位图图纸,全链路离线(不连 CAD、不连 8080 端口)。 渲染在内存内完成,复用既有墨迹热力图 + 自适应瓦片规划。 - 新增 dwg_review/sources.py - detect_source / plan_file / collect 统一入口 - PdfReader:pypdfium2 惰性导入,页序即图框序,处理 /Rotate 与 crop 边距 - ImageReader:世界单位 = 源像素,snap_box 整数对齐保证窗口与像素严格一致 - ink_grid:纯 PIL 灰度阈值 → 占用网格(不引入 numpy) - ReviewContext.create(connect_cad=False):离线时 client/tools 均为 None - 全链路 ctx.tools is None 守卫:review 只读子循环 / inspect_region / annotator / checks 的窗口类检查 / 绘图区最大化 - checklist.build_system_prompt(allow_tools=False, offline=True):离线提示词 - __main__:位置参数 source,按扩展名自动判定源类型并决定是否连 CAD - config 新增 8 个常量(PDF_MAX_PAGES / 文本最小字数 / 各源缩放上限 / 墨迹阈值等) - tiling.content_predicate 与 heatmap.cell_box 提升为公开函数 验证: - pytest 457 passed - verify_pdf_source.py:PDF 23/23、图片 9/9(不需 CAD),含实测瓦片字高像素与 旋转映射自检(文本区墨迹 0.311 vs 忽略 /Rotate 反向对照 0.145) - 真实 LLM 端到端:20 页 HVAC 图纸前 3 页跑通,结论具体可核验且未编造 handle 已知局限:页边线在墨迹网格里会把整页连成单簇,瓦片常退化为整页象限(CAD 侧 靠 drop_oversized 丢图框块,离线侧暂无等价手段),留待后续打磨。
116 lines
3.2 KiB
Python
116 lines
3.2 KiB
Python
"""`dwg_review.evidence_model` 单元测试。"""
|
|
|
|
from dwg_review import evidence_model as em
|
|
|
|
|
|
def test_make_image_defaults():
|
|
assert em.make_image("QUJD") == {"b64": "QUJD", "mime": "image/png", "label": None}
|
|
|
|
|
|
def test_make_image_custom():
|
|
assert em.make_image("QUJD", "image/jpeg", "tile-1") == {
|
|
"b64": "QUJD",
|
|
"mime": "image/jpeg",
|
|
"label": "tile-1",
|
|
}
|
|
|
|
|
|
def test_make_image_empty_mime_falls_back():
|
|
assert em.make_image("x", "")["mime"] == "image/png"
|
|
|
|
|
|
def test_empty_envelope_default():
|
|
assert em.empty_envelope() == {"total": 0, "items": []}
|
|
|
|
|
|
def test_empty_envelope_total():
|
|
env = em.empty_envelope(7)
|
|
assert env == {"total": 7, "items": []}
|
|
# items 必须是**新列表**(调用方可能各自 append,不能共享同一对象)
|
|
assert em.empty_envelope()["items"] is not em.empty_envelope()["items"]
|
|
|
|
|
|
def test_empty_envelope_int_coercion():
|
|
assert em.empty_envelope("3")["total"] == 3
|
|
|
|
|
|
def test_source_type_of_default_cad():
|
|
assert em.source_type_of({}) == em.SOURCE_CAD
|
|
assert em.source_type_of(None) == em.SOURCE_CAD
|
|
assert em.source_type_of({"source_type": ""}) == em.SOURCE_CAD
|
|
|
|
|
|
def test_source_type_of_explicit():
|
|
assert em.source_type_of({"source_type": "pdf"}) == "pdf"
|
|
assert em.source_type_of({"source_type": "image"}) == "image"
|
|
|
|
|
|
def test_evidence_images_new_form():
|
|
ev = {
|
|
"images": [
|
|
em.make_image("A", label="overall"),
|
|
em.make_image("B", label="tile-1"),
|
|
]
|
|
}
|
|
out = em.evidence_images(ev)
|
|
assert [i["b64"] for i in out] == ["A", "B"]
|
|
assert [i["label"] for i in out] == ["overall", "tile-1"]
|
|
|
|
|
|
def test_evidence_images_filters_empty_b64():
|
|
ev = {"images": [{"b64": "", "mime": "image/png"}, {"b64": "A"}]}
|
|
out = em.evidence_images(ev)
|
|
assert len(out) == 1
|
|
assert out[0]["b64"] == "A"
|
|
|
|
|
|
def test_evidence_images_legacy_fallback():
|
|
ev = {"image_b64": "LEG", "image_mime": "image/jpeg"}
|
|
assert em.evidence_images(ev) == [
|
|
{"b64": "LEG", "mime": "image/jpeg", "label": None, "window": None}
|
|
]
|
|
|
|
|
|
def test_evidence_images_legacy_default_mime():
|
|
assert em.evidence_images({"image_b64": "LEG"})[0]["mime"] == "image/png"
|
|
|
|
|
|
def test_evidence_images_empty():
|
|
assert em.evidence_images({}) == []
|
|
assert em.evidence_images(None) == []
|
|
assert em.evidence_images({"images": []}) == []
|
|
|
|
|
|
def test_evidence_images_prefers_new_over_legacy():
|
|
ev = {"images": [em.make_image("NEW")], "image_b64": "OLD"}
|
|
assert [i["b64"] for i in em.evidence_images(ev)] == ["NEW"]
|
|
|
|
|
|
def test_primary_image_prefers_overall():
|
|
ev = {
|
|
"images": [
|
|
em.make_image("A", label="tile-1"),
|
|
em.make_image("B", label="overall"),
|
|
]
|
|
}
|
|
assert em.primary_image(ev)["b64"] == "B"
|
|
|
|
|
|
def test_primary_image_first_when_no_overall():
|
|
ev = {"images": [em.make_image("A", label="tile-1"), em.make_image("B")]}
|
|
assert em.primary_image(ev)["b64"] == "A"
|
|
|
|
|
|
def test_primary_image_none_when_empty():
|
|
assert em.primary_image({}) is None
|
|
|
|
|
|
def test_image_labels():
|
|
ev = {
|
|
"images": [
|
|
em.make_image("A", label="overall"),
|
|
em.make_image("B", label="tile-1"),
|
|
]
|
|
}
|
|
assert em.image_labels(ev) == ["overall", "tile-1"]
|