dsh-image-gen 0.9.0 → 0.9.2
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 +452 -442
- package/README.md +452 -442
- package/lib/client.js +286 -30
- package/lib/index.js +251 -98
- package/lib/types/client/index.d.ts +1 -0
- 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 +3 -0
- package/lib/types/fetch-diagnostics.d.ts +10 -0
- package/lib/types/google.d.ts +4 -1
- package/lib/types/subscription/vendors/antigravity.d.ts +1 -1
- package/package.json +139 -139
- package/skills/install-dsh-image-gen/SKILL.md +22 -22
package/lib/client.js
CHANGED
|
@@ -337,7 +337,7 @@ window.__ModuleLoader__.load({
|
|
|
337
337
|
}
|
|
338
338
|
if (!isRecord(value) || Object.keys(value).length === 0) throw new Error("ComfyUI workflow must be a non-empty API-format JSON object");
|
|
339
339
|
if (!Object.values(value).some((node) => {
|
|
340
|
-
const inputs = record$
|
|
340
|
+
const inputs = record$2(node)?.inputs;
|
|
341
341
|
return inputs !== void 0 && containsPromptPlaceholder(inputs);
|
|
342
342
|
})) throw new Error(`ComfyUI workflow must contain ${COMFYUI_PROMPT_PLACEHOLDER} (or ${LEGACY_PROMPT_PLACEHOLDER}) in a text input`);
|
|
343
343
|
return value;
|
|
@@ -346,7 +346,7 @@ window.__ModuleLoader__.load({
|
|
|
346
346
|
function countImagePlaceholders(workflow) {
|
|
347
347
|
let count = 0;
|
|
348
348
|
for (const node of Object.values(workflow)) {
|
|
349
|
-
const inputs = record$
|
|
349
|
+
const inputs = record$2(record$2(node)?.inputs);
|
|
350
350
|
if (inputs !== void 0 && isImagePlaceholder(inputs[IMAGE_INPUT_KEY])) count += 1;
|
|
351
351
|
}
|
|
352
352
|
return count;
|
|
@@ -362,7 +362,7 @@ window.__ModuleLoader__.load({
|
|
|
362
362
|
function isRecord(value) {
|
|
363
363
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
364
364
|
}
|
|
365
|
-
function record$
|
|
365
|
+
function record$2(value) {
|
|
366
366
|
return isRecord(value) ? value : void 0;
|
|
367
367
|
}
|
|
368
368
|
//#endregion
|
|
@@ -116729,8 +116729,27 @@ img.ProseMirror-separator {
|
|
|
116729
116729
|
//#region lib/types/client/tl/tl-canvas-bridge.js
|
|
116730
116730
|
const pending$1 = /* @__PURE__ */ new Map();
|
|
116731
116731
|
const consumers = /* @__PURE__ */ new Set();
|
|
116732
|
+
const availabilityListeners = /* @__PURE__ */ new Set();
|
|
116732
116733
|
let delivering = false;
|
|
116733
116734
|
let generation = 0;
|
|
116735
|
+
/** History actions must not silently queue into a canvas that is not open. */
|
|
116736
|
+
function hasTlLandingConsumer() {
|
|
116737
|
+
return consumers.size > 0;
|
|
116738
|
+
}
|
|
116739
|
+
function subscribeTlLandingAvailability(listener) {
|
|
116740
|
+
availabilityListeners.add(listener);
|
|
116741
|
+
return () => {
|
|
116742
|
+
availabilityListeners.delete(listener);
|
|
116743
|
+
};
|
|
116744
|
+
}
|
|
116745
|
+
function sendTlLandingToOpenCanvas(item) {
|
|
116746
|
+
if (!hasTlLandingConsumer()) return false;
|
|
116747
|
+
pushTlLandings([{
|
|
116748
|
+
...item,
|
|
116749
|
+
onlyWhileCanvasOpen: true
|
|
116750
|
+
}]);
|
|
116751
|
+
return true;
|
|
116752
|
+
}
|
|
116734
116753
|
/** Invalidates async landings that started before the user cleared the canvas. */
|
|
116735
116754
|
function getTlLandingGeneration() {
|
|
116736
116755
|
return generation;
|
|
@@ -116750,12 +116769,18 @@ img.ProseMirror-separator {
|
|
|
116750
116769
|
}
|
|
116751
116770
|
/** Register a ready editor. False means it unmounted before committing. */
|
|
116752
116771
|
function registerTlLandingConsumer(consumer) {
|
|
116772
|
+
const wasAvailable = hasTlLandingConsumer();
|
|
116753
116773
|
consumers.add(consumer);
|
|
116774
|
+
if (!wasAvailable) for (const listener of availabilityListeners) listener();
|
|
116754
116775
|
deliver();
|
|
116776
|
+
let registered = true;
|
|
116755
116777
|
return () => {
|
|
116778
|
+
if (!registered) return;
|
|
116779
|
+
registered = false;
|
|
116756
116780
|
consumers.delete(consumer);
|
|
116757
116781
|
if (consumers.size === 0) {
|
|
116758
|
-
for (const [id, item] of pending$1) if (item.fromConversation) pending$1.delete(id);
|
|
116782
|
+
for (const [id, item] of pending$1) if (item.fromConversation || item.onlyWhileCanvasOpen) pending$1.delete(id);
|
|
116783
|
+
for (const listener of availabilityListeners) listener();
|
|
116759
116784
|
}
|
|
116760
116785
|
};
|
|
116761
116786
|
}
|
|
@@ -116782,6 +116807,84 @@ img.ProseMirror-separator {
|
|
|
116782
116807
|
}
|
|
116783
116808
|
}
|
|
116784
116809
|
//#endregion
|
|
116810
|
+
//#region lib/types/client/tl/gallery-image-transfer.js
|
|
116811
|
+
const GALLERY_IMAGE_MIME = "application/x-dsh-image-gen-gallery-image";
|
|
116812
|
+
const EXTENSIONS = /* @__PURE__ */ new Map([
|
|
116813
|
+
["image/png", "png"],
|
|
116814
|
+
["image/jpeg", "jpg"],
|
|
116815
|
+
["image/webp", "webp"],
|
|
116816
|
+
["image/gif", "gif"]
|
|
116817
|
+
]);
|
|
116818
|
+
function galleryLanding(item) {
|
|
116819
|
+
return {
|
|
116820
|
+
galleryId: item.id,
|
|
116821
|
+
attachment: item.attachment,
|
|
116822
|
+
prompt: item.prompt.slice(0, 120),
|
|
116823
|
+
provider: item.provider,
|
|
116824
|
+
model: item.model
|
|
116825
|
+
};
|
|
116826
|
+
}
|
|
116827
|
+
/** A real file also works when the host drops custom MIME data between containers. */
|
|
116828
|
+
function startGalleryImageDrag(event, item, blob) {
|
|
116829
|
+
const transfer = event.dataTransfer;
|
|
116830
|
+
const mediaType = blob?.type || item.attachment.mediaType;
|
|
116831
|
+
const extension = EXTENSIONS.get(mediaType);
|
|
116832
|
+
if (!transfer || !blob?.size || !extension) {
|
|
116833
|
+
event.preventDefault();
|
|
116834
|
+
return false;
|
|
116835
|
+
}
|
|
116836
|
+
try {
|
|
116837
|
+
const name = item.id.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 100) || "image";
|
|
116838
|
+
const file = new File([blob], `${name}.${extension}`, { type: mediaType });
|
|
116839
|
+
transfer.items.clear();
|
|
116840
|
+
if (transfer.items.add(file) === null) throw new Error("Drag file unavailable");
|
|
116841
|
+
transfer.effectAllowed = "copy";
|
|
116842
|
+
try {
|
|
116843
|
+
transfer.setData(GALLERY_IMAGE_MIME, JSON.stringify(galleryLanding(item)));
|
|
116844
|
+
} catch {}
|
|
116845
|
+
return true;
|
|
116846
|
+
} catch {
|
|
116847
|
+
event.preventDefault();
|
|
116848
|
+
return false;
|
|
116849
|
+
}
|
|
116850
|
+
}
|
|
116851
|
+
function readGalleryImageDrop(transfer) {
|
|
116852
|
+
try {
|
|
116853
|
+
const raw = transfer.getData(GALLERY_IMAGE_MIME);
|
|
116854
|
+
if (!raw || raw.length > 64e3) return void 0;
|
|
116855
|
+
const value = JSON.parse(raw);
|
|
116856
|
+
if (!record$1(value) || !text(value.galleryId) || !record$1(value.attachment)) return void 0;
|
|
116857
|
+
const a = value.attachment;
|
|
116858
|
+
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;
|
|
116859
|
+
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;
|
|
116860
|
+
return {
|
|
116861
|
+
galleryId: value.galleryId,
|
|
116862
|
+
attachment: {
|
|
116863
|
+
attachmentId: a.attachmentId,
|
|
116864
|
+
mediaType: a.mediaType,
|
|
116865
|
+
bytes: a.bytes,
|
|
116866
|
+
width: a.width,
|
|
116867
|
+
height: a.height,
|
|
116868
|
+
...typeof a.name === "string" ? { name: a.name } : {}
|
|
116869
|
+
},
|
|
116870
|
+
prompt: value.prompt,
|
|
116871
|
+
provider: value.provider,
|
|
116872
|
+
model: value.model
|
|
116873
|
+
};
|
|
116874
|
+
} catch {
|
|
116875
|
+
return;
|
|
116876
|
+
}
|
|
116877
|
+
}
|
|
116878
|
+
function record$1(value) {
|
|
116879
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
116880
|
+
}
|
|
116881
|
+
function text(value) {
|
|
116882
|
+
return typeof value === "string" && value.length > 0 && value.length <= 1024;
|
|
116883
|
+
}
|
|
116884
|
+
function dimension(value) {
|
|
116885
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
116886
|
+
}
|
|
116887
|
+
//#endregion
|
|
116785
116888
|
//#region lib/types/client/tl/studio-tl-canvas.js
|
|
116786
116889
|
/**
|
|
116787
116890
|
* Infinite canvas surface for the Studio workbench, backed by tldraw.
|
|
@@ -116850,7 +116953,7 @@ img.ProseMirror-separator {
|
|
|
116850
116953
|
const collapsed = prompt.replace(/\s+/g, " ").trim();
|
|
116851
116954
|
return collapsed.length === 0 ? void 0 : collapsed.slice(0, 120);
|
|
116852
116955
|
}
|
|
116853
|
-
async function landTlItems(editor, items, isActive) {
|
|
116956
|
+
async function landTlItems(editor, items, isActive, onUnreadable) {
|
|
116854
116957
|
const landedIds = landedIdsOf(editor);
|
|
116855
116958
|
const pending = items.filter((item) => !landedIds.has(item.galleryId));
|
|
116856
116959
|
if (pending.length === 0) return true;
|
|
@@ -116879,6 +116982,7 @@ img.ProseMirror-separator {
|
|
|
116879
116982
|
});
|
|
116880
116983
|
} catch (error) {
|
|
116881
116984
|
console.warn("[dsh-image-gen] canvas landing skipped (attachment unreadable):", item.galleryId, error);
|
|
116985
|
+
if (isActive()) onUnreadable?.();
|
|
116882
116986
|
continue;
|
|
116883
116987
|
}
|
|
116884
116988
|
const size = displaySizeOf(item.attachment);
|
|
@@ -116985,9 +117089,12 @@ img.ProseMirror-separator {
|
|
|
116985
117089
|
phase: "idle",
|
|
116986
117090
|
count: 0
|
|
116987
117091
|
});
|
|
117092
|
+
const [landingError, setLandingError] = (0, react.useState)(false);
|
|
116988
117093
|
const retrySync = (0, react.useRef)(() => {});
|
|
117094
|
+
const editorRef = (0, react.useRef)(null);
|
|
116989
117095
|
const onMount = (0, react.useCallback)((editor) => {
|
|
116990
117096
|
let active = true;
|
|
117097
|
+
editorRef.current = editor;
|
|
116991
117098
|
editor.run(() => editor.selectNone());
|
|
116992
117099
|
mountedEditors.add(editor);
|
|
116993
117100
|
applyBrandTheme(editor);
|
|
@@ -116996,11 +117103,13 @@ img.ProseMirror-separator {
|
|
|
116996
117103
|
console.info(`[dsh-image-gen] tldraw mounted (instance ${editor.id})`);
|
|
116997
117104
|
const stopLanding = registerTlLandingConsumer((items) => {
|
|
116998
117105
|
const generation = getTlLandingGeneration();
|
|
116999
|
-
|
|
117106
|
+
setLandingError(false);
|
|
117107
|
+
return landTlItems(editor, items, () => active && generation === getTlLandingGeneration(), () => setLandingError(true));
|
|
117000
117108
|
});
|
|
117001
117109
|
let stopSync = startCanvasSync(editor, setSyncStatus);
|
|
117002
117110
|
retrySync.current = () => stopSync.retry();
|
|
117003
117111
|
const clear = () => {
|
|
117112
|
+
setLandingError(false);
|
|
117004
117113
|
stopSync();
|
|
117005
117114
|
editor.complete();
|
|
117006
117115
|
editor.run(() => {
|
|
@@ -117024,6 +117133,7 @@ img.ProseMirror-separator {
|
|
|
117024
117133
|
mountedCanvases.add(clear);
|
|
117025
117134
|
return () => {
|
|
117026
117135
|
active = false;
|
|
117136
|
+
if (editorRef.current === editor) editorRef.current = null;
|
|
117027
117137
|
mountedEditors.delete(editor);
|
|
117028
117138
|
mountedCanvases.delete(clear);
|
|
117029
117139
|
stopLanding();
|
|
@@ -117035,17 +117145,30 @@ img.ProseMirror-separator {
|
|
|
117035
117145
|
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
117146
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
117037
117147
|
className: "dsh-ig-tl-canvas",
|
|
117148
|
+
onDropCapture: (event) => {
|
|
117149
|
+
const item = readGalleryImageDrop(event.dataTransfer);
|
|
117150
|
+
const editor = editorRef.current;
|
|
117151
|
+
if (!item || !editor) return;
|
|
117152
|
+
event.preventDefault();
|
|
117153
|
+
event.stopPropagation();
|
|
117154
|
+
setLandingError(false);
|
|
117155
|
+
const generation = getTlLandingGeneration();
|
|
117156
|
+
landTlItems(editor, [item], () => editorRef.current === editor && generation === getTlLandingGeneration(), () => setLandingError(true)).catch((error) => {
|
|
117157
|
+
if (editorRef.current === editor) setLandingError(true);
|
|
117158
|
+
console.warn("[dsh-image-gen] history image drop failed:", error);
|
|
117159
|
+
});
|
|
117160
|
+
},
|
|
117038
117161
|
children: [(0, react_jsx_runtime.jsx)(Tldraw, {
|
|
117039
117162
|
persistenceKey: "dsh-image-gen-workbench-v1",
|
|
117040
117163
|
sessionId,
|
|
117041
117164
|
components: TL_COMPONENTS,
|
|
117042
117165
|
onMount
|
|
117043
|
-
}), syncStatus.phase !== "idle" && (0, react_jsx_runtime.jsxs)("div", {
|
|
117166
|
+
}), (landingError || syncStatus.phase !== "idle") && (0, react_jsx_runtime.jsxs)("div", {
|
|
117044
117167
|
className: "dsh-ig-canvas-sync-status",
|
|
117045
|
-
"data-phase": syncStatus.phase,
|
|
117168
|
+
"data-phase": landingError ? "error" : syncStatus.phase,
|
|
117046
117169
|
role: "status",
|
|
117047
117170
|
"aria-live": "polite",
|
|
117048
|
-
children: [(0, react_jsx_runtime.
|
|
117171
|
+
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
117172
|
type: "button",
|
|
117050
117173
|
onClick: () => retrySync.current(),
|
|
117051
117174
|
children: lang === "en" ? "Retry" : "重试"
|
|
@@ -117062,6 +117185,26 @@ img.ProseMirror-separator {
|
|
|
117062
117185
|
return en ? "Check the connection or re-import an unavailable image, then retry." : "请检查连接;若原图已失效,请重新导入后重试。";
|
|
117063
117186
|
}
|
|
117064
117187
|
//#endregion
|
|
117188
|
+
//#region lib/types/client/tl/gallery-canvas-button.js
|
|
117189
|
+
/** An explicit alternative to native dragging, including a visible unavailable state. */
|
|
117190
|
+
const GalleryCanvasButton = ({ item, lang, disabled, className, onToast }) => {
|
|
117191
|
+
const available = (0, react.useSyncExternalStore)(subscribeTlLandingAvailability, hasTlLandingConsumer, () => false);
|
|
117192
|
+
const open = lang === "en" ? "Open the infinite canvas first" : "请先打开无限画布";
|
|
117193
|
+
const title = !available ? open : disabled ? lang === "en" ? "Wait for the image to load" : "请等待图片加载完成" : lang === "en" ? "Send to canvas" : "发送到画布";
|
|
117194
|
+
return (0, react_jsx_runtime.jsx)("button", {
|
|
117195
|
+
type: "button",
|
|
117196
|
+
className,
|
|
117197
|
+
title,
|
|
117198
|
+
"aria-label": title,
|
|
117199
|
+
disabled: !available || disabled,
|
|
117200
|
+
onClick: (event) => {
|
|
117201
|
+
event.stopPropagation();
|
|
117202
|
+
onToast(sendTlLandingToOpenCanvas(galleryLanding(item)) ? lang === "en" ? "Sent to canvas" : "已发送到画布" : open);
|
|
117203
|
+
},
|
|
117204
|
+
children: (0, react_jsx_runtime.jsx)(Frame, { size: 14 })
|
|
117205
|
+
});
|
|
117206
|
+
};
|
|
117207
|
+
//#endregion
|
|
117065
117208
|
//#region lib/types/client/studio-view.js
|
|
117066
117209
|
/** Below this workbench width the recent-generations rail folds automatically. */
|
|
117067
117210
|
const WORKBENCH_NARROW_WIDTH = 560;
|
|
@@ -118351,6 +118494,8 @@ img.ProseMirror-separator {
|
|
|
118351
118494
|
}) : displayItems.map((item) => (0, react_jsx_runtime.jsx)(RecentItem, {
|
|
118352
118495
|
item,
|
|
118353
118496
|
active: selected?.id === item.id,
|
|
118497
|
+
lang,
|
|
118498
|
+
onToast: flash,
|
|
118354
118499
|
onClick: () => selectItem(item)
|
|
118355
118500
|
}, item.id)), items.length > visibleLimit && (0, react_jsx_runtime.jsx)("button", {
|
|
118356
118501
|
type: "button",
|
|
@@ -118376,6 +118521,8 @@ img.ProseMirror-separator {
|
|
|
118376
118521
|
children: list.map((item) => (0, react_jsx_runtime.jsx)(RecentItem, {
|
|
118377
118522
|
item,
|
|
118378
118523
|
active: false,
|
|
118524
|
+
lang,
|
|
118525
|
+
onToast: flash,
|
|
118379
118526
|
onClick: () => void applyFavoriteImage(item)
|
|
118380
118527
|
}, item.id))
|
|
118381
118528
|
});
|
|
@@ -119602,23 +119749,37 @@ img.ProseMirror-separator {
|
|
|
119602
119749
|
label: opt.value === "__default__" ? lang === "en" ? "Provider default (omit)" : "渠道默认(不发送)" : LOCALIZED_QUALITIES[opt.value]?.[lang] ?? opt.label
|
|
119603
119750
|
}));
|
|
119604
119751
|
}
|
|
119605
|
-
const RecentItem = ({ item, active, onClick }) => {
|
|
119752
|
+
const RecentItem = ({ item, active, lang, onToast, onClick }) => {
|
|
119606
119753
|
const [setRef, inView] = useInView();
|
|
119607
119754
|
const image = useAttachmentImage(item.attachment, inView);
|
|
119608
|
-
return (0, react_jsx_runtime.
|
|
119609
|
-
ref: setRef,
|
|
119610
|
-
type: "button",
|
|
119755
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
119611
119756
|
className: `dsh-ig-recent-item ${active ? "is-active" : ""}`,
|
|
119612
|
-
|
|
119613
|
-
|
|
119614
|
-
|
|
119615
|
-
className: "dsh-ig-recent-
|
|
119616
|
-
|
|
119617
|
-
|
|
119618
|
-
|
|
119619
|
-
|
|
119620
|
-
|
|
119621
|
-
|
|
119757
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
119758
|
+
ref: setRef,
|
|
119759
|
+
type: "button",
|
|
119760
|
+
className: "dsh-ig-recent-select",
|
|
119761
|
+
onClick,
|
|
119762
|
+
title: item.prompt,
|
|
119763
|
+
draggable: Boolean(image.blob?.size),
|
|
119764
|
+
onDragStart: (event) => {
|
|
119765
|
+
startGalleryImageDrag(event, item, image.blob);
|
|
119766
|
+
},
|
|
119767
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
119768
|
+
className: "dsh-ig-recent-thumb",
|
|
119769
|
+
children: image.url !== null ? (0, react_jsx_runtime.jsx)("img", {
|
|
119770
|
+
src: image.url,
|
|
119771
|
+
alt: "",
|
|
119772
|
+
loading: "lazy",
|
|
119773
|
+
draggable: false
|
|
119774
|
+
}) : (0, react_jsx_runtime.jsx)(ImagePlus, { size: 18 })
|
|
119775
|
+
})
|
|
119776
|
+
}), (0, react_jsx_runtime.jsx)(GalleryCanvasButton, {
|
|
119777
|
+
item,
|
|
119778
|
+
lang,
|
|
119779
|
+
disabled: !image.blob?.size,
|
|
119780
|
+
className: "dsh-ig-recent-send",
|
|
119781
|
+
onToast
|
|
119782
|
+
})]
|
|
119622
119783
|
});
|
|
119623
119784
|
};
|
|
119624
119785
|
const FavoriteFolderBar = ({ folders, active, onSelect, onDelete, deleteLabel }) => {
|
|
@@ -123457,6 +123618,7 @@ img.ProseMirror-separator {
|
|
|
123457
123618
|
}) : (0, react_jsx_runtime.jsx)("div", {
|
|
123458
123619
|
className: "dsh-ig-gallery-grid",
|
|
123459
123620
|
children: filteredItems.map((item, idx) => (0, react_jsx_runtime.jsx)(GalleryCard, {
|
|
123621
|
+
lang,
|
|
123460
123622
|
item,
|
|
123461
123623
|
index: idx,
|
|
123462
123624
|
isManageMode,
|
|
@@ -123841,7 +124003,7 @@ img.ProseMirror-separator {
|
|
|
123841
124003
|
]
|
|
123842
124004
|
});
|
|
123843
124005
|
};
|
|
123844
|
-
const GalleryCard = ({ item, index: _index, isManageMode, isSelected, t, onClick, onToggleSelect, onRequestDelete, onPreview: _onPreview, onBlobLoaded, onToast }) => {
|
|
124006
|
+
const GalleryCard = ({ lang, item, index: _index, isManageMode, isSelected, t, onClick, onToggleSelect, onRequestDelete, onPreview: _onPreview, onBlobLoaded, onToast }) => {
|
|
123845
124007
|
const [url, setUrl] = (0, react.useState)();
|
|
123846
124008
|
const [blob, setBlob] = (0, react.useState)();
|
|
123847
124009
|
const [loading, setLoading] = (0, react.useState)(true);
|
|
@@ -123931,11 +124093,23 @@ img.ProseMirror-separator {
|
|
|
123931
124093
|
className: "dsh-ig-gallery-card-img",
|
|
123932
124094
|
src: url,
|
|
123933
124095
|
alt: item.prompt,
|
|
123934
|
-
loading: "lazy"
|
|
124096
|
+
loading: "lazy",
|
|
124097
|
+
draggable: !isManageMode && Boolean(blob?.size),
|
|
124098
|
+
onDragStart: (event) => {
|
|
124099
|
+
if (isManageMode) event.preventDefault();
|
|
124100
|
+
else startGalleryImageDrag(event, item, blob);
|
|
124101
|
+
}
|
|
123935
124102
|
}),
|
|
123936
124103
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
123937
124104
|
className: "dsh-ig-card-toolbar",
|
|
123938
124105
|
children: [
|
|
124106
|
+
!isManageMode && (0, react_jsx_runtime.jsx)(GalleryCanvasButton, {
|
|
124107
|
+
item,
|
|
124108
|
+
lang,
|
|
124109
|
+
disabled: !blob?.size,
|
|
124110
|
+
className: "dsh-ig-tool-btn",
|
|
124111
|
+
onToast
|
|
124112
|
+
}),
|
|
123939
124113
|
(0, react_jsx_runtime.jsx)("button", {
|
|
123940
124114
|
type: "button",
|
|
123941
124115
|
className: "dsh-ig-tool-btn",
|
|
@@ -124229,12 +124403,48 @@ img.ProseMirror-separator {
|
|
|
124229
124403
|
}
|
|
124230
124404
|
//#endregion
|
|
124231
124405
|
//#region lib/types/client/tl/conversation-landings.js
|
|
124406
|
+
/** Keep one landing subscription while the optional UI service loads or unloads. */
|
|
124407
|
+
function createCanvasSessionSelection() {
|
|
124408
|
+
let current;
|
|
124409
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
124410
|
+
const notify = () => {
|
|
124411
|
+
for (const listener of listeners) listener();
|
|
124412
|
+
};
|
|
124413
|
+
return {
|
|
124414
|
+
getSnapshot: () => current?.getSnapshot(),
|
|
124415
|
+
subscribe: (listener) => {
|
|
124416
|
+
listeners.add(listener);
|
|
124417
|
+
return () => {
|
|
124418
|
+
listeners.delete(listener);
|
|
124419
|
+
};
|
|
124420
|
+
},
|
|
124421
|
+
bind(source) {
|
|
124422
|
+
current = source;
|
|
124423
|
+
const stop = source.subscribe(notify);
|
|
124424
|
+
notify();
|
|
124425
|
+
return () => {
|
|
124426
|
+
stop();
|
|
124427
|
+
if (current !== source) return;
|
|
124428
|
+
current = void 0;
|
|
124429
|
+
notify();
|
|
124430
|
+
};
|
|
124431
|
+
}
|
|
124432
|
+
};
|
|
124433
|
+
}
|
|
124434
|
+
function currentSessionId(sessions, selection) {
|
|
124435
|
+
const selected = selection?.getSnapshot();
|
|
124436
|
+
if (selected !== void 0) return selected.key || void 0;
|
|
124437
|
+
const snapshot = sessions.list.getSnapshot();
|
|
124438
|
+
if (snapshot.current) return snapshot.current;
|
|
124439
|
+
const mainViews = Object.values(snapshot.byId ?? {}).filter((row) => (row.retainedBy?.mainView ?? 0) > 0);
|
|
124440
|
+
return mainViews.length === 1 ? mainViews[0].id : void 0;
|
|
124441
|
+
}
|
|
124232
124442
|
/** Subscribe to live additions, never to card rendering or history replay. */
|
|
124233
|
-
function startConversationLandings(sessions) {
|
|
124443
|
+
function startConversationLandings(sessions, selection) {
|
|
124234
124444
|
let source;
|
|
124235
124445
|
let stopEvents;
|
|
124236
124446
|
const followCurrent = () => {
|
|
124237
|
-
const id = sessions
|
|
124447
|
+
const id = currentSessionId(sessions, selection);
|
|
124238
124448
|
const next = id === void 0 ? void 0 : sessions.binding(id)?.eventSource;
|
|
124239
124449
|
if (next === source) return;
|
|
124240
124450
|
stopEvents?.();
|
|
@@ -124263,15 +124473,20 @@ img.ProseMirror-separator {
|
|
|
124263
124473
|
});
|
|
124264
124474
|
};
|
|
124265
124475
|
const stopList = sessions.list.subscribe(followCurrent);
|
|
124476
|
+
const stopSelection = selection?.subscribe(followCurrent);
|
|
124266
124477
|
followCurrent();
|
|
124267
124478
|
return () => {
|
|
124268
124479
|
stopList();
|
|
124480
|
+
stopSelection?.();
|
|
124269
124481
|
stopEvents?.();
|
|
124270
124482
|
};
|
|
124271
124483
|
}
|
|
124272
124484
|
//#endregion
|
|
124273
124485
|
//#region lib/types/client/studio-style.js
|
|
124274
124486
|
const STUDIO_STYLE = `
|
|
124487
|
+
.dsh-ig-recent-select{display:block;width:100%;height:100%;padding:0;border:0;border-radius:inherit;background:transparent;cursor:pointer}
|
|
124488
|
+
.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}
|
|
124489
|
+
.dsh-ig-recent-send:disabled{opacity:.45;cursor:not-allowed}
|
|
124275
124490
|
.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
124491
|
.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
124492
|
body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a}
|
|
@@ -125221,7 +125436,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125221
125436
|
`;
|
|
125222
125437
|
//#endregion
|
|
125223
125438
|
//#region lib/types/client/index.js
|
|
125224
|
-
console.info(`[dsh-image-gen] canvas bundle 2026-10-
|
|
125439
|
+
console.info(`[dsh-image-gen] canvas bundle 2026-10-19T16:02:35.438Z`);
|
|
125225
125440
|
/** Right-sidebar tab-type registration id (DSH 0.1.5 `sidebarRightTabs`). */
|
|
125226
125441
|
const SIDEBAR_STUDIO_TAB_ID = "dsh-image-gen/studio";
|
|
125227
125442
|
/** The tab kind: a page type opened by kind, recognizing no resource address. */
|
|
@@ -125296,6 +125511,11 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125296
125511
|
reset: "重置",
|
|
125297
125512
|
resetTitle: "重置为默认官方地址",
|
|
125298
125513
|
endpointHintGoogle: "Google 官方地址或反代端点(全路径)。",
|
|
125514
|
+
googleProtocol: "请求协议",
|
|
125515
|
+
googleInteractions: "Interactions(默认)",
|
|
125516
|
+
googleNative: "原生 generateContent",
|
|
125517
|
+
saveGoogleProtocolFirst: "请求协议尚未保存,请先点击保存,再拉取模型或测试连接。",
|
|
125518
|
+
endpointHintGoogleNative: "填写 API 基础地址(如 https://example.com/v1beta);也兼容 Interactions 或 generateContent 完整地址。",
|
|
125299
125519
|
endpointHintOpenAI: "官方 api.openai.com 的 /v1 地址;中转站请使用下方「OpenAI 兼容」行。",
|
|
125300
125520
|
endpointHintOpenAICompat: "中转站/自建服务的 OpenAI 兼容 /v1 地址(必填),例如 https://your-relay.example.com/v1。",
|
|
125301
125521
|
editFormat: "图生图请求形态",
|
|
@@ -125461,6 +125681,11 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125461
125681
|
reset: "Reset",
|
|
125462
125682
|
resetTitle: "Reset to official default URL",
|
|
125463
125683
|
endpointHintGoogle: "Official Google endpoint or reverse proxy (full path).",
|
|
125684
|
+
googleProtocol: "Request protocol",
|
|
125685
|
+
googleInteractions: "Interactions (default)",
|
|
125686
|
+
googleNative: "Native generateContent",
|
|
125687
|
+
saveGoogleProtocolFirst: "Save the request protocol before fetching models or testing the connection.",
|
|
125688
|
+
endpointHintGoogleNative: "API base URL (e.g. https://example.com/v1beta). Full Interactions or generateContent URLs also work.",
|
|
125464
125689
|
endpointHintOpenAI: "Official api.openai.com /v1 base URL; for relays use the \"OpenAI-compatible\" row below.",
|
|
125465
125690
|
endpointHintOpenAICompat: "OpenAI-compatible /v1 base URL of your relay or self-hosted service (required), e.g. https://your-relay.example.com/v1.",
|
|
125466
125691
|
editFormat: "Edit request format",
|
|
@@ -125881,7 +126106,13 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
125881
126106
|
ctx.inject(["sessions"], (owner) => {
|
|
125882
126107
|
const sessions = owner.get("sessions");
|
|
125883
126108
|
if (typeof sessions?.binding !== "function" || typeof sessions.list?.subscribe !== "function") return;
|
|
125884
|
-
|
|
126109
|
+
const selection = createCanvasSessionSelection();
|
|
126110
|
+
owner.effect(() => startConversationLandings(sessions, selection), "dsh-image-gen: live canvas images");
|
|
126111
|
+
owner.inject(["uiSession"], (uiOwner) => {
|
|
126112
|
+
const current = uiOwner.get("uiSession")?.adapter?.current;
|
|
126113
|
+
if (typeof current?.getSnapshot !== "function" || typeof current.subscribe !== "function") return;
|
|
126114
|
+
uiOwner.effect(() => selection.bind(current), "dsh-image-gen: current canvas session");
|
|
126115
|
+
});
|
|
125885
126116
|
});
|
|
125886
126117
|
ctx.effect(() => {
|
|
125887
126118
|
const style = document.createElement("style");
|
|
@@ -126098,6 +126329,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126098
126329
|
expanded: false,
|
|
126099
126330
|
model: "",
|
|
126100
126331
|
baseURL: "",
|
|
126332
|
+
googleNative: false,
|
|
126101
126333
|
keyInput: "",
|
|
126102
126334
|
keyStatus: "checking",
|
|
126103
126335
|
keyInfo: void 0,
|
|
@@ -126187,6 +126419,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126187
126419
|
...emptyProviderRow(),
|
|
126188
126420
|
model: modelOf(provider, value),
|
|
126189
126421
|
baseURL: baseURLOf(provider, value),
|
|
126422
|
+
...provider === "google" ? { googleNative: value?.googleNative === true } : {},
|
|
126190
126423
|
...provider === "openai" ? { sizeTableText: editExtraTextOf(value?.openaiSizes) } : {},
|
|
126191
126424
|
...provider === "comfyui" ? {
|
|
126192
126425
|
workflows: resolveComfyUIWorkflows(value ?? {}),
|
|
@@ -126573,6 +126806,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126573
126806
|
if (provider === "openai") for (const tiers of Object.values(sizeTable)) for (const size of Object.values(tiers)) validateOfficialSize(row.model, size);
|
|
126574
126807
|
await saveSetting(modelFieldOf(provider), row.model);
|
|
126575
126808
|
await saveSetting(baseURLFieldOf(provider), row.baseURL);
|
|
126809
|
+
if (provider === "google") await saveSetting("googleNative", row.googleNative);
|
|
126576
126810
|
if (provider === "openai") await saveSetting("openaiSizes", sizeTable);
|
|
126577
126811
|
if (provider === "openai-compat") {
|
|
126578
126812
|
await saveSetting("openaiCompatEditFormat", row.editFormat);
|
|
@@ -126624,6 +126858,7 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126624
126858
|
const address = row.baseURL.trim();
|
|
126625
126859
|
if (address.length === 0) return t("endpointRequired");
|
|
126626
126860
|
if (address !== baseURLOf(provider, props.scope.getSnapshot().value).trim()) return t("saveEndpointFirst");
|
|
126861
|
+
if (provider === "google" && row.googleNative !== (props.scope.getSnapshot().value?.googleNative === true)) return t("saveGoogleProtocolFirst");
|
|
126627
126862
|
};
|
|
126628
126863
|
/** Localize the host's missing-address error while preserving upstream details. */
|
|
126629
126864
|
const providerErrorMessage = (message) => message === "Base URL is not configured" ? t("savedEndpointMissing") : message ?? t("testFailed");
|
|
@@ -126995,10 +127230,31 @@ body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a
|
|
|
126995
127230
|
}),
|
|
126996
127231
|
(0, react_jsx_runtime.jsx)("span", {
|
|
126997
127232
|
className: "dsh-ig-hint",
|
|
126998
|
-
children: t(CLOUD_HINT_KEYS[provider])
|
|
127233
|
+
children: t(provider === "google" && row.googleNative ? "endpointHintGoogleNative" : CLOUD_HINT_KEYS[provider])
|
|
126999
127234
|
})
|
|
127000
127235
|
]
|
|
127001
127236
|
}),
|
|
127237
|
+
provider === "google" ? (0, react_jsx_runtime.jsxs)("label", {
|
|
127238
|
+
className: "dsh-ig-field",
|
|
127239
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
127240
|
+
className: "dsh-ig-label",
|
|
127241
|
+
children: t("googleProtocol")
|
|
127242
|
+
}), (0, react_jsx_runtime.jsxs)("select", {
|
|
127243
|
+
className: "dsh-ig-input",
|
|
127244
|
+
value: row.googleNative ? "native" : "interactions",
|
|
127245
|
+
onChange: (event) => {
|
|
127246
|
+
updateRow(provider, { googleNative: event.target.value === "native" });
|
|
127247
|
+
},
|
|
127248
|
+
disabled: !settingsWritable,
|
|
127249
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
127250
|
+
value: "interactions",
|
|
127251
|
+
children: t("googleInteractions")
|
|
127252
|
+
}), (0, react_jsx_runtime.jsx)("option", {
|
|
127253
|
+
value: "native",
|
|
127254
|
+
children: t("googleNative")
|
|
127255
|
+
})]
|
|
127256
|
+
})]
|
|
127257
|
+
}) : null,
|
|
127002
127258
|
(0, react_jsx_runtime.jsxs)("label", {
|
|
127003
127259
|
className: "dsh-ig-field",
|
|
127004
127260
|
children: [
|