init: 商品图合规检测工具(豆包初筛 + DeepSeek 复检级联)

- src 标准布局:config/providers/pipeline/report + CLI/Tk GUI 双入口
- 级联省钱:豆包全量初筛,仅无违规/违规不明图进 DeepSeek 复检(含两票复核)
- 输出:时间戳目录 + 分类文件夹图片归档 + Excel 报表
- 30 个单元测试(tests/,测试图片不入库)
This commit is contained in:
yeuimu
2026-09-02 15:28:51 +08:00
commit 08d26710b4
20 changed files with 2513 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
# -*- 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", "vote_note": "", "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")]
rows[2]["vote_note"] = "票型2:1(无违规 / 无违规 / 12. 侵权),建议人工复核"
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, 10)]
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 == "豆包初筛"
assert "人工复核" in ws.cell(row=7, column=8).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