@dickpy/dsh-imagegen 1.5.6 → 1.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/lib/client.js +426 -390
- package/lib/client.js.map +1 -1
- package/lib/index.js +181 -5
- package/package.json +81 -81
- package/src/canvas-store.ts +375 -375
- package/src/client/ImageGenPanel.tsx +2823 -2807
- package/src/client/SettingsCard.tsx +1128 -1128
- package/src/client/locales.ts +1515 -1509
- package/src/client/panel.module.css +7 -0
- package/src/engine.ts +998 -845
- package/src/gallery-store.ts +311 -311
- package/src/history-store.ts +275 -275
- package/src/image-storage-path.ts +12 -12
- package/src/index.ts +430 -429
- package/src/model-catalog.ts +149 -124
- package/src/presets.ts +95 -86
- package/src/prompt-enhancer.ts +151 -137
- package/src/protocol.ts +580 -580
package/lib/index.js
CHANGED
|
@@ -41,7 +41,7 @@ function installSettingsSectionCompat(ctx, ns, schema, entry, hooks) {
|
|
|
41
41
|
/** Settings namespace this plugin owns (host settings seam + bridge). */
|
|
42
42
|
const IMAGEGEN_SETTINGS_NAMESPACE = "dsh-imagegen";
|
|
43
43
|
/** Published package version shared by the host updater and the client UI. */
|
|
44
|
-
const PLUGIN_VERSION = "1.5.
|
|
44
|
+
const PLUGIN_VERSION = "1.5.7";
|
|
45
45
|
/** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
|
|
46
46
|
const SETTINGS_API = {
|
|
47
47
|
describe: "/api/dsh-imagegen/settings/describe",
|
|
@@ -230,8 +230,27 @@ const ENTRIES = {
|
|
|
230
230
|
supportsEdit: true,
|
|
231
231
|
supportsAspectRatio: true,
|
|
232
232
|
qualityTiers: ["auto"]
|
|
233
|
+
},
|
|
234
|
+
minimax: {
|
|
235
|
+
label: "MiniMax",
|
|
236
|
+
labelZh: "MiniMax 图像",
|
|
237
|
+
known: true,
|
|
238
|
+
supportsEdit: true,
|
|
239
|
+
supportsAspectRatio: true,
|
|
240
|
+
qualityTiers: ["auto"]
|
|
233
241
|
}
|
|
234
242
|
};
|
|
243
|
+
/** Documented upstream prompt hard limits (UTF-16 code units). The engine
|
|
244
|
+
* fast-fails on these before any network call and the panel counter shows
|
|
245
|
+
* them live; families absent here have no documented limit. */
|
|
246
|
+
const PROMPT_CHAR_LIMITS = { minimax: 1500 };
|
|
247
|
+
/** The documented prompt character limit for a model id, or null when the
|
|
248
|
+
* family has no known limit. Single source of truth for engine enforcement
|
|
249
|
+
* and the panel's live counter. */
|
|
250
|
+
function promptCharLimit(model) {
|
|
251
|
+
const { family } = describeModel(model);
|
|
252
|
+
return (family !== "unknown" ? PROMPT_CHAR_LIMITS[family] : void 0) ?? null;
|
|
253
|
+
}
|
|
235
254
|
/** Official Gemini image ids served by Nano Banana gateways. */
|
|
236
255
|
const NANOBANANA_GEMINI_IDS = /* @__PURE__ */ new Set([
|
|
237
256
|
"gemini-3-pro-image",
|
|
@@ -272,6 +291,10 @@ function describeModel(model) {
|
|
|
272
291
|
family: "qwen",
|
|
273
292
|
...ENTRIES.qwen
|
|
274
293
|
};
|
|
294
|
+
if (/^(?:minimax[-_/])?image-\d+/i.test(id)) return {
|
|
295
|
+
family: "minimax",
|
|
296
|
+
...ENTRIES.minimax
|
|
297
|
+
};
|
|
275
298
|
return {
|
|
276
299
|
family: "unknown",
|
|
277
300
|
label: "unknown",
|
|
@@ -381,6 +404,17 @@ async function listImageModels(config) {
|
|
|
381
404
|
async function listPromptModels(config) {
|
|
382
405
|
return listOpenAIModels(config);
|
|
383
406
|
}
|
|
407
|
+
/** Remove reasoning-model artifacts from a chat model's visible content:
|
|
408
|
+
* complete `<think>…</think>` blocks first, then anything from a dangling
|
|
409
|
+
* unclosed `<think>` to the end of the text. Reasoning models served through
|
|
410
|
+
* OpenAI-compatible endpoints (MiniMax M3, DeepSeek R1, Qwen QVQ, …) inline
|
|
411
|
+
* these blocks in `message.content`; leaking them into the prompt box both
|
|
412
|
+
* pollutes the prompt and can push it past image models' length limits. */
|
|
413
|
+
function stripReasoning(text) {
|
|
414
|
+
const withoutClosed = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
|
|
415
|
+
const dangling = /<think>/i.exec(withoutClosed);
|
|
416
|
+
return (dangling === null ? withoutClosed : withoutClosed.slice(0, dangling.index)).trim();
|
|
417
|
+
}
|
|
384
418
|
/** Expand a concise image request into a production-ready image prompt. */
|
|
385
419
|
async function enhancePrompt(config, prompt) {
|
|
386
420
|
if (config.apiUrl.trim() === "" || config.model.trim() === "") throw new Error("prompt enhancement model is not configured");
|
|
@@ -402,7 +436,9 @@ async function enhancePrompt(config, prompt) {
|
|
|
402
436
|
const choices = Array.isArray(body.choices) ? body.choices : [];
|
|
403
437
|
const content = choices[0] !== null && typeof choices[0] === "object" ? choices[0].message?.content : void 0;
|
|
404
438
|
if (typeof content !== "string" || content.trim() === "") throw new Error("chat model returned an empty prompt");
|
|
405
|
-
|
|
439
|
+
const enhanced = stripReasoning(content);
|
|
440
|
+
if (enhanced === "") throw new Error("chat model returned only reasoning content (empty <think> payload)");
|
|
441
|
+
return enhanced;
|
|
406
442
|
}
|
|
407
443
|
//#endregion
|
|
408
444
|
//#region src/image-models.ts
|
|
@@ -505,6 +541,28 @@ function isZhipuImage(model) {
|
|
|
505
541
|
function isQwenImage(model) {
|
|
506
542
|
return modelFamily(model) === "qwen";
|
|
507
543
|
}
|
|
544
|
+
/** Whether the model is MiniMax image-01, which speaks MiniMax's native
|
|
545
|
+
* `/image_generation` contract (NOT OpenAI-compatible): `aspect_ratio`,
|
|
546
|
+
* `subject_reference` for image-to-image, `data.image_base64[]` results, and
|
|
547
|
+
* errors reported as HTTP 200 + non-zero `base_resp.status_code`. */
|
|
548
|
+
function isMiniMaxImage(model) {
|
|
549
|
+
return modelFamily(model) === "minimax";
|
|
550
|
+
}
|
|
551
|
+
/** Aspect ratios MiniMax image-01 documents (the panel vocabulary is a superset). */
|
|
552
|
+
const MINIMAX_RATIOS = /* @__PURE__ */ new Set([
|
|
553
|
+
"1:1",
|
|
554
|
+
"16:9",
|
|
555
|
+
"4:3",
|
|
556
|
+
"3:2",
|
|
557
|
+
"2:3",
|
|
558
|
+
"3:4",
|
|
559
|
+
"9:16",
|
|
560
|
+
"21:9"
|
|
561
|
+
]);
|
|
562
|
+
/** MiniMax caps one request at 9 images. */
|
|
563
|
+
const MINIMAX_MAX_N = 9;
|
|
564
|
+
/** MiniMax image-01 rejects prompts of 1500+ characters; the exact number
|
|
565
|
+
* lives in model-catalog.ts so the panel counter and this guard agree. */
|
|
508
566
|
function isGlmImage(model) {
|
|
509
567
|
return /^glm-image(?:-|$)/i.test(model.trim());
|
|
510
568
|
}
|
|
@@ -634,6 +692,19 @@ function isPresignedUrl(value) {
|
|
|
634
692
|
if (params.has("x-amz-signature") || params.has("x-amz-credential")) return true;
|
|
635
693
|
return params.has("signature") && (params.has("expires") || params.has("googleaccessid") || params.has("awsaccesskeyid"));
|
|
636
694
|
}
|
|
695
|
+
/**
|
|
696
|
+
* Whether a result URL lives on the same origin as the configured API base.
|
|
697
|
+
* The upstream Bearer key is only ever forwarded to this origin: a provider
|
|
698
|
+
* (or a compromised relay) that hands back an image URL on a foreign host
|
|
699
|
+
* must not be able to harvest the key through that download.
|
|
700
|
+
*/
|
|
701
|
+
function isSameOriginAsApi(value, apiUrl) {
|
|
702
|
+
try {
|
|
703
|
+
return new URL(value).origin === new URL(apiUrl).origin;
|
|
704
|
+
} catch {
|
|
705
|
+
return false;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
637
708
|
/** Clamp the requested image count into the API-accepted range. */
|
|
638
709
|
function clampCount(n) {
|
|
639
710
|
if (!Number.isFinite(n)) return 1;
|
|
@@ -713,8 +784,9 @@ async function normalizeItem(item, upstream, signal) {
|
|
|
713
784
|
try {
|
|
714
785
|
let response;
|
|
715
786
|
try {
|
|
787
|
+
const forwardKey = upstream.apiKey !== "" && !isPresignedUrl(url) && isSameOriginAsApi(url, upstream.apiUrl);
|
|
716
788
|
response = await fetch(url, {
|
|
717
|
-
...
|
|
789
|
+
...forwardKey ? { headers: { authorization: `Bearer ${upstream.apiKey}` } } : {},
|
|
718
790
|
signal: budget.signal
|
|
719
791
|
});
|
|
720
792
|
} catch (error) {
|
|
@@ -1068,6 +1140,99 @@ async function generateQwenImage(baseUrl, upstream, request, options) {
|
|
|
1068
1140
|
}
|
|
1069
1141
|
}
|
|
1070
1142
|
/**
|
|
1143
|
+
* MiniMax image-01 (native `/image_generation`): one JSON request that batches
|
|
1144
|
+
* up to 9 images and returns them inline as base64. Image-to-image rides the
|
|
1145
|
+
* `subject_reference` array (a character reference, data URL accepted). The
|
|
1146
|
+
* endpoint answers HTTP 200 even on failure, so `base_resp.status_code` is the
|
|
1147
|
+
* real verdict.
|
|
1148
|
+
*/
|
|
1149
|
+
async function generateMiniMaxImage(baseUrl, upstream, request, options) {
|
|
1150
|
+
const model = wireModel(request);
|
|
1151
|
+
const promptLimit = promptCharLimit(model);
|
|
1152
|
+
if (promptLimit !== null && request.prompt.length >= promptLimit) throw new ImageGenError(`MiniMax image-01 要求提示词少于 ${promptLimit} 字符(当前 ${request.prompt.length}),请精简后重试`, "prompt-too-long");
|
|
1153
|
+
const body = {
|
|
1154
|
+
model,
|
|
1155
|
+
prompt: request.prompt,
|
|
1156
|
+
response_format: "base64"
|
|
1157
|
+
};
|
|
1158
|
+
const ratio = request.size.trim();
|
|
1159
|
+
if (ratio !== "" && ratio !== "auto") {
|
|
1160
|
+
if (!MINIMAX_RATIOS.has(ratio)) throw new ImageGenError(`MiniMax image-01 不支持 ${ratio} 宽高比,可选:${Array.from(MINIMAX_RATIOS).join(" / ")}`, "size-unsupported");
|
|
1161
|
+
body.aspect_ratio = ratio;
|
|
1162
|
+
}
|
|
1163
|
+
const count = Math.min(MINIMAX_MAX_N, clampCount(request.n));
|
|
1164
|
+
if (count > 1) body.n = count;
|
|
1165
|
+
if (request.mode === "edit") {
|
|
1166
|
+
if (typeof request.image !== "string" || request.image === "") throw new ImageGenError("图生图需要上传参考图片", "edit-image-missing");
|
|
1167
|
+
const parsed = parseDataUrl(request.image);
|
|
1168
|
+
if (parsed === void 0) throw new ImageGenError("参考图片格式无效", "edit-image-invalid");
|
|
1169
|
+
if (Buffer.from(parsed.base64, "base64").byteLength > MAX_EDIT_IMAGE_BYTES) throw new ImageGenError("参考图片超过 10MB 上限", "edit-image-too-large");
|
|
1170
|
+
body.subject_reference = [{
|
|
1171
|
+
type: "character",
|
|
1172
|
+
image_file: request.image
|
|
1173
|
+
}];
|
|
1174
|
+
}
|
|
1175
|
+
const budget = requestSignal(options.signal, UPSTREAM_TIMEOUT_MS);
|
|
1176
|
+
try {
|
|
1177
|
+
let response;
|
|
1178
|
+
try {
|
|
1179
|
+
response = await fetch(`${baseUrl}/image_generation`, {
|
|
1180
|
+
method: "POST",
|
|
1181
|
+
headers: {
|
|
1182
|
+
authorization: `Bearer ${upstream.apiKey.trim()}`,
|
|
1183
|
+
"content-type": "application/json"
|
|
1184
|
+
},
|
|
1185
|
+
body: JSON.stringify(body),
|
|
1186
|
+
signal: budget.signal
|
|
1187
|
+
});
|
|
1188
|
+
} catch (error) {
|
|
1189
|
+
if (isBudgetTimeout(error)) throw new ImageGenError("上游接口响应超时(240 秒)", "upstream-timeout");
|
|
1190
|
+
if (options.signal?.aborted === true) throw new ImageGenError("任务已取消", "cancelled");
|
|
1191
|
+
throw new ImageGenError(`无法连接上游接口:${error instanceof Error ? error.message : String(error)}`, "upstream-unreachable");
|
|
1192
|
+
}
|
|
1193
|
+
let payload;
|
|
1194
|
+
try {
|
|
1195
|
+
payload = await response.json();
|
|
1196
|
+
} catch (error) {
|
|
1197
|
+
if (isBudgetTimeout(error)) throw new ImageGenError("上游接口响应超时(240 秒)", "upstream-timeout");
|
|
1198
|
+
if (options.signal?.aborted === true) throw new ImageGenError("任务已取消", "cancelled");
|
|
1199
|
+
throw new ImageGenError(`上游接口返回了非 JSON 响应(HTTP ${response.status})`, "upstream-invalid");
|
|
1200
|
+
}
|
|
1201
|
+
if (payload === null || typeof payload !== "object") throw new ImageGenError(upstreamMessage(payload, response.status), "upstream-rejected");
|
|
1202
|
+
const record = payload;
|
|
1203
|
+
const baseResp = record.base_resp;
|
|
1204
|
+
if (baseResp !== null && typeof baseResp === "object") {
|
|
1205
|
+
const status = baseResp.status_code;
|
|
1206
|
+
if (typeof status === "number" && status !== 0) {
|
|
1207
|
+
const msg = baseResp.status_msg;
|
|
1208
|
+
throw new ImageGenError(`MiniMax 拒绝请求(${status}):${typeof msg === "string" && msg !== "" ? msg : "unknown error"}`, status === 1004 || status === 2049 ? "upstream-unauthorized" : "upstream-rejected");
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
if (!response.ok) throw new ImageGenError(upstreamMessage(payload, response.status), "upstream-rejected");
|
|
1212
|
+
const data = record.data;
|
|
1213
|
+
const b64s = data !== null && typeof data === "object" && Array.isArray(data.image_base64) ? data.image_base64.filter((item) => typeof item === "string" && item.trim() !== "") : [];
|
|
1214
|
+
const urls = data !== null && typeof data === "object" && Array.isArray(data.image_urls) ? data.image_urls.filter((item) => typeof item === "string" && item !== "") : [];
|
|
1215
|
+
if (b64s.length === 0 && urls.length === 0) throw new ImageGenError("上游响应缺少图片内容", "upstream-empty");
|
|
1216
|
+
const images = b64s.map((raw) => {
|
|
1217
|
+
const b64 = bareBase64(raw);
|
|
1218
|
+
return {
|
|
1219
|
+
b64,
|
|
1220
|
+
mime: detectImageMime(Buffer.from(b64, "base64")) ?? "image/jpeg"
|
|
1221
|
+
};
|
|
1222
|
+
});
|
|
1223
|
+
for (const url of urls) {
|
|
1224
|
+
const normalized = await normalizeItem({ url }, upstream, options.signal);
|
|
1225
|
+
images.push({
|
|
1226
|
+
b64: normalized.b64,
|
|
1227
|
+
mime: normalized.mime
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
return { images };
|
|
1231
|
+
} finally {
|
|
1232
|
+
budget.dispose();
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1071
1236
|
* Forward one generate request to the configured endpoint. The requested image
|
|
1072
1237
|
* count is satisfied with N parallel single-image requests (the `n` batch
|
|
1073
1238
|
* parameter is never sent, because Responses-API-based gateways reject it as
|
|
@@ -1078,6 +1243,7 @@ async function generateImage(upstream, request, options = {}) {
|
|
|
1078
1243
|
if (baseUrl === "") throw new ImageGenError("api_url 未配置:请先在「设置 → 插件 → 可配置」中填写", "config-missing");
|
|
1079
1244
|
if (upstream.apiKey.trim() === "") throw new ImageGenError("api_key 未配置:请先在「设置 → 插件 → 可配置」中填写", "config-missing");
|
|
1080
1245
|
if (isQwenImage(wireModel(request))) return generateQwenImage(baseUrl, upstream, request, options);
|
|
1246
|
+
if (isMiniMaxImage(wireModel(request))) return generateMiniMaxImage(baseUrl, upstream, request, options);
|
|
1081
1247
|
if (request.mode === "edit" && isZhipuImage(wireModel(request))) throw new ImageGenError("智谱 GLM-Image 当前仅支持文生图,请切换到文生图模式或选择支持图生图的模型", "edit-unsupported");
|
|
1082
1248
|
const params = effectiveParams(request);
|
|
1083
1249
|
const count = effectiveCount(request);
|
|
@@ -2795,6 +2961,16 @@ const IMAGE_PRESETS = [
|
|
|
2795
2961
|
}
|
|
2796
2962
|
]
|
|
2797
2963
|
},
|
|
2964
|
+
{
|
|
2965
|
+
id: "minimax-official",
|
|
2966
|
+
name: "MiniMax 官方(国际站)",
|
|
2967
|
+
apiUrl: "https://api.minimax.io/v1",
|
|
2968
|
+
hint: "MiniMax 原生 /image_generation 接口:image-01(国内站请把地址改为 https://api.minimaxi.com/v1;/models 不列出图片模型,请直接使用预填目录)",
|
|
2969
|
+
models: [{
|
|
2970
|
+
alias: "image-01",
|
|
2971
|
+
id: "image-01"
|
|
2972
|
+
}]
|
|
2973
|
+
},
|
|
2798
2974
|
{
|
|
2799
2975
|
id: "xai-grok",
|
|
2800
2976
|
name: "xAI(Grok)",
|
|
@@ -5024,7 +5200,7 @@ const DEFAULT_ALLOW_AGENT_IMAGE_GENERATION = true;
|
|
|
5024
5200
|
/** Order of the announcement section within the tool-guidance band. */
|
|
5025
5201
|
const SECTION_ORDER = 150;
|
|
5026
5202
|
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
5027
|
-
const IMAGEGEN_GUIDANCE = "本机已安装 dsh-imagegen 插件(DSH AI 生图):侧边栏「AI 生图」入口。能力:通过「渠道」对接 OpenAI 兼容图像生成 API(每个渠道 = 一个 API 端点 + 各自的模型目录),支持文生图(/images/generations)与图生图(/images/edits,上传参考图,grok-imagine 模型按官方 JSON image_url 协议发送,nanobanana 系列按 aspect_ratio / image_size 参数协议发送;seedream 系列统一走 /images/generations,参考图以 JSON image 数组发送;智谱 `glm-image` 使用官方 `/api/paas/v4/images/generations`,当前仅支持文生图;qwen-image 系列使用阿里云 DashScope 原生接口(api_url 填 https://dashscope.aliyuncs.com/api/v1,不支持 OpenAI 兼容模式,该渠道不可复用于提示词增强,尺寸自动映射为宽*高)。API 地址与密钥在 GUI 设置中按渠道配置,密钥仅存于本机设置文档;生成请求由本地宿主代理转发,结果以 base64 返回面板,可预览与下载。模型只能使用用户在各渠道配置目录中的模型;检测模型时会过滤聊天、Embedding 等非图片模型,但模型出现在 /models 中仍不等于其网关原生支持生图协议,遇到 Qwen、Gemini 等非 OpenAI 生图协议时应如实说明上游兼容性。可一键把满意的图片加入「画廊」。内置「提示词模板库」(面板提示词框左下角「模板库」按钮):多来源标签页(精选案例库 / 沧河案例库,后续可扩展),打包 awesome-gpt-image-2 的数百条提示词案例,可搜索、筛选、收藏(星标,宿主持久化)与复用;各来源列表独立刷新,宿主每 12 小时后台自动同步一次。Agent 可直接调用 `generate_image` 提交文生图,也可用 `edit_image` 图生图;默认保持工具调用等待直到任务完成,完成图片显示在工具调用对应的左侧结果区域,模型收到状态和附件引用,不会额外伪造用户消息。用户也可以使用 `/edit_image <修改描述>`,命令会直接读取当前对话最近图片并调用插件图片模型,不经过对话模型的图片能力检查。若明确需要后台执行,可传 `wait_for_completion: false`,之后再用 `get_image_generation_task` 查询;不要反复轮询。限制:生成消耗上游 API 额度;图片内容由上游模型生成,可能不符合预期或包含不适宜内容;api_key 以明文存储在设置文档中;参考图会发送至所配置的 API 服务;模板库在线刷新与参考图首次加载需要访问对应来源站点(vibeui.top / gpt-image2.canghe.ai)。用户提到「生图 / 绘画 / 生成图片 / 文生图 / 图生图 / 画廊 / 提示词模板」时即指本插件,请据此协作。";
|
|
5203
|
+
const IMAGEGEN_GUIDANCE = "本机已安装 dsh-imagegen 插件(DSH AI 生图):侧边栏「AI 生图」入口。能力:通过「渠道」对接 OpenAI 兼容图像生成 API(每个渠道 = 一个 API 端点 + 各自的模型目录),支持文生图(/images/generations)与图生图(/images/edits,上传参考图,grok-imagine 模型按官方 JSON image_url 协议发送,nanobanana 系列按 aspect_ratio / image_size 参数协议发送;seedream 系列统一走 /images/generations,参考图以 JSON image 数组发送;智谱 `glm-image` 使用官方 `/api/paas/v4/images/generations`,当前仅支持文生图;qwen-image 系列使用阿里云 DashScope 原生接口(api_url 填 https://dashscope.aliyuncs.com/api/v1,不支持 OpenAI 兼容模式,该渠道不可复用于提示词增强,尺寸自动映射为宽*高)。MiniMax `image-01` 使用 MiniMax 原生 `/image_generation` 接口(api_url 填 https://api.minimax.io/v1 或国内站 https://api.minimaxi.com/v1,支持 1:1/16:9/4:3/3:2/2:3/3:4/9:16/21:9 宽高比,一次最多 9 张;图生图为单张 subject_reference 主体参考(保持人物/主体一致,非像素级局部编辑);其 /models 只列聊天模型,图片模型需用预设目录)。API 地址与密钥在 GUI 设置中按渠道配置,密钥仅存于本机设置文档;生成请求由本地宿主代理转发,结果以 base64 返回面板,可预览与下载。模型只能使用用户在各渠道配置目录中的模型;检测模型时会过滤聊天、Embedding 等非图片模型,但模型出现在 /models 中仍不等于其网关原生支持生图协议,遇到 Qwen、MiniMax、Gemini 等非 OpenAI 生图协议时应如实说明上游兼容性。可一键把满意的图片加入「画廊」。内置「提示词模板库」(面板提示词框左下角「模板库」按钮):多来源标签页(精选案例库 / 沧河案例库,后续可扩展),打包 awesome-gpt-image-2 的数百条提示词案例,可搜索、筛选、收藏(星标,宿主持久化)与复用;各来源列表独立刷新,宿主每 12 小时后台自动同步一次。Agent 可直接调用 `generate_image` 提交文生图,也可用 `edit_image` 图生图;默认保持工具调用等待直到任务完成,完成图片显示在工具调用对应的左侧结果区域,模型收到状态和附件引用,不会额外伪造用户消息。用户也可以使用 `/edit_image <修改描述>`,命令会直接读取当前对话最近图片并调用插件图片模型,不经过对话模型的图片能力检查。若明确需要后台执行,可传 `wait_for_completion: false`,之后再用 `get_image_generation_task` 查询;不要反复轮询。限制:生成消耗上游 API 额度;图片内容由上游模型生成,可能不符合预期或包含不适宜内容;api_key 以明文存储在设置文档中;参考图会发送至所配置的 API 服务;模板库在线刷新与参考图首次加载需要访问对应来源站点(vibeui.top / gpt-image2.canghe.ai)。用户提到「生图 / 绘画 / 生成图片 / 文生图 / 图生图 / 画廊 / 提示词模板」时即指本插件,请据此协作。";
|
|
5028
5204
|
/** Append the live channel × model table so an Agent can honor user choices. */
|
|
5029
5205
|
function guidanceFor(channels, defaultChannelId) {
|
|
5030
5206
|
if (channels.length === 0) return `${IMAGEGEN_GUIDANCE} 尚未配置任何渠道:请先在「设置 → 插件 → AI 生图」添加渠道并填写 API 地址与密钥。`;
|
|
@@ -5247,4 +5423,4 @@ function apply(ctx, config) {
|
|
|
5247
5423
|
};
|
|
5248
5424
|
}
|
|
5249
5425
|
//#endregion
|
|
5250
|
-
export { CURRENT_VERSION, Config, IMAGEGEN_GUIDANCE, ImageGenError, ImageGenSettingsNamespace, ImageGenerationRuntime, addTemplateFavorite, appendGallery, apply, checkForUpdate, clearGallery, clearTemplateFavoritesMemo, clearTemplateMemo, clearUpdateCache, compareVersions, generateImage, inject, installUpdate, latestSessionImage, listGallery, listTemplateFavorites, listTemplates, makeRoutes, name, profileFromProcess, putObject, readGalleryImage, readTemplateImage, refreshTemplates, registerAgentImageTools, registerEditImageCommand, removeGallery, removeTemplateFavorite, sampleTemplates, setStorageSyncHandler, syncAllTemplates, testStorage, updateGalleryTags };
|
|
5426
|
+
export { CURRENT_VERSION, Config, IMAGEGEN_GUIDANCE, ImageGenError, ImageGenSettingsNamespace, ImageGenerationRuntime, addTemplateFavorite, appendGallery, apply, checkForUpdate, clearGallery, clearTemplateFavoritesMemo, clearTemplateMemo, clearUpdateCache, compareVersions, generateImage, inject, installUpdate, latestSessionImage, listGallery, listTemplateFavorites, listTemplates, makeRoutes, name, profileFromProcess, promptCharLimit, putObject, readGalleryImage, readTemplateImage, refreshTemplates, registerAgentImageTools, registerEditImageCommand, removeGallery, removeTemplateFavorite, sampleTemplates, setStorageSyncHandler, syncAllTemplates, testStorage, updateGalleryTags };
|
package/package.json
CHANGED
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@dickpy/dsh-imagegen",
|
|
3
|
-
"description": "AI image generation plugin for the dsh web GUI: text-to-image and image-to-image through configurable provider channels (gpt-image-2 / grok-imagine-image / nanobanana series / seedream-5.0-pro / dall-e-3, with native xAI Grok Imagine, Google Nano Banana and ByteDance Seedream request shaping), with per-channel model catalogs and a New Session / Image Generation tab entry opening a three-column studio beside the native conversation.",
|
|
4
|
-
"version": "1.5.
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "lib/index.js",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./lib/index.js",
|
|
9
|
-
"./client": "./lib/client.js",
|
|
10
|
-
"./package.json": "./package.json"
|
|
11
|
-
},
|
|
12
|
-
"dsh": {
|
|
13
|
-
"bundle": {
|
|
14
|
-
"patch": "./cordis.patch.yml"
|
|
15
|
-
},
|
|
16
|
-
"client": {
|
|
17
|
-
"inject": [
|
|
18
|
-
"@deepseek-ai/dsh-client-store",
|
|
19
|
-
"@deepseek-ai/dsh-api-remotes",
|
|
20
|
-
"@deepseek-ai/dsh-api-session-controller",
|
|
21
|
-
"@deepseek-ai/dsh-client-connection",
|
|
22
|
-
"@deepseek-ai/dsh-client-ui-conversation",
|
|
23
|
-
"@deepseek-ai/dsh-client-ui-renderer",
|
|
24
|
-
"@deepseek-ai/dsh-client-ui-settings",
|
|
25
|
-
"@deepseek-ai/dsh-client-ui-tool"
|
|
26
|
-
],
|
|
27
|
-
"platform": "web"
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"schemastery": "^3.18.0"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@deepseek-ai/cordis": "^4.0.2",
|
|
35
|
-
"@deepseek-ai/dsh-api-remotes": "0.1.2-alpha.2",
|
|
36
|
-
"@deepseek-ai/dsh-api-session-controller": "0.1.2-alpha.2",
|
|
37
|
-
"@deepseek-ai/dsh-attachment": "0.1.2-alpha.2",
|
|
38
|
-
"@deepseek-ai/dsh-client-connection": "0.1.2-alpha.2",
|
|
39
|
-
"@deepseek-ai/dsh-client-locale": "0.1.2-alpha.2",
|
|
40
|
-
"@deepseek-ai/dsh-client-store": "0.1.2-alpha.2",
|
|
41
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1.2-alpha.2",
|
|
42
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-alpha.2",
|
|
43
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.1.2-alpha.2",
|
|
44
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.1.2-alpha.2",
|
|
45
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-alpha.2",
|
|
46
|
-
"@deepseek-ai/dsh-commands": "0.1.2-alpha.2",
|
|
47
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.2-alpha.2",
|
|
48
|
-
"@deepseek-ai/dsh-llm": "0.1.2-alpha.2",
|
|
49
|
-
"@deepseek-ai/dsh-settings": "0.1.2-alpha.2",
|
|
50
|
-
"@deepseek-ai/dsh-system-prompt": "0.1.2-alpha.2",
|
|
51
|
-
"@deepseek-ai/dsh-tools": "0.1.2-alpha.2",
|
|
52
|
-
"@types/node": "^22.20.0",
|
|
53
|
-
"@types/react": "~18.3.1",
|
|
54
|
-
"@types/react-dom": "^18.3.5",
|
|
55
|
-
"jsdom": "25.0.1",
|
|
56
|
-
"lightningcss": "1.32.0",
|
|
57
|
-
"react": "^18.3.1",
|
|
58
|
-
"react-dom": "^18.3.1",
|
|
59
|
-
"schemastery": "^3.18.0",
|
|
60
|
-
"tsdown": "0.22.2",
|
|
61
|
-
"typescript": "~5.7.2"
|
|
62
|
-
},
|
|
63
|
-
"files": [
|
|
64
|
-
"lib",
|
|
65
|
-
"src",
|
|
66
|
-
"cordis.patch.yml",
|
|
67
|
-
"docs",
|
|
68
|
-
"README.md"
|
|
69
|
-
],
|
|
70
|
-
"license": "Apache-2.0",
|
|
71
|
-
"repository": {
|
|
72
|
-
"type": "git",
|
|
73
|
-
"url": "git+https://github.com/dickpy/dsh-imagegen.git"
|
|
74
|
-
},
|
|
75
|
-
"scripts": {
|
|
76
|
-
"build": "tsdown",
|
|
77
|
-
"watch": "tsdown --watch",
|
|
78
|
-
"typecheck": "tsc --noEmit",
|
|
79
|
-
"fetch-templates": "node scripts/fetch-templates.mjs"
|
|
80
|
-
}
|
|
81
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@dickpy/dsh-imagegen",
|
|
3
|
+
"description": "AI image generation plugin for the dsh web GUI: text-to-image and image-to-image through configurable provider channels (gpt-image-2 / grok-imagine-image / nanobanana series / seedream-5.0-pro / dall-e-3, with native xAI Grok Imagine, Google Nano Banana and ByteDance Seedream request shaping), with per-channel model catalogs and a New Session / Image Generation tab entry opening a three-column studio beside the native conversation.",
|
|
4
|
+
"version": "1.5.7",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./lib/index.js",
|
|
9
|
+
"./client": "./lib/client.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"dsh": {
|
|
13
|
+
"bundle": {
|
|
14
|
+
"patch": "./cordis.patch.yml"
|
|
15
|
+
},
|
|
16
|
+
"client": {
|
|
17
|
+
"inject": [
|
|
18
|
+
"@deepseek-ai/dsh-client-store",
|
|
19
|
+
"@deepseek-ai/dsh-api-remotes",
|
|
20
|
+
"@deepseek-ai/dsh-api-session-controller",
|
|
21
|
+
"@deepseek-ai/dsh-client-connection",
|
|
22
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
23
|
+
"@deepseek-ai/dsh-client-ui-renderer",
|
|
24
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
25
|
+
"@deepseek-ai/dsh-client-ui-tool"
|
|
26
|
+
],
|
|
27
|
+
"platform": "web"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"schemastery": "^3.18.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
35
|
+
"@deepseek-ai/dsh-api-remotes": "0.1.2-alpha.2",
|
|
36
|
+
"@deepseek-ai/dsh-api-session-controller": "0.1.2-alpha.2",
|
|
37
|
+
"@deepseek-ai/dsh-attachment": "0.1.2-alpha.2",
|
|
38
|
+
"@deepseek-ai/dsh-client-connection": "0.1.2-alpha.2",
|
|
39
|
+
"@deepseek-ai/dsh-client-locale": "0.1.2-alpha.2",
|
|
40
|
+
"@deepseek-ai/dsh-client-store": "0.1.2-alpha.2",
|
|
41
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.2-alpha.2",
|
|
42
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-alpha.2",
|
|
43
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.2-alpha.2",
|
|
44
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.2-alpha.2",
|
|
45
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-alpha.2",
|
|
46
|
+
"@deepseek-ai/dsh-commands": "0.1.2-alpha.2",
|
|
47
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.2-alpha.2",
|
|
48
|
+
"@deepseek-ai/dsh-llm": "0.1.2-alpha.2",
|
|
49
|
+
"@deepseek-ai/dsh-settings": "0.1.2-alpha.2",
|
|
50
|
+
"@deepseek-ai/dsh-system-prompt": "0.1.2-alpha.2",
|
|
51
|
+
"@deepseek-ai/dsh-tools": "0.1.2-alpha.2",
|
|
52
|
+
"@types/node": "^22.20.0",
|
|
53
|
+
"@types/react": "~18.3.1",
|
|
54
|
+
"@types/react-dom": "^18.3.5",
|
|
55
|
+
"jsdom": "25.0.1",
|
|
56
|
+
"lightningcss": "1.32.0",
|
|
57
|
+
"react": "^18.3.1",
|
|
58
|
+
"react-dom": "^18.3.1",
|
|
59
|
+
"schemastery": "^3.18.0",
|
|
60
|
+
"tsdown": "0.22.2",
|
|
61
|
+
"typescript": "~5.7.2"
|
|
62
|
+
},
|
|
63
|
+
"files": [
|
|
64
|
+
"lib",
|
|
65
|
+
"src",
|
|
66
|
+
"cordis.patch.yml",
|
|
67
|
+
"docs",
|
|
68
|
+
"README.md"
|
|
69
|
+
],
|
|
70
|
+
"license": "Apache-2.0",
|
|
71
|
+
"repository": {
|
|
72
|
+
"type": "git",
|
|
73
|
+
"url": "git+https://github.com/dickpy/dsh-imagegen.git"
|
|
74
|
+
},
|
|
75
|
+
"scripts": {
|
|
76
|
+
"build": "tsdown",
|
|
77
|
+
"watch": "tsdown --watch",
|
|
78
|
+
"typecheck": "tsc --noEmit",
|
|
79
|
+
"fetch-templates": "node scripts/fetch-templates.mjs"
|
|
80
|
+
}
|
|
81
|
+
}
|