dsh-image-gen 0.9.1 → 0.9.3
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.en.md +454 -442
- package/README.md +454 -442
- package/lib/client.js +349 -46
- package/lib/index.js +323 -165
- package/lib/types/client/index.d.ts +3 -1
- package/lib/types/client/studio-style.d.ts +1 -1
- package/lib/types/client/tl/conversation-landings.d.ts +16 -1
- package/lib/types/client/tl/gallery-canvas-button.d.ts +10 -0
- package/lib/types/client/tl/gallery-image-transfer.d.ts +12 -0
- package/lib/types/client/tl/studio-tl-canvas.d.ts +3 -0
- package/lib/types/client/tl/tl-canvas-bridge.d.ts +6 -0
- package/lib/types/config.d.ts +7 -2
- package/lib/types/google.d.ts +4 -1
- package/lib/types/image-tool-context.d.ts +3 -0
- package/lib/types/openai-compatible.d.ts +1 -1
- package/lib/types/shared.d.ts +4 -0
- package/package.json +139 -139
- package/skills/install-dsh-image-gen/SKILL.md +22 -22
package/lib/client.js
CHANGED
|
@@ -75,7 +75,7 @@ window.__ModuleLoader__.load({
|
|
|
75
75
|
//#region lib/types/watermark.js
|
|
76
76
|
/** Model names alone do not establish the protocol of an unknown relay. */
|
|
77
77
|
function officialContract(config, mode) {
|
|
78
|
-
const model = (mode === "generate" ? config.openaiCompatExtraBody : config.openaiCompatEditExtra)?.model ?? config.openaiCompatModel;
|
|
78
|
+
const model = (mode === "generate" ? config.openaiCompatExtraBody : config.openaiCompatEditExtra)?.model ?? (mode === "edit" ? config.openaiCompatEditModel?.trim() || config.openaiCompatModel : config.openaiCompatModel);
|
|
79
79
|
if (typeof model !== "string") return void 0;
|
|
80
80
|
try {
|
|
81
81
|
const url = new URL(config.openaiCompatBaseURL ?? "");
|
|
@@ -87,6 +87,10 @@ window.__ModuleLoader__.load({
|
|
|
87
87
|
}
|
|
88
88
|
/** Known official edit contracts take precedence over relay-specific format settings. */
|
|
89
89
|
function compatEditFormat(config) {
|
|
90
|
+
try {
|
|
91
|
+
const url = new URL(config.openaiCompatBaseURL ?? "");
|
|
92
|
+
if (url.protocol === "https:" && !url.port && !url.search && !url.hash && (url.hostname === "api.siliconflow.cn" || url.hostname === "api.siliconflow.com") && url.pathname.replace(/\/+$/, "") === "/v1") return "siliconflowJson";
|
|
93
|
+
} catch {}
|
|
90
94
|
const contract = officialContract(config, "edit");
|
|
91
95
|
if (contract === "sensenova") return "jsonImageUrlArray";
|
|
92
96
|
if (contract === "qwen") return "qwenJson";
|
|
@@ -181,6 +185,10 @@ window.__ModuleLoader__.load({
|
|
|
181
185
|
"off",
|
|
182
186
|
"on"
|
|
183
187
|
];
|
|
188
|
+
/** A model picker/request must use the same operation-specific default. */
|
|
189
|
+
function studioModelForMode(profile, mode) {
|
|
190
|
+
return mode === "edit" ? profile.editModel ?? profile.model : profile.model;
|
|
191
|
+
}
|
|
184
192
|
function studioWatermarkCapability(profile, mode) {
|
|
185
193
|
return profile?.watermarkCapabilities?.[mode] ?? (mode === "generate" && profile?.watermarkOptions?.length ? { status: "supported" } : {
|
|
186
194
|
status: "unknown",
|
|
@@ -337,7 +345,7 @@ window.__ModuleLoader__.load({
|
|
|
337
345
|
}
|
|
338
346
|
if (!isRecord(value) || Object.keys(value).length === 0) throw new Error("ComfyUI workflow must be a non-empty API-format JSON object");
|
|
339
347
|
if (!Object.values(value).some((node) => {
|
|
340
|
-
const inputs = record$
|
|
348
|
+
const inputs = record$2(node)?.inputs;
|
|
341
349
|
return inputs !== void 0 && containsPromptPlaceholder(inputs);
|
|
342
350
|
})) throw new Error(`ComfyUI workflow must contain ${COMFYUI_PROMPT_PLACEHOLDER} (or ${LEGACY_PROMPT_PLACEHOLDER}) in a text input`);
|
|
343
351
|
return value;
|
|
@@ -346,7 +354,7 @@ window.__ModuleLoader__.load({
|
|
|
346
354
|
function countImagePlaceholders(workflow) {
|
|
347
355
|
let count = 0;
|
|
348
356
|
for (const node of Object.values(workflow)) {
|
|
349
|
-
const inputs = record$
|
|
357
|
+
const inputs = record$2(record$2(node)?.inputs);
|
|
350
358
|
if (inputs !== void 0 && isImagePlaceholder(inputs[IMAGE_INPUT_KEY])) count += 1;
|
|
351
359
|
}
|
|
352
360
|
return count;
|
|
@@ -362,7 +370,7 @@ window.__ModuleLoader__.load({
|
|
|
362
370
|
function isRecord(value) {
|
|
363
371
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
364
372
|
}
|
|
365
|
-
function record$
|
|
373
|
+
function record$2(value) {
|
|
366
374
|
return isRecord(value) ? value : void 0;
|
|
367
375
|
}
|
|
368
376
|
//#endregion
|
|
@@ -116729,8 +116737,27 @@ img.ProseMirror-separator {
|
|
|
116729
116737
|
//#region lib/types/client/tl/tl-canvas-bridge.js
|
|
116730
116738
|
const pending$1 = /* @__PURE__ */ new Map();
|
|
116731
116739
|
const consumers = /* @__PURE__ */ new Set();
|
|
116740
|
+
const availabilityListeners = /* @__PURE__ */ new Set();
|
|
116732
116741
|
let delivering = false;
|
|
116733
116742
|
let generation = 0;
|
|
116743
|
+
/** History actions must not silently queue into a canvas that is not open. */
|
|
116744
|
+
function hasTlLandingConsumer() {
|
|
116745
|
+
return consumers.size > 0;
|
|
116746
|
+
}
|
|
116747
|
+
function subscribeTlLandingAvailability(listener) {
|
|
116748
|
+
availabilityListeners.add(listener);
|
|
116749
|
+
return () => {
|
|
116750
|
+
availabilityListeners.delete(listener);
|
|
116751
|
+
};
|
|
116752
|
+
}
|
|
116753
|
+
function sendTlLandingToOpenCanvas(item) {
|
|
116754
|
+
if (!hasTlLandingConsumer()) return false;
|
|
116755
|
+
pushTlLandings([{
|
|
116756
|
+
...item,
|
|
116757
|
+
onlyWhileCanvasOpen: true
|
|
116758
|
+
}]);
|
|
116759
|
+
return true;
|
|
116760
|
+
}
|
|
116734
116761
|
/** Invalidates async landings that started before the user cleared the canvas. */
|
|
116735
116762
|
function getTlLandingGeneration() {
|
|
116736
116763
|
return generation;
|
|
@@ -116750,12 +116777,18 @@ img.ProseMirror-separator {
|
|
|
116750
116777
|
}
|
|
116751
116778
|
/** Register a ready editor. False means it unmounted before committing. */
|
|
116752
116779
|
function registerTlLandingConsumer(consumer) {
|
|
116780
|
+
const wasAvailable = hasTlLandingConsumer();
|
|
116753
116781
|
consumers.add(consumer);
|
|
116782
|
+
if (!wasAvailable) for (const listener of availabilityListeners) listener();
|
|
116754
116783
|
deliver();
|
|
116784
|
+
let registered = true;
|
|
116755
116785
|
return () => {
|
|
116786
|
+
if (!registered) return;
|
|
116787
|
+
registered = false;
|
|
116756
116788
|
consumers.delete(consumer);
|
|
116757
116789
|
if (consumers.size === 0) {
|
|
116758
|
-
for (const [id, item] of pending$1) if (item.fromConversation) pending$1.delete(id);
|
|
116790
|
+
for (const [id, item] of pending$1) if (item.fromConversation || item.onlyWhileCanvasOpen) pending$1.delete(id);
|
|
116791
|
+
for (const listener of availabilityListeners) listener();
|
|
116759
116792
|
}
|
|
116760
116793
|
};
|
|
116761
116794
|
}
|
|
@@ -116782,6 +116815,84 @@ img.ProseMirror-separator {
|
|
|
116782
116815
|
}
|
|
116783
116816
|
}
|
|
116784
116817
|
//#endregion
|
|
116818
|
+
//#region lib/types/client/tl/gallery-image-transfer.js
|
|
116819
|
+
const GALLERY_IMAGE_MIME = "application/x-dsh-image-gen-gallery-image";
|
|
116820
|
+
const EXTENSIONS = /* @__PURE__ */ new Map([
|
|
116821
|
+
["image/png", "png"],
|
|
116822
|
+
["image/jpeg", "jpg"],
|
|
116823
|
+
["image/webp", "webp"],
|
|
116824
|
+
["image/gif", "gif"]
|
|
116825
|
+
]);
|
|
116826
|
+
function galleryLanding(item) {
|
|
116827
|
+
return {
|
|
116828
|
+
galleryId: item.id,
|
|
116829
|
+
attachment: item.attachment,
|
|
116830
|
+
prompt: item.prompt.slice(0, 120),
|
|
116831
|
+
provider: item.provider,
|
|
116832
|
+
model: item.model
|
|
116833
|
+
};
|
|
116834
|
+
}
|
|
116835
|
+
/** A real file also works when the host drops custom MIME data between containers. */
|
|
116836
|
+
function startGalleryImageDrag(event, item, blob) {
|
|
116837
|
+
const transfer = event.dataTransfer;
|
|
116838
|
+
const mediaType = blob?.type || item.attachment.mediaType;
|
|
116839
|
+
const extension = EXTENSIONS.get(mediaType);
|
|
116840
|
+
if (!transfer || !blob?.size || !extension) {
|
|
116841
|
+
event.preventDefault();
|
|
116842
|
+
return false;
|
|
116843
|
+
}
|
|
116844
|
+
try {
|
|
116845
|
+
const name = item.id.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 100) || "image";
|
|
116846
|
+
const file = new File([blob], `${name}.${extension}`, { type: mediaType });
|
|
116847
|
+
transfer.items.clear();
|
|
116848
|
+
if (transfer.items.add(file) === null) throw new Error("Drag file unavailable");
|
|
116849
|
+
transfer.effectAllowed = "copy";
|
|
116850
|
+
try {
|
|
116851
|
+
transfer.setData(GALLERY_IMAGE_MIME, JSON.stringify(galleryLanding(item)));
|
|
116852
|
+
} catch {}
|
|
116853
|
+
return true;
|
|
116854
|
+
} catch {
|
|
116855
|
+
event.preventDefault();
|
|
116856
|
+
return false;
|
|
116857
|
+
}
|
|
116858
|
+
}
|
|
116859
|
+
function readGalleryImageDrop(transfer) {
|
|
116860
|
+
try {
|
|
116861
|
+
const raw = transfer.getData(GALLERY_IMAGE_MIME);
|
|
116862
|
+
if (!raw || raw.length > 64e3) return void 0;
|
|
116863
|
+
const value = JSON.parse(raw);
|
|
116864
|
+
if (!record$1(value) || !text(value.galleryId) || !record$1(value.attachment)) return void 0;
|
|
116865
|
+
const a = value.attachment;
|
|
116866
|
+
if (!text(a.attachmentId) || typeof a.mediaType !== "string" || !EXTENSIONS.has(a.mediaType) || !dimension(a.bytes) || !dimension(a.width) || !dimension(a.height) || a.name !== void 0 && (typeof a.name !== "string" || a.name.length > 1024)) return void 0;
|
|
116867
|
+
if (typeof value.prompt !== "string" || value.prompt.length > 120 || typeof value.provider !== "string" || !text(value.provider) || typeof value.model !== "string" || value.model.length > 1024) return void 0;
|
|
116868
|
+
return {
|
|
116869
|
+
galleryId: value.galleryId,
|
|
116870
|
+
attachment: {
|
|
116871
|
+
attachmentId: a.attachmentId,
|
|
116872
|
+
mediaType: a.mediaType,
|
|
116873
|
+
bytes: a.bytes,
|
|
116874
|
+
width: a.width,
|
|
116875
|
+
height: a.height,
|
|
116876
|
+
...typeof a.name === "string" ? { name: a.name } : {}
|
|
116877
|
+
},
|
|
116878
|
+
prompt: value.prompt,
|
|
116879
|
+
provider: value.provider,
|
|
116880
|
+
model: value.model
|
|
116881
|
+
};
|
|
116882
|
+
} catch {
|
|
116883
|
+
return;
|
|
116884
|
+
}
|
|
116885
|
+
}
|
|
116886
|
+
function record$1(value) {
|
|
116887
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
116888
|
+
}
|
|
116889
|
+
function text(value) {
|
|
116890
|
+
return typeof value === "string" && value.length > 0 && value.length <= 1024;
|
|
116891
|
+
}
|
|
116892
|
+
function dimension(value) {
|
|
116893
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
116894
|
+
}
|
|
116895
|
+
//#endregion
|
|
116785
116896
|
//#region lib/types/client/tl/studio-tl-canvas.js
|
|
116786
116897
|
/**
|
|
116787
116898
|
* Infinite canvas surface for the Studio workbench, backed by tldraw.
|
|
@@ -116850,7 +116961,7 @@ img.ProseMirror-separator {
|
|
|
116850
116961
|
const collapsed = prompt.replace(/\s+/g, " ").trim();
|
|
116851
116962
|
return collapsed.length === 0 ? void 0 : collapsed.slice(0, 120);
|
|
116852
116963
|
}
|
|
116853
|
-
async function landTlItems(editor, items, isActive) {
|
|
116964
|
+
async function landTlItems(editor, items, isActive, onUnreadable) {
|
|
116854
116965
|
const landedIds = landedIdsOf(editor);
|
|
116855
116966
|
const pending = items.filter((item) => !landedIds.has(item.galleryId));
|
|
116856
116967
|
if (pending.length === 0) return true;
|
|
@@ -116879,6 +116990,7 @@ img.ProseMirror-separator {
|
|
|
116879
116990
|
});
|
|
116880
116991
|
} catch (error) {
|
|
116881
116992
|
console.warn("[dsh-image-gen] canvas landing skipped (attachment unreadable):", item.galleryId, error);
|
|
116993
|
+
if (isActive()) onUnreadable?.();
|
|
116882
116994
|
continue;
|
|
116883
116995
|
}
|
|
116884
116996
|
const size = displaySizeOf(item.attachment);
|
|
@@ -116985,9 +117097,12 @@ img.ProseMirror-separator {
|
|
|
116985
117097
|
phase: "idle",
|
|
116986
117098
|
count: 0
|
|
116987
117099
|
});
|
|
117100
|
+
const [landingError, setLandingError] = (0, react.useState)(false);
|
|
116988
117101
|
const retrySync = (0, react.useRef)(() => {});
|
|
117102
|
+
const editorRef = (0, react.useRef)(null);
|
|
116989
117103
|
const onMount = (0, react.useCallback)((editor) => {
|
|
116990
117104
|
let active = true;
|
|
117105
|
+
editorRef.current = editor;
|
|
116991
117106
|
editor.run(() => editor.selectNone());
|
|
116992
117107
|
mountedEditors.add(editor);
|
|
116993
117108
|
applyBrandTheme(editor);
|
|
@@ -116996,11 +117111,13 @@ img.ProseMirror-separator {
|
|
|
116996
117111
|
console.info(`[dsh-image-gen] tldraw mounted (instance ${editor.id})`);
|
|
116997
117112
|
const stopLanding = registerTlLandingConsumer((items) => {
|
|
116998
117113
|
const generation = getTlLandingGeneration();
|
|
116999
|
-
|
|
117114
|
+
setLandingError(false);
|
|
117115
|
+
return landTlItems(editor, items, () => active && generation === getTlLandingGeneration(), () => setLandingError(true));
|
|
117000
117116
|
});
|
|
117001
117117
|
let stopSync = startCanvasSync(editor, setSyncStatus);
|
|
117002
117118
|
retrySync.current = () => stopSync.retry();
|
|
117003
117119
|
const clear = () => {
|
|
117120
|
+
setLandingError(false);
|
|
117004
117121
|
stopSync();
|
|
117005
117122
|
editor.complete();
|
|
117006
117123
|
editor.run(() => {
|
|
@@ -117024,6 +117141,7 @@ img.ProseMirror-separator {
|
|
|
117024
117141
|
mountedCanvases.add(clear);
|
|
117025
117142
|
return () => {
|
|
117026
117143
|
active = false;
|
|
117144
|
+
if (editorRef.current === editor) editorRef.current = null;
|
|
117027
117145
|
mountedEditors.delete(editor);
|
|
117028
117146
|
mountedCanvases.delete(clear);
|
|
117029
117147
|
stopLanding();
|
|
@@ -117035,17 +117153,30 @@ img.ProseMirror-separator {
|
|
|
117035
117153
|
const statusText = lang === "en" ? syncStatus.phase === "ready" ? `Selection ready · ${syncStatus.count} shapes` : syncStatus.phase === "preparing" ? `Preparing selection · ${syncStatus.count} shapes…` : "Selection sync failed" : syncStatus.phase === "ready" ? `选区已就绪 · ${syncStatus.count} 个元素` : syncStatus.phase === "preparing" ? `正在准备选区 · ${syncStatus.count} 个元素…` : "选区同步失败";
|
|
117036
117154
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
117037
117155
|
className: "dsh-ig-tl-canvas",
|
|
117156
|
+
onDropCapture: (event) => {
|
|
117157
|
+
const item = readGalleryImageDrop(event.dataTransfer);
|
|
117158
|
+
const editor = editorRef.current;
|
|
117159
|
+
if (!item || !editor) return;
|
|
117160
|
+
event.preventDefault();
|
|
117161
|
+
event.stopPropagation();
|
|
117162
|
+
setLandingError(false);
|
|
117163
|
+
const generation = getTlLandingGeneration();
|
|
117164
|
+
landTlItems(editor, [item], () => editorRef.current === editor && generation === getTlLandingGeneration(), () => setLandingError(true)).catch((error) => {
|
|
117165
|
+
if (editorRef.current === editor) setLandingError(true);
|
|
117166
|
+
console.warn("[dsh-image-gen] history image drop failed:", error);
|
|
117167
|
+
});
|
|
117168
|
+
},
|
|
117038
117169
|
children: [(0, react_jsx_runtime.jsx)(Tldraw, {
|
|
117039
117170
|
persistenceKey: "dsh-image-gen-workbench-v1",
|
|
117040
117171
|
sessionId,
|
|
117041
117172
|
components: TL_COMPONENTS,
|
|
117042
117173
|
onMount
|
|
117043
|
-
}), syncStatus.phase !== "idle" && (0, react_jsx_runtime.jsxs)("div", {
|
|
117174
|
+
}), (landingError || syncStatus.phase !== "idle") && (0, react_jsx_runtime.jsxs)("div", {
|
|
117044
117175
|
className: "dsh-ig-canvas-sync-status",
|
|
117045
|
-
"data-phase": syncStatus.phase,
|
|
117176
|
+
"data-phase": landingError ? "error" : syncStatus.phase,
|
|
117046
117177
|
role: "status",
|
|
117047
117178
|
"aria-live": "polite",
|
|
117048
|
-
children: [(0, react_jsx_runtime.
|
|
117179
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: landingError ? lang === "en" ? "Could not read the original image. Reload it and try again." : "无法读取原图,请重新加载图片后重试。" : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [statusText, syncStatus.phase === "error" ? `:${canvasSyncError(syncStatus.error, lang)}` : ""] }) }), !landingError && syncStatus.phase === "error" && (0, react_jsx_runtime.jsx)("button", {
|
|
117049
117180
|
type: "button",
|
|
117050
117181
|
onClick: () => retrySync.current(),
|
|
117051
117182
|
children: lang === "en" ? "Retry" : "重试"
|
|
@@ -117062,6 +117193,26 @@ img.ProseMirror-separator {
|
|
|
117062
117193
|
return en ? "Check the connection or re-import an unavailable image, then retry." : "请检查连接;若原图已失效,请重新导入后重试。";
|
|
117063
117194
|
}
|
|
117064
117195
|
//#endregion
|
|
117196
|
+
//#region lib/types/client/tl/gallery-canvas-button.js
|
|
117197
|
+
/** An explicit alternative to native dragging, including a visible unavailable state. */
|
|
117198
|
+
const GalleryCanvasButton = ({ item, lang, disabled, className, onToast }) => {
|
|
117199
|
+
const available = (0, react.useSyncExternalStore)(subscribeTlLandingAvailability, hasTlLandingConsumer, () => false);
|
|
117200
|
+
const open = lang === "en" ? "Open the infinite canvas first" : "请先打开无限画布";
|
|
117201
|
+
const title = !available ? open : disabled ? lang === "en" ? "Wait for the image to load" : "请等待图片加载完成" : lang === "en" ? "Send to canvas" : "发送到画布";
|
|
117202
|
+
return (0, react_jsx_runtime.jsx)("button", {
|
|
117203
|
+
type: "button",
|
|
117204
|
+
className,
|
|
117205
|
+
title,
|
|
117206
|
+
"aria-label": title,
|
|
117207
|
+
disabled: !available || disabled,
|
|
117208
|
+
onClick: (event) => {
|
|
117209
|
+
event.stopPropagation();
|
|
117210
|
+
onToast(sendTlLandingToOpenCanvas(galleryLanding(item)) ? lang === "en" ? "Sent to canvas" : "已发送到画布" : open);
|
|
117211
|
+
},
|
|
117212
|
+
children: (0, react_jsx_runtime.jsx)(Frame, { size: 14 })
|
|
117213
|
+
});
|
|
117214
|
+
};
|
|
117215
|
+
//#endregion
|
|
117065
117216
|
//#region lib/types/client/studio-view.js
|
|
117066
117217
|
/** Below this workbench width the recent-generations rail folds automatically. */
|
|
117067
117218
|
const WORKBENCH_NARROW_WIDTH = 560;
|
|
@@ -117619,6 +117770,7 @@ img.ProseMirror-separator {
|
|
|
117619
117770
|
};
|
|
117620
117771
|
}, []);
|
|
117621
117772
|
const activeProfile = (0, react.useMemo)(() => config?.providers.find((item) => item.provider === provider), [config, provider]);
|
|
117773
|
+
const requestModel = mode === "edit" && activeProfile?.editModel ? studioModelForMode(activeProfile, mode) : model;
|
|
117622
117774
|
const configuredCount = config?.providers.filter((item) => item.configured).length ?? 0;
|
|
117623
117775
|
const apiConfiguredCount = config?.providers.filter((item) => item.configured && !isSubscriptionProvider(item.provider)).length ?? 0;
|
|
117624
117776
|
const subscriptionSignedInCount = config?.providers.filter((item) => item.configured && isSubscriptionProvider(item.provider)).length ?? 0;
|
|
@@ -117962,7 +118114,7 @@ img.ProseMirror-separator {
|
|
|
117962
118114
|
body: JSON.stringify({
|
|
117963
118115
|
mode,
|
|
117964
118116
|
provider: target.profile.provider,
|
|
117965
|
-
model: target.profile
|
|
118117
|
+
model: studioModelForMode(target.profile, mode),
|
|
117966
118118
|
prompt: prompt.trim(),
|
|
117967
118119
|
ratio: target.ratio,
|
|
117968
118120
|
quality: target.quality,
|
|
@@ -118031,7 +118183,7 @@ img.ProseMirror-separator {
|
|
|
118031
118183
|
body: JSON.stringify({
|
|
118032
118184
|
mode,
|
|
118033
118185
|
provider,
|
|
118034
|
-
model,
|
|
118186
|
+
model: requestModel,
|
|
118035
118187
|
prompt: prompt.trim(),
|
|
118036
118188
|
ratio,
|
|
118037
118189
|
quality: selectedQuality,
|
|
@@ -118351,6 +118503,8 @@ img.ProseMirror-separator {
|
|
|
118351
118503
|
}) : displayItems.map((item) => (0, react_jsx_runtime.jsx)(RecentItem, {
|
|
118352
118504
|
item,
|
|
118353
118505
|
active: selected?.id === item.id,
|
|
118506
|
+
lang,
|
|
118507
|
+
onToast: flash,
|
|
118354
118508
|
onClick: () => selectItem(item)
|
|
118355
118509
|
}, item.id)), items.length > visibleLimit && (0, react_jsx_runtime.jsx)("button", {
|
|
118356
118510
|
type: "button",
|
|
@@ -118376,6 +118530,8 @@ img.ProseMirror-separator {
|
|
|
118376
118530
|
children: list.map((item) => (0, react_jsx_runtime.jsx)(RecentItem, {
|
|
118377
118531
|
item,
|
|
118378
118532
|
active: false,
|
|
118533
|
+
lang,
|
|
118534
|
+
onToast: flash,
|
|
118379
118535
|
onClick: () => void applyFavoriteImage(item)
|
|
118380
118536
|
}, item.id))
|
|
118381
118537
|
});
|
|
@@ -118612,7 +118768,7 @@ img.ProseMirror-separator {
|
|
|
118612
118768
|
className: p.configured ? "is-configured" : "is-missing",
|
|
118613
118769
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
118614
118770
|
className: "dsh-ig-status-item-name",
|
|
118615
|
-
children: [(0, react_jsx_runtime.jsx)("strong", { children: p.label }), (0, react_jsx_runtime.jsx)("small", { children: p
|
|
118771
|
+
children: [(0, react_jsx_runtime.jsx)("strong", { children: p.label }), (0, react_jsx_runtime.jsx)("small", { children: studioModelForMode(p, mode) })]
|
|
118616
118772
|
}), (0, react_jsx_runtime.jsx)("span", {
|
|
118617
118773
|
className: "dsh-ig-status-item-tag",
|
|
118618
118774
|
children: isSubscriptionProvider(p.provider) ? p.configured ? t("subSignedIn") : t("subSignedOut") : p.configured ? t("configured") : t("unconfigured")
|
|
@@ -118736,7 +118892,7 @@ img.ProseMirror-separator {
|
|
|
118736
118892
|
children: (0, react_jsx_runtime.jsx)(Sparkles, { size: 28 })
|
|
118737
118893
|
}),
|
|
118738
118894
|
(0, react_jsx_runtime.jsx)("strong", { children: comparisonEnabled ? t("comparing", { count: String(comparisonTargets.length) }) : count > 1 ? t("generatingCount", { count: String(count) }) : t("generating") }),
|
|
118739
|
-
(0, react_jsx_runtime.jsx)("span", { children: comparisonEnabled ? comparisonTargets.map((target) => target.profile.label).join(" · ") : `${activeProfile?.label ?? ""} · ${
|
|
118895
|
+
(0, react_jsx_runtime.jsx)("span", { children: comparisonEnabled ? comparisonTargets.map((target) => target.profile.label).join(" · ") : `${activeProfile?.label ?? ""} · ${requestModel}` })
|
|
118740
118896
|
]
|
|
118741
118897
|
}) : currentBatch && currentBatch.length > 1 ? (0, react_jsx_runtime.jsx)("div", {
|
|
118742
118898
|
className: "dsh-ig-canvas-cluster",
|
|
@@ -119050,8 +119206,8 @@ img.ProseMirror-separator {
|
|
|
119050
119206
|
(0, react_jsx_runtime.jsxs)("span", {
|
|
119051
119207
|
className: "dsh-ig-model-copy",
|
|
119052
119208
|
children: [(0, react_jsx_runtime.jsx)("strong", { children: item.label }), (0, react_jsx_runtime.jsx)("small", {
|
|
119053
|
-
title: item
|
|
119054
|
-
children: item
|
|
119209
|
+
title: studioModelForMode(item, mode),
|
|
119210
|
+
children: studioModelForMode(item, mode)
|
|
119055
119211
|
})]
|
|
119056
119212
|
}),
|
|
119057
119213
|
target && (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -119120,11 +119276,11 @@ img.ProseMirror-separator {
|
|
|
119120
119276
|
}))
|
|
119121
119277
|
}), (0, react_jsx_runtime.jsx)(FieldSelect, {
|
|
119122
119278
|
label: t("model"),
|
|
119123
|
-
value:
|
|
119279
|
+
value: requestModel,
|
|
119124
119280
|
onChange: setModel,
|
|
119125
119281
|
options: activeProfile === void 0 ? [] : [{
|
|
119126
|
-
value: activeProfile
|
|
119127
|
-
label: activeProfile
|
|
119282
|
+
value: studioModelForMode(activeProfile, mode),
|
|
119283
|
+
label: studioModelForMode(activeProfile, mode)
|
|
119128
119284
|
}]
|
|
119129
119285
|
})]
|
|
119130
119286
|
}),
|
|
@@ -119602,23 +119758,37 @@ img.ProseMirror-separator {
|
|
|
119602
119758
|
label: opt.value === "__default__" ? lang === "en" ? "Provider default (omit)" : "渠道默认(不发送)" : LOCALIZED_QUALITIES[opt.value]?.[lang] ?? opt.label
|
|
119603
119759
|
}));
|
|
119604
119760
|
}
|
|
119605
|
-
const RecentItem = ({ item, active, onClick }) => {
|
|
119761
|
+
const RecentItem = ({ item, active, lang, onToast, onClick }) => {
|
|
119606
119762
|
const [setRef, inView] = useInView();
|
|
119607
119763
|
const image = useAttachmentImage(item.attachment, inView);
|
|
119608
|
-
return (0, react_jsx_runtime.
|
|
119609
|
-
ref: setRef,
|
|
119610
|
-
type: "button",
|
|
119764
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
119611
119765
|
className: `dsh-ig-recent-item ${active ? "is-active" : ""}`,
|
|
119612
|
-
|
|
119613
|
-
|
|
119614
|
-
|
|
119615
|
-
className: "dsh-ig-recent-
|
|
119616
|
-
|
|
119617
|
-
|
|
119618
|
-
|
|
119619
|
-
|
|
119620
|
-
|
|
119621
|
-
|
|
119766
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
119767
|
+
ref: setRef,
|
|
119768
|
+
type: "button",
|
|
119769
|
+
className: "dsh-ig-recent-select",
|
|
119770
|
+
onClick,
|
|
119771
|
+
title: item.prompt,
|
|
119772
|
+
draggable: Boolean(image.blob?.size),
|
|
119773
|
+
onDragStart: (event) => {
|
|
119774
|
+
startGalleryImageDrag(event, item, image.blob);
|
|
119775
|
+
},
|
|
119776
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
119777
|
+
className: "dsh-ig-recent-thumb",
|
|
119778
|
+
children: image.url !== null ? (0, react_jsx_runtime.jsx)("img", {
|
|
119779
|
+
src: image.url,
|
|
119780
|
+
alt: "",
|
|
119781
|
+
loading: "lazy",
|
|
119782
|
+
draggable: false
|
|
119783
|
+
}) : (0, react_jsx_runtime.jsx)(ImagePlus, { size: 18 })
|
|
119784
|
+
})
|
|
119785
|
+
}), (0, react_jsx_runtime.jsx)(GalleryCanvasButton, {
|
|
119786
|
+
item,
|
|
119787
|
+
lang,
|
|
119788
|
+
disabled: !image.blob?.size,
|
|
119789
|
+
className: "dsh-ig-recent-send",
|
|
119790
|
+
onToast
|
|
119791
|
+
})]
|
|
119622
119792
|
});
|
|
119623
119793
|
};
|
|
119624
119794
|
const FavoriteFolderBar = ({ folders, active, onSelect, onDelete, deleteLabel }) => {
|
|
@@ -123457,6 +123627,7 @@ img.ProseMirror-separator {
|
|
|
123457
123627
|
}) : (0, react_jsx_runtime.jsx)("div", {
|
|
123458
123628
|
className: "dsh-ig-gallery-grid",
|
|
123459
123629
|
children: filteredItems.map((item, idx) => (0, react_jsx_runtime.jsx)(GalleryCard, {
|
|
123630
|
+
lang,
|
|
123460
123631
|
item,
|
|
123461
123632
|
index: idx,
|
|
123462
123633
|
isManageMode,
|
|
@@ -123841,7 +124012,7 @@ img.ProseMirror-separator {
|
|
|
123841
124012
|
]
|
|
123842
124013
|
});
|
|
123843
124014
|
};
|
|
123844
|
-
const GalleryCard = ({ item, index: _index, isManageMode, isSelected, t, onClick, onToggleSelect, onRequestDelete, onPreview: _onPreview, onBlobLoaded, onToast }) => {
|
|
124015
|
+
const GalleryCard = ({ lang, item, index: _index, isManageMode, isSelected, t, onClick, onToggleSelect, onRequestDelete, onPreview: _onPreview, onBlobLoaded, onToast }) => {
|
|
123845
124016
|
const [url, setUrl] = (0, react.useState)();
|
|
123846
124017
|
const [blob, setBlob] = (0, react.useState)();
|
|
123847
124018
|
const [loading, setLoading] = (0, react.useState)(true);
|
|
@@ -123931,11 +124102,23 @@ img.ProseMirror-separator {
|
|
|
123931
124102
|
className: "dsh-ig-gallery-card-img",
|
|
123932
124103
|
src: url,
|
|
123933
124104
|
alt: item.prompt,
|
|
123934
|
-
loading: "lazy"
|
|
124105
|
+
loading: "lazy",
|
|
124106
|
+
draggable: !isManageMode && Boolean(blob?.size),
|
|
124107
|
+
onDragStart: (event) => {
|
|
124108
|
+
if (isManageMode) event.preventDefault();
|
|
124109
|
+
else startGalleryImageDrag(event, item, blob);
|
|
124110
|
+
}
|
|
123935
124111
|
}),
|
|
123936
124112
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
123937
124113
|
className: "dsh-ig-card-toolbar",
|
|
123938
124114
|
children: [
|
|
124115
|
+
!isManageMode && (0, react_jsx_runtime.jsx)(GalleryCanvasButton, {
|
|
124116
|
+
item,
|
|
124117
|
+
lang,
|
|
124118
|
+
disabled: !blob?.size,
|
|
124119
|
+
className: "dsh-ig-tool-btn",
|
|
124120
|
+
onToast
|
|
124121
|
+
}),
|
|
123939
124122
|
(0, react_jsx_runtime.jsx)("button", {
|
|
123940
124123
|
type: "button",
|
|
123941
124124
|
className: "dsh-ig-tool-btn",
|
|
@@ -124229,12 +124412,48 @@ img.ProseMirror-separator {
|
|
|
124229
124412
|
}
|
|
124230
124413
|
//#endregion
|
|
124231
124414
|
//#region lib/types/client/tl/conversation-landings.js
|
|
124415
|
+
/** Keep one landing subscription while the optional UI service loads or unloads. */
|
|
124416
|
+
function createCanvasSessionSelection() {
|
|
124417
|
+
let current;
|
|
124418
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
124419
|
+
const notify = () => {
|
|
124420
|
+
for (const listener of listeners) listener();
|
|
124421
|
+
};
|
|
124422
|
+
return {
|
|
124423
|
+
getSnapshot: () => current?.getSnapshot(),
|
|
124424
|
+
subscribe: (listener) => {
|
|
124425
|
+
listeners.add(listener);
|
|
124426
|
+
return () => {
|
|
124427
|
+
listeners.delete(listener);
|
|
124428
|
+
};
|
|
124429
|
+
},
|
|
124430
|
+
bind(source) {
|
|
124431
|
+
current = source;
|
|
124432
|
+
const stop = source.subscribe(notify);
|
|
124433
|
+
notify();
|
|
124434
|
+
return () => {
|
|
124435
|
+
stop();
|
|
124436
|
+
if (current !== source) return;
|
|
124437
|
+
current = void 0;
|
|
124438
|
+
notify();
|
|
124439
|
+
};
|
|
124440
|
+
}
|
|
124441
|
+
};
|
|
124442
|
+
}
|
|
124443
|
+
function currentSessionId(sessions, selection) {
|
|
124444
|
+
const selected = selection?.getSnapshot();
|
|
124445
|
+
if (selected !== void 0) return selected.key || void 0;
|
|
124446
|
+
const snapshot = sessions.list.getSnapshot();
|
|
124447
|
+
if (snapshot.current) return snapshot.current;
|
|
124448
|
+
const mainViews = Object.values(snapshot.byId ?? {}).filter((row) => (row.retainedBy?.mainView ?? 0) > 0);
|
|
124449
|
+
return mainViews.length === 1 ? mainViews[0].id : void 0;
|
|
124450
|
+
}
|
|
124232
124451
|
/** Subscribe to live additions, never to card rendering or history replay. */
|
|
124233
|
-
function startConversationLandings(sessions) {
|
|
124452
|
+
function startConversationLandings(sessions, selection) {
|
|
124234
124453
|
let source;
|
|
124235
124454
|
let stopEvents;
|
|
124236
124455
|
const followCurrent = () => {
|
|
124237
|
-
const id = sessions
|
|
124456
|
+
const id = currentSessionId(sessions, selection);
|
|
124238
124457
|
const next = id === void 0 ? void 0 : sessions.binding(id)?.eventSource;
|
|
124239
124458
|
if (next === source) return;
|
|
124240
124459
|
stopEvents?.();
|
|
@@ -124263,15 +124482,20 @@ img.ProseMirror-separator {
|
|
|
124263
124482
|
});
|
|
124264
124483
|
};
|
|
124265
124484
|
const stopList = sessions.list.subscribe(followCurrent);
|
|
124485
|
+
const stopSelection = selection?.subscribe(followCurrent);
|
|
124266
124486
|
followCurrent();
|
|
124267
124487
|
return () => {
|
|
124268
124488
|
stopList();
|
|
124489
|
+
stopSelection?.();
|
|
124269
124490
|
stopEvents?.();
|
|
124270
124491
|
};
|
|
124271
124492
|
}
|
|
124272
124493
|
//#endregion
|
|
124273
124494
|
//#region lib/types/client/studio-style.js
|
|
124274
124495
|
const STUDIO_STYLE = `
|
|
124496
|
+
.dsh-ig-recent-select{display:block;width:100%;height:100%;padding:0;border:0;border-radius:inherit;background:transparent;cursor:pointer}
|
|
124497
|
+
.dsh-ig-recent-send{position:absolute;right:3px;bottom:3px;display:flex;align-items:center;justify-content:center;width:25px;height:25px;padding:0;border:1px solid var(--ig-line);border-radius:5px;background:var(--ig-bg-panel);cursor:pointer}
|
|
124498
|
+
.dsh-ig-recent-send:disabled{opacity:.45;cursor:not-allowed}
|
|
124275
124499
|
.dsh-ig-gallery-page-body.is-workbench{flex:1 1 0;height:100%;min-height:0;padding:0;overflow:hidden;display:flex;flex-direction:column}
|
|
124276
124500
|
.dsh-ig-workbench{--ig-blue:var(--dsw-alias-brand-primary-new-colorprimary-new-color,#2f64f5);--ig-blue-line:color-mix(in srgb,var(--ig-blue) 45%,transparent);--ig-line:var(--dsw-alias-border-l2,color-mix(in srgb,currentColor 11%,transparent));--ig-soft:color-mix(in srgb,currentColor 4%,transparent);--ig-fg:var(--dsw-alias-label-primary,var(--foreground,#182033));--ig-fg-2:var(--dsw-alias-label-secondary,#5a6478);--ig-fg-3:var(--dsw-alias-label-tertiary,#717b90);--ig-fg-cap:var(--dsw-alias-label-caption,#929bad);--ig-bg:var(--dsw-alias-bg-layer-1,var(--background,#fff));--ig-bg-panel:var(--dsw-alias-bg-layer-2,color-mix(in srgb,var(--background,#fff) 96%,#f5f7fb));--ig-bg-thumb:var(--dsw-alias-bg-skeleton,#eef1f7);--ig-danger:#b63737;--ig-warn:#8b671c;position:relative;display:flex;flex-direction:column;min-height:0;height:100%;overflow:hidden;padding:10px 12px 12px;color:var(--ig-fg);box-sizing:border-box;background:radial-gradient(circle at 60% -20%,rgba(63,104,246,.07),transparent 30%)}
|
|
124277
124501
|
body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a}
|
|
@@ -125221,7 +125445,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125221
125445
|
`;
|
|
125222
125446
|
//#endregion
|
|
125223
125447
|
//#region lib/types/client/index.js
|
|
125224
|
-
console.info(`[dsh-image-gen] canvas bundle 2026-10-
|
|
125448
|
+
console.info(`[dsh-image-gen] canvas bundle 2026-10-26T00:24:12.240Z`);
|
|
125225
125449
|
/** Right-sidebar tab-type registration id (DSH 0.1.5 `sidebarRightTabs`). */
|
|
125226
125450
|
const SIDEBAR_STUDIO_TAB_ID = "dsh-image-gen/studio";
|
|
125227
125451
|
/** The tab kind: a page type opened by kind, recognizing no resource address. */
|
|
@@ -125296,14 +125520,23 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125296
125520
|
reset: "重置",
|
|
125297
125521
|
resetTitle: "重置为默认官方地址",
|
|
125298
125522
|
endpointHintGoogle: "Google 官方地址或反代端点(全路径)。",
|
|
125523
|
+
googleProtocol: "请求协议",
|
|
125524
|
+
googleInteractions: "Interactions(默认)",
|
|
125525
|
+
googleNative: "原生 generateContent",
|
|
125526
|
+
saveGoogleProtocolFirst: "请求协议尚未保存,请先点击保存,再拉取模型或测试连接。",
|
|
125527
|
+
endpointHintGoogleNative: "填写 API 基础地址(如 https://example.com/v1beta);也兼容 Interactions 或 generateContent 完整地址。",
|
|
125299
125528
|
endpointHintOpenAI: "官方 api.openai.com 的 /v1 地址;中转站请使用下方「OpenAI 兼容」行。",
|
|
125300
125529
|
endpointHintOpenAICompat: "中转站/自建服务的 OpenAI 兼容 /v1 地址(必填),例如 https://your-relay.example.com/v1。",
|
|
125301
125530
|
editFormat: "图生图请求形态",
|
|
125531
|
+
editModel: "图生图模型(可选)",
|
|
125532
|
+
editModelHint: "留空沿用上方模型。硅基流动可分别填写 Qwen/Qwen-Image(文生图)和 Qwen/Qwen-Image-Edit(图生图)。",
|
|
125533
|
+
editFormatSiliconFlow: "硅基流动 JSON(image 字符串)",
|
|
125534
|
+
editFormatSiliconFlowHint: "编辑尺寸由参考图决定,不发送尺寸和质量字段。Qwen-Image-Edit 支持一张图,Edit-2509 最多三张;参考图字段由插件填入。",
|
|
125302
125535
|
editFormatMultipart: "标准 multipart(OpenAI 官方)",
|
|
125303
125536
|
editFormatAutomatic: "自动:官方接口 JSON 格式",
|
|
125304
125537
|
editFormatJsonImageUrlArray: "JSON images 数组(商汤等中转)",
|
|
125305
125538
|
editFormatFormReferenceImages: "multipart + reference_images JSON 数组(base64)",
|
|
125306
|
-
editFormatHint: "
|
|
125539
|
+
editFormatHint: "商汤、通义、硅基流动已确认的官方接口自动使用对应 JSON 格式;其他中转按接口文档选择。文生图不受影响。",
|
|
125307
125540
|
editExtra: "附加 JSON 字段",
|
|
125308
125541
|
editExtraPlaceholder: "{\"watermark\": false, \"prompt_extend\": true}",
|
|
125309
125542
|
editExtraHint: "仅 JSON 形态生效;会合并到请求体末尾,可覆盖默认字段。留空表示不附加。",
|
|
@@ -125461,14 +125694,23 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125461
125694
|
reset: "Reset",
|
|
125462
125695
|
resetTitle: "Reset to official default URL",
|
|
125463
125696
|
endpointHintGoogle: "Official Google endpoint or reverse proxy (full path).",
|
|
125697
|
+
googleProtocol: "Request protocol",
|
|
125698
|
+
googleInteractions: "Interactions (default)",
|
|
125699
|
+
googleNative: "Native generateContent",
|
|
125700
|
+
saveGoogleProtocolFirst: "Save the request protocol before fetching models or testing the connection.",
|
|
125701
|
+
endpointHintGoogleNative: "API base URL (e.g. https://example.com/v1beta). Full Interactions or generateContent URLs also work.",
|
|
125464
125702
|
endpointHintOpenAI: "Official api.openai.com /v1 base URL; for relays use the \"OpenAI-compatible\" row below.",
|
|
125465
125703
|
endpointHintOpenAICompat: "OpenAI-compatible /v1 base URL of your relay or self-hosted service (required), e.g. https://your-relay.example.com/v1.",
|
|
125466
125704
|
editFormat: "Edit request format",
|
|
125705
|
+
editModel: "Editing model (optional)",
|
|
125706
|
+
editModelHint: "Leave empty to reuse the model above. SiliconFlow can use Qwen/Qwen-Image for generation and Qwen/Qwen-Image-Edit for editing.",
|
|
125707
|
+
editFormatSiliconFlow: "SiliconFlow JSON (image string)",
|
|
125708
|
+
editFormatSiliconFlowHint: "Edit dimensions follow the reference; size and quality fields are omitted. Qwen-Image-Edit supports one reference, Edit-2509 up to three. The plugin fills the image fields.",
|
|
125467
125709
|
editFormatMultipart: "Standard multipart (official OpenAI)",
|
|
125468
125710
|
editFormatAutomatic: "Automatic: official JSON contract",
|
|
125469
125711
|
editFormatJsonImageUrlArray: "JSON images array (SenseNova etc.)",
|
|
125470
125712
|
editFormatFormReferenceImages: "Multipart with a reference_images JSON array (base64)",
|
|
125471
|
-
editFormatHint: "Recognized official SenseNova and
|
|
125713
|
+
editFormatHint: "Recognized official SenseNova, Qwen and SiliconFlow endpoints automatically use their JSON edit contracts. Choose other relay formats according to their documentation. Text-to-image is unaffected.",
|
|
125472
125714
|
editExtra: "Extra JSON fields",
|
|
125473
125715
|
editExtraPlaceholder: "{\"watermark\": false, \"prompt_extend\": true}",
|
|
125474
125716
|
editExtraHint: "Only used with the JSON format; merged into the request body last and may override defaults. Leave empty for none.",
|
|
@@ -125881,7 +126123,13 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125881
126123
|
ctx.inject(["sessions"], (owner) => {
|
|
125882
126124
|
const sessions = owner.get("sessions");
|
|
125883
126125
|
if (typeof sessions?.binding !== "function" || typeof sessions.list?.subscribe !== "function") return;
|
|
125884
|
-
|
|
126126
|
+
const selection = createCanvasSessionSelection();
|
|
126127
|
+
owner.effect(() => startConversationLandings(sessions, selection), "dsh-image-gen: live canvas images");
|
|
126128
|
+
owner.inject(["uiSession"], (uiOwner) => {
|
|
126129
|
+
const current = uiOwner.get("uiSession")?.adapter?.current;
|
|
126130
|
+
if (typeof current?.getSnapshot !== "function" || typeof current.subscribe !== "function") return;
|
|
126131
|
+
uiOwner.effect(() => selection.bind(current), "dsh-image-gen: current canvas session");
|
|
126132
|
+
});
|
|
125885
126133
|
});
|
|
125886
126134
|
ctx.effect(() => {
|
|
125887
126135
|
const style = document.createElement("style");
|
|
@@ -126097,7 +126345,9 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126097
126345
|
return {
|
|
126098
126346
|
expanded: false,
|
|
126099
126347
|
model: "",
|
|
126348
|
+
editModel: "",
|
|
126100
126349
|
baseURL: "",
|
|
126350
|
+
googleNative: false,
|
|
126101
126351
|
keyInput: "",
|
|
126102
126352
|
keyStatus: "checking",
|
|
126103
126353
|
keyInfo: void 0,
|
|
@@ -126178,7 +126428,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126178
126428
|
}
|
|
126179
126429
|
/** Persisted or selected edit-format value → row state; unknown values fall back to standard multipart. */
|
|
126180
126430
|
function parseEditFormat(value) {
|
|
126181
|
-
return value === "jsonImageUrlArray" || value === "formReferenceImages" ? value : "multipart";
|
|
126431
|
+
return value === "jsonImageUrlArray" || value === "formReferenceImages" || value === "siliconflowJson" ? value : "multipart";
|
|
126182
126432
|
}
|
|
126183
126433
|
/** Build one row per provider from persisted settings, including ComfyUI extras. */
|
|
126184
126434
|
function rowsFromSettings(value) {
|
|
@@ -126187,6 +126437,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126187
126437
|
...emptyProviderRow(),
|
|
126188
126438
|
model: modelOf(provider, value),
|
|
126189
126439
|
baseURL: baseURLOf(provider, value),
|
|
126440
|
+
...provider === "google" ? { googleNative: value?.googleNative === true } : {},
|
|
126190
126441
|
...provider === "openai" ? { sizeTableText: editExtraTextOf(value?.openaiSizes) } : {},
|
|
126191
126442
|
...provider === "comfyui" ? {
|
|
126192
126443
|
workflows: resolveComfyUIWorkflows(value ?? {}),
|
|
@@ -126194,6 +126445,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126194
126445
|
timeoutSeconds: Math.max(1, Math.round((value?.comfyuiTimeoutMs ?? 3e5) / 1e3))
|
|
126195
126446
|
} : {},
|
|
126196
126447
|
...provider === "openai-compat" ? {
|
|
126448
|
+
editModel: value?.openaiCompatEditModel ?? "",
|
|
126197
126449
|
editFormat: parseEditFormat(value?.openaiCompatEditFormat),
|
|
126198
126450
|
editExtraText: editExtraTextOf(value?.openaiCompatEditExtra),
|
|
126199
126451
|
sizeTableText: editExtraTextOf(value?.openaiCompatSizes),
|
|
@@ -126446,6 +126698,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126446
126698
|
for (const provider of IMAGE_PROVIDERS) next[provider] = {
|
|
126447
126699
|
...current[provider],
|
|
126448
126700
|
model: modelOf(provider, value),
|
|
126701
|
+
...provider === "openai-compat" ? { editModel: value?.openaiCompatEditModel ?? "" } : {},
|
|
126449
126702
|
baseURL: baseURLOf(provider, value),
|
|
126450
126703
|
...provider === "comfyui" ? {
|
|
126451
126704
|
workflows: resolveComfyUIWorkflows(value ?? {}),
|
|
@@ -126573,8 +126826,10 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126573
126826
|
if (provider === "openai") for (const tiers of Object.values(sizeTable)) for (const size of Object.values(tiers)) validateOfficialSize(row.model, size);
|
|
126574
126827
|
await saveSetting(modelFieldOf(provider), row.model);
|
|
126575
126828
|
await saveSetting(baseURLFieldOf(provider), row.baseURL);
|
|
126829
|
+
if (provider === "google") await saveSetting("googleNative", row.googleNative);
|
|
126576
126830
|
if (provider === "openai") await saveSetting("openaiSizes", sizeTable);
|
|
126577
126831
|
if (provider === "openai-compat") {
|
|
126832
|
+
await saveSetting("openaiCompatEditModel", row.editModel.trim());
|
|
126578
126833
|
await saveSetting("openaiCompatEditFormat", row.editFormat);
|
|
126579
126834
|
await saveSetting("openaiCompatEditExtra", editExtra);
|
|
126580
126835
|
await saveSetting("openaiCompatSizes", sizeTable);
|
|
@@ -126624,6 +126879,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126624
126879
|
const address = row.baseURL.trim();
|
|
126625
126880
|
if (address.length === 0) return t("endpointRequired");
|
|
126626
126881
|
if (address !== baseURLOf(provider, props.scope.getSnapshot().value).trim()) return t("saveEndpointFirst");
|
|
126882
|
+
if (provider === "google" && row.googleNative !== (props.scope.getSnapshot().value?.googleNative === true)) return t("saveGoogleProtocolFirst");
|
|
126627
126883
|
};
|
|
126628
126884
|
/** Localize the host's missing-address error while preserving upstream details. */
|
|
126629
126885
|
const providerErrorMessage = (message) => message === "Base URL is not configured" ? t("savedEndpointMissing") : message ?? t("testFailed");
|
|
@@ -126925,7 +127181,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126925
127181
|
const row = rows[provider];
|
|
126926
127182
|
const officialEditFormat = provider === "openai-compat" ? compatEditFormat({
|
|
126927
127183
|
openaiCompatBaseURL: row.baseURL,
|
|
126928
|
-
openaiCompatModel: row.model
|
|
127184
|
+
openaiCompatModel: row.editModel.trim() || row.model
|
|
126929
127185
|
}) : "multipart";
|
|
126930
127186
|
const automaticEditFormat = officialEditFormat !== "multipart";
|
|
126931
127187
|
const editFormat = automaticEditFormat ? officialEditFormat : row.editFormat;
|
|
@@ -126995,10 +127251,31 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126995
127251
|
}),
|
|
126996
127252
|
(0, react_jsx_runtime.jsx)("span", {
|
|
126997
127253
|
className: "dsh-ig-hint",
|
|
126998
|
-
children: t(CLOUD_HINT_KEYS[provider])
|
|
127254
|
+
children: t(provider === "google" && row.googleNative ? "endpointHintGoogleNative" : CLOUD_HINT_KEYS[provider])
|
|
126999
127255
|
})
|
|
127000
127256
|
]
|
|
127001
127257
|
}),
|
|
127258
|
+
provider === "google" ? (0, react_jsx_runtime.jsxs)("label", {
|
|
127259
|
+
className: "dsh-ig-field",
|
|
127260
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
127261
|
+
className: "dsh-ig-label",
|
|
127262
|
+
children: t("googleProtocol")
|
|
127263
|
+
}), (0, react_jsx_runtime.jsxs)("select", {
|
|
127264
|
+
className: "dsh-ig-input",
|
|
127265
|
+
value: row.googleNative ? "native" : "interactions",
|
|
127266
|
+
onChange: (event) => {
|
|
127267
|
+
updateRow(provider, { googleNative: event.target.value === "native" });
|
|
127268
|
+
},
|
|
127269
|
+
disabled: !settingsWritable,
|
|
127270
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
127271
|
+
value: "interactions",
|
|
127272
|
+
children: t("googleInteractions")
|
|
127273
|
+
}), (0, react_jsx_runtime.jsx)("option", {
|
|
127274
|
+
value: "native",
|
|
127275
|
+
children: t("googleNative")
|
|
127276
|
+
})]
|
|
127277
|
+
})]
|
|
127278
|
+
}) : null,
|
|
127002
127279
|
(0, react_jsx_runtime.jsxs)("label", {
|
|
127003
127280
|
className: "dsh-ig-field",
|
|
127004
127281
|
children: [
|
|
@@ -127052,6 +127329,28 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
127052
127329
|
}) : null
|
|
127053
127330
|
]
|
|
127054
127331
|
}),
|
|
127332
|
+
provider === "openai-compat" ? (0, react_jsx_runtime.jsxs)("label", {
|
|
127333
|
+
className: "dsh-ig-field",
|
|
127334
|
+
children: [
|
|
127335
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
127336
|
+
className: "dsh-ig-label",
|
|
127337
|
+
children: t("editModel")
|
|
127338
|
+
}),
|
|
127339
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
127340
|
+
className: "dsh-ig-input",
|
|
127341
|
+
value: row.editModel,
|
|
127342
|
+
onChange: (event) => {
|
|
127343
|
+
updateRow(provider, { editModel: event.target.value });
|
|
127344
|
+
},
|
|
127345
|
+
list: "dsh-ig-openai-compat-model-options",
|
|
127346
|
+
disabled: !settingsWritable
|
|
127347
|
+
}),
|
|
127348
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
127349
|
+
className: "dsh-ig-hint",
|
|
127350
|
+
children: t("editModelHint")
|
|
127351
|
+
})
|
|
127352
|
+
]
|
|
127353
|
+
}) : null,
|
|
127055
127354
|
provider === "openai-compat" ? (0, react_jsx_runtime.jsxs)("label", {
|
|
127056
127355
|
className: "dsh-ig-field",
|
|
127057
127356
|
children: [
|
|
@@ -127082,12 +127381,16 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
127082
127381
|
(0, react_jsx_runtime.jsx)("option", {
|
|
127083
127382
|
value: "formReferenceImages",
|
|
127084
127383
|
children: t("editFormatFormReferenceImages")
|
|
127384
|
+
}),
|
|
127385
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
127386
|
+
value: "siliconflowJson",
|
|
127387
|
+
children: t("editFormatSiliconFlow")
|
|
127085
127388
|
})
|
|
127086
127389
|
]
|
|
127087
127390
|
}),
|
|
127088
127391
|
(0, react_jsx_runtime.jsx)("span", {
|
|
127089
127392
|
className: "dsh-ig-hint",
|
|
127090
|
-
children: t("editFormatHint")
|
|
127393
|
+
children: t(editFormat === "siliconflowJson" ? "editFormatSiliconFlowHint" : "editFormatHint")
|
|
127091
127394
|
})
|
|
127092
127395
|
]
|
|
127093
127396
|
}) : null,
|
|
@@ -127260,7 +127563,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
127260
127563
|
]
|
|
127261
127564
|
})
|
|
127262
127565
|
] }) : null,
|
|
127263
|
-
provider === "openai-compat" && (editFormat === "jsonImageUrlArray" || editFormat === "qwenJson") ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [editFormat === "jsonImageUrlArray" ? (0, react_jsx_runtime.jsxs)("label", {
|
|
127566
|
+
provider === "openai-compat" && (editFormat === "jsonImageUrlArray" || editFormat === "qwenJson" || editFormat === "siliconflowJson") ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [editFormat === "jsonImageUrlArray" ? (0, react_jsx_runtime.jsxs)("label", {
|
|
127264
127567
|
className: "dsh-ig-field",
|
|
127265
127568
|
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
127266
127569
|
className: "dsh-ig-label",
|