feat: 结构化输出按官方规范 + 两段式重试 + DeepSeek 复检开关

- 豆包: 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)
This commit is contained in:
2026-09-03 11:44:10 +08:00
parent ae3a4e06f1
commit b413104587
12 changed files with 832 additions and 289 deletions
+3 -5
View File
@@ -7,7 +7,7 @@ from violation_detector.report import build_report, organize_output, sanitize_di
def ROW(cat, fname="img.jpg", channel="豆包初筛"):
return {"file": fname, "category": cat, "channel": channel, "attr": "属性",
"logic": "逻辑", "status": "ok", "vote_note": "", "remark": ""}
"logic": "逻辑", "status": "ok", "remark": ""}
def test_sanitize_dirname():
@@ -48,7 +48,6 @@ 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")
@@ -56,13 +55,12 @@ def test_build_report_structure(tmp_path):
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)]
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 == "豆包初筛"
assert "人工复核" in ws.cell(row=7, column=8).value
ws2 = wb["统计汇总"]
cats = [ws2.cell(row=r, column=2).value for r in (5, 6)]