- 豆包: response_format.json_schema(strict);DeepSeek: 切 Responses API text.format.json_schema (官方 chat/completions 通道不支持 json_schema),不支持时自动降级 json_object([output] schema) - 重试两段式:传输错误 cfg.retries 次;解析失败/空正文有独立 3 次专用重试,仍失败落 parse_fail - 移除三票复核(decide_final/_verify_clean/verify_clean),DeepSeek 单次判定即终稿 - 新增 [run] deepseek_recheck 开关(默认 no=仅豆包初筛;yes=追加 DeepSeek 复检) - GUI 不再覆盖 config 提示词;prompt 相对/前导斜杠路径按 exe 目录解析 - 报表去「票型/复核」列并同步说明;README/config.example.ini 同步 - 测试新增输出格式、重试、开关与提示词路径用例(50 passed)
72 lines
3.0 KiB
Python
72 lines
3.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""report 模块测试:目录名清洗、输出组织(时间戳+分类归档)、Excel 报表。"""
|
|
from openpyxl import load_workbook
|
|
|
|
from violation_detector.report import build_report, organize_output, sanitize_dirname
|
|
|
|
|
|
def ROW(cat, fname="img.jpg", channel="豆包初筛"):
|
|
return {"file": fname, "category": cat, "channel": channel, "attr": "属性",
|
|
"logic": "逻辑", "status": "ok", "remark": ""}
|
|
|
|
|
|
def test_sanitize_dirname():
|
|
assert sanitize_dirname("12. 侵权 - 其他") == "12. 侵权 - 其他"
|
|
bad = 'a<b>c:"d/e\\f|g?h*i'
|
|
clean = sanitize_dirname(bad)
|
|
for ch in '<>:"/\\|?*':
|
|
assert ch not in clean
|
|
assert clean == "a_b_c__d_e_f_g_h_i"
|
|
assert sanitize_dirname(" . ") == "未分类"
|
|
assert len(sanitize_dirname("长" * 100)) <= 80
|
|
|
|
|
|
def test_organize_output_copies_images_by_category(tmp_path):
|
|
src = tmp_path / "src"
|
|
src.mkdir()
|
|
for name in ("a.jpg", "b.jpg", "c.jpg"):
|
|
(src / name).write_bytes(b"img")
|
|
rows = [ROW("12. 侵权 - 除人物外的其他侵权", "a.jpg"),
|
|
ROW("无违规", "b.jpg"),
|
|
ROW("12. 侵权 - 除人物外的其他侵权", "c.jpg")]
|
|
ts_dir = organize_output(rows, str(src), str(tmp_path / "out"))
|
|
assert ts_dir.name.startswith("检测结果_")
|
|
assert (ts_dir / "12. 侵权 - 除人物外的其他侵权" / "a.jpg").read_bytes() == b"img"
|
|
assert (ts_dir / "12. 侵权 - 除人物外的其他侵权" / "c.jpg").exists()
|
|
assert (ts_dir / "无违规" / "b.jpg").exists()
|
|
# 源文件保留(复制而非移动)
|
|
assert (src / "a.jpg").exists()
|
|
|
|
|
|
def test_organize_output_missing_image_no_crash(tmp_path):
|
|
rows = [ROW("无违规", "不存在.jpg")]
|
|
ts_dir = organize_output(rows, str(tmp_path), str(tmp_path / "out"))
|
|
assert (ts_dir / "无违规").is_dir()
|
|
|
|
|
|
def test_build_report_structure(tmp_path):
|
|
rows = [ROW("12. 侵权 - 除人物外的其他侵权", "a.jpg"),
|
|
ROW("无违规", "b.jpg", channel="DeepSeek复检"),
|
|
ROW("无违规", "b.jpg")]
|
|
out = build_report(rows, str(tmp_path), {"mode": "cascade", "ds_calls": 3,
|
|
"ds_peak_cost": 0.1, "ds_idle_cost": 0.05})
|
|
assert out.endswith(".xlsx")
|
|
|
|
wb = load_workbook(out)
|
|
ws = wb["检测结果"]
|
|
assert ws["B2"].value.startswith("商品图合规检测工具")
|
|
headers = [ws.cell(row=4, column=c).value for c in range(2, 9)]
|
|
assert headers == ["序号", "文件名", "违规分类", "判定通道", "文字/图形属性",
|
|
"侵权/违规逻辑", "备注"]
|
|
assert ws.cell(row=5, column=2).value == 1
|
|
assert ws.cell(row=6, column=5).value == "DeepSeek复检"
|
|
assert ws.cell(row=5, column=5).value == "豆包初筛"
|
|
|
|
ws2 = wb["统计汇总"]
|
|
cats = [ws2.cell(row=r, column=2).value for r in (5, 6)]
|
|
assert cats[0].startswith("12.") and cats[1] == "无违规"
|
|
assert ws2.cell(row=5, column=3).value == 1
|
|
assert ws2.cell(row=6, column=3).value == 2
|
|
# 合计行
|
|
assert ws2.cell(row=7, column=3).value == 3
|