maomomo-article-writer/references/image-generation.md

271 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 图片生成脚本与后端选择
需要实际生成配图文件、使用 API/CLI fallback、批量生成 assets或排查图片接口配置时先读本文件。
## 后端选择
优先顺序:
1. Codex / 当前 agent 的内置图片生成工具。适合大多数配图任务。
2. `scripts/maomomo_image_gen.py` API/CLI fallback。适合用户明确要求 API/CLI、内置工具不可用、需要批量 manifest、或希望把生成过程记录到文件时。
不要因为脚本存在就强制使用脚本。若内置图片工具可用,仍优先使用内置工具生成独立 PNG再保存到 `assets/`
生成第一张图前,必须向用户确认:
- 已检查哪种内置图片生成工具是否可用。
- 准备使用的生图后端。
- 是否需要 `scripts/maomomo_image_gen.py` fallback以及原因。
- 当前会沿用环境变量或配置文件中的 baseURL、model、quality不会擅自改成 `low`
确认后,整篇文章所有图片保持同一个生图后端和质量配置。只有用户明确要求切换,或当前后端无法完成必需能力时,才重新确认后端。
## 配置来源
脚本按以下顺序读取配置:
- `MAOMOMO_IMAGE_API_KEY` / `OPENAI_API_KEY`
- `MAOMOMO_IMAGE_BASE_URL` / `OPENAI_BASE_URL`
- `MAOMOMO_IMAGE_MODEL` / `CODEX_PPT_IMAGE_MODEL`
- `~/.codex/config.toml` 中的 `base_url`
- `~/.codex/auth.json` 中可识别的 API key
`scripts/maomomo_image_gen.py` 必须兼容 Python 3.10 及以下没有内置 `tomllib` 的环境;读取 `~/.codex/config.toml` 时应使用脚本内置的轻量 TOML fallback不要求用户额外安装 `tomli`
不要在日志、回答、Markdown 或 manifest 中写入完整 API key。
## 单张生成
```bash
uv run python scripts/maomomo_image_gen.py generate \
--out article/origin_image/hsbc-mastercard-alipay-campaign-01-cover.png \
--style warm-fintech-guide \
--title "汇丰 Mastercard 支付宝活动" \
--image-type "封面图" \
--core-text "先看报名、门槛和封顶,避免白刷"
```
先只看 prompt
```bash
uv run python scripts/maomomo_image_gen.py generate \
--out article/origin_image/hsbc-mastercard-alipay-campaign-01-cover.png \
--style data-card-dashboard \
--title "返现计算图" \
--image-type "计算图" \
--core-text "HKD 190 ÷ 9% ≈ HKD 2,112超过部分没有额外收益" \
--dry-run
```
## prompt 文件输入
- `prompts/*.json` 用于管理图片 job、路径、参考素材、可见文字白名单和完整 prompt。
- 如果生成脚本的 `--prompt-file` 读取纯文本,必须先从 JSON 的 `prompt` 字段抽取为同名 `.prompt.txt`,再把 `.prompt.txt` 传给图片接口。
- 不要把整个 JSON 文件作为 `--prompt-file` 传入;否则模型可能把 JSON 外壳、字段名或管理信息画进图片。
- 抽取出的 `.prompt.txt` 仍必须包含可见文字限制:只允许出现指定业务文案、`MAOMOMO` 和已核对允许出现的品牌 / 支付标识不得出现风格标签、prompt 描述、额外 slogan 或无关文字。
推荐抽取方式:
```bash
uv run python - <<'PY'
from pathlib import Path
import json
path = Path("article/prompts/hsbc-mastercard-alipay-campaign_01.json")
data = json.loads(path.read_text(encoding="utf-8"))
prompt = str(data["prompt"]).strip()
out = path.with_suffix(".prompt.txt")
out.write_text(prompt + "\n", encoding="utf-8", newline="\n")
print(out)
PY
```
然后生成:
```bash
uv run python scripts/maomomo_image_gen.py generate \
--out article/origin_image/hsbc-mastercard-alipay-campaign-01-cover.png \
--prompt-file article/prompts/hsbc-mastercard-alipay-campaign_01.prompt.txt
```
## 批量 manifest
manifest 示例:
```json
{
"images": [
{
"file_name": "origin_image/hsbc-mastercard-alipay-campaign-01-cover.png",
"type": "封面图",
"title": "汇丰 Mastercard 支付宝活动",
"core_text": "先报名,再看门槛和封顶",
"alt_text": "MAOMOMO 汇丰 Mastercard 支付宝返现活动封面图",
"style": "warm-fintech-guide",
"visual_direction": "2D 扁平风",
"delivery_batch": "batch-01-cover",
"allowed_brand_marks": ["HSBC", "Mastercard", "支付宝"],
"brand_mark_sources": [
{
"name": "Mastercard",
"source_url": "https://example.com/official-source",
"source_type": "官方活动页 / 官方品牌资源页 / 用户素材",
"checked_at": "YYYY-MM-DD"
}
],
"brand_mark_rule": "这些标识必须来自官方活动材料或用户素材核对;只能小尺寸辅助出现,不能抢 MAOMOMO 主标识位置",
"aspect_ratio": "16:9"
},
{
"file_name": "origin_image/hsbc-mastercard-alipay-campaign-02-calculation.png",
"type": "计算图",
"title": "怎么刷到刚刚好",
"core_text": "HKD 190 ÷ 9% ≈ HKD 2,112超过部分没有额外收益",
"style": "data-card-dashboard"
}
]
}
```
运行:
```bash
uv run python scripts/maomomo_image_gen.py batch \
--manifest article/image_manifest.json \
--base-dir article
```
`file_name` 必须与本次生成目录一致,且最终文件必须真实存在。发布用 Markdown 默认引用 `assets/`,因此输出到 `origin_image/` 后要在 QA 通过时同步到同名 `assets/` 文件。
重要限制:
- 不要在样张确认前运行批量生成。
- 默认用 `generate` 单张生成;`batch` 只用于用户明确授权的全量生成或 dry-run prompt 输出。
- 即使使用 `batch`,脚本也是逐项请求图片接口;生成后仍要逐张 QA并把通过的图片同步到 `assets/`
- 发布用 Markdown 默认引用 `assets/`,因此如果 manifest 输出到 `origin_image/`,必须在 QA 后复制到对应 `assets/` 路径。
- 金融活动 manifest 中涉及信用卡、支付卡、支付网络或机构 Logo 时,必须记录 `reference_assets`、`payment_network`、`allowed_brand_marks`、`brand_mark_sources` 和 `card_art_rule`,并在 QA 中核对卡组织和第三方 Logo 没有画错,也没有抢 MAOMOMO 主标识位置。用户未提供 Logo / 卡面素材时,先尽力查找官方或可信来源并保存到 `sources/`;无法核对时使用通用符号,不要凭记忆画真实 Logo。
- manifest、prompt、`deck_spec.json` 和发布稿中的港币金额统一使用 `HKD`,来源原文抽取文件除外。
- 小红书卡片 manifest 必须记录 `aspect_ratio`、`visual_direction`、`delivery_batch` 和 `portrait_composition_rules`prompt 必须包含 `native portrait composition`、`no squeezed elements`、`no stretched card / logo / text`、`vertical layout redesigned for Xiaohongshu`。
- 小红书卡片默认不生成完整文章、Markdown 或 ZIP最终文件清单以 `final_manifest.json` 为准。
## 内置风格名
可用:
- `warm-fintech-guide`
- `clean-professional`
- `clean-editorial`
- `data-card-dashboard`
- `handdrawn-note`
- `creative-magazine`
- `retro-flat-illustration`
- `e-ink-editorial`
- `scientific-defense`
- `mckinsey-brief`
- `xiaohongshu-vertical`
查看完整描述:
```bash
uv run python scripts/maomomo_image_gen.py styles
```
## 失败处理
- API key 缺失:提示用户配置环境变量或检查 Codex 配置,不要编造图片文件。
- 接口失败:保留已生成图片,说明失败项,必要时用 `--dry-run` 交付 prompt 清单作为临时排查材料。
- 如果脚本实际请求到了默认 `https://api.openai.com/v1`,但项目配置应使用兼容接口,先检查 `MAOMOMO_IMAGE_BASE_URL` / `OPENAI_BASE_URL``~/.codex/config.toml` 解析结果Python 3.10 及以下必须走脚本内置 TOML fallback。不要把兼容接口的 key 误发到默认 OpenAI API 后反复重试。
- 真实银行 / 券商 / 钱包截图等敏感素材需要上传图片 API 做 edit 前,先向用户确认实际 API 地址 / baseURL、接口归属、是否为用户自有兼容服务以及是否允许外发。确认且安全策略允许后才上传未确认、确认不允许或安全策略不允许时先生成“不含真实截图”的空白模板再本地嵌入真实截图状态记录 `backend_used` 写成类似 `GPT Image2 template + local screenshot embedding`,并在 QA note 说明截图未外发。
- 图片文字乱码或金额错误:重新生成该单张图片;不要手工覆盖文字伪装成模型输出。
- 图片不符合风格:先更新 manifest 的 `style` / `core_text` / `extra`,再重跑对应项。
- 图片生成超时:可以对同一张图重试较长超时;不要为了快擅自降低 `quality`
- Playwright 只用于已有 HTML / SVG / 网页截图检查,不能替代 GPT Image2 / 图片 API 生成海报、OG 图、卡片图或文章配图。
## 状态记录
每张图片 job 的 dispatch、result 和 blocker 都要写入项目状态文件。推荐状态文件:
```text
{article_dir}/slide_jobs.json
{article_dir}/slide_run_state.json
```
记录字段至少包括:
- job id例如 `hsbc-mastercard-alipay-campaign_01`
- prompt 文件,例如 `prompts/hsbc-mastercard-alipay-campaign_01.json`
- 输出原图,例如 `origin_image/hsbc-mastercard-alipay-campaign-01-cover.png`
- 发布图,例如 `assets/hsbc-mastercard-alipay-campaign-01-cover.png`
- 状态:`pending`、`dispatched`、`recorded`、`blocked`
- 生图后端、agent id、QA note、失败原因
- 小红书卡片字段:`aspect_ratio`、`visual_direction`、`delivery_batch`
- 最终交付字段:`qa_status`、`entered_assets`、`final`、`github_pushed`、`github_batch`
使用 `scripts/maomomo_job_state.py` 更新状态,不要手工改 JSON 后声称完成。
初始化状态:
```bash
uv run python scripts/maomomo_job_state.py init article \
--selected-backend "built-in image tool"
```
查看状态:
```bash
uv run python scripts/maomomo_job_state.py status article
```
记录 dispatch
```bash
uv run python scripts/maomomo_job_state.py dispatch article \
--job hsbc-mastercard-alipay-campaign_02 \
--agent-id "<agent id>" \
--prompt-file prompts/hsbc-mastercard-alipay-campaign_02.json
```
单张 QA 通过后,记录结果并同步到 `origin_image/``assets/`
```bash
uv run python scripts/maomomo_job_state.py result article \
--job hsbc-mastercard-alipay-campaign_02 \
--agent-id "<agent id>" \
--backend-used "built-in image tool" \
--selected-source /absolute/path/to/generated.png \
--qa-note "文字清楚,日期、金额、公式和卡组织已核对,风格与样张一致。"
```
记录 blocker
```bash
uv run python scripts/maomomo_job_state.py blocker article \
--job hsbc-mastercard-alipay-campaign_02 \
--agent-id "<agent id>" \
--reason "选定图片后端在 worker 中不可用"
```
如果状态脚本失败,最终报告必须说明原因,并附上状态文件当前路径和未完成 job。
生成最终 manifest
```bash
uv run python scripts/maomomo_job_state.py final-manifest article
```
`final_manifest.json` 只写入状态为 `recorded`、QA 已通过、且 `assets/` 文件真实存在的图片。最终推送、打包或给链接时只能读取该文件,不能扫描整个目录。
记录 GitHub 批次:
运行前必须先按 `references/github-delivery.md` 完成交付仓库和专用凭据配置;`github-batch` 只记录已经真实推送后的批次结果,不负责创建仓库、保存密钥或生成假链接。
```bash
uv run python scripts/maomomo_job_state.py github-batch article \
--batch batch-01-cover \
--commit "<commit sha>" \
--url "https://github.com/org/repo/commit/<commit sha>" \
--paths assets/example-01-cover.png prompts/example_01.json
```
每批推送后都要写入 batch 记录。状态文件里的单图记录会同步标记 `github_pushed=true`、`github_batch=batch-xx`;最终回复从 `github_batches.json` 或状态文件读取批次数量和链接。