Files
violation-detector/src/violation_detector/cli.py
T
yeuimu bca1ceeea5 config: [run] verify_clean 可配置无违规两票复核开关
- config.ini [run] verify_clean = yes/no(默认 yes),GUI/CLI 均跟随
- CLI --no-verify 仍可强制关闭;非法值回落默认开启
- 模板/示例/README 同步,新增配置测试(共 36 个全部通过)
2026-09-02 16:39:53 +08:00

91 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""CLI 入口:python -m violation_detector <图片文件夹> [选项]"""
import argparse
import asyncio
import logging
import sys
from . import __version__
from .config import DEFAULT_CONFIG, load_config, missing_fields
from .logutil import log_file, setup_logging
from .pipeline import run_detection
from .report import build_report, organize_output
logger = logging.getLogger("violation_detector.cli")
def build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(
prog="violation-detector",
description="服装商品图合规检测:豆包视觉初筛 + DeepSeek 复检级联,输出 Excel 报表")
p.add_argument("folder", help="待检测图片文件夹")
p.add_argument("-o", "--output", default=None, help="报表输出目录(默认为图片文件夹)")
p.add_argument("-c", "--config", default=None, help="配置文件路径(默认 config.ini")
p.add_argument("--prompt", default=None, help="提示词文件路径(覆盖配置)")
p.add_argument("--mode", choices=["cascade", "doubao", "deepseek"], default=None,
help="检测模式(默认取 config.ini [run] mode,未配置则 cascade):"
"cascade=豆包初筛+DeepSeek复检,doubao=仅豆包,deepseek=仅 DeepSeek 全量")
p.add_argument("--workers-ark", type=int, default=None, help="豆包并发数")
p.add_argument("--workers-ds", type=int, default=None, help="DeepSeek 并发数")
p.add_argument("--max-tokens", type=int, default=None,
help="DeepSeek max_tokens(默认 5000,实测零失败最小档)")
p.add_argument("--no-verify", action="store_true", help="跳过 DeepSeek 无违规两票复核")
p.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
return p
def main(argv=None) -> int:
args = build_parser().parse_args(argv)
log_path = setup_logging(console=True)
logger.info("商品图合规检测工具 v%s 启动,日志文件:%s", __version__, log_path)
cfg = load_config(args.config)
if args.prompt:
cfg.prompt_file = args.prompt
if args.workers_ark:
cfg.ark_workers = args.workers_ark
if args.workers_ds:
cfg.deepseek_workers = args.workers_ds
if args.max_tokens:
cfg.max_tokens = args.max_tokens
mode = args.mode or cfg.mode
# 复核开关:CLI --no-verify 强制关;否则跟随 config.ini [run] verify_clean
verify = cfg.verify_clean and not args.no_verify
missing = missing_fields(cfg, mode)
if missing:
print(f"配置不完整,请编辑 {DEFAULT_CONFIG} 填写以下必填项:")
for m in missing:
print(f" - {m}")
return 2
try:
rows, summary = asyncio.run(run_detection(
args.folder, cfg, mode=mode, verify=verify))
except FileNotFoundError as e:
logger.error("路径或文件不存在:%s", e)
return 1
except KeyboardInterrupt:
logger.warning("用户中断")
return 130
except Exception: # noqa: BLE001 顶层兜底:完整堆栈进日志与控制台
logger.exception("检测过程发生未预期异常")
print(f"\n检测失败,完整日志:{log_file()}")
return 1
try:
out_dir = args.output or args.folder
ts_dir = organize_output(rows, args.folder, out_dir)
xlsx = build_report(rows, str(ts_dir), {"mode": mode, **{
k: summary.get(k) for k in ("ds_calls", "ds_peak_cost", "ds_idle_cost")}})
except Exception: # noqa: BLE001
logger.exception("输出组织/报表生成失败")
print(f"\n报表生成失败,完整日志:{log_file()}")
return 1
print(f"\n分类输出目录:{ts_dir}")
print(f"报表已生成:{xlsx}")
return 0
if __name__ == "__main__":
sys.exit(main())