init: 商品图合规检测工具(豆包初筛 + DeepSeek 复检级联)
- src 标准布局:config/providers/pipeline/report + CLI/Tk GUI 双入口 - 级联省钱:豆包全量初筛,仅无违规/违规不明图进 DeepSeek 复检(含两票复核) - 输出:时间戳目录 + 分类文件夹图片归档 + Excel 报表 - 30 个单元测试(tests/,测试图片不入库)
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""pipeline 模块测试:排序、投票裁决、成本计算、缓存路径。"""
|
||||
from violation_detector.pipeline import (
|
||||
_cache_path, _cat_num, deepseek_cost, decide_final, natural_key,
|
||||
)
|
||||
|
||||
|
||||
def R(cat):
|
||||
return {"category": cat, "attr": "a", "logic": "l", "file": "x.jpg",
|
||||
"usage": {"prompt": 2199, "completion": 2282, "cached": 1792}}
|
||||
|
||||
|
||||
def test_natural_key_sort():
|
||||
names = ["10_a.jpg", "2_a.jpg", "1_a.jpg", "21_a.jpg", "3_a.jpg"]
|
||||
assert sorted(names, key=natural_key) == ["1_a.jpg", "2_a.jpg", "3_a.jpg",
|
||||
"10_a.jpg", "21_a.jpg"]
|
||||
|
||||
|
||||
def test_cat_num():
|
||||
assert _cat_num("12. 侵权 - 其他") == 12
|
||||
assert _cat_num("1. 烟草") == 1
|
||||
# 无编号的结论统一排到最后(无违规/违规不变动分类,不影响裁决)
|
||||
assert _cat_num("无违规") == 99
|
||||
assert _cat_num("违规不明") == 99
|
||||
|
||||
|
||||
def test_decide_final_unanimous_clean():
|
||||
final, note = decide_final([R("无违规"), R("无违规"), R("无违规")])
|
||||
assert final["category"] == "无违规"
|
||||
assert "3票一致" in note
|
||||
|
||||
|
||||
def test_decide_final_clean_majority_keeps_but_flags():
|
||||
final, note = decide_final([R("无违规"), R("无违规"), R("12. 侵权 - 除人物外的其他侵权")])
|
||||
assert final["category"] == "无违规"
|
||||
assert "2:1" in note and "人工复核" in note
|
||||
|
||||
|
||||
def test_decide_final_violation_majority_wins():
|
||||
final, note = decide_final(
|
||||
[R("无违规"), R("12. 侵权 - 除人物外的其他侵权"), R("12. 侵权 - 除人物外的其他侵权")])
|
||||
assert final["category"].startswith("12.")
|
||||
assert "人工复核" in note
|
||||
|
||||
|
||||
def test_decide_final_three_way_split_takes_lowest_number():
|
||||
final, note = decide_final([R("无违规"), R("13. 侵权 - 人物相关"), R("5. 负向敏感")])
|
||||
assert final["category"].startswith("5.")
|
||||
assert "从严" in note
|
||||
|
||||
|
||||
def test_decide_final_two_violations_differ_majority_none():
|
||||
# 两张违规票不同、一张无违规:违规方 2 票 > 1,并列取序号最小
|
||||
final, _ = decide_final([R("无违规"), R("13. 侵权 - 人物相关"), R("12. 侵权 - 其他")])
|
||||
assert final["category"].startswith("12.")
|
||||
|
||||
|
||||
def test_deepseek_cost_known_usage():
|
||||
# miss 407 + cached 1792 + completion 2282
|
||||
results = {"a": R("无违规")}
|
||||
peak, idle, comp = deepseek_cost(results)
|
||||
expect_peak = (407 * 3.0 + 1792 * 0.10 + 2282 * 9.0) / 1e6
|
||||
expect_idle = (407 * 1.5 + 1792 * 0.05 + 2282 * 4.5) / 1e6
|
||||
assert abs(peak - expect_peak) < 1e-9
|
||||
assert abs(idle - expect_idle) < 1e-9
|
||||
assert comp == 2282
|
||||
|
||||
|
||||
def test_deepseek_cost_empty():
|
||||
assert deepseek_cost({}) == (0.0, 0.0, 0.0)
|
||||
|
||||
|
||||
def test_cache_path_sanitizes_folder(tmp_path):
|
||||
p = _cache_path("ark", str(tmp_path / "we ird\\name+:x"))
|
||||
assert p.parent.exists()
|
||||
assert p.name.startswith("ark_")
|
||||
for ch in ' :+':
|
||||
assert ch not in p.name
|
||||
Reference in New Issue
Block a user