# Image Gen Studio

> 当用户需要生成图片、AI 画图、上传图片后用文字修改、编辑图片、涂抹遮罩修改图片、多图融合参考生成、识别解析图片属性（类型/风格/时代/元素/镜头/配色/搭配/穿搭/视觉）、管理生成资产、使用AI 图像 API 生图时调用。弹出交互式 HTML 图像工作室（本地代理解决 CORS + curl 转发修复 CF TLS 指纹拦截），支持：文生图、独立导航的文改图（单图上传 + 文字描述修改）、图片上传 + Canvas 画笔遮罩涂抹编辑（红色高亮标注法 / 原生 mask）、2-10 张参考图融合生成、生成结果自动保存到本地资产库、LLM 图片识别（gpt-5.6-luna 优先失败自动回退 gemini）、502 等通讯异常自动诊断与修复、API Key 管理与校验。触发词：生图、生成图片、画图、文改图、文字修改图片、图生图、图像编辑、遮罩编辑、多图融合、图片识别、识别图片、我的资产、资产库、AI 图像生图、micu image、image studio。

- Skill: `sangjiexun/image-gen-studio` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add sangjiexun/image-gen-studio`
- Raw SKILL.md: https://api.skillmd.com/api/skills/sangjiexun/image-gen-studio/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: sangjiexun (https://skillmd.com/u/sangjiexun)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/sangjiexun/image-gen-studio

---


# AI 图像工作室 (image-gen-studio)

在对话中弹出**交互式 HTML 图像工作台**，本地代理转发AI 图像 API，完整支持五大能力：

| 能力 | Gemini 引擎（当前可用） | gpt-image-2 引擎 |
|---|---|---|
| 文生图 | `/v1beta/...:generateContent` | `/v1/images/generations` |
| 文改图（单图+文字） | 单图 inline_data 多模态编辑 | `/v1/images/edits` + `image` |
| 遮罩编辑 | 红色高亮标注法（多模态理解） | `/v1/images/edits` + 原生 mask PNG |
| 多图融合（2-10 张） | 多 image parts 直传 | `/v1/images/edits` + `image[]` |
| 分辨率 | 跟随提示词/比例（~1K-2K） | 1K / 2K / 4K（16 倍数校验） |
| 资产库 + LLM 识别 | 生成结果自动保存 / gpt-5.6-luna→gemini 识别 | 同左 |

## v2 新增（2026-08-21）

1. **通讯诊断与自动修复**：前端失败自动弹诊断面板（错误分类：502 上游断连 / 401 Key 无效 / 503 模型无通道 / 代理不可达 / 超时），逐项检测浏览器网络→本地代理→上游 API，一键「重试上次操作」。
2. **生成结果本地资产库**：每次生成/编辑/融合自动保存到 `--assets-dir`（默认 `$MICU_ASSETS_DIR` 或当前目录 `assets/`），前端「🗂️ 我的资产」Tab 网格浏览、下载、删除；资产 API：`POST /api/assets/save`、`GET /api/assets/list`、`GET /api/assets/file/<name>`、`DELETE /api/assets/<name>`。
3. **LLM 图片识别**：`POST /api/vision` 传 `{image_b64, mime, api_keys:{gemini,gpt}, engine}`，服务端按 gpt-5.6-luna（OpenAI 端点）→ gemini-3-pro-image-preview（原生端点）顺序自动回退，解析 9 维度：图片类型/风格/时代/元素/镜头角度/配色/搭配类型/穿搭类/视觉类，输出 JSON。

## v3 新增（2026-08-21）：自动分类归档 + GitHub 同步

**完整自动链路**：生成图片 → 保存资产 → 后台自动识别「图片类型」→ 写回 index.json 的 `meta.category` → 按分类建目录 → 上传 GitHub 仓库 `sangjiexun/digital-asset` → 重建 README.md 目录树。

- **github_sync.py**（`scripts/github_sync.py`）：用 GitHub Contents API（`api.github.com`，Python urllib，绕过 git push 代理 502）上传图片到 `{分类目录}/{文件名}`，重建 README.md（总览统计 + 树状目录 + 分类明细表）。支持 `--watch` 监听模式、`--dry-run` 预演。
- **代理自动触发**：`POST /api/assets/save` 带 `auto_enhance:true` + `meta_keys:{gemini,gpt}` 时，保存响应立即返回，后台线程「识别→写回 category→调 github_sync.py 同步」。
- **手动触发**：`GET /api/assets/sync`（前端「🚀 同步到 GitHub」按钮）。
- **前端资产卡**：显示分类徽标（识别中/分类名），顶部 GitHub 仓库链接。
- **分类规则**：`meta.category` 或 `meta.图片类型` → 非法字符转 `_`，无分类归 `unsorted/`。

**关键坑点（必记）**：
- GitHub Contents API 的 **中文路径必须先 `urllib.parse.quote(path, safe="/")`**，否则 urllib 请求行触发 `UnicodeEncodeError: ordinal not in range(128)`。
- GitHub PAT 从 Keychain 读：`security find-internet-password -s github.com -w`（40 位），脚本内 `get_token()` 已封装，不硬编码。
- `api.github.com` 用 Python urllib 可直连（网页 github.com 被代理拦、git push 502，但 API 正常）。
- README 相对链接中文路径 `./数字艺术/xxx.jpg` 在 GitHub 网页端可正常跳转。

## v4 新增（2026-08-21）：手动上传照片到指定分类

- **前端**：资产 Tab 顶部新增「📤 上传照片到数字资产分类」卡片——拖拽/点击多选图片（≤10 张）→ 下拉选择分类（或自定义分类名）→ 可选自定义文件名 → 上传。
- **后端**：
  - `GET /api/assets/categories` 返回分类列表（本地 index 已有分类 + github_sync 扫描 + 常见分类兜底）。
  - `POST /api/assets/upload` body `{data_b64, ext, category, name?}` 保存到本地资产（写死 `meta.category`）+ 后台同步 GitHub。
  - 自定义文件名自动清洗非法字符、扩展名校验（png/jpg/jpeg/webp/gif/bmp）、重名自动加序号去重。
- 上传后自动同步到 GitHub `{分类}/{文件名}`，支持中文文件名。

## v4.1 修复（2026-08-21）：上传预览图 + 每次同步 README

- **Bug 1：资产网格里中文文件名图片显示黑色占位**
  - **根因**：`do_GET` 路由 `assets_get(name)` 拿到的 `name` 是 URL 编码形式（如 `%E4%B8%AD...jpg`），未 `unquote` 就传给 `os.path.basename`，导致 `os.path.isfile` 找不到真实中文文件 → HTTP 404 → 前端 `<img src>` 加载失败。
  - **修复**：`do_GET` / `do_DELETE` 路由处对 `name` 调 `urllib.parse.unquote(path[...])` 解码。

- **Bug 2：每次上传没触发 README 更新**
  - **根因**：旧 `_trigger_github_sync` 调 `sync_once` 全量扫描本地资产，遇到沙盒 SIGKILL (exit 137) 就提前终止，README 没机会重建。
  - **修复**：拆为「单文件快速通道 + 独立 README 重建」两个子命令
    - `github_sync.py --upload-only NAME --upload-category CAT --upload-stdin`：只同步一张图（从 stdin 读字节避免落盘）。
    - `github_sync.py --rebuild-readme`：单独重建 README。
    - `proxy_server._trigger_github_sync(name, category, img_bytes)` 接收三参数，在 `assets_upload` 末尾串行跑两个独立 subprocess（即使第一段挂掉 README 也会重建）。
  - **关键坑**：`bytes` input 不能配 `text=True`（会触发 `'bytes' object has no attribute 'encode'`），要用 `capture_output=True`（无 text）+ `.decode('utf-8','replace')`。

- **前端 `renderUploadPreview` 改造**：DOM API 替代 innerHTML 拼接；`FileReader.readAsDataURL` 替代 `URL.createObjectURL`（更稳，避 iframe 沙盒限制 + 内存泄漏）；加文件名 label（>10 字截断 + hover 显示全名）；删除按钮改 addEventListener + stopPropagation。

## ⚠️ 502 根因与修复（2026-08-21 实测确认）

- **根因**：Python urllib 的 TLS/HTTP 指纹被上游 Cloudflare 拦截。带图的大 JSON 请求（编辑/多图融合 base64）直接 `SSL: UNEXPECTED_EOF_WHILE_READING` / `Remote end closed connection`，而**同请求用系统 curl 100% 成功**。
- **修复**：proxy_server.py 改用**系统 curl 子进程**转发上游请求 + 强制浏览器 UA（curl 转发时忽略传入 UA，一律 `-H "User-Agent: Mozilla/5.0 ... Chrome/126.0"`），502/524/空响应自动指数退避重试最多 3 次。
- **识别引擎 gpt-5.6-luna 状态**：2026-08-21 实测 Gemini Key 分组下 `model_not_found`（503，无可用 channel，属 vip_2_image 分组）；工作台已做自动回退，等用户换新 Key 后 gpt-5.6-luna 即可用。

## 标准启动流程（用户要交互式生图时）

```bash
# 1. 后台启动代理服务器（端口 8230，被占用时换 --port 8231 等）
python3 ~/.workbuddy/skills/image-gen-studio/scripts/proxy_server.py \
  --port 8230 --assets-dir "$HOME/image-gen-studio-assets"

# 2. 用 present_files 展示 http://localhost:8230 打开工作台
#    （HTML 文件本体在 ~/.workbuddy/skills/image-gen-studio/assets/image-studio.html）
```

**重要**：
- 代理必须在沙盒外运行（需要绑定端口 + 出网），Bash 启动时若沙盒拦截需申请权限
- 启动后先自己 curl 一次 `http://localhost:8230/api/health`（返回 `{"ok":true,"version":"2.0"}`）验证代理；再 curl `http://localhost:8230/api/v1/models`（带 Gemini Key Bearer 头）验证上游
- 工作台默认引擎 = Gemini（Key 有效）；gpt-image-2 的 vip_2_image Key 若 401，提示用户去 https://www.micuapi.ai 令牌页面换新 Key，填入工作台「设置」页
- 代理进程是长驻服务，会话结束不必杀掉；端口冲突时换端口重启

## 快速直出模式（用户只说"生成一张 XX"）

不必开工作台，直接 curl 生图并 present_files：

```bash
# Gemini 文生图（可用线路）
curl -s -X POST "https://www.micuapi.ai/v1beta/models/gemini-3-pro-image-preview:generateContent?key=<GEMINI_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"contents":[{"role":"user","parts":[{"text":"<PROMPT>"}]}],
       "generationConfig":{"responseModalities":["TEXT","IMAGE"]}}' \
  --max-time 180 -o /tmp/gemini_resp.json

# 从 resp 中提取 candidates[].content.parts[].inlineData.data (base64) 落盘 PNG
```

gpt-image-2 直出（需有效 vip_2_image Key）：
```bash
curl -s -X POST "https://www.micuapi.ai/v1/images/generations" \
  -H "Authorization: Bearer <GPT_KEY>" -H "Content-Type: application/json" \
  -d '{"model":"gpt-image-2","prompt":"<PROMPT>","size":"1024x1024","n":1,"response_format":"b64_json"}' \
  --max-time 180
# 响应 data[0].b64_json 或 data[0].url
```

识别图片（v2，走代理，自动回退）：
```bash
curl -s -X POST "http://localhost:8230/api/vision" -H "Content-Type: application/json" \
  -d '{"image_b64":"<BASE64>","mime":"image/png","engine":"gpt-5.6-luna",
       "api_keys":{"gemini":"<KEY>","gpt":"<KEY>"}}' --max-time 200
```

## 申请 API Key（推荐）

本技能依赖 **AI 图像 API（micuapi.ai）**。未注册可在此免费申请 Key，注册后在工作台「设置」页粘贴即可使用：

👉 **申请地址：https://www.micuapi.ai/sign-up?aff=dp17**

支持 Gemini 原生图像端点与 gpt-image-2 Images API 双引擎，按量计费。

## API Key（存于工作台 localStorage，勿写入 git）

- **Gemini Key / gpt-image-2 Key**：不在源码中提供。请通过上方链接申请，启动工作台后在「设置」页填写，或通过受控环境变量/本地密钥管理器注入。
- **gpt-image-2 Key**：不在源码中提供。需使用具备对应模型分组权限的有效 Key，并在工作台「设置」页填写。
- Key 仅存于浏览器 localStorage 或本机环境，不得提交到 Git；校验端点：`GET /v1/models`（带 Bearer 头）。

## 关键技术事实（实测确认）

1. **Gemini 模型不能走 OpenAI 图像端点**：`/v1/images/generations` 只支持 imagen 系列，gemini 模型会报 `not supported model for image generation`。Gemini 必须走 `/v1beta/models/{model}:generateContent?key=` 原生端点。
2. **Gemini 响应格式**：`candidates[].content.parts[].inlineData`（camelCase）或 `inline_data`（snake_case）都可能出现，mime 为 image/jpeg / image/png，data 是 base64。
3. **gpt-image-2 编辑**：`POST /v1/images/edits` multipart；`image` 字段传原图文件，`mask` 字段传 PNG（**alpha=0 透明区 = 修改区，alpha=255 = 保留**），mask 尺寸必须与原图一致。
4. **gpt-image-2 多图融合**：同 `/v1/images/edits`，多图用字段名 **`image[]`**（每张 append 一次），2-10 张，总字节 ≤ 10MB。旧 `generations + image_urls` 已被AI 图像静默忽略（会返回 image_tokens=0），不要用。
5. **多图融合 prompt 前缀**（防拼贴）：`Reference images are provided. Synthesize their visual elements (style, palette, composition, subjects) into ONE single new image per the instruction below. Do NOT collage, tile, or montage the references side-by-side unless explicitly asked.\n\nInstruction:\n{用户指令}`
6. **Gemini 遮罩编辑替代方案**（工作台已实现）：把遮罩笔触以 50% 透明红色叠加到原图上导出，配合指令「红色高亮区域需修改，其余像素保持不变」。效果弱于原生 mask 但可用。
7. **尺寸规则**（gpt-image-2）：宽高 16 倍数、最长边 ≤3840、长宽比 ≤3:1、总像素 655,360–8,294,400；2K/4K 自动切 `gpt-image-2-openai` 并强制 n=1 串行。
8. **n>1 的正确姿势**：客户端循环 n 次每次 n=1（MCP 官方做法），不要一次传 n=N。
9. **502 SSL EOF 根因**：Python urllib TLS 指纹被 CF 拦截 → 代理一律用系统 curl 转发（见上方 v2 章节）。验证 curl 与 urllib 差异的最小复现：同一 349KB 带图 JSON，curl 成功 / urllib `UNEXPECTED_EOF_WHILE_READING`。
10. **gpt-5.6-luna**：OpenAI 兼容 vision 模型，走 `/v1/chat/completions` + `image_url` data URL；当前 Gemini Key 分组无 channel（503），需 vip_2_image 分组 Key；识别服务端已实现自动回退 gemini-3-pro-image-preview。
11. **Gemini 背景移除不保证直接返回透明 PNG**：即使提示词明确要求 `alpha=0` 和 PNG，`gemini-3-pro-image-preview` 仍可能返回 `image/jpeg`（实测为均匀 RGB 灰底）。不得把 JPEG 改扩展名冒充透明 PNG。可靠流程：先让模型生成纯色均匀背景的高质量主体图，再用边界连通区域分割生成真实 RGBA PNG。推荐算法：取图像四周 20px 的中位色为背景色；计算 RGB 欧氏距离；从四边种子用 `scipy.ndimage.binary_propagation` 仅扩展到背景候选；对 3–28 色距做渐变 alpha 以保留抗锯齿；去除小于 20px 的孤立连通噪点；最后用 Pillow 保存 RGBA PNG，并强制验证 `mode=RGBA`、alpha extrema `(0,255)`、透明像素数 > 0。

## 文件清单

```
~/.workbuddy/skills/image-gen-studio/
├── SKILL.md                      # 本文件
├── assets/
│   └── image-studio.html         # 交互式工作台 v3（双引擎、遮罩画笔、多图栅格、资产画廊、识别弹窗、诊断弹窗、GitHub 同步）
├── scripts/
│   ├── proxy_server.py           # 本地代理 v4.1（curl 转发 + 自动重试 + 资产库 API + /api/vision + 自动分类+GitHub 同步 + 单文件快速通道）
│   └── github_sync.py            # GitHub 同步器 v4.1（Contents API 上传 + README 目录树重建 + --upload-only/--rebuild-readme 子命令）
└── references/
    └── api-reference.md          # API 端点 / 参数 / 响应格式速查
```

## 故障排查

| 症状 | 原因与处理 |
|---|---|
| 工作台打开但「未连接」 | 代理没启动 / 端口不对；重启 proxy_server.py |
| 401 Invalid token | Key 失效，去 micuapi.ai 令牌页换新，填入设置页 |
| HTTP 500 not supported model | Gemini 模型误走 OpenAI 端点；检查引擎选择 |
| CF 524 / 超时 | 4K 请求过大；gpt 引擎 4K 必须走 openai 高质量线路（slb 节点） |
| 生图只有文字没有图 | 响应 parts 只有 text；换 gemini-3-pro-image-preview 重试 |
| mask 无效 | mask 必须 PNG、尺寸与原图完全一致、透明区=修改区 |
| HTTP 502 SSL EOF / Remote end closed | 旧版 urllib 转发被 CF 拦截；确认代理为 v2（curl 转发），重启代理 |
| HTTP 403 code 1010 | curl 转发时 UA 被上游拦截；确认代理强制浏览器 UA（v2.1 起默认） |
| 503 model_not_found | 模型在当前 Key 分组无通道；换引擎/换 Key（识别会自动回退 gemini） |
| 资产不显示 | 检查 assets/ 目录存在、index.json 可读写；前端「🔄 刷新」 |


