DSH · 插件教程 · 配置导出
生图工具:插件与配置教程
把当前这台 DSH Web 上的生图能力拆开讲清楚:它是哪个插件、接到谁、每个配置项管什么、怎么改、出问题怎么查。内容按机器上的实际配置导出,可以直接当交接材料。
导出时间 2026-10-21 15:22(Asia/Shanghai)。依据 dsh --profile web --dump-config 的组合结果、凭据库中的键名、以及 dsh.service 的运行状态。文中不含任何密钥值。
gpt-image-2.5,配置已经在跑。2. 换模型只改
cordis.patch.yml 里的 model(仅 API Key 模式有效),然后重载服务。3. 换供应商要同时改
baseUrl 和 apiKeyEnv,对方必须提供 OpenAI 兼容的 /images/generations。
这套东西是什么
image_gen 是一个注册给模型调用的工具。用户在对话里说“生成一张……”,模型决定调用它,参数经过 Host 侧插件校验后发到 OpenAI 兼容网关;回来的图片写进 DSH 附件仓,界面渲染成有预览和下载的卡片,会话重载后还能回放同一张。
插件本体是 dsh-studio-image-gen(dsh-image-gen 的 Studio 分支:每张图有稳定的 IMG- 编号,预览卡片浮在对话上方)。它同时提供 Host 半(注册工具、鉴权、HTTP 取图)和浏览器半(工具卡、灯箱、下载)。
IMG- 编号),图片字节留在界面元数据里。这样即使当前对话切到不支持视觉的文本模型,历史也不会因为图片块而卡住。
生成链路
旁路两条:卡片通过 Host 私有路由按 sessionId + callId 取图;归属索引写进 $DSH_HOME/image-gen-index/,会话删掉后由后台清扫。
现网快照
cordis.patch.yml 只在 15:19 改过主题偏好(dark → light),image-gen 段落自 14:27 的快照以来逐字节相同。所以上面的值就是进程正在用的值,而不是“下次重启才生效”的值。
配置放在哪
| 路径 | 作用 | 改它会发生什么 |
|---|---|---|
~/.dsh/profiles/web/package.json |
依赖声明 + dsh.profile.bundles 列表 |
决定插件是否被装进 profile、是否随启动加载 |
~/.dsh/profiles/web/cordis.patch.yml |
本机覆盖层,id: image-gen 的 config |
改完必须重载服务;只覆盖写出来的字段 |
/home/ubuntu/dsh/plugins/dsh-studio-image-gen/cordis.patch.yml |
插件自带 bundle patch,只负责 insert 一行 image-gen |
一般不动;升级插件时会被覆盖 |
~/.dsh/.credentials.yaml |
凭据仓库,refs 下是按名字索引的密钥 |
写入后由凭据服务热发布,无需重启 |
合并顺序是 插件 schema 默认值 → bundle patch → profile patch。profile patch 里没写的键一律落回默认值,所以覆盖层可以只保留真正要改的 4 行:
# 生图插件:使用 hfsy NewAPI 网关(OpenAI 兼容 images/generations)
- id: image-gen
config:
authMode: api-key
apiKeyEnv: HFSY_API_KEY
baseUrl: https://www.hfsyapi.cn/v1
model: gpt-image-2.5
.credentials.yaml(或凭据页)里,不要写进 patch——patch 会进截图、进 Git、进备份。另外别直接改插件目录里的 cordis.patch.yml,升级会被覆盖,而且与 profile 层的意图混在一起。
配置项全表
“现网”列取自组合后的实际配置;标 已改 的 4 项是相对默认值的覆盖,其余均为 schema 默认。
| 字段 | 默认 | 现网 | 说明 |
|---|---|---|---|
| 接入 | |||
authMode已改 |
auto | api-key | auto:先试 Codex 订阅,非取消类失败再回落到 Key;api-key:只用 Key;codex-subscription:禁止回落 |
apiKeyEnv已改 |
OPENAI_API_KEY | HFSY_API_KEY | 凭据引用名,必须与 .credentials.yaml 的 refs 键完全一致 |
baseUrl已改 |
api.openai.com/v1 | hfsyapi.cn/v1 | 网关根地址,插件拼成 <baseUrl>/images/generations;非回环必须是 https,且不能带 query/fragment/账号密码 |
model已改 |
gpt-image-2 | gpt-image-2.5 | 部署默认模型,仅 API Key 模式生效;单次调用可用 model 参数覆盖 |
| 默认出图参数 | |||
defaultSize |
auto | auto | 未指定尺寸时的出图尺寸;取值规则见「工具参数」一节 |
defaultQuality |
auto | auto | auto / low / medium / high |
defaultOutputFormat |
png | png | png / jpeg / webp;Codex 订阅模式只收 PNG |
defaultOutputCompression |
90 | 90 | 0–100,只对 JPEG/WebP 生效;对 PNG 指定压缩会被直接拒绝 |
defaultBackground |
auto | auto | auto 或 opaque;GPT Image 2 不支持透明背景 |
| 传输与稳健性 | |||
moderation |
auto | auto | auto / low,透传给上游审核强度 |
partialImages |
3 | 3 | 0–3;API Key 模式下最多展示几张服务端真实局部图(Codex 模式强制 0) |
requestTimeoutMs |
120000 | 120000 | 整次操作超时,允许 10 000–300 000 ms |
maxRetries |
2 | 2 | 0–5;总尝试次数 = maxRetries + 1,只重试 429/5xx/网络类故障 |
retryBaseMs |
1000 | 1000 | 100–30 000 ms,指数退避起点(有上限) |
maxConcurrent |
2 | 2 | 1–8;达到上限立刻报错,不排队 |
凭据与认证模式
| 模式 | 凭据来源 | 模型 | 接口地址 | 格式 / 渐进图 |
|---|---|---|---|---|
| api-key 当前 | apiKeyEnv 指向的 DSH 凭据(现为 HFSY_API_KEY) |
配置的 model,可按次覆盖 |
baseUrl |
PNG/JPEG/WebP · 最多 3 张真实局部图 |
| codex-subscription | dsh-codex-connect 管理的 ChatGPT OAuth |
写死 gpt-image-2 |
固定 chatgpt.com/backend-api/codex |
仅 PNG · 无局部图(显影动画代替) |
| auto | 先订阅、失败再回落 Key | 随实际走通的通道 | 随通道 | 随通道 |
凭据解析的优先级是:~/.dsh/.credentials.yaml → 进程环境变量 → 启动目录 .env → ~/.dsh/.env。管理库优先,所以凭据页里存过 Key,就不会被 shell 里残留的旧变量顶掉。
dsh-codex-connect,也没有 ChatGPT 订阅登录态;加上供应商已经换成 hfsy 网关,只有 API Key 模式能让 baseUrl / model 生效。当前 refs 里已有 HFSY_API_KEY,所以不必在启动环境里再 export 一次。
安装与启用
把插件放进 profile
两种等价做法:在凭据齐全的机器上一条命令装进去,或手工保证 package.json 的 dependencies 与 dsh.profile.bundles 都包含它。这是本机现在的做法——依赖指向本地源码目录,方便改。
# 本地 link 安装(当前方式) dsh plugin --profile web add link:/home/ubuntu/dsh/plugins/dsh-studio-image-gen # package.json 里对应两处: # "dependencies": "dsh-studio-image-gen": "link:/home/ubuntu/dsh/plugins/dsh-studio-image-gen" # "dsh.profile.bundles": "dsh-studio-image-gen"
存好凭据
在 DSH 的凭据设置里新增一条,名字必须等于 apiKeyEnv(这里是 HFSY_API_KEY)。文件形式就是 ~/.dsh/.credentials.yaml 的 refs 段:
refs:
HFSY_API_KEY: <你的 hfsy 密钥>
# 同文件还存有 DEEPSEEK_API_KEY、OPENCODE_GO_API_KEY
凭据服务会热加载这个文件,新增/改名后不用重启;但改了 patch 里的 apiKeyEnv 仍要重载。
写覆盖配置
把上面那段 4 行的 image-gen 配置贴进 profile patch。想调默认尺寸、质量、超时,就在同一段里补键,值照抄「配置项全表」的默认列。
重载并验证
# 组合结果里看这一段是否生效 dsh --profile web --dump-config | sed -n "/id: image-gen/,/^# ==/p" # 重载(重启 + 30 次探测 + 失败自动回滚) ~/.dsh/reload-dsh.sh # 起来了吗 systemctl --user is-active dsh.service curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:13080/
最后在对话里生成一张 1024×1024 的测试图;卡片出现成图、能预览下载,就算链路通了。
怎么调用
不需要写命令,直接描述需求即可;模型会自己拼参数。想控制结果,就把尺寸、画幅、质量、格式写进需求里。
# 基础 生成一张电影感 16:9 产品摄影:半透明机械键盘放在深色玻璃桌面上, 紫色轮廓光,浅景深,不要文字。 # 指定尺寸与质量 用 1536x1024、high 质量,画一张海边日落的扁平插画。 # 指定格式(要更小的文件) 生成一张 1024x1024 的贴纸风图标,输出 webp、压缩 80。 # 单次换模型(仅 api-key 模式有效) 用 gpt-image-2pro 生成一张 2048x2048 的科幻城市全景。
Generated an image with gpt-image-2.5 (1024×1024, PNG, 18.4s). Image id: IMG-XXXXXX. 之后用户提到这个编号,指的就是这张图。
工具参数
| 参数 | 取值 | 缺省 | 约束 |
|---|---|---|---|
prompt | 字符串 | 必填 | 1–32 000 字符,且不超过 64 000 UTF-8 字节 |
model | 字符串 | 配置的 model | 仅 API Key 模式;如 gpt-image-2.5、gpt-image-2pro |
size | auto 或 宽x高 | defaultSize | 边长可被 16 整除、单边 ≤ 3840、宽高比 1:3–3:1、总像素 655 360–8 294 400 |
quality | auto / low / medium / high | defaultQuality | — |
output_format | png / jpeg / webp | defaultOutputFormat | Codex 订阅模式只接受 PNG |
output_compression | 整数 0–100 | defaultOutputCompression | 只对 JPEG/WebP;PNG 传了会报错 |
background | auto / opaque | defaultBackground | 不支持透明背景 |
合法尺寸怎么算(几个能直接用的值)
需要同时满足:两边都是 16 的倍数、单边 ≤ 3840、总像素在 655 360–8 294 400 之间、宽高比在 1:3 到 3:1 之间。
可直接用:1024x1024(1:1)、1536x1024(3:2)、1024x1536(2:3)、2048x2048(1:1 高清)、1920x1080(16:9)、1080x1920(竖屏)、3840x2160(4K 上限,正好 8 294 400 像素)。
反例:1000x1000(不是 16 的倍数)、4096x4096(超边且超像素)、3840x480(比例 8:1)。
卡片与图片编号
- 渐进显示:API Key 模式最多收到 3 张服务端真实局部图,在同一画布上交叉淡入、逐步对焦;Codex 订阅通道是非流式,用显影动画撑到成图返回。系统开启“减少动态效果”时动画自动降级。
- 成图持久化:只有最终图片会写成 DSH 不可变附件,因此刷新页面、重开会话都能回放同一张卡片。
- 编号:
IMG-XXXXXX由callId哈希得到,同一次调用稳定不变;卡片上可复制,对话里提它等于指这张图。 - 取图:浏览器拿到的是 Host 私有路由,不是公开静态目录。Host 先在会话记录里核对该
callId确实属于这个会话,再读附件——“猜 URL 看别人的图”走不通。
| 用途 | 参数 | 说明 |
|---|---|---|
| 缩略图 | variant=thumb | 列表/卡片内的小图,WebP,写进 $DSH_HOME/image-gen-cache |
| 预览 | variant=display | 默认值,灯箱用 |
| 原图 | variant=orig | 原始附件字节 |
| 下载 | download=1 | 附上 content-disposition,文件名取提示词前 48 字符 |
路由形如 /api/dsh-image-gen/image?sessionId=…&callId=…&variant=display。附件是内容寻址的,响应标了 immutable 长缓存,同一 URL 永远对应同一份字节。
改配置与重载
插件配置在启动时组合成快照,改文件不会热生效。改 cordis.patch.yml 之后必须重载。
# 推荐:带健康探测和自动回滚 ~/.dsh/reload-dsh.sh # 脚本做的事: # 1. 把改动后的文件复制成 cordis.patch.yml.applied # 2. systemctl --user restart dsh.service # 3. 每 2 秒探测 13080,最多 30 次 # 4. 起不来就用 cordis.patch.yml.rollback 回滚再重启 # 手动等价(不保留回滚) systemctl --user restart dsh.service
回滚材料就在 profile 目录:cordis.patch.yml.rollback、.bak.20261021-015536、以及 backups/ 下按时间戳存的副本。
cordis.patch.yml,可能把注释和手工排版一起抹掉。习惯手写注释的话,优先直接编辑文件,改完跑重载脚本。
避坑清单
走订阅时请求模型固定为 gpt-image-2,改 patch 里的 model 没用。要换模型,必须让 authMode 落在 api-key(或 auto 实际回落到 key)。
订阅模式传 output_format 非 png、或传 output_compression,会直接报错,而不是忽略。
GPT Image 2 拒绝透明。background 只有 auto 和 opaque,要“抠图效果”请在提示词里写明背景颜色。
baseUrl 除回环外必须 https,不能带 query、fragment、账号密码;对方的 /images/generations 要能返回 data[0].b64_json,或发 image_generation.partial_image / completed 的 SSE 事件。
maxConcurrent 是 2:同时第三张图不会排队等待,而是立刻报“Too many image generations are already running”。批量出图请串行。
429、5xx、网络/协议类故障会退避重试;内容审核拒绝和参数错误一次就停,重复调用只是浪费额度。
插件 inject 必须包含 webServer,否则 0.2.x 下注册 RPC 通道时抛 cannot get property "webServer" without inject,表现为插件静默不激活。
取图路由沿用浏览器的鉴权与同源校验。反向代理若把 Host(含端口)改掉,会出现页面能开、图片 403 的怪现象;nginx 用 $http_host 而不是 $host。
排错对照
| 症状 | 大概率原因 | 处理 |
|---|---|---|
No credential is configured for HFSY_API_KEY |
refs 里没有这个名字,或大小写/拼写不一致 | 在凭据页补一条同名凭据,或把 apiKeyEnv 改成已存在的键名后重载 |
| 上游返回 401 / 403 | Key 失效、额度耗尽,或反代的同源校验没过 | 先换浏览器直连 13080 复现;再查网关后台的 Key 状态与余额 |
| 模型不存在 / model not found | 网关没有该模型,或名字拼错 | 换回 gpt-image-2.5,或对照网关模型列表改 model |
404 image not authorized by this session |
URL 里的 callId 不属于该会话(旧链接、串了会话) |
回到原会话从卡片重新打开;别手工拼 URL |
| 请求超时 | 大尺寸 + high 质量,120s 不够 | 调大 requestTimeoutMs(≤300 000),或降质量、改 JPEG/WebP |
| 尺寸报错 | 不是 16 的倍数、超边、比例或像素越界 | 用「工具参数」里列出的合法值 |
| 卡片一直停在显影 | 上游慢;或反向代理开了缓冲,SSE 局部图不落地 | 反代关掉 proxy_buffering;订阅模式本来就是非流式,等成图即可 |
| 工具在会话里根本不存在 | profile 的 bundles 没加插件,或改完没重载 | dsh --profile web --dump-config | grep image-gen 确认后重载 |
| 图片能生成,刷新后看不见 | 附件仓不可用,或卡片依赖的浏览器模块没加载 | 看 Host 日志里的 [image-gen] 记录;确认 ~/.dsh/attachments 可读、页面已刷新到最新 bundle |
文件与数据
| 路径 | 内容 |
|---|---|
/home/ubuntu/dsh/plugins/dsh-studio-image-gen/src/index.ts | Host 入口:配置 schema、工具注册、取图路由、归属索引与清扫 |
…/src/openai.ts | OpenAI 兼容传输:端点拼接、尺寸校验、SSE/JSON 解析、重试 |
…/src/codex.ts | 订阅模式:读 dsh-codex-connect 的 OAuth,刷新与固定端点 |
…/src/client/index.tsx | 浏览器半:显影动画、局部图淡入、完成卡片、灯箱 |
…/lib/index.js · lib/client.js | 构建产物(实际被加载的是这两份) |
~/.dsh/profiles/web/cordis.patch.yml | 本机覆盖配置 |
~/.dsh/.credentials.yaml | 凭据仓库(refs) |
$DSH_HOME/image-gen-index/*.json | 每张成图的归属记录:attachmentId、sessionId、hostPath、创建时间 |
$DSH_HOME/image-gen-cache/ | 缩略图/预览图的 WebP 缓存(尽力而为,可删) |
~/.dsh/attachments/v1/ | 不可变成图附件本体(全仓约 102 MB) |
~/.dsh/reload-dsh.sh | 重载脚本:重启 + 探测 + 回滚 |
会话被删掉后,后台会按索引逐条 stat 对应会话,清掉孤儿图片;启动 90 秒后跑第一次,之后每 6 小时一次,1 小时内新建的条目跳过。所以删会话不会马上腾空间,最多等一轮清扫。
不包含:任何 Key 的值、OAuth token、聊天内容、成图字节。凭据只以名字出现。
依据:
dsh --profile web --dump-config(15:21)、~/.dsh/.credentials.yaml 键名、systemctl --user 服务状态、插件源码 0.2.0(git HEAD 68290ee)。本页为静态文档,可离线保存;部署位置
/var/www/dsh-image-gen-doc/,访问前缀 /image-gen-doc/。