ip-as-logo-skill 批量出头像 / 先约定素材目录和文件命名

文章导读
批量出头像最容易翻车的地方不在生成环节,而在生成之后对不上号:一次跑十几张,文件名要么是工具默认的时间戳,要么是重复的 output.png,分不清哪张对应哪个角色、哪个风格版本。可行的做法是把顺序倒过来——先固定素材目录结构、输入清单和输出命名规则,再让批量任务按清单逐行跑。清单里每行代表一个角色或一个版本,输出名由清单直接决定,出图之后靠文件名就能追回来源。
📋 目录
  1. Ⅰ 把每个角色的输入写成一行清单
  2. Ⅱ 定输出命名规则并与输入清单一一对应
  3. Ⅲ 用循环骨架逐行跑,不要一次塞全部描述
  4. Ⅳ 跑完后用文件名与清单做双向核对
  5. Ⅴ 把失败行单独重跑,不动已成功的图
A A

批量出头像最容易翻车的地方不在生成环节,而在生成之后对不上号:一次跑十几张,文件名要么是工具默认的时间戳,要么是重复的 output.png,分不清哪张对应哪个角色、哪个风格版本。可行的做法是把顺序倒过来——先固定素材目录结构、输入清单和输出命名规则,再让批量任务按清单逐行跑。清单里每行代表一个角色或一个版本,输出名由清单直接决定,出图之后靠文件名就能追回来源。

批量出头像前先把输入清单和输出命名规则固定下来:清单一行一个角色,每行带唯一输出名;命名结构包含角色、风格、序号;跑批逐行读取并写日志,跑完用文件名和清单双向核对数量、重名、缺失;失败行单独标记、重跑到隔离目录。适用于一次生成十张以上、需要回查来源的场景;具体命令参数以你所用工具的实际帮助输出为准。

把每个角色的输入写成一行清单

清单的作用是让批量任务只有一个输入来源,改角色、加版本都只改这一处,不要临时在命令行里手敲描述。建议用 CSV 或 TSV,字段固定四个:角色名、形象描述、风格锚点、期望输出名。角色名和期望输出名都要求唯一,风格锚点写成你自己能复用的短语(比如“扁平简约-蓝灰”“厚涂-暖光”),不要写成长句。

角色名,形象描述,风格锚点,期望输出名
lin,短发戴眼镜的年轻程序员,扁平简约-蓝灰,lin_flat_01
lin,短发戴眼镜的年轻程序员,厚涂-暖光,lin_paint_01
momo,圆脸扎丸子头的女生,扁平简约-蓝灰,momo_flat_01

同一个角色出多个版本就写多行,靠风格锚点和序号区分,而不是把两种风格塞进同一行描述。目录建议先分成 assets/(参考图、参考色)与 out/(产物)两层,清单文件放在项目根目录,例如 list.csv。清单里不要用逗号做字段分隔同时又让描述里带逗号;如果描述必须带逗号,改用制表符分隔,或者给描述字段加引号。

定输出命名规则并与输入清单一一对应

命名结构建议直接用清单里的字段拼出来,形如 {角色}_{风格}_{序号}.png,例如 lin_flat_01.png。风格用英文或拼音短标签,序号固定两位数以上,避免出现 1 和 10 排序混乱。扩展名统一小写。这样任何人拿到一张图,都能从文件名反查回清单的某一行。

ip-as-logo-skill 批量出头像 / 先约定素材目录和文件命名

文件名里需要避开的字符包括:空格、/、\、:、*、?、"、<、>、|,以及 shell 里有特殊含义的 $、反引号、!、&、圆括号,行首的 # 也建议不用。中文全角括号、全角空格同样容易在脚本里踩坑,统一换成下划线。命名规则一旦定了就别中途改,否则后面的核对脚本要重写。

用循环骨架逐行跑,不要一次塞全部描述

逐行跑的好处是任何一行失败都能定位到具体角色,而不是整批全废。下面是一个通用骨架,读取 CSV、跳过空行和注释行、每行写一条日志,路径和调用处都用占位符,参数请替换成你的工具实际支持的选项:

while IFS=, read -r name desc style out; do
  # 跳过表头、空行和注释行
  [ -z "$name" ] && continue
  case "$name" in \#*) continue ;; esac

  echo "[$name] start -> $out" >> run.log
  <你的生成命令> `--prompt` "$desc" `--style` "$style" `--output` "out/$out" \
    >> run.log 2>&1 \
    && echo "[$name] OK $out" >> run.log \
    || echo "[$name] FAIL $out" >> run.log
done < list.csv

三个细节值得留意:IFS=, 只在这条命令里生效,不影响当前 shell;日志统一追加到一个文件,失败行和成功行用同一个前缀,方便后面 grep;continue 用来跳过表头,避免第一行被当成角色名去生成。如果工具本身支持批量接口,可以换成一次读一行的循环调用,但依然要保持“一行一角色”的粒度,失败才能隔离。

ip-as-logo-skill 批量出头像 / 先约定素材目录和文件命名

跑完后用文件名与清单做双向核对

核对分三个动作:数量、重名、缺失,外加一个反向动作——找出清单里没有的多余文件。

先生成一份期望名单,再和实际产物比对:

ip-as-logo-skill 批量出头像 / 先约定素材目录和文件命名
# 期望名单:跳过表头,取第 4 列
 tail -n +2 list.csv | cut -d, -f4 | sed 's/$/.png/' | sort > expect.txt

# 实际产物
ls out | sort > actual.txt

# 数量
wc -l < expect.txt
tail -n +2 list.csv | wc -l
ls out | wc -l

# 重名
ls out | sort | uniq -d

# 缺失:清单里有、产物里没有
comm -23 expect.txt actual.txt

# 多余:产物里有、清单里没有
comm -13 expect.txt actual.txt

不用命令行也行:把 ls out 导出的清单和输入清单的“期望输出名”列贴进同一张表格,按名称排序后用条件格式找两列差异。无论哪种方式,判断标准是一样的——期望名单与产物名单的交集之外,任何一侧多出来的条目都要解释清楚。人为在 out/ 里手动改名或补图,会让核对结果失真,所以手改之后要同步回 list.csv。

把失败行单独重跑,不动已成功的图

日志里用 FAIL 前缀标记失败行的做法,重跑时直接复用:

# 从日志里捞出失败的角色名与输出名
grep 'FAIL' run.log | awk '{print $1, $NF}' > retry.txt

# 重跑时把输出隔离到独立目录,不覆盖 out/
while read -r tag out; do
  name=$(echo "$tag" | tr -d '[]')
  <你的生成命令> `--prompt` "$desc" `--output` "out_retry/$out" >> retry.log 2>&1 \
    && echo "[retry][$name] OK" >> retry.log \
    || echo "[retry][$name] FAIL" >> retry.log
done < retry.txt

要点是重跑写到 out_retry/ 而不是直接写回 out/。这样即使重跑又把已经成功的某个文件名覆盖掉,损失也只发生在隔离目录里。等重跑结果核对无误,再把 out_retry/ 里确认过的文件改名或移动到 out/,此时先看一眼 ls out_retry | sort | uniq -d,避免把重名文件带进来。整批生成完成后,run.log、expect.txt、actual.txt 建议一并留档,下次改角色或换风格时,可以直接对比上一批的清单名和产物名,判断哪些是新增、哪些需要重出。