Skip to main content
Glama

图包审批工具 · Asset Approval Tool

本地跑的素材对照审批工具:左边原图、右边成品并排看,一键标记 ✅通过 / ❌打回 / ⚠️存疑, 打回时点问题标签、在图上圈出问题位置,结果实时写盘、可导出 JSON + CSV 给下游程序读。

English: A local, offline web tool for reviewing large batches of visual/text assets side by side (original vs. localized output). Mark pass/reject/unsure, tag the problem, draw boxes on the image, filter and batch-operate, export machine-readable results. Ships with a demo dataset — clone and run, no configuration needed. It also speaks MCP and has a CLI, so AI agents can drive the review loop directly.

  • 纯本地运行,不联网,不需要数据库

  • 克隆下来直接跑,自带合成演示素材

  • 上千张素材不卡(缩略图懒加载 + 磁盘缓存 + 指纹失效)

  • 结果实时落盘,关掉浏览器不丢,支持断点续审

  • 三种驱动方式:网页界面 / 命令行 / MCP(给 AI agent)

  • 素材重渲后自动识别哪些结论已过期;不同渲染批次可以派生成互相隔离的集合

单张对照

缩略图墙


一、快速开始

git clone https://github.com/Smirk1921/asset-approval-tool.git
cd asset-approval-tool
pip install -r requirements.txt
python app.py

浏览器会自动打开 http://127.0.0.1:8765/。Windows 上也可以直接双击 启动.bat。

仓库自带一套合成演示素材(demo/,8 张卡片 + 12 条文本槽位),其中 5 张的成品 故意做了缺陷——文字溢出、图标缺失、标题混排、文字重叠、黑底黑字。打开就能上手试, 不用先准备自己的素材。

要换成自己的素材:改 config.json 里的路径,或者复制 config.example.json 改一份, python app.py --config 你的配置.json。代码里没有任何写死的路径。

常用参数:

python app.py --config 别的配置.json     # 换一份配置文件
python app.py --port 8800                # 换端口
python app.py --no-browser               # 不自动开浏览器
python app.py --restart                  # 先停掉占用该端口的旧实例再启动
python app.py --probe                    # 只探测该端口有没有本工具在跑(在跑退出码 3)

Related MCP server: Loopbreaker

二、界面怎么用

单张对照

图片素材:左边源A(原图)、右边源B(成品),同步缩放平移。滚轮缩放、按住拖拽平移、 双击在「适应窗口 / 原始大小」之间切换。文本素材:左右分栏显示原文 / 译文, 可切上下分栏、调字号、开同步滚动。

一键标记 + 问题标签

点 ✅通过 / ❌打回 / ⚠️存疑,或直接按 1 2 3。每次操作立刻写盘。

标签也能用键盘:标签上写着各自的键(默认 Q W E T Y U I O P 对应前 9 个)。 按一下 = 打回 + 贴这个标签,一张卡可以连按几个再按 → 走人。

对照看图

叠加对比(按 X):把原图和成品叠在同一张上,拖中间那条竖线决定左右各露多少, 一眼看出哪里多字、少字、错位。按住空格临时看全幅原图;点「半透明重叠」可以让成品 半透明盖在原图上。两侧分辨率不同时会自动统一显示尺寸,保证逐像素对得上。

圈图标注

点 ✏️ 圈图(或按 R),在图上拖拽画框,右侧写这条问题的说明。可以圈多处。 在缩略图墙上把鼠标移到某张卡上,右下角出现 ✏️,点它直接进这张的圈注模式; 画完按 Esc 退出会自动回到墙上刚才那张。

圈选框按图片比例保存(0~1 的相对值),换窗口大小、缩放都不影响; 导出时给下游的也是相对坐标,「CSV(圈注明细)」还会同时给出像素坐标。

缩略图墙

一屏扫过去,边框颜色标状态:灰=未审、绿=通过、红=打回、黄=存疑、黄色虚线=源文件已变。 未审的左上角有蓝点,已审的默认淡显(可关),所以「还剩哪些没看」一眼能扫出来。

筛选与搜索

  • 快捷按钮带条数:全部 / 未审 / 通过 / 打回 / 存疑,一眼看到还剩多少没审。

  • 筛选:状态 + 属性(分组、类型、扩展…)+ 问题标签组合筛选,另有几个特殊条件: 未打任何标签、有圈选、有备注、源文件已变、打回且无标签。

  • 搜索框:按文件名、素材 id、卡号、标题模糊搜。

批量操作

对当前筛选结果一键标记,按钮上直接写着会作用到多少条,执行前弹确认框, 执行后提示条里有 撤销。在缩略图墙点 多选 可以只作用于勾选的那些。

集合与批次

  • 顶栏 素材集 下拉随时切换;当前集合会写进网址(?set=xxx),刷新和分享链接都停在同一个集合。

  • 派生新集合…:从当前集合派生出独立的新集合——可以换成品目录(重渲后的新目录), 也可以只包含当前筛选出的那几张。不用把文件拷来拷去,也不用改配置文件。

  • 归档本轮,开始新一轮…:同一批素材重审时,把当前结果存档、批次清空、轮次 +1; 下一轮点 筛出上轮打回的 优先复审。

  • 改了 config.json 后不用自己想起刷新:页面会提示「配置已更新」,点一下就重载。

源文件被重渲了怎么办

审批结果会记下审批那一刻源文件的指纹。重渲完素材后只要刷新浏览器(F5), 工具就会自己发现,并提示:

⚠ 有 31 条素材在你审批之后源文件又被改过(重渲过),这些结果可能已经过期。

然后你可以:只看这些 / 清除它们的结果,重新审 / 忽略。 在单张对照视图里,这样的素材右侧会直接标出「⚠ 审批后已被改过,此结论可能过期」, 并给一个 清除结论,重新审 按钮,不用翻回列表去找。 统计条上也会多出一个 ⚠ 需复审 N 的快捷筛选。

想让它全自动(源一变就把结论清成未审)可以在配置里设 "auto_reset_stale": true。 默认是关的:静默清掉已经下过的结论风险太大,工具默认只提示、由你决定。 没被改过的素材结果照旧保留,不会被误清。图片 URL 里也带了同一个指纹, 所以浏览器必定拉新图,不用 Ctrl+Shift+R。文本素材集同理:改了译文 JSON,刷新就能看到。

轮次归档

审完一批想留档、然后在同一批素材上开新轮:

  • 归档本轮,开始新一轮… —— 当前结果整体存成 results/<素材集>.roundN.json, 当前批次清空、轮次 +1,缩略图缓存一并清掉。

  • 筛出上轮打回的 —— 下一轮开始时点它,直接筛出上一轮所有打回的素材,优先复审。

导出

  • JSON:完整结构,含圈选坐标、标签、备注、审批时间,给程序读。

  • CSV:表格,带 BOM,Excel 双击直接打开不乱码。

  • CSV(圈注明细):每处圈选单独一行,坐标同时给百分比和像素,下游可直接定位修复。

  • 修正建议(JSON):把打回原因按标签展开成"下一步该怎么改"的清单,话术由你在配置的 tag_advice 里定义,工具只负责贴出来。

  • 导出圈选裁剪(ZIP):把每处圈注的矩形从原图上裁出来打包——圈出"这里缺个图标", 导出的就是现成的抠图素材。

字段含义见 docs/审批结果字段说明.md。


三、快捷键

键

作用

← → / A D

上一个 / 下一个

1 2 3

通过 / 打回 / 存疑

0

清除标记(回到未审)

Q W E T Y U I O P

贴上对应的前 9 个问题标签(没审过的会顺手置成打回)

V / G

单张对照 / 缩略图墙

R / X

圈图模式 / 叠加对比

F / Z / S

适应窗口 / 原始大小 / 左右同步

空格(叠加模式下)

临时看全幅原图

/

跳到搜索框

Ctrl+Z / Esc

撤销上一步 / 退出圈图或关闭弹窗

键位在 shortcuts 里改,标签键位在 tag_shortcuts 里改,改完点 ⚙ →「重新扫描配置」 即时生效不用重启。标签键和别的键撞车时,启动会直接提示改哪几个。


四、给 AI agent 用

这个工具不只是给人点的——agent 也能直接驱动它,形成「agent 看素材 → 判断 → 写结论」的闭环。

首选 MCP,工具直接出现在 agent 的工具列表里:

{
  "mcpServers": {
    "asset-approval": {
      "command": "python",
      "args": ["/绝对路径/mcp_server.py"]
    }
  }
}

提供 14 个工具:approval_status、list_items、get_item、get_item_images、 review_item、batch_review、export_results、clear_stale_results、start_new_round、 list_previous_round_rejects、export_crops、lookup_item、compare_sets、derive_set。

其中 get_item_images 会把图片本身返回给 agent(MCP image content 块)。 stitch=true 时它把原图和成品拼成一张对照图(左原图、右成品,已按同一尺寸对齐)—— 模型一次只能吃一张图时这是唯一靠谱的做法,能一次吃多张的模型也建议用它: 靠文字描述去对齐两张图,图标位置、分段间距、字体差异都会丢。

命令行同样可用,每次调用输出一个 JSON:

python agent.py status
python agent.py items --set demo_cards --status unreviewed --limit 20
python agent.py item  --set demo_cards --id 102_front.png
python agent.py review --set demo_cards --id 102_front.png --status 打回 \
    --tags 文字溢出 --note "正文超出文本框" \
    --annotate "0.09,0.55,0.82,0.28,b,正文溢出到框外"
python agent.py image-pair --set demo_cards --id 102_front.png --out pair.png
python agent.py review-batch --set demo_cards --file reviews.json --dry-run
python agent.py batch --set demo_cards --filter-status unreviewed --status pass --dry-run
python agent.py export --set demo_cards --format annotations --only problem --out 问题清单.csv
python agent.py export-crops --set demo_cards --zip 圈选裁剪.zip

几条为 agent 工作流准备的命令:image-pair(拼对照图,可批量)、review-batch (一次写回多条,全部校验通过才写)、derive-set(派生隔离集合)、export-crops、 lookup / compare(跨集合查同一张卡的历史结论)。

几条为 agent 专门做的设计:

  • 自动选路:服务在跑就走 HTTP(和网页版共用同一份状态),没跑就直接读写文件。 避免「agent 改了文件、被服务下一次保存覆盖」。服务跑在非默认端口时会给出提示; 真要用 --offline 直连写而被拦下来,说明服务正在跑,加 --force 才能强行覆盖。

  • 标签纠错:写成"图标丢失"这种同义词会被拦下并提示"是不是要写『图标缺失』", 避免标签写花了之后筛不出来。

  • 批量必须给范围:batch 不给 ids 也不给筛选条件会直接报错, 想作用于全部要显式写 filter_status="all"。防的是「一句都通过刷掉整个素材集」。

  • dry_run 预演:先看会命中哪些,再决定执行。

  • 中英文都认:pass / 通过 等价,unreviewed / 未审 等价。

  • 错误可读:失败时返回 {"ok": false, "error": "……"},直接说明怎么改。

详见 AGENTS.md(给 agent 的操作须知)和 docs/agent-接口.md(完整接口参考)。


五、配置文件

路径全部写在 config.json 里,代码里没有任何写死的路径。改完点 ⚙ → 「重新扫描配置」即可生效,配置文件会整个重读。

顶层

字段

说明

host / port

本地服务地址端口

data_dir

放审批结果和缩略图缓存的目录

tags

问题标签预设列表

tag_shortcuts

标签快捷键,按顺序对应 tags 的前几个

templates

常用标签组合,例如 [{"id":"text_layout","name":"文字排版","tags":["文字溢出","分段错"]}];review --template text_layout 直接用

tag_advice

标签 → 修正建议话术,export --format advice 时展开成清单。具体说什么由使用方定义,工具不含任何项目专属内容

auto_reset_stale

true 时启动就把「源文件已变」的结果清成未审(默认 false,只提示不自动清)

shortcuts

快捷键,值是按键数组,如 "pass": ["1", "y"]

wall_page_size

缩略图墙每页几张,默认 60

auto_advance

是否默认勾选「标记后自动跳下一张」

thumb.max_size / quality

缩略图尺寸与 JPEG 质量

素材集(sets 数组)

字段

说明

id

唯一标识,也是结果文件名

name

界面上显示的名字

type

image 或 text

pair

配对方式,见下表

items_from

以哪一侧为准:b(只看有成品,推荐)/ a / union

a / b

源A、源B。图片是 {"root": "目录", "label": "显示名"};文本可用 {"kind":"json","path":"...","fields":[...],"label":"..."}

include / exclude

文件名通配符,默认排除 _*、.*、~*

recurse

是否递归扫子目录(默认 true)

id_regex / id_template

文本素材集里把 JSON 的长键变成好读的 id,如 卡{card}-槽{row}-{col}

group_field

用元数据里的哪个字段当「分组」

meta

可选。清单文件,给素材补属性

only_ids

可选。素材白名单,只审这些 id(用来从大集合里"只看这批",不必拷贝文件)

派生出来的集合放在 sets.d/*.json,工具只写这个目录,不会动你手写的 config.json。 删掉文件就等于删掉集合。

三种配对方式(pair)

值

适用

说明

basename

图片、文本文件

两个目录里同名的文件配成一对,可递归

manifest

图片

清单里每条记录对应一张素材,文件名由 key_template 生成

json_key

文本

源A / 源B 各是一个 JSON,按顶层键配对

basename 例子(原图放扁平目录、成品按类型分子目录,靠文件名对齐):

{
  "id": "my_cards",
  "name": "单卡对照(原图 ↔ 成品)",
  "type": "image",
  "pair": "basename",
  "items_from": "b",
  "a": { "root": "D:/素材/原图", "label": "原图" },
  "b": { "root": "D:/素材/成品", "label": "成品" },
  "include": ["*_front.png", "*_back.png"],
  "exclude": ["_*", ".*"],
  "recurse": true,
  "meta": {
    "path": "D:/素材/清单.json",
    "join": "filename",
    "key_template": "{card_id}_front.png",
    "id_field": "card_id",
    "fields": ["卡号", "类型", "扩展", "状态", "英文标题"],
    "facets": ["类型", "扩展"]
  }
}

元数据(meta)

字段

说明

path

清单文件(JSON 数组,或「键→记录」的对象)

join

怎么和素材对上:filename(按文件名)/ key(按 JSON 键)

key_template

用记录里的字段拼出文件名,如 {card_id}_front.png

id_field

pair: manifest 时,用哪个字段当素材 id

name_field

可选,用哪个字段当显示名

fields

要在界面上显示哪些字段

rename

字段改名,如 {"cat": "分类"}

facets

哪些字段做成筛选下拉框;写 [] 表示都不要。不写则自动选(取值种类 ≤30 的才做)

文本来源的 fields 取值语法

写法

含义

"zh"

普通字段

"lines"

数组,元素直接拼起来

"lines[].t"

对象数组,取每个元素的 t 字段

多个字段按顺序用换行拼接。


六、目录结构

├── app.py                    网页版服务入口
├── agent.py                  命令行接口(给 AI agent / 脚本)
├── mcp_server.py             MCP 服务(stdio,无额外依赖)
├── config.json               当前配置(指向自带的 demo 素材)
├── config.example.json       配置模板,含四种素材集写法示例
├── core/
│   ├── config.py             配置读取与校验(含 sets.d 合并)
│   ├── materials.py          素材扫描与配对、源文件指纹
│   ├── results.py            审批结果读写 / 导出 / 轮次归档
│   ├── thumbs.py             缩略图生成与缓存
│   ├── images.py             对照图拼接、圈注裁剪
│   ├── agent_common.py       状态/标签/圈选规范化(两条通路共用)
│   ├── agent_ext.py          扩展能力:拼接/裁剪/批量写回/派生集合/跨集合查询
│   └── agent_api.py          操作层:HTTP 与直连两套实现
├── static/                   前端(原生 JS,无外部依赖)
├── demo/                     合成演示素材(可重新生成)
│   └── generate_demo.py
├── sets.d/                   派生集合(工具自动生成,可 gitignore)
├── docs/
│   ├── agent-接口.md         命令行 / MCP / HTTP 接口参考
│   ├── agent-工作流示例.md    几个可以直接照抄的完整流程
│   ├── 审批结果字段说明.md     结果 JSON/CSV 字段说明
│   └── screenshot-*.png
├── AGENTS.md                 给 AI agent 的操作须知
├── data/                     运行后生成(已 gitignore)
│   ├── app.pid
│   ├── results/              审批结果 + history 流水 + 轮次归档
│   └── thumbs/               缩略图缓存
├── 启动.bat / 启动.sh
└── requirements.txt

七、常见问题

端口被占用:python app.py --port 8800;如果是上一个没关掉的工具实例, python app.py --restart 直接接管。python app.py --probe 可以查它是否还在跑。

服务会不会被误关:启动.bat / 启动.sh 会做三件事——已在运行时不重复起第二个 (两个实例会互相覆盖结果)、进程被意外杀掉 3 秒后自动拉起(最多 20 次)、 把 PID 写到 data/app.pid 供外部查询。双击启动的那个黑窗口要一直开着。

素材没扫出来 / 数量不对:看启动日志里该素材集的条数和警告;确认 include / exclude 通配符、recurse 设置,以及 items_from 选的是哪一侧。

重渲了素材要不要重审:不用手动处理。刷新浏览器后工具会自己比出哪几条源文件变了 (见上面「源文件被重渲了怎么办」),只影响真被改过的那些。

想清缩略图缓存:⚙ → 清空缩略图缓存;「归档本轮」时也会自动清。

审批结果会不会被误删:结果文件损坏时不会被静默清空,会改名存一份 <id>.bad-<时间>.json 再重来。


八、依赖与许可

  • Python 3.10+,依赖只有 Flask 和 Pillow(pip install -r requirements.txt)

  • 前端是原生 JS,没有任何外部库,完全离线

  • 许可:MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides tools for agents to manage a local review graph, tracking acceptance behaviors, evidence, review passes, and human waivers to decouple review convergence from shipping readiness.
    3
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    A local-first, auditable code review MCP server that freezes Git changes, creates immutable ReviewBundles, provides role-isolated contexts for correctness, security, architecture, and test reviewers, validates structured findings, and generates deterministic JSON/Markdown reports.
    3 npm
    1
    Apache 2.0