- 新增 evidence_model.py:统一证据模型(source_type + images 列表),访问器兼容旧 image_b64/image_mime 单图字段 - phases/evidence.py:新增 collect() 多源分发 seam(仅 CAD)、capture_images() 整体+等分象限多图(结束复位视口)、sub_windows() - phases/review.py:多图逐张下采样喂 LLM,payload 增加 source_type - config.py:EVIDENCE_DETAIL_TILES=4 / EVIDENCE_MAX_IMAGES=5(默认开启多图) - 新增 tests/test_evidence_model.py,更新 evidence/review 断言与 fakes 归一
89 lines
2.8 KiB
Python
89 lines
2.8 KiB
Python
"""统一证据模型:多来源(CAD / PDF / 图片)证据的字段常量与访问器。
|
||
|
||
设计要点:
|
||
- evidence 是跨阶段 + 落盘的「线格式」数据,统一用 dict 承载(不用 dataclass)。
|
||
- 图片统一为 `images: [{"b64","mime","label"}]`;访问器兼容旧的 `image_b64/image_mime`
|
||
单图字段(历史 evidence.json 与旧测试构造仍可读)。
|
||
- 本模块不含任何 CAD / 工具逻辑,可被 phases、findings、__main__、tests 共同引用。
|
||
"""
|
||
|
||
SOURCE_CAD = "cad"
|
||
SOURCE_PDF = "pdf"
|
||
SOURCE_IMAGE = "image"
|
||
|
||
# 结构化证据键(CAD 侧各查询工具产出的信封);下游 handle 收集 / 派生检查统一引用,
|
||
# 避免在多处硬编码同一组键名。
|
||
STRUCTURED_SOURCES = ("entities", "texts", "dimensions", "blocks", "polylines")
|
||
|
||
|
||
def make_image(b64, mime="image/png", label=None):
|
||
"""构造 images 列表元素。"""
|
||
return {"b64": b64, "mime": mime or "image/png", "label": label}
|
||
|
||
|
||
def source_type_of(container):
|
||
"""读取来源类型,缺省视为 CAD。
|
||
|
||
container 可以是审查单元(unit)/ 图框 / evidence 等任何 dict。
|
||
"""
|
||
if isinstance(container, dict):
|
||
value = container.get("source_type")
|
||
if isinstance(value, str) and value:
|
||
return value
|
||
return SOURCE_CAD
|
||
|
||
|
||
def evidence_images(evidence):
|
||
"""规范化证据里的图片列表(单点归一)。
|
||
|
||
优先读 `images`;否则回退旧的 `image_b64` / `image_mime` 单图字段。
|
||
统一返回 `[{"b64","mime","label"}]`,过滤掉空 b64。
|
||
"""
|
||
if not isinstance(evidence, dict):
|
||
return []
|
||
images = []
|
||
raw = evidence.get("images")
|
||
if isinstance(raw, list):
|
||
for item in raw:
|
||
if not isinstance(item, dict):
|
||
continue
|
||
b64 = item.get("b64")
|
||
if not b64:
|
||
continue
|
||
images.append(
|
||
{
|
||
"b64": b64,
|
||
"mime": item.get("mime") or "image/png",
|
||
"label": item.get("label"),
|
||
}
|
||
)
|
||
if images:
|
||
return images
|
||
# 回退:旧的单图字段
|
||
b64 = evidence.get("image_b64")
|
||
if b64:
|
||
return [
|
||
{
|
||
"b64": b64,
|
||
"mime": evidence.get("image_mime") or "image/png",
|
||
"label": None,
|
||
}
|
||
]
|
||
return []
|
||
|
||
|
||
def primary_image(evidence):
|
||
"""返回首图(label == "overall" 优先),无图返回 None。"""
|
||
images = evidence_images(evidence)
|
||
if not images:
|
||
return None
|
||
for img in images:
|
||
if img.get("label") == "overall":
|
||
return img
|
||
return images[0]
|
||
|
||
|
||
def image_labels(evidence):
|
||
"""返回图片标签列表(用于日志 / payload 说明)。"""
|
||
return [img.get("label") for img in evidence_images(evidence)]
|