dsh-image-gen 0.4.0 → 0.5.0
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 +262 -90
- package/README.md +256 -94
- package/README.zh-CN.md +2 -171
- package/docs/assets/readme/chat-example.webp +0 -0
- package/docs/assets/readme/comfyui-workflows.webp +0 -0
- package/docs/assets/readme/gallery-management.webp +0 -0
- package/docs/assets/readme/hero-en.webp +0 -0
- package/docs/assets/readme/hero-zh.webp +0 -0
- package/docs/assets/readme/inspiration-library.webp +0 -0
- package/docs/assets/readme/multi-model-compare.webp +0 -0
- package/docs/assets/readme/provider-settings.webp +0 -0
- package/docs/assets/readme/regenerating.webp +0 -0
- package/docs/assets/readme/revision-switcher.webp +0 -0
- package/docs/assets/readme/studio-workbench.webp +0 -0
- package/docs/assets/readme/workflow-overview.webp +0 -0
- package/lib/client.js +1521 -395
- package/lib/client.js.map +1 -1
- package/lib/index.js +5584 -181
- package/lib/types/client/conversation-image-revisions.d.ts +1 -1
- package/lib/types/client/gallery-view.d.ts +8 -2
- package/lib/types/client/image-ref.d.ts +24 -1
- package/lib/types/client/index.d.ts +26 -2
- package/lib/types/client/provider-pill.d.ts +49 -0
- package/lib/types/client/studio-style.d.ts +1 -1
- package/lib/types/config.d.ts +39 -10
- package/lib/types/credentials.d.ts +15 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/openai-compatible.d.ts +1 -1
- package/lib/types/redact.d.ts +2 -0
- package/lib/types/shared.d.ts +37 -2
- package/lib/types/test-route.d.ts +73 -0
- package/package.json +14 -16
package/lib/client.js
CHANGED
|
@@ -17,20 +17,52 @@ window.__ModuleLoader__.load({
|
|
|
17
17
|
const INSPIRATION_ROUTE = "/plugins/dsh-image-gen/inspiration";
|
|
18
18
|
/** Browser route used for saving generated images to workspace on demand. */
|
|
19
19
|
const SAVE_WORKSPACE_ROUTE = "/plugins/dsh-image-gen/save-workspace";
|
|
20
|
+
/** Browser route the settings card probes provider connectivity through. */
|
|
21
|
+
const TEST_CONNECTION_ROUTE = "/plugins/dsh-image-gen/test";
|
|
20
22
|
/** Namespace persisted through DSH Settings. */
|
|
21
23
|
const IMAGE_GENERATION_NAMESPACE = "image-generation";
|
|
24
|
+
/** Supported providers. */
|
|
25
|
+
const IMAGE_PROVIDERS = [
|
|
26
|
+
"google",
|
|
27
|
+
"openai",
|
|
28
|
+
"openai-compat",
|
|
29
|
+
"seedream",
|
|
30
|
+
"dashscope",
|
|
31
|
+
"xai",
|
|
32
|
+
"zhipu",
|
|
33
|
+
"comfyui"
|
|
34
|
+
];
|
|
22
35
|
/** Providers supported by the first browser workbench release. */
|
|
23
36
|
const CLOUD_IMAGE_PROVIDERS = [
|
|
24
37
|
"google",
|
|
25
38
|
"openai",
|
|
39
|
+
"openai-compat",
|
|
26
40
|
"seedream",
|
|
27
|
-
"dashscope"
|
|
41
|
+
"dashscope",
|
|
42
|
+
"xai",
|
|
43
|
+
"zhipu"
|
|
28
44
|
];
|
|
45
|
+
/** The credential reference each cloud provider's API key is stored under. */
|
|
46
|
+
const CLOUD_CREDENTIAL_REFS = {
|
|
47
|
+
google: "GEMINI_API_KEY",
|
|
48
|
+
openai: "OPENAI_API_KEY",
|
|
49
|
+
"openai-compat": "DSH_IMAGE_GEN_OPENAI_COMPAT_KEY",
|
|
50
|
+
seedream: "ARK_API_KEY",
|
|
51
|
+
dashscope: "DASHSCOPE_API_KEY",
|
|
52
|
+
xai: "XAI_API_KEY",
|
|
53
|
+
zhipu: "ZHIPUAI_API_KEY"
|
|
54
|
+
};
|
|
55
|
+
/** The credential reference storing this provider's API key, when it uses one. */
|
|
56
|
+
function cloudCredentialRef(provider) {
|
|
57
|
+
return CLOUD_IMAGE_PROVIDERS.includes(provider) ? CLOUD_CREDENTIAL_REFS[provider] : void 0;
|
|
58
|
+
}
|
|
29
59
|
/** Default endpoints and base URLs. */
|
|
30
60
|
const DEFAULT_GOOGLE_ENDPOINT = "https://generativelanguage.googleapis.com/v1beta/interactions";
|
|
31
61
|
const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
32
62
|
const DEFAULT_SEEDREAM_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3";
|
|
33
63
|
const DEFAULT_DASHSCOPE_ENDPOINT = "https://dashscope.aliyuncs.com/api/v1";
|
|
64
|
+
const DEFAULT_XAI_BASE_URL = "https://api.x.ai/v1";
|
|
65
|
+
const DEFAULT_ZHIPU_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
|
34
66
|
const DEFAULT_COMFYUI_BASE_URL = "http://127.0.0.1:8188";
|
|
35
67
|
const DEFAULT_COMFYUI_TIMEOUT_MS = 3e5;
|
|
36
68
|
const DEFAULT_COMFYUI_WORKFLOW_LABEL = "API workflow";
|
|
@@ -39,6 +71,8 @@ window.__ModuleLoader__.load({
|
|
|
39
71
|
const DEFAULT_OPENAI_MODEL = "gpt-image-2";
|
|
40
72
|
const DEFAULT_SEEDREAM_MODEL = "doubao-seedream-5-0-260128";
|
|
41
73
|
const DEFAULT_DASHSCOPE_MODEL = "qwen-image-3.0";
|
|
74
|
+
const DEFAULT_XAI_MODEL = "grok-imagine-image";
|
|
75
|
+
const DEFAULT_ZHIPU_MODEL = "glm-image";
|
|
42
76
|
/** Named workflows, falling back to the legacy single-workflow fields when the list is empty. */
|
|
43
77
|
function resolveComfyUIWorkflows(source) {
|
|
44
78
|
const named = [];
|
|
@@ -85,15 +119,21 @@ window.__ModuleLoader__.load({
|
|
|
85
119
|
const DEFAULT_MODELS = {
|
|
86
120
|
google: DEFAULT_GOOGLE_MODEL,
|
|
87
121
|
openai: DEFAULT_OPENAI_MODEL,
|
|
122
|
+
"openai-compat": "",
|
|
88
123
|
seedream: DEFAULT_SEEDREAM_MODEL,
|
|
89
124
|
dashscope: DEFAULT_DASHSCOPE_MODEL,
|
|
125
|
+
xai: DEFAULT_XAI_MODEL,
|
|
126
|
+
zhipu: DEFAULT_ZHIPU_MODEL,
|
|
90
127
|
comfyui: DEFAULT_COMFYUI_WORKFLOW_LABEL
|
|
91
128
|
};
|
|
92
129
|
const DEFAULT_BASE_URLS = {
|
|
93
130
|
google: DEFAULT_GOOGLE_ENDPOINT,
|
|
94
131
|
openai: DEFAULT_OPENAI_BASE_URL,
|
|
132
|
+
"openai-compat": "",
|
|
95
133
|
seedream: DEFAULT_SEEDREAM_BASE_URL,
|
|
96
134
|
dashscope: DEFAULT_DASHSCOPE_ENDPOINT,
|
|
135
|
+
xai: DEFAULT_XAI_BASE_URL,
|
|
136
|
+
zhipu: DEFAULT_ZHIPU_BASE_URL,
|
|
97
137
|
comfyui: DEFAULT_COMFYUI_BASE_URL
|
|
98
138
|
};
|
|
99
139
|
//#endregion
|
|
@@ -1360,12 +1400,12 @@ window.__ModuleLoader__.load({
|
|
|
1360
1400
|
comparePartial: "{success} 个模型生成成功,{failed} 个失败",
|
|
1361
1401
|
comparing: "正在对比(共 {count} 个模型)…",
|
|
1362
1402
|
compareStart: "开始对比",
|
|
1363
|
-
saveToGallery: "
|
|
1364
|
-
saveSelected: "
|
|
1365
|
-
savedToGallery: "
|
|
1366
|
-
savedSelected: "
|
|
1367
|
-
inGallery: "
|
|
1368
|
-
needSelectResult: "
|
|
1403
|
+
saveToGallery: "保存",
|
|
1404
|
+
saveSelected: "保存({count})",
|
|
1405
|
+
savedToGallery: "已保存到画廊",
|
|
1406
|
+
savedSelected: "已保存 {count} 张图片",
|
|
1407
|
+
inGallery: "已保存",
|
|
1408
|
+
needSelectResult: "请先勾选要保存的图片",
|
|
1369
1409
|
retry: "重新加载",
|
|
1370
1410
|
configLoadFailed: "工作台配置加载失败,请检查服务后重试。",
|
|
1371
1411
|
noProvider: "请先在设置中配置至少一个云端图像 Provider 的 API Key。",
|
|
@@ -4267,7 +4307,7 @@ window.__ModuleLoader__.load({
|
|
|
4267
4307
|
ratio: "auto",
|
|
4268
4308
|
quality: normalized === "1K" || normalized === "4K" ? normalized : "2K"
|
|
4269
4309
|
};
|
|
4270
|
-
if (provider === "openai") return {
|
|
4310
|
+
if (provider === "openai" || provider === "openai-compat" || provider === "xai" || provider === "zhipu") return {
|
|
4271
4311
|
ratio: ratioFromSize(normalized, "x"),
|
|
4272
4312
|
quality: "standard"
|
|
4273
4313
|
};
|
|
@@ -4309,9 +4349,12 @@ window.__ModuleLoader__.load({
|
|
|
4309
4349
|
tabTasks: "任务",
|
|
4310
4350
|
filterAllProviders: "全部提供商",
|
|
4311
4351
|
filterGoogle: "Google Gemini",
|
|
4312
|
-
filterOpenAI: "OpenAI
|
|
4352
|
+
filterOpenAI: "OpenAI",
|
|
4353
|
+
filterOpenAICompat: "OpenAI 兼容",
|
|
4313
4354
|
filterSeedream: "字节 Seedream",
|
|
4314
4355
|
filterDashScope: "阿里 DashScope",
|
|
4356
|
+
filterXAI: "xAI Grok",
|
|
4357
|
+
filterZhipu: "智谱 GLM",
|
|
4315
4358
|
filterComfyUI: "本地 ComfyUI",
|
|
4316
4359
|
filterAllModels: "全部模型",
|
|
4317
4360
|
filterAllRatios: "全部比例",
|
|
@@ -4391,9 +4434,12 @@ window.__ModuleLoader__.load({
|
|
|
4391
4434
|
tabTasks: "Tasks",
|
|
4392
4435
|
filterAllProviders: "All Providers",
|
|
4393
4436
|
filterGoogle: "Google Gemini",
|
|
4394
|
-
filterOpenAI: "OpenAI
|
|
4437
|
+
filterOpenAI: "OpenAI",
|
|
4438
|
+
filterOpenAICompat: "OpenAI-compatible",
|
|
4395
4439
|
filterSeedream: "ByteDance Seedream",
|
|
4396
4440
|
filterDashScope: "Aliyun DashScope",
|
|
4441
|
+
filterXAI: "xAI Grok",
|
|
4442
|
+
filterZhipu: "Zhipu GLM",
|
|
4397
4443
|
filterComfyUI: "Local ComfyUI",
|
|
4398
4444
|
filterAllModels: "All Models",
|
|
4399
4445
|
filterAllRatios: "All Ratios",
|
|
@@ -5079,6 +5125,10 @@ window.__ModuleLoader__.load({
|
|
|
5079
5125
|
value: "openai",
|
|
5080
5126
|
children: t("filterOpenAI")
|
|
5081
5127
|
}),
|
|
5128
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
5129
|
+
value: "openai-compat",
|
|
5130
|
+
children: t("filterOpenAICompat")
|
|
5131
|
+
}),
|
|
5082
5132
|
(0, react_jsx_runtime.jsx)("option", {
|
|
5083
5133
|
value: "seedream",
|
|
5084
5134
|
children: t("filterSeedream")
|
|
@@ -5087,6 +5137,14 @@ window.__ModuleLoader__.load({
|
|
|
5087
5137
|
value: "dashscope",
|
|
5088
5138
|
children: t("filterDashScope")
|
|
5089
5139
|
}),
|
|
5140
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
5141
|
+
value: "xai",
|
|
5142
|
+
children: t("filterXAI")
|
|
5143
|
+
}),
|
|
5144
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
5145
|
+
value: "zhipu",
|
|
5146
|
+
children: t("filterZhipu")
|
|
5147
|
+
}),
|
|
5090
5148
|
(0, react_jsx_runtime.jsx)("option", {
|
|
5091
5149
|
value: "comfyui",
|
|
5092
5150
|
children: t("filterComfyUI")
|
|
@@ -5872,7 +5930,7 @@ window.__ModuleLoader__.load({
|
|
|
5872
5930
|
@keyframes dshIgPulse{50%{transform:scale(1.06);box-shadow:0 0 0 16px rgba(47,100,245,.025)}}
|
|
5873
5931
|
.dsh-ig-workbench-toast{position:fixed;bottom:28px;left:50%;transform:translateX(-50%);background:rgba(15,23,42,0.88);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);color:#fff;padding:8px 18px;border-radius:10px;font-size:12.5px;font-weight:500;box-shadow:0 12px 32px rgba(0,0,0,0.3);z-index:99999;animation:dshIgFade .15s ease-out;pointer-events:none}
|
|
5874
5932
|
@keyframes dshIgFade{from{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%,0)}}
|
|
5875
|
-
@media(max-width:1120px){.dsh-ig-workbench-grid{grid-template-columns:190px minmax(360px,1fr) 300px}.dsh-ig-result-actions button
|
|
5933
|
+
@media(max-width:1120px){.dsh-ig-workbench-grid{grid-template-columns:190px minmax(360px,1fr) 300px}.dsh-ig-result-actions button,.dsh-ig-result-strip button{padding:0 7px;font-size:10px;gap:4px}.dsh-ig-result-actions>div,.dsh-ig-result-strip>div{gap:5px}}
|
|
5876
5934
|
@media(max-width:900px){.dsh-ig-gallery-page-body.is-workbench{height:auto;overflow:auto}.dsh-ig-workbench{height:auto;min-height:100%;overflow:visible;padding:12px}.dsh-ig-workbench-heading{height:auto;padding-bottom:12px;align-items:center}.dsh-ig-provider-quick>span{display:none}.dsh-ig-workbench-grid{height:auto;display:flex;flex:none;flex-direction:column;overflow:visible}.dsh-ig-recent-panel{height:auto;overflow:hidden;border-right:0;border-bottom:1px solid var(--ig-line)}.dsh-ig-recent-scroll{height:auto;display:flex;overflow-x:auto;overflow-y:hidden;padding:8px}.dsh-ig-recent-item{min-width:220px}.dsh-ig-canvas-column{height:auto;min-height:560px}.dsh-ig-generate-panel{height:auto;border-left:0;border-top:1px solid var(--ig-line);min-height:560px}.dsh-ig-generator-form{height:auto;overflow:visible}.dsh-ig-canvas{height:auto;min-height:360px}}
|
|
5877
5935
|
@media(max-width:560px){.dsh-ig-workbench-heading>div{display:block}.dsh-ig-workbench-heading h1{font-size:15px}.dsh-ig-provider-quick select{min-width:128px;max-width:150px}.dsh-ig-canvas{padding:12px;min-height:300px}.dsh-ig-result-strip,.dsh-ig-result-actions{align-items:flex-start;flex-direction:column}.dsh-ig-result-strip>div,.dsh-ig-result-actions>div{width:100%}.dsh-ig-result-strip button,.dsh-ig-result-actions button{flex:1;justify-content:center}.dsh-ig-result-actions button span{display:inline}.dsh-ig-field-grid{grid-template-columns:1fr}.dsh-ig-result-meta span+span:before{display:none}}
|
|
5878
5936
|
@media(prefers-reduced-motion:reduce){.dsh-ig-workbench *{scroll-behavior:auto!important;animation-duration:.01ms!important;transition-duration:.01ms!important}}
|
|
@@ -6137,7 +6195,7 @@ window.__ModuleLoader__.load({
|
|
|
6137
6195
|
function isRevision(value) {
|
|
6138
6196
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
6139
6197
|
const candidate = value;
|
|
6140
|
-
return isAttachment(candidate.attachment) &&
|
|
6198
|
+
return isAttachment(candidate.attachment) && typeof candidate.provider === "string" && CLOUD_IMAGE_PROVIDERS.includes(candidate.provider) && typeof candidate.prompt === "string" && typeof candidate.model === "string" && typeof candidate.output === "string" && typeof candidate.createdAt === "number" && Number.isFinite(candidate.createdAt) && typeof candidate.ratio === "string" && typeof candidate.quality === "string";
|
|
6141
6199
|
}
|
|
6142
6200
|
function isAttachment(value) {
|
|
6143
6201
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
@@ -6145,33 +6203,388 @@ window.__ModuleLoader__.load({
|
|
|
6145
6203
|
return typeof candidate.attachmentId === "string" && (candidate.mediaType === "image/png" || candidate.mediaType === "image/jpeg" || candidate.mediaType === "image/webp" || candidate.mediaType === "image/gif") && typeof candidate.bytes === "number" && typeof candidate.width === "number" && typeof candidate.height === "number";
|
|
6146
6204
|
}
|
|
6147
6205
|
//#endregion
|
|
6148
|
-
//#region lib/types/client/
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6206
|
+
//#region lib/types/client/provider-pill.js
|
|
6207
|
+
/**
|
|
6208
|
+
* Composer tool-row pill: switch the default image provider without leaving
|
|
6209
|
+
* the chat. Registered into the official 'conversation.input.right' slot; the
|
|
6210
|
+
* write path is the same `provider` settings field the settings card uses, so
|
|
6211
|
+
* the two views can never disagree.
|
|
6212
|
+
*/
|
|
6213
|
+
const PILL_DICT = {
|
|
6214
|
+
zh: {
|
|
6215
|
+
pillLabel: "生图",
|
|
6216
|
+
menuTitle: "生图模型",
|
|
6217
|
+
keyConfigured: "Key 已配置",
|
|
6218
|
+
keyMissing: "未配置 Key",
|
|
6219
|
+
noKeyNeeded: "无需 Key",
|
|
6220
|
+
noWorkflow: "未导入工作流",
|
|
6221
|
+
readOnly: "图像设置为只读,无法在此切换",
|
|
6222
|
+
switchFailed: "切换失败"
|
|
6223
|
+
},
|
|
6224
|
+
en: {
|
|
6225
|
+
pillLabel: "Image",
|
|
6226
|
+
menuTitle: "Image model",
|
|
6227
|
+
keyConfigured: "Key configured",
|
|
6228
|
+
keyMissing: "No key",
|
|
6229
|
+
noKeyNeeded: "No key needed",
|
|
6230
|
+
noWorkflow: "No workflow",
|
|
6231
|
+
readOnly: "Image settings are read-only; switch them in the config source",
|
|
6232
|
+
switchFailed: "Switch failed"
|
|
6233
|
+
}
|
|
6234
|
+
};
|
|
6235
|
+
/** Short row labels; the settings card keeps the longer descriptive names. */
|
|
6236
|
+
const PILL_PROVIDER_LABELS = {
|
|
6237
|
+
google: "Gemini",
|
|
6238
|
+
openai: "OpenAI",
|
|
6239
|
+
"openai-compat": "OpenAI 兼容",
|
|
6240
|
+
seedream: "Seedream",
|
|
6241
|
+
dashscope: "DashScope",
|
|
6242
|
+
xai: "Grok",
|
|
6243
|
+
zhipu: "智谱 GLM",
|
|
6244
|
+
comfyui: "ComfyUI"
|
|
6154
6245
|
};
|
|
6246
|
+
/** Whether the user opted into the composer pill; hidden (not merely inert) when off. */
|
|
6247
|
+
function pillVisible(value) {
|
|
6248
|
+
return value?.showProviderPill === true;
|
|
6249
|
+
}
|
|
6250
|
+
/** Model (or ComfyUI workflow) a provider row will use with the persisted settings. */
|
|
6251
|
+
function pillModelOf(provider, value) {
|
|
6252
|
+
if (provider === "comfyui") {
|
|
6253
|
+
const workflow = activeComfyUIWorkflow(value ?? {});
|
|
6254
|
+
return workflow === void 0 ? "" : workflow.name;
|
|
6255
|
+
}
|
|
6256
|
+
const stored = provider === "google" ? value?.googleModel : provider === "openai" ? value?.openaiModel : provider === "openai-compat" ? value?.openaiCompatModel : provider === "seedream" ? value?.seedreamModel : provider === "dashscope" ? value?.dashscopeModel : provider === "xai" ? value?.xaiModel : value?.zhipuModel;
|
|
6257
|
+
return typeof stored === "string" && stored.length > 0 ? stored : DEFAULT_MODELS[provider];
|
|
6258
|
+
}
|
|
6259
|
+
/** One fixed-position provider menu anchored to the pill button. */
|
|
6260
|
+
function ImageProviderPill(props) {
|
|
6261
|
+
const [snapshot, setSnapshot] = (0, react.useState)(() => props.scope.getSnapshot());
|
|
6262
|
+
const [lang, setLang] = (0, react.useState)(() => props.locale?.getSnapshot?.()?.active?.startsWith("en") ? "en" : "zh");
|
|
6263
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
6264
|
+
const [pending, setPending] = (0, react.useState)(void 0);
|
|
6265
|
+
const [error, setError] = (0, react.useState)("");
|
|
6266
|
+
const [dots, setDots] = (0, react.useState)({
|
|
6267
|
+
google: "unknown",
|
|
6268
|
+
openai: "unknown",
|
|
6269
|
+
"openai-compat": "unknown",
|
|
6270
|
+
seedream: "unknown",
|
|
6271
|
+
dashscope: "unknown",
|
|
6272
|
+
xai: "unknown",
|
|
6273
|
+
zhipu: "unknown"
|
|
6274
|
+
});
|
|
6275
|
+
const [keyTick, setKeyTick] = (0, react.useState)(0);
|
|
6276
|
+
const buttonRef = (0, react.useRef)(null);
|
|
6277
|
+
const [menuStyle, setMenuStyle] = (0, react.useState)(null);
|
|
6278
|
+
(0, react.useEffect)(() => props.scope.subscribe(() => {
|
|
6279
|
+
setSnapshot(props.scope.getSnapshot());
|
|
6280
|
+
}), [props.scope]);
|
|
6281
|
+
(0, react.useEffect)(() => props.locale?.subscribe?.(() => {
|
|
6282
|
+
setLang(props.locale?.getSnapshot?.()?.active?.startsWith("en") ? "en" : "zh");
|
|
6283
|
+
}), [props.locale]);
|
|
6284
|
+
(0, react.useEffect)(() => props.credentialEvents?.listen(() => {
|
|
6285
|
+
setKeyTick((tick) => tick + 1);
|
|
6286
|
+
}), [props.credentialEvents]);
|
|
6287
|
+
(0, react.useEffect)(() => {
|
|
6288
|
+
let active = true;
|
|
6289
|
+
const refs = [];
|
|
6290
|
+
for (const provider of CLOUD_IMAGE_PROVIDERS) {
|
|
6291
|
+
const ref = cloudCredentialRef(provider);
|
|
6292
|
+
if (ref !== void 0) refs.push(ref);
|
|
6293
|
+
}
|
|
6294
|
+
props.credentials.describe(refs).then((response) => {
|
|
6295
|
+
if (!active) return;
|
|
6296
|
+
const next = {};
|
|
6297
|
+
for (const provider of CLOUD_IMAGE_PROVIDERS) {
|
|
6298
|
+
const info = response.ok ? response.value?.[cloudCredentialRef(provider)] : void 0;
|
|
6299
|
+
next[provider] = response.ok ? info?.configured ? "configured" : "missing" : "unknown";
|
|
6300
|
+
}
|
|
6301
|
+
setDots(next);
|
|
6302
|
+
}).catch(() => {
|
|
6303
|
+
if (!active) return;
|
|
6304
|
+
setDots({
|
|
6305
|
+
google: "unknown",
|
|
6306
|
+
openai: "unknown",
|
|
6307
|
+
"openai-compat": "unknown",
|
|
6308
|
+
seedream: "unknown",
|
|
6309
|
+
dashscope: "unknown",
|
|
6310
|
+
xai: "unknown",
|
|
6311
|
+
zhipu: "unknown"
|
|
6312
|
+
});
|
|
6313
|
+
});
|
|
6314
|
+
return () => {
|
|
6315
|
+
active = false;
|
|
6316
|
+
};
|
|
6317
|
+
}, [props.credentials, keyTick]);
|
|
6318
|
+
const t = (keyName) => (lang === "en" ? PILL_DICT.en : PILL_DICT.zh)[keyName];
|
|
6319
|
+
const current = snapshot.value?.provider ?? "google";
|
|
6320
|
+
const writable = snapshot.writable;
|
|
6321
|
+
(0, react.useEffect)(() => {
|
|
6322
|
+
if (!open) {
|
|
6323
|
+
setMenuStyle(null);
|
|
6324
|
+
return;
|
|
6325
|
+
}
|
|
6326
|
+
const rect = buttonRef.current?.getBoundingClientRect();
|
|
6327
|
+
if (rect !== void 0) setMenuStyle({
|
|
6328
|
+
left: rect.left,
|
|
6329
|
+
bottom: window.innerHeight - rect.top + 6
|
|
6330
|
+
});
|
|
6331
|
+
}, [open]);
|
|
6332
|
+
(0, react.useEffect)(() => {
|
|
6333
|
+
if (!open) return;
|
|
6334
|
+
const onPointerDown = (event) => {
|
|
6335
|
+
const target = event.target;
|
|
6336
|
+
if (target instanceof Node && buttonRef.current !== null && !buttonRef.current.contains(target) && !(target instanceof Element && target.closest(".dsh-ig-pill-menu") !== null)) setOpen(false);
|
|
6337
|
+
};
|
|
6338
|
+
const onKeyDown = (event) => {
|
|
6339
|
+
if (event.key === "Escape") setOpen(false);
|
|
6340
|
+
};
|
|
6341
|
+
const onReflow = () => {
|
|
6342
|
+
setOpen(false);
|
|
6343
|
+
};
|
|
6344
|
+
document.addEventListener("mousedown", onPointerDown, true);
|
|
6345
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
6346
|
+
window.addEventListener("resize", onReflow);
|
|
6347
|
+
window.addEventListener("scroll", onReflow, true);
|
|
6348
|
+
return () => {
|
|
6349
|
+
document.removeEventListener("mousedown", onPointerDown, true);
|
|
6350
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
6351
|
+
window.removeEventListener("resize", onReflow);
|
|
6352
|
+
window.removeEventListener("scroll", onReflow, true);
|
|
6353
|
+
};
|
|
6354
|
+
}, [open]);
|
|
6355
|
+
if (!pillVisible(snapshot.value)) return null;
|
|
6356
|
+
/** Same write path as the settings card: one field, one disposer, no implicit side effects. */
|
|
6357
|
+
const select = (provider) => {
|
|
6358
|
+
if (pending !== void 0 || provider === current) {
|
|
6359
|
+
setOpen(false);
|
|
6360
|
+
return;
|
|
6361
|
+
}
|
|
6362
|
+
setError("");
|
|
6363
|
+
setPending(provider);
|
|
6364
|
+
props.scope.set("provider", provider).then(() => {
|
|
6365
|
+
setOpen(false);
|
|
6366
|
+
}).catch((cause) => {
|
|
6367
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
6368
|
+
}).finally(() => {
|
|
6369
|
+
setPending(void 0);
|
|
6370
|
+
});
|
|
6371
|
+
};
|
|
6372
|
+
const dotClassOf = (provider) => {
|
|
6373
|
+
if (provider === "comfyui") return "dsh-ig-pill-dot-neutral";
|
|
6374
|
+
const dot = dots[provider];
|
|
6375
|
+
return dot === "configured" ? "dsh-ig-pill-dot-ok" : dot === "missing" ? "dsh-ig-pill-dot-missing" : "dsh-ig-pill-dot-neutral";
|
|
6376
|
+
};
|
|
6377
|
+
const subtitleOf = (provider) => {
|
|
6378
|
+
if (provider === "comfyui") {
|
|
6379
|
+
const workflow = pillModelOf(provider, snapshot.value);
|
|
6380
|
+
return workflow.length > 0 ? `${t("noKeyNeeded")} · ${workflow}` : `${t("noKeyNeeded")} · ${t("noWorkflow")}`;
|
|
6381
|
+
}
|
|
6382
|
+
const dot = dots[provider];
|
|
6383
|
+
const model = pillModelOf(provider, snapshot.value);
|
|
6384
|
+
if (dot === "configured") return `${t("keyConfigured")} · ${model}`;
|
|
6385
|
+
if (dot === "missing") return `${t("keyMissing")} · ${model}`;
|
|
6386
|
+
return model;
|
|
6387
|
+
};
|
|
6388
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
6389
|
+
className: "dsh-ig-pill-root",
|
|
6390
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
6391
|
+
type: "button",
|
|
6392
|
+
ref: buttonRef,
|
|
6393
|
+
className: `dsh-ig-pill-button${open ? " dsh-ig-pill-button-open" : ""}`,
|
|
6394
|
+
"aria-haspopup": "menu",
|
|
6395
|
+
"aria-expanded": open,
|
|
6396
|
+
title: writable ? t("menuTitle") : t("readOnly"),
|
|
6397
|
+
disabled: !writable,
|
|
6398
|
+
onClick: () => {
|
|
6399
|
+
setOpen((value) => !value);
|
|
6400
|
+
},
|
|
6401
|
+
children: [
|
|
6402
|
+
(0, react_jsx_runtime.jsxs)("svg", {
|
|
6403
|
+
className: "dsh-ig-pill-icon",
|
|
6404
|
+
width: "13",
|
|
6405
|
+
height: "13",
|
|
6406
|
+
viewBox: "0 0 16 16",
|
|
6407
|
+
fill: "none",
|
|
6408
|
+
stroke: "currentColor",
|
|
6409
|
+
strokeWidth: "1.6",
|
|
6410
|
+
strokeLinecap: "round",
|
|
6411
|
+
strokeLinejoin: "round",
|
|
6412
|
+
"aria-hidden": "true",
|
|
6413
|
+
children: [
|
|
6414
|
+
(0, react_jsx_runtime.jsx)("rect", {
|
|
6415
|
+
x: "1.5",
|
|
6416
|
+
y: "2.5",
|
|
6417
|
+
width: "13",
|
|
6418
|
+
height: "11",
|
|
6419
|
+
rx: "2"
|
|
6420
|
+
}),
|
|
6421
|
+
(0, react_jsx_runtime.jsx)("circle", {
|
|
6422
|
+
cx: "5.5",
|
|
6423
|
+
cy: "6.5",
|
|
6424
|
+
r: "1.3"
|
|
6425
|
+
}),
|
|
6426
|
+
(0, react_jsx_runtime.jsx)("path", { d: "M14.5 10.5l-3.2-3.2-6.3 6.2" })
|
|
6427
|
+
]
|
|
6428
|
+
}),
|
|
6429
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
6430
|
+
className: "dsh-ig-pill-provider",
|
|
6431
|
+
children: PILL_PROVIDER_LABELS[current]
|
|
6432
|
+
}),
|
|
6433
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
6434
|
+
className: `dsh-ig-pill-caret${open ? " dsh-ig-pill-caret-open" : ""}`,
|
|
6435
|
+
"aria-hidden": "true",
|
|
6436
|
+
children: (0, react_jsx_runtime.jsx)("svg", {
|
|
6437
|
+
width: "10",
|
|
6438
|
+
height: "10",
|
|
6439
|
+
viewBox: "0 0 16 16",
|
|
6440
|
+
fill: "none",
|
|
6441
|
+
stroke: "currentColor",
|
|
6442
|
+
strokeWidth: "2",
|
|
6443
|
+
strokeLinecap: "round",
|
|
6444
|
+
strokeLinejoin: "round",
|
|
6445
|
+
children: (0, react_jsx_runtime.jsx)("path", { d: "M4 10l4-4 4 4" })
|
|
6446
|
+
})
|
|
6447
|
+
})
|
|
6448
|
+
]
|
|
6449
|
+
}), open && menuStyle !== null ? (0, react_jsx_runtime.jsxs)("div", {
|
|
6450
|
+
className: "dsh-ig-pill-menu",
|
|
6451
|
+
role: "menu",
|
|
6452
|
+
"aria-label": t("menuTitle"),
|
|
6453
|
+
style: menuStyle,
|
|
6454
|
+
children: [
|
|
6455
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
6456
|
+
className: "dsh-ig-pill-menu-title",
|
|
6457
|
+
children: t("menuTitle")
|
|
6458
|
+
}),
|
|
6459
|
+
IMAGE_PROVIDERS.map((provider) => (0, react_jsx_runtime.jsxs)("button", {
|
|
6460
|
+
type: "button",
|
|
6461
|
+
role: "menuitemradio",
|
|
6462
|
+
"aria-checked": provider === current,
|
|
6463
|
+
className: `dsh-ig-pill-option${provider === current ? " dsh-ig-pill-option-active" : ""}`,
|
|
6464
|
+
disabled: pending !== void 0,
|
|
6465
|
+
onClick: () => {
|
|
6466
|
+
select(provider);
|
|
6467
|
+
},
|
|
6468
|
+
children: [
|
|
6469
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
6470
|
+
className: `dsh-ig-pill-dot ${dotClassOf(provider)}`,
|
|
6471
|
+
"aria-hidden": "true"
|
|
6472
|
+
}),
|
|
6473
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
6474
|
+
className: "dsh-ig-pill-option-text",
|
|
6475
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
6476
|
+
className: "dsh-ig-pill-option-name",
|
|
6477
|
+
children: PILL_PROVIDER_LABELS[provider]
|
|
6478
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
6479
|
+
className: "dsh-ig-pill-option-sub",
|
|
6480
|
+
children: subtitleOf(provider)
|
|
6481
|
+
})]
|
|
6482
|
+
}),
|
|
6483
|
+
provider === current ? (0, react_jsx_runtime.jsx)("span", {
|
|
6484
|
+
className: "dsh-ig-pill-check",
|
|
6485
|
+
"aria-hidden": "true",
|
|
6486
|
+
children: (0, react_jsx_runtime.jsx)("svg", {
|
|
6487
|
+
width: "13",
|
|
6488
|
+
height: "13",
|
|
6489
|
+
viewBox: "0 0 16 16",
|
|
6490
|
+
fill: "none",
|
|
6491
|
+
stroke: "currentColor",
|
|
6492
|
+
strokeWidth: "2.2",
|
|
6493
|
+
strokeLinecap: "round",
|
|
6494
|
+
strokeLinejoin: "round",
|
|
6495
|
+
children: (0, react_jsx_runtime.jsx)("path", { d: "M2.5 8.5l3.5 3.5 7-8" })
|
|
6496
|
+
})
|
|
6497
|
+
}) : null
|
|
6498
|
+
]
|
|
6499
|
+
}, provider)),
|
|
6500
|
+
error.length > 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
6501
|
+
className: "dsh-ig-pill-error",
|
|
6502
|
+
role: "alert",
|
|
6503
|
+
children: [
|
|
6504
|
+
t("switchFailed"),
|
|
6505
|
+
":",
|
|
6506
|
+
error
|
|
6507
|
+
]
|
|
6508
|
+
}) : null
|
|
6509
|
+
]
|
|
6510
|
+
}) : null]
|
|
6511
|
+
});
|
|
6512
|
+
}
|
|
6513
|
+
/** Styles for the pill and its fixed-position menu; injected by the client entry. */
|
|
6514
|
+
const PROVIDER_PILL_STYLE = `
|
|
6515
|
+
.dsh-ig-pill-root{position:relative;display:inline-flex;align-items:center;height:26px}
|
|
6516
|
+
.dsh-ig-pill-button{display:inline-flex;align-items:center;gap:5px;height:26px;padding:0 8px 0 7px;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:13px;background:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-label-secondary,#4b5563);font:inherit;font-size:12px;line-height:1;cursor:pointer;transition:border-color .15s,background .15s,color .15s;-webkit-user-select:none;user-select:none}
|
|
6517
|
+
.dsh-ig-pill-button:hover:not(:disabled){border-color:var(--dsw-alias-label-dimmed,#9ca3af);color:var(--dsw-alias-label-primary,#111827)}
|
|
6518
|
+
.dsh-ig-pill-button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4c78ff);outline-offset:1px}
|
|
6519
|
+
.dsh-ig-pill-button:disabled{opacity:.5;cursor:not-allowed}
|
|
6520
|
+
.dsh-ig-pill-button-open{border-color:var(--dsw-alias-brand-primary,#4c78ff);color:var(--dsw-alias-label-primary,#111827)}
|
|
6521
|
+
.dsh-ig-pill-icon{flex:none;color:var(--dsw-alias-brand-primary,#4c78ff)}
|
|
6522
|
+
.dsh-ig-pill-provider{max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
6523
|
+
.dsh-ig-pill-caret{display:inline-flex;flex:none;transition:transform .15s}
|
|
6524
|
+
.dsh-ig-pill-caret-open{transform:rotate(180deg)}
|
|
6525
|
+
.dsh-ig-pill-menu{position:fixed;z-index:1000;min-width:264px;max-width:min(320px,calc(100vw - 24px));padding:6px;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;background:var(--dsw-alias-bg-layer-3,#fff);box-shadow:0 12px 32px rgba(0,0,0,.16),0 2px 8px rgba(0,0,0,.08);max-height:min(320px,calc(100vh - 48px));overflow-y:auto}
|
|
6526
|
+
.dsh-ig-pill-menu-title{padding:6px 8px 4px;font-size:11px;font-weight:600;color:var(--dsw-alias-label-tertiary,#6b7280)}
|
|
6527
|
+
.dsh-ig-pill-option{display:flex;width:100%;align-items:center;gap:9px;padding:7px 8px;border:0;border-radius:8px;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer}
|
|
6528
|
+
.dsh-ig-pill-option:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2,#f3f4f6)}
|
|
6529
|
+
.dsh-ig-pill-option:disabled{opacity:.6;cursor:default}
|
|
6530
|
+
.dsh-ig-pill-option:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4c78ff);outline-offset:-2px}
|
|
6531
|
+
.dsh-ig-pill-option-active{background:var(--dsw-alias-brand-primary-soft,rgba(76,120,255,.10))}
|
|
6532
|
+
.dsh-ig-pill-dot{flex:none;width:7px;height:7px;border-radius:50%}
|
|
6533
|
+
.dsh-ig-pill-dot-ok{background:#22c55e}
|
|
6534
|
+
.dsh-ig-pill-dot-missing{background:var(--dsw-alias-border-l2,#d1d5db)}
|
|
6535
|
+
.dsh-ig-pill-dot-neutral{background:var(--dsw-alias-brand-primary,#4c78ff)}
|
|
6536
|
+
.dsh-ig-pill-option-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
|
|
6537
|
+
.dsh-ig-pill-option-name{font-size:12.5px;font-weight:500;color:var(--dsw-alias-label-primary,#111827);line-height:1.2}
|
|
6538
|
+
.dsh-ig-pill-option-sub{font-size:11px;color:var(--dsw-alias-label-tertiary,#6b7280);line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
6539
|
+
.dsh-ig-pill-check{flex:none;color:var(--dsw-alias-brand-primary,#4c78ff)}
|
|
6540
|
+
.dsh-ig-pill-error{margin-top:4px;padding:6px 8px;border-radius:8px;background:rgba(239,68,68,.08);color:#ef4444;font-size:11.5px;line-height:1.4;word-break:break-all}
|
|
6541
|
+
`;
|
|
6542
|
+
//#endregion
|
|
6543
|
+
//#region lib/types/client/index.js
|
|
6155
6544
|
const DICT = {
|
|
6156
6545
|
zh: {
|
|
6157
6546
|
title: "图像生成",
|
|
6158
|
-
description: "
|
|
6159
|
-
|
|
6547
|
+
description: "配置各 Provider 的 Key 与模型,并选择默认 Provider。",
|
|
6548
|
+
defaultProvider: "默认 Provider",
|
|
6549
|
+
defaultProviderHint: "Agent 生图默认使用;Studio 与工具调用可临时指定其他 Provider。",
|
|
6550
|
+
settingsReadOnly: "设置由配置文件提供,只读;如需修改请编辑对应的配置来源。",
|
|
6160
6551
|
providerGoogle: "Google Gemini",
|
|
6161
|
-
providerOpenAI: "OpenAI
|
|
6552
|
+
providerOpenAI: "OpenAI",
|
|
6553
|
+
providerOpenAICompat: "OpenAI 兼容(中转站)",
|
|
6162
6554
|
providerSeedream: "字节 Seedream",
|
|
6163
6555
|
providerDashScope: "阿里 DashScope (通义万相 / Qwen)",
|
|
6556
|
+
providerXAI: "xAI Grok Imagine",
|
|
6557
|
+
providerZhipu: "智谱 GLM-Image",
|
|
6164
6558
|
providerComfyUI: "本地 ComfyUI",
|
|
6165
6559
|
apiKeyLabel: "{provider} API Key",
|
|
6166
6560
|
apiKeyPlaceholder: "留空即可保留已配置的 Key",
|
|
6167
6561
|
apiKeyHint: "安全保存为 {key};页面不会读回明文。",
|
|
6562
|
+
keyReadOnly: "Key 由 {source} 提供且只读;请在该来源中修改。",
|
|
6563
|
+
badgeChecking: "检查中…",
|
|
6564
|
+
badgeConfigured: "Key 已配置",
|
|
6565
|
+
badgeMissing: "Key 未配置",
|
|
6566
|
+
badgeUnknown: "状态未知",
|
|
6567
|
+
comfyuiNoKey: "无需 API Key",
|
|
6568
|
+
testConnection: "测试连接",
|
|
6569
|
+
testing: "正在测试…",
|
|
6570
|
+
testOk: "连接成功",
|
|
6571
|
+
testFailed: "连接失败",
|
|
6572
|
+
testUnauthorized: "Key 无效或无权限",
|
|
6573
|
+
clearKey: "清除 Key",
|
|
6574
|
+
keyCleared: "已清除 Key",
|
|
6575
|
+
clearKeyFailed: "清除 Key 失败",
|
|
6576
|
+
saveKeyFailed: "保存 Key 失败",
|
|
6577
|
+
clearKeyUnsupported: "当前版本 DSH 不支持在此清除 Key,请到凭据管理中删除。",
|
|
6168
6578
|
endpoint: "接口地址",
|
|
6169
6579
|
reset: "重置",
|
|
6170
6580
|
resetTitle: "重置为默认官方地址",
|
|
6171
6581
|
endpointHintGoogle: "Google 官方地址或反代端点(全路径)。",
|
|
6172
|
-
endpointHintOpenAI: "
|
|
6582
|
+
endpointHintOpenAI: "官方 api.openai.com 的 /v1 地址;中转站请使用下方「OpenAI 兼容」行。",
|
|
6583
|
+
endpointHintOpenAICompat: "中转站/自建服务的 OpenAI 兼容 /v1 地址(必填),例如 https://your-relay.example.com/v1。",
|
|
6173
6584
|
endpointHintSeedream: "火山方舟兼容的 /api/v3 地址。",
|
|
6174
6585
|
endpointHintDashScope: "阿里云百炼 DashScope 官方接口地址。",
|
|
6586
|
+
endpointHintXAI: "xAI 官方 api.x.ai 的 /v1 地址。",
|
|
6587
|
+
endpointHintZhipu: "智谱开放平台 open.bigmodel.cn 的 /api/paas/v4 地址。",
|
|
6175
6588
|
endpointHintComfyUI: "正在运行且 DSH Host 可以访问的 ComfyUI 地址,默认使用本机 8188 端口。",
|
|
6176
6589
|
model: "模型",
|
|
6177
6590
|
workflow: "API Workflow 工作流",
|
|
@@ -6188,17 +6601,23 @@ window.__ModuleLoader__.load({
|
|
|
6188
6601
|
workflowDuplicateName: "工作流名称不能重复。",
|
|
6189
6602
|
timeout: "生成超时(秒)",
|
|
6190
6603
|
timeoutHint: "包括提交、等待和下载图片;默认 300 秒。",
|
|
6604
|
+
workspaceSection: "工作区",
|
|
6191
6605
|
saveToWorkspace: "保存到工作区",
|
|
6192
6606
|
saveToWorkspaceHint: "每次生成后,把图片文件保存到当前会话工作区。",
|
|
6193
6607
|
folder: "工作区文件夹",
|
|
6194
6608
|
folderHint: "相对当前会话工作区的子目录;留空表示工作区根目录。",
|
|
6609
|
+
uiSection: "界面",
|
|
6610
|
+
showPill: "在对话输入栏显示生图切换胶囊",
|
|
6611
|
+
showPillHint: "开启后,输入框工具行会显示一枚胶囊,随手切换默认生图 Provider,无需进入设置;默认关闭。",
|
|
6612
|
+
fetchModels: "拉取模型",
|
|
6613
|
+
fetchingModels: "拉取中…",
|
|
6614
|
+
fetchModelsHint: "点击「拉取模型」用当前 Key 获取可用生图模型列表;也可手动输入。",
|
|
6615
|
+
modelsFound: "找到 {n} 个生图模型,点击模型框选择",
|
|
6616
|
+
modelsNone: "未筛出生图模型,可手动输入模型名",
|
|
6195
6617
|
saving: "保存中…",
|
|
6196
6618
|
save: "保存",
|
|
6197
6619
|
saved: "已保存",
|
|
6198
6620
|
savedToPath: "已保存到",
|
|
6199
|
-
checkingKey: "正在检查 API Key…",
|
|
6200
|
-
keyConfigured: "已配置 API Key",
|
|
6201
|
-
keyNotConfigured: "尚未配置 API Key",
|
|
6202
6621
|
generating: "正在生成图片…",
|
|
6203
6622
|
loading: "正在加载图片…",
|
|
6204
6623
|
loadFailed: "图片读取失败 ({status})",
|
|
@@ -6223,23 +6642,47 @@ window.__ModuleLoader__.load({
|
|
|
6223
6642
|
},
|
|
6224
6643
|
en: {
|
|
6225
6644
|
title: "Image Generation",
|
|
6226
|
-
description: "
|
|
6227
|
-
|
|
6645
|
+
description: "Configure each provider key and model, then pick the default provider.",
|
|
6646
|
+
defaultProvider: "Default provider",
|
|
6647
|
+
defaultProviderHint: "Used by the Agent by default; the Studio and tool calls can switch per call.",
|
|
6648
|
+
settingsReadOnly: "Settings come from a profile file and are read-only; edit that source to change them.",
|
|
6228
6649
|
providerGoogle: "Google Gemini",
|
|
6229
|
-
providerOpenAI: "OpenAI
|
|
6650
|
+
providerOpenAI: "OpenAI",
|
|
6651
|
+
providerOpenAICompat: "OpenAI-compatible (relay)",
|
|
6230
6652
|
providerSeedream: "ByteDance Seedream",
|
|
6231
6653
|
providerDashScope: "Aliyun DashScope (Wanx / Qwen)",
|
|
6654
|
+
providerXAI: "xAI Grok Imagine",
|
|
6655
|
+
providerZhipu: "Zhipu GLM-Image",
|
|
6232
6656
|
providerComfyUI: "Local ComfyUI",
|
|
6233
6657
|
apiKeyLabel: "{provider} API Key",
|
|
6234
6658
|
apiKeyPlaceholder: "Leave empty to keep configured key",
|
|
6235
6659
|
apiKeyHint: "Securely saved as {key}; never read back in plaintext.",
|
|
6660
|
+
keyReadOnly: "Key is supplied read-only by {source}; update it there.",
|
|
6661
|
+
badgeChecking: "Checking…",
|
|
6662
|
+
badgeConfigured: "Key set",
|
|
6663
|
+
badgeMissing: "Key missing",
|
|
6664
|
+
badgeUnknown: "Unknown",
|
|
6665
|
+
comfyuiNoKey: "No API key needed",
|
|
6666
|
+
testConnection: "Test connection",
|
|
6667
|
+
testing: "Testing…",
|
|
6668
|
+
testOk: "Connection OK",
|
|
6669
|
+
testFailed: "Connection failed",
|
|
6670
|
+
testUnauthorized: "API key rejected",
|
|
6671
|
+
clearKey: "Clear key",
|
|
6672
|
+
keyCleared: "Key cleared",
|
|
6673
|
+
clearKeyFailed: "Failed to clear key",
|
|
6674
|
+
saveKeyFailed: "Failed to save the key",
|
|
6675
|
+
clearKeyUnsupported: "This DSH build cannot clear keys here; remove it from credential management instead.",
|
|
6236
6676
|
endpoint: "Endpoint / Base URL",
|
|
6237
6677
|
reset: "Reset",
|
|
6238
6678
|
resetTitle: "Reset to official default URL",
|
|
6239
6679
|
endpointHintGoogle: "Official Google endpoint or reverse proxy (full path).",
|
|
6240
|
-
endpointHintOpenAI: "
|
|
6680
|
+
endpointHintOpenAI: "Official api.openai.com /v1 base URL; for relays use the \"OpenAI-compatible\" row below.",
|
|
6681
|
+
endpointHintOpenAICompat: "OpenAI-compatible /v1 base URL of your relay or self-hosted service (required), e.g. https://your-relay.example.com/v1.",
|
|
6241
6682
|
endpointHintSeedream: "Volcengine Ark compatible /api/v3 base URL.",
|
|
6242
6683
|
endpointHintDashScope: "Official Aliyun DashScope endpoint.",
|
|
6684
|
+
endpointHintXAI: "Official xAI api.x.ai /v1 base URL.",
|
|
6685
|
+
endpointHintZhipu: "Zhipu open.bigmodel.cn /api/paas/v4 base URL.",
|
|
6243
6686
|
endpointHintComfyUI: "A running ComfyUI server reachable by the DSH Host; the default points to port 8188 on this computer.",
|
|
6244
6687
|
model: "Model",
|
|
6245
6688
|
workflow: "API Workflows",
|
|
@@ -6256,17 +6699,23 @@ window.__ModuleLoader__.load({
|
|
|
6256
6699
|
workflowDuplicateName: "Workflow names must be unique.",
|
|
6257
6700
|
timeout: "Generation timeout (seconds)",
|
|
6258
6701
|
timeoutHint: "Covers submission, waiting, and image download; defaults to 300 seconds.",
|
|
6702
|
+
workspaceSection: "Workspace",
|
|
6259
6703
|
saveToWorkspace: "Save to workspace",
|
|
6260
6704
|
saveToWorkspaceHint: "Write each generated image as a file into the session workspace.",
|
|
6261
6705
|
folder: "Workspace folder",
|
|
6262
6706
|
folderHint: "Subdirectory of the session workspace; empty means the workspace root.",
|
|
6707
|
+
uiSection: "Interface",
|
|
6708
|
+
showPill: "Show the image provider pill in the chat input bar",
|
|
6709
|
+
showPillHint: "Adds a small pill to the composer tool row for switching the default image provider without opening settings; off by default.",
|
|
6710
|
+
fetchModels: "Fetch models",
|
|
6711
|
+
fetchingModels: "Fetching…",
|
|
6712
|
+
fetchModelsHint: "Click \"Fetch models\" to list image-capable models with the stored key; manual input still works.",
|
|
6713
|
+
modelsFound: "{n} image models found; open the model field to pick one",
|
|
6714
|
+
modelsNone: "No image models found; type the model name manually",
|
|
6263
6715
|
saving: "Saving…",
|
|
6264
6716
|
save: "Save",
|
|
6265
6717
|
saved: "Saved",
|
|
6266
6718
|
savedToPath: "Saved to",
|
|
6267
|
-
checkingKey: "Checking API Key…",
|
|
6268
|
-
keyConfigured: "API Key configured",
|
|
6269
|
-
keyNotConfigured: "API Key not configured",
|
|
6270
6719
|
generating: "Generating image…",
|
|
6271
6720
|
loading: "Loading image…",
|
|
6272
6721
|
loadFailed: "Failed to load image ({status})",
|
|
@@ -6322,6 +6771,7 @@ window.__ModuleLoader__.load({
|
|
|
6322
6771
|
.dsh-ig-btn-reset{appearance:none;border:1px solid var(--dsw-alias-border-l2,#d7dbe0);border-radius:8px;padding:7px 12px;background:var(--dsw-alias-bg-layer-3,#f9fafb);color:var(--dsw-alias-label-secondary,inherit);font:inherit;font-size:13px;cursor:pointer;white-space:nowrap;transition:background .15s,border-color .15s}
|
|
6323
6772
|
.dsh-ig-btn-reset:hover{background:var(--dsw-alias-bg-layer-2,#edf0f3);border-color:var(--dsw-alias-label-dimmed,#9ca3af)}
|
|
6324
6773
|
.dsh-ig-hint,.dsh-ig-status{margin:0;color:var(--dsw-alias-label-tertiary,#7b818b);font-size:12px;line-height:1.4}
|
|
6774
|
+
.dsh-ig-hint-error{color:var(--dsw-alias-label-error,#d33)}
|
|
6325
6775
|
.dsh-ig-status-error{color:var(--dsw-alias-label-error,#d33);font-weight:500}
|
|
6326
6776
|
.dsh-ig-actions{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:16px;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2,#eee)}
|
|
6327
6777
|
.dsh-ig-check-row{display:flex;align-items:center;gap:8px;cursor:pointer}
|
|
@@ -6330,6 +6780,45 @@ window.__ModuleLoader__.load({
|
|
|
6330
6780
|
.dsh-ig-save{appearance:none;border:0;border-radius:8px;padding:6px 16px;background:var(--dsw-alias-label-primary,#111827);color:var(--dsw-alias-bg-layer-3,#fff);font:inherit;font-size:13px;font-weight:500;cursor:pointer;transition:opacity .15s}
|
|
6331
6781
|
.dsh-ig-save:disabled{opacity:.4;cursor:default}
|
|
6332
6782
|
|
|
6783
|
+
/* Provider list: one expandable row per provider, each saving independently. */
|
|
6784
|
+
.dsh-ig-providers{display:grid;gap:10px;margin-top:14px}
|
|
6785
|
+
.dsh-ig-provider-row{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:10px;background:var(--dsw-alias-bg-layer-3,transparent);overflow:hidden;transition:border-color .16s}
|
|
6786
|
+
.dsh-ig-provider-row-open{border-color:var(--dsw-alias-label-dimmed,#9ca3af)}
|
|
6787
|
+
.dsh-ig-provider-head{width:100%;appearance:none;border:0;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer;display:flex;align-items:center;gap:10px;padding:11px 12px}
|
|
6788
|
+
.dsh-ig-provider-head:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4c78ff);outline-offset:-2px}
|
|
6789
|
+
.dsh-ig-provider-name{flex:1;min-width:0;font-size:13.5px;font-weight:550;color:var(--dsw-alias-label-primary,inherit)}
|
|
6790
|
+
.dsh-ig-provider-chevron{flex:none;color:var(--dsw-alias-label-tertiary,#7b818b);transition:transform .16s;display:inline-flex;align-items:center}
|
|
6791
|
+
.dsh-ig-provider-chevron-open{transform:rotate(180deg)}
|
|
6792
|
+
.dsh-ig-provider-body{border-top:1px solid var(--dsw-alias-border-l2,#eee);padding:2px 12px 14px}
|
|
6793
|
+
.dsh-ig-badge{flex:none;display:inline-flex;align-items:center;gap:5px;font-size:11.5px;line-height:1.6;padding:2px 9px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2,#d7dbe0);color:var(--dsw-alias-label-secondary,inherit);white-space:nowrap;max-width:60%;overflow:hidden;text-overflow:ellipsis}
|
|
6794
|
+
.dsh-ig-badge-dot{width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
|
|
6795
|
+
.dsh-ig-badge-ok{border-color:rgba(34,197,94,.45);color:#15803d;background:rgba(34,197,94,.08)}
|
|
6796
|
+
.dsh-ig-badge-missing{border-color:rgba(239,68,68,.4);color:#b91c1c;background:rgba(239,68,68,.06)}
|
|
6797
|
+
.dsh-ig-badge-neutral{color:var(--dsw-alias-label-tertiary,#7b818b)}
|
|
6798
|
+
.dsh-ig-badge-checking .dsh-ig-badge-dot{animation:dsh-ig-pulse 1s ease-in-out infinite}
|
|
6799
|
+
@keyframes dsh-ig-pulse{50%{opacity:.25}}
|
|
6800
|
+
|
|
6801
|
+
/* Default provider radio pills. */
|
|
6802
|
+
.dsh-ig-radios{display:flex;flex-wrap:wrap;gap:8px}
|
|
6803
|
+
.dsh-ig-radio{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--dsw-alias-border-l2,#d7dbe0);border-radius:999px;padding:5px 12px;cursor:pointer;font-size:12.5px;color:var(--dsw-alias-label-secondary,inherit);transition:border-color .15s,background .15s}
|
|
6804
|
+
.dsh-ig-radio:hover{border-color:var(--dsw-alias-label-dimmed,#9ca3af)}
|
|
6805
|
+
.dsh-ig-radio-checked{border-color:var(--dsw-alias-brand-primary,#4c78ff);background:rgba(76,120,255,.08);color:var(--dsw-alias-label-primary,inherit)}
|
|
6806
|
+
.dsh-ig-radio input[type=radio]{width:14px;height:14px;accent-color:var(--dsw-alias-brand-primary,#4c78ff);margin:0;cursor:pointer}
|
|
6807
|
+
|
|
6808
|
+
/* Row-level actions: test connection, clear key, save. */
|
|
6809
|
+
.dsh-ig-row-actions{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px;flex-wrap:wrap}
|
|
6810
|
+
.dsh-ig-row-buttons{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
6811
|
+
.dsh-ig-btn-secondary{appearance:none;border:1px solid var(--dsw-alias-border-l2,#d7dbe0);border-radius:8px;padding:6px 14px;background:var(--dsw-alias-bg-layer-3,#f9fafb);color:var(--dsw-alias-label-secondary,inherit);font:inherit;font-size:13px;cursor:pointer;white-space:nowrap;transition:background .15s,border-color .15s,opacity .15s}
|
|
6812
|
+
.dsh-ig-btn-secondary:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2,#edf0f3);border-color:var(--dsw-alias-label-dimmed,#9ca3af)}
|
|
6813
|
+
.dsh-ig-btn-secondary:disabled{opacity:.45;cursor:default}
|
|
6814
|
+
.dsh-ig-btn-danger{color:#b91c1c;border-color:rgba(239,68,68,.4)}
|
|
6815
|
+
.dsh-ig-btn-danger:hover:not(:disabled){background:rgba(239,68,68,.08);border-color:rgba(239,68,68,.6)}
|
|
6816
|
+
|
|
6817
|
+
/* Workspace section within the settings card. */
|
|
6818
|
+
.dsh-ig-section{display:grid;gap:6px;margin-top:16px;padding-top:14px;border-top:1px solid var(--dsw-alias-border-l2,#eee)}
|
|
6819
|
+
.dsh-ig-section-title{font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--dsw-alias-label-tertiary,#7b818b);text-transform:uppercase}
|
|
6820
|
+
.dsh-ig-status-readonly{color:var(--dsw-alias-label-tertiary,#7b818b);font-style:italic}
|
|
6821
|
+
|
|
6333
6822
|
.dsh-ig-result{display:grid;gap:10px;max-width:520px}
|
|
6334
6823
|
.dsh-ig-promoted-results{display:grid;gap:16px}
|
|
6335
6824
|
.dsh-ig-result-title{font-size:14px;font-weight:600}
|
|
@@ -6551,7 +7040,7 @@ window.__ModuleLoader__.load({
|
|
|
6551
7040
|
ctx.effect(() => {
|
|
6552
7041
|
const style = document.createElement("style");
|
|
6553
7042
|
style.dataset.plugin = "dsh-image-gen";
|
|
6554
|
-
style.textContent = `${STYLE}\n${STUDIO_STYLE}\n${INSPIRATION_STYLE}`;
|
|
7043
|
+
style.textContent = `${STYLE}\n${STUDIO_STYLE}\n${INSPIRATION_STYLE}\n${PROVIDER_PILL_STYLE}`;
|
|
6555
7044
|
document.head.appendChild(style);
|
|
6556
7045
|
return () => {
|
|
6557
7046
|
style.remove();
|
|
@@ -6570,6 +7059,21 @@ window.__ModuleLoader__.load({
|
|
|
6570
7059
|
inject: () => ({ locale })
|
|
6571
7060
|
}, PromotedImageResultNode));
|
|
6572
7061
|
});
|
|
7062
|
+
const credentialListeners = /* @__PURE__ */ new Set();
|
|
7063
|
+
const notifyCredentialsUpdated = () => {
|
|
7064
|
+
for (const listener of credentialListeners) listener();
|
|
7065
|
+
};
|
|
7066
|
+
ctx.effect(() => {
|
|
7067
|
+
const remote = ctx.get("remote");
|
|
7068
|
+
if (typeof remote?.$on !== "function") return () => {};
|
|
7069
|
+
return remote.$on("credentials/reference-updated", notifyCredentialsUpdated);
|
|
7070
|
+
}, "dsh-image-gen: credential events");
|
|
7071
|
+
const credentialEvents = { listen(callback) {
|
|
7072
|
+
credentialListeners.add(callback);
|
|
7073
|
+
return () => {
|
|
7074
|
+
credentialListeners.delete(callback);
|
|
7075
|
+
};
|
|
7076
|
+
} };
|
|
6573
7077
|
const injectSettingsItem = (owner, credentials) => {
|
|
6574
7078
|
const ownerRegister = owner.slots.register.bind(owner.slots);
|
|
6575
7079
|
owner.slots.inject("settings.plugin.item", () => ownerRegister({
|
|
@@ -6578,18 +7082,38 @@ window.__ModuleLoader__.load({
|
|
|
6578
7082
|
inject: () => ({
|
|
6579
7083
|
scope,
|
|
6580
7084
|
credentials,
|
|
6581
|
-
locale
|
|
7085
|
+
locale,
|
|
7086
|
+
credentialEvents
|
|
6582
7087
|
})
|
|
6583
7088
|
}, ImageGenerationSettingsCard));
|
|
6584
7089
|
};
|
|
7090
|
+
const injectComposerPill = (owner, credentials) => {
|
|
7091
|
+
const ownerRegister = owner.slots.register.bind(owner.slots);
|
|
7092
|
+
owner.slots.inject("conversation.input.right", () => ownerRegister({
|
|
7093
|
+
name: "conversation.input.right",
|
|
7094
|
+
id: "image-provider",
|
|
7095
|
+
order: 10,
|
|
7096
|
+
inject: () => ({
|
|
7097
|
+
scope,
|
|
7098
|
+
credentials,
|
|
7099
|
+
locale,
|
|
7100
|
+
credentialEvents
|
|
7101
|
+
})
|
|
7102
|
+
}, ImageProviderPill));
|
|
7103
|
+
};
|
|
6585
7104
|
const remoteCredentials = asCredentialsRemote(ctx.get("remote.credentials"));
|
|
6586
7105
|
const legacyCredentials = credentialsFromLegacyConnection(ctx.get("connection"));
|
|
6587
|
-
if (remoteCredentials !== void 0)
|
|
6588
|
-
|
|
6589
|
-
|
|
7106
|
+
if (remoteCredentials !== void 0) {
|
|
7107
|
+
injectSettingsItem(ctx, remoteCredentials);
|
|
7108
|
+
injectComposerPill(ctx, remoteCredentials);
|
|
7109
|
+
} else if (legacyCredentials !== void 0) {
|
|
7110
|
+
injectSettingsItem(ctx, legacyCredentials);
|
|
7111
|
+
injectComposerPill(ctx, legacyCredentials);
|
|
7112
|
+
} else ctx.inject(["remote.credentials"], (remoteCtx) => {
|
|
6590
7113
|
const credentials = asCredentialsRemote(remoteCtx.get("remote.credentials"));
|
|
6591
7114
|
if (credentials === void 0) throw new Error("dsh-image-gen: remote.credentials has an incompatible interface");
|
|
6592
7115
|
injectSettingsItem(remoteCtx, credentials);
|
|
7116
|
+
injectComposerPill(remoteCtx, credentials);
|
|
6593
7117
|
});
|
|
6594
7118
|
ctx.slots.inject("tool.call.toolview", () => register({
|
|
6595
7119
|
name: "tool.call.toolview",
|
|
@@ -6653,32 +7177,102 @@ window.__ModuleLoader__.load({
|
|
|
6653
7177
|
}
|
|
6654
7178
|
};
|
|
6655
7179
|
}
|
|
6656
|
-
|
|
7180
|
+
function emptyProviderRow() {
|
|
7181
|
+
return {
|
|
7182
|
+
expanded: false,
|
|
7183
|
+
model: "",
|
|
7184
|
+
baseURL: "",
|
|
7185
|
+
keyInput: "",
|
|
7186
|
+
keyStatus: "checking",
|
|
7187
|
+
keyInfo: void 0,
|
|
7188
|
+
testing: false,
|
|
7189
|
+
testResult: void 0,
|
|
7190
|
+
fetchingModels: false,
|
|
7191
|
+
modelOptions: [],
|
|
7192
|
+
modelFetchMessage: "",
|
|
7193
|
+
modelFetchIsError: false,
|
|
7194
|
+
saving: false,
|
|
7195
|
+
message: "",
|
|
7196
|
+
messageIsError: false,
|
|
7197
|
+
workflows: [],
|
|
7198
|
+
activeWorkflow: "",
|
|
7199
|
+
timeoutSeconds: DEFAULT_COMFYUI_TIMEOUT_MS / 1e3
|
|
7200
|
+
};
|
|
7201
|
+
}
|
|
7202
|
+
/** Settings field each cloud provider persists its model under. */
|
|
7203
|
+
const CLOUD_MODEL_FIELDS = {
|
|
7204
|
+
google: "googleModel",
|
|
7205
|
+
openai: "openaiModel",
|
|
7206
|
+
"openai-compat": "openaiCompatModel",
|
|
7207
|
+
seedream: "seedreamModel",
|
|
7208
|
+
dashscope: "dashscopeModel",
|
|
7209
|
+
xai: "xaiModel",
|
|
7210
|
+
zhipu: "zhipuModel"
|
|
7211
|
+
};
|
|
7212
|
+
/** Settings field each cloud provider persists its endpoint or base URL under. */
|
|
7213
|
+
const CLOUD_URL_FIELDS = {
|
|
7214
|
+
google: "googleEndpoint",
|
|
7215
|
+
openai: "openaiBaseURL",
|
|
7216
|
+
"openai-compat": "openaiCompatBaseURL",
|
|
7217
|
+
seedream: "seedreamBaseURL",
|
|
7218
|
+
dashscope: "dashscopeEndpoint",
|
|
7219
|
+
xai: "xaiBaseURL",
|
|
7220
|
+
zhipu: "zhipuBaseURL"
|
|
7221
|
+
};
|
|
7222
|
+
/** Dictionary key of each cloud provider's endpoint hint. */
|
|
7223
|
+
const CLOUD_HINT_KEYS = {
|
|
7224
|
+
google: "endpointHintGoogle",
|
|
7225
|
+
openai: "endpointHintOpenAI",
|
|
7226
|
+
"openai-compat": "endpointHintOpenAICompat",
|
|
7227
|
+
seedream: "endpointHintSeedream",
|
|
7228
|
+
dashscope: "endpointHintDashScope",
|
|
7229
|
+
xai: "endpointHintXAI",
|
|
7230
|
+
zhipu: "endpointHintZhipu"
|
|
7231
|
+
};
|
|
7232
|
+
/** Config field a cloud provider persists its model under. */
|
|
7233
|
+
function modelFieldOf(provider) {
|
|
7234
|
+
return CLOUD_MODEL_FIELDS[provider];
|
|
7235
|
+
}
|
|
7236
|
+
/** Config field a cloud provider persists its endpoint or base URL under. */
|
|
7237
|
+
function baseURLFieldOf(provider) {
|
|
7238
|
+
return CLOUD_URL_FIELDS[provider];
|
|
7239
|
+
}
|
|
7240
|
+
/** Providers whose settings row offers the "pull models" button. */
|
|
7241
|
+
function modelPullSupported(_provider) {
|
|
7242
|
+
return true;
|
|
7243
|
+
}
|
|
7244
|
+
/** Build one row per provider from persisted settings, including ComfyUI extras. */
|
|
7245
|
+
function rowsFromSettings(value) {
|
|
7246
|
+
const rows = {};
|
|
7247
|
+
for (const provider of IMAGE_PROVIDERS) rows[provider] = {
|
|
7248
|
+
...emptyProviderRow(),
|
|
7249
|
+
model: modelOf(provider, value),
|
|
7250
|
+
baseURL: baseURLOf(provider, value),
|
|
7251
|
+
...provider === "comfyui" ? {
|
|
7252
|
+
workflows: resolveComfyUIWorkflows(value ?? {}),
|
|
7253
|
+
activeWorkflow: activeComfyUIWorkflow(value ?? {})?.name ?? "",
|
|
7254
|
+
timeoutSeconds: Math.max(1, Math.round((value?.comfyuiTimeoutMs ?? 3e5) / 1e3))
|
|
7255
|
+
} : {}
|
|
7256
|
+
};
|
|
7257
|
+
return rows;
|
|
7258
|
+
}
|
|
7259
|
+
/** Edit each provider independently, pick an explicit default, and verify keys inline. */
|
|
6657
7260
|
function ImageGenerationSettingsCard(props) {
|
|
6658
7261
|
const [open, setOpen] = (0, react.useState)(false);
|
|
6659
7262
|
const [snapshot, setSnapshot] = (0, react.useState)(() => props.scope.getSnapshot());
|
|
6660
7263
|
const [lang, setLang] = (0, react.useState)(() => props.locale?.getSnapshot?.()?.active?.startsWith("en") ? "en" : "zh");
|
|
6661
|
-
const [
|
|
6662
|
-
const [
|
|
6663
|
-
const [
|
|
6664
|
-
const [
|
|
6665
|
-
const [
|
|
6666
|
-
const [
|
|
6667
|
-
const [
|
|
6668
|
-
const [
|
|
6669
|
-
const [
|
|
6670
|
-
const [
|
|
6671
|
-
const [
|
|
6672
|
-
const [
|
|
6673
|
-
const [messageIsError, setMessageIsError] = (0, react.useState)(false);
|
|
6674
|
-
const reportMessage = (text) => {
|
|
6675
|
-
setMessage(text);
|
|
6676
|
-
setMessageIsError(false);
|
|
6677
|
-
};
|
|
6678
|
-
const reportError = (text) => {
|
|
6679
|
-
setMessage(text);
|
|
6680
|
-
setMessageIsError(true);
|
|
6681
|
-
};
|
|
7264
|
+
const [defaultProvider, setDefaultProvider] = (0, react.useState)(() => props.scope.getSnapshot().value?.provider ?? "google");
|
|
7265
|
+
const [providerMessage, setProviderMessage] = (0, react.useState)("");
|
|
7266
|
+
const [providerMessageIsError, setProviderMessageIsError] = (0, react.useState)(false);
|
|
7267
|
+
const [saveToWorkspace, setSaveToWorkspace] = (0, react.useState)(() => props.scope.getSnapshot().value?.saveToWorkspace ?? true);
|
|
7268
|
+
const [workspaceFolder, setWorkspaceFolder] = (0, react.useState)(() => props.scope.getSnapshot().value?.workspaceFolder ?? "dsh-image-gen");
|
|
7269
|
+
const [showPill, setShowPill] = (0, react.useState)(() => props.scope.getSnapshot().value?.showProviderPill === true);
|
|
7270
|
+
const [uiMessage, setUiMessage] = (0, react.useState)("");
|
|
7271
|
+
const [uiMessageIsError, setUiMessageIsError] = (0, react.useState)(false);
|
|
7272
|
+
const [workspaceMessage, setWorkspaceMessage] = (0, react.useState)("");
|
|
7273
|
+
const [workspaceMessageIsError, setWorkspaceMessageIsError] = (0, react.useState)(false);
|
|
7274
|
+
const [rows, setRows] = (0, react.useState)(() => rowsFromSettings(props.scope.getSnapshot().value));
|
|
7275
|
+
const [keyTick, setKeyTick] = (0, react.useState)(0);
|
|
6682
7276
|
(0, react.useEffect)(() => props.scope.subscribe(() => {
|
|
6683
7277
|
setSnapshot(props.scope.getSnapshot());
|
|
6684
7278
|
}), [props.scope]);
|
|
@@ -6687,6 +7281,10 @@ window.__ModuleLoader__.load({
|
|
|
6687
7281
|
setLang(props.locale?.getSnapshot?.()?.active?.startsWith("en") ? "en" : "zh");
|
|
6688
7282
|
});
|
|
6689
7283
|
}, [props.locale]);
|
|
7284
|
+
const credentialEvents = props.credentialEvents;
|
|
7285
|
+
(0, react.useEffect)(() => credentialEvents?.listen(() => {
|
|
7286
|
+
setKeyTick((tick) => tick + 1);
|
|
7287
|
+
}), [credentialEvents]);
|
|
6690
7288
|
const t = (keyName, params) => {
|
|
6691
7289
|
let text = (lang === "en" ? DICT.en : DICT.zh)[keyName] || DICT.zh[keyName] || keyName;
|
|
6692
7290
|
if (params) for (const [k, v] of Object.entries(params)) text = text.replace(`{${k}}`, v);
|
|
@@ -6695,46 +7293,103 @@ window.__ModuleLoader__.load({
|
|
|
6695
7293
|
const providerLabels = {
|
|
6696
7294
|
google: t("providerGoogle"),
|
|
6697
7295
|
openai: t("providerOpenAI"),
|
|
7296
|
+
"openai-compat": t("providerOpenAICompat"),
|
|
6698
7297
|
seedream: t("providerSeedream"),
|
|
6699
7298
|
dashscope: t("providerDashScope"),
|
|
7299
|
+
xai: t("providerXAI"),
|
|
7300
|
+
zhipu: t("providerZhipu"),
|
|
6700
7301
|
comfyui: t("providerComfyUI")
|
|
6701
7302
|
};
|
|
6702
7303
|
(0, react.useEffect)(() => {
|
|
6703
7304
|
const value = snapshot.value;
|
|
6704
|
-
|
|
6705
|
-
setProvider(next);
|
|
6706
|
-
setModel(modelOf(next, value));
|
|
6707
|
-
setBaseURL(baseURLOf(next, value));
|
|
6708
|
-
setWorkflows(resolveComfyUIWorkflows(value ?? {}));
|
|
6709
|
-
setActiveWorkflow(activeComfyUIWorkflow(value ?? {})?.name ?? "");
|
|
6710
|
-
setTimeoutSeconds(Math.max(1, Math.round((value?.comfyuiTimeoutMs ?? 3e5) / 1e3)));
|
|
7305
|
+
setDefaultProvider(value?.provider ?? "google");
|
|
6711
7306
|
setSaveToWorkspace(value?.saveToWorkspace ?? true);
|
|
6712
7307
|
setWorkspaceFolder(value?.workspaceFolder ?? "dsh-image-gen");
|
|
7308
|
+
setShowPill(value?.showProviderPill === true);
|
|
7309
|
+
setRows((current) => {
|
|
7310
|
+
const next = {};
|
|
7311
|
+
for (const provider of IMAGE_PROVIDERS) next[provider] = {
|
|
7312
|
+
...current[provider],
|
|
7313
|
+
model: modelOf(provider, value),
|
|
7314
|
+
baseURL: baseURLOf(provider, value),
|
|
7315
|
+
...provider === "comfyui" ? {
|
|
7316
|
+
workflows: resolveComfyUIWorkflows(value ?? {}),
|
|
7317
|
+
activeWorkflow: activeComfyUIWorkflow(value ?? {})?.name ?? "",
|
|
7318
|
+
timeoutSeconds: Math.max(1, Math.round((value?.comfyuiTimeoutMs ?? 3e5) / 1e3))
|
|
7319
|
+
} : {}
|
|
7320
|
+
};
|
|
7321
|
+
return next;
|
|
7322
|
+
});
|
|
6713
7323
|
}, [snapshot]);
|
|
7324
|
+
const credentials = props.credentials;
|
|
6714
7325
|
(0, react.useEffect)(() => {
|
|
6715
|
-
const keyRef = KEY_REF[provider];
|
|
6716
|
-
if (keyRef === void 0) {
|
|
6717
|
-
setConfigured(void 0);
|
|
6718
|
-
return;
|
|
6719
|
-
}
|
|
6720
7326
|
let active = true;
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
7327
|
+
for (const provider of CLOUD_IMAGE_PROVIDERS) {
|
|
7328
|
+
const keyRef = cloudCredentialRef(provider);
|
|
7329
|
+
if (keyRef === void 0) continue;
|
|
7330
|
+
setRows((current) => ({
|
|
7331
|
+
...current,
|
|
7332
|
+
[provider]: {
|
|
7333
|
+
...current[provider],
|
|
7334
|
+
keyStatus: "checking"
|
|
7335
|
+
}
|
|
7336
|
+
}));
|
|
7337
|
+
credentials.describe([keyRef]).then((response) => {
|
|
7338
|
+
if (!active) return;
|
|
7339
|
+
const info = response.ok ? response.value?.[keyRef] : void 0;
|
|
7340
|
+
setRows((current) => ({
|
|
7341
|
+
...current,
|
|
7342
|
+
[provider]: {
|
|
7343
|
+
...current[provider],
|
|
7344
|
+
keyStatus: response.ok ? info?.configured ? "configured" : "missing" : "unknown",
|
|
7345
|
+
keyInfo: info
|
|
7346
|
+
}
|
|
7347
|
+
}));
|
|
7348
|
+
}).catch(() => {
|
|
7349
|
+
if (!active) return;
|
|
7350
|
+
setRows((current) => ({
|
|
7351
|
+
...current,
|
|
7352
|
+
[provider]: {
|
|
7353
|
+
...current[provider],
|
|
7354
|
+
keyStatus: "unknown"
|
|
7355
|
+
}
|
|
7356
|
+
}));
|
|
7357
|
+
});
|
|
7358
|
+
}
|
|
6726
7359
|
return () => {
|
|
6727
7360
|
active = false;
|
|
6728
7361
|
};
|
|
6729
|
-
}, [
|
|
6730
|
-
const
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
7362
|
+
}, [credentials, keyTick]);
|
|
7363
|
+
const updateRow = (provider, patch) => {
|
|
7364
|
+
setRows((current) => ({
|
|
7365
|
+
...current,
|
|
7366
|
+
[provider]: {
|
|
7367
|
+
...current[provider],
|
|
7368
|
+
...patch
|
|
7369
|
+
}
|
|
7370
|
+
}));
|
|
7371
|
+
};
|
|
7372
|
+
/** The only action that ever changes the default provider; saving a key never does. */
|
|
7373
|
+
const selectDefaultProvider = (provider) => {
|
|
7374
|
+
setDefaultProvider(provider);
|
|
7375
|
+
setProviderMessage("");
|
|
7376
|
+
setProviderMessageIsError(false);
|
|
7377
|
+
props.scope.set("provider", provider).catch((cause) => {
|
|
7378
|
+
setDefaultProvider(snapshot.value?.provider ?? "google");
|
|
7379
|
+
setProviderMessage(cause instanceof Error ? cause.message : String(cause));
|
|
7380
|
+
setProviderMessageIsError(true);
|
|
7381
|
+
});
|
|
7382
|
+
};
|
|
7383
|
+
const saveProviderRow = async (provider) => {
|
|
7384
|
+
const row = rows[provider];
|
|
7385
|
+
updateRow(provider, {
|
|
7386
|
+
saving: true,
|
|
7387
|
+
message: "",
|
|
7388
|
+
messageIsError: false
|
|
7389
|
+
});
|
|
6734
7390
|
try {
|
|
6735
|
-
await props.scope.set("provider", provider);
|
|
6736
7391
|
if (provider === "comfyui") {
|
|
6737
|
-
const entries = workflows.map((entry) => ({
|
|
7392
|
+
const entries = row.workflows.map((entry) => ({
|
|
6738
7393
|
name: entry.name.trim(),
|
|
6739
7394
|
json: entry.json,
|
|
6740
7395
|
presetPrompt: (entry.presetPrompt ?? "").trim()
|
|
@@ -6744,98 +7399,702 @@ window.__ModuleLoader__.load({
|
|
|
6744
7399
|
validateComfyUIWorkflowJson(entry.json);
|
|
6745
7400
|
}
|
|
6746
7401
|
if (new Set(entries.map((entry) => entry.name)).size !== entries.length) throw new Error(t("workflowDuplicateName"));
|
|
6747
|
-
const activeEntry = entries.find((entry) => entry.name === activeWorkflow) ?? entries[0];
|
|
6748
|
-
await props.scope.set("comfyuiBaseURL", baseURL);
|
|
7402
|
+
const activeEntry = entries.find((entry) => entry.name === row.activeWorkflow) ?? entries[0];
|
|
7403
|
+
await props.scope.set("comfyuiBaseURL", row.baseURL);
|
|
6749
7404
|
await props.scope.set("comfyuiWorkflows", entries);
|
|
6750
7405
|
await props.scope.set("comfyuiActiveWorkflow", activeEntry === void 0 ? "" : activeEntry.name);
|
|
6751
7406
|
await props.scope.set("comfyuiWorkflowJson", activeEntry === void 0 ? "" : activeEntry.json);
|
|
6752
7407
|
await props.scope.set("comfyuiWorkflowName", activeEntry === void 0 ? "" : activeEntry.name);
|
|
6753
|
-
await props.scope.set("comfyuiTimeoutMs", Math.max(1, Math.round(timeoutSeconds)) * 1e3);
|
|
7408
|
+
await props.scope.set("comfyuiTimeoutMs", Math.max(1, Math.round(row.timeoutSeconds)) * 1e3);
|
|
6754
7409
|
} else {
|
|
6755
|
-
await props.scope.set(provider
|
|
6756
|
-
await props.scope.set(provider
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
7410
|
+
await props.scope.set(modelFieldOf(provider), row.model);
|
|
7411
|
+
await props.scope.set(baseURLFieldOf(provider), row.baseURL);
|
|
7412
|
+
if (row.keyInput.trim().length > 0) {
|
|
7413
|
+
const keyRef = cloudCredentialRef(provider);
|
|
7414
|
+
if (keyRef === void 0) throw new Error(t("comfyuiNoKey"));
|
|
7415
|
+
const response = await props.credentials.set(keyRef, row.keyInput.trim());
|
|
7416
|
+
if (!response.ok) throw new Error(response.error?.message ?? t("saveKeyFailed"));
|
|
7417
|
+
updateRow(provider, {
|
|
7418
|
+
keyInput: "",
|
|
7419
|
+
keyStatus: "configured"
|
|
7420
|
+
});
|
|
7421
|
+
}
|
|
6767
7422
|
}
|
|
6768
|
-
|
|
7423
|
+
updateRow(provider, {
|
|
7424
|
+
message: t("saved"),
|
|
7425
|
+
messageIsError: false
|
|
7426
|
+
});
|
|
7427
|
+
} catch (cause) {
|
|
7428
|
+
updateRow(provider, {
|
|
7429
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
7430
|
+
messageIsError: true
|
|
7431
|
+
});
|
|
7432
|
+
} finally {
|
|
7433
|
+
updateRow(provider, { saving: false });
|
|
7434
|
+
}
|
|
7435
|
+
};
|
|
7436
|
+
/** Probe through the host route so the browser side never touches credential values. */
|
|
7437
|
+
const testConnection = async (provider) => {
|
|
7438
|
+
updateRow(provider, {
|
|
7439
|
+
testing: true,
|
|
7440
|
+
testResult: void 0,
|
|
7441
|
+
message: "",
|
|
7442
|
+
messageIsError: false
|
|
7443
|
+
});
|
|
7444
|
+
try {
|
|
7445
|
+
const response = await fetch(TEST_CONNECTION_ROUTE, {
|
|
7446
|
+
method: "POST",
|
|
7447
|
+
headers: { "content-type": "application/json" },
|
|
7448
|
+
body: JSON.stringify({ provider })
|
|
7449
|
+
});
|
|
7450
|
+
if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
|
|
7451
|
+
updateRow(provider, { testResult: await response.json() });
|
|
7452
|
+
} catch (cause) {
|
|
7453
|
+
updateRow(provider, { testResult: {
|
|
7454
|
+
ok: false,
|
|
7455
|
+
reason: "error",
|
|
7456
|
+
message: cause instanceof Error ? cause.message : String(cause)
|
|
7457
|
+
} });
|
|
7458
|
+
} finally {
|
|
7459
|
+
updateRow(provider, { testing: false });
|
|
7460
|
+
}
|
|
7461
|
+
};
|
|
7462
|
+
/** Pull the provider's image-capable model ids through the host route (Google and the OpenAI family). */
|
|
7463
|
+
const fetchProviderModels = async (provider) => {
|
|
7464
|
+
updateRow(provider, {
|
|
7465
|
+
fetchingModels: true,
|
|
7466
|
+
modelFetchMessage: "",
|
|
7467
|
+
modelFetchIsError: false
|
|
7468
|
+
});
|
|
7469
|
+
try {
|
|
7470
|
+
const response = await fetch(TEST_CONNECTION_ROUTE, {
|
|
7471
|
+
method: "POST",
|
|
7472
|
+
headers: { "content-type": "application/json" },
|
|
7473
|
+
body: JSON.stringify({
|
|
7474
|
+
provider,
|
|
7475
|
+
action: "models"
|
|
7476
|
+
})
|
|
7477
|
+
});
|
|
7478
|
+
if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
|
|
7479
|
+
const payload = await response.json();
|
|
7480
|
+
if (payload.ok && Array.isArray(payload.models)) {
|
|
7481
|
+
const models = payload.models.filter((id) => typeof id === "string");
|
|
7482
|
+
updateRow(provider, {
|
|
7483
|
+
modelOptions: models,
|
|
7484
|
+
modelFetchMessage: models.length > 0 ? t("modelsFound", { n: String(models.length) }) : t("modelsNone"),
|
|
7485
|
+
modelFetchIsError: models.length === 0
|
|
7486
|
+
});
|
|
7487
|
+
} else if (payload.reason === "missing-key") updateRow(provider, {
|
|
7488
|
+
modelFetchMessage: t("badgeMissing"),
|
|
7489
|
+
modelFetchIsError: true
|
|
7490
|
+
});
|
|
7491
|
+
else if (payload.reason === "unauthorized") updateRow(provider, {
|
|
7492
|
+
modelFetchMessage: t("testUnauthorized"),
|
|
7493
|
+
modelFetchIsError: true
|
|
7494
|
+
});
|
|
7495
|
+
else updateRow(provider, {
|
|
7496
|
+
modelFetchMessage: payload.message ?? t("testFailed"),
|
|
7497
|
+
modelFetchIsError: true
|
|
7498
|
+
});
|
|
7499
|
+
} catch (cause) {
|
|
7500
|
+
updateRow(provider, {
|
|
7501
|
+
modelFetchMessage: cause instanceof Error ? cause.message : String(cause),
|
|
7502
|
+
modelFetchIsError: true
|
|
7503
|
+
});
|
|
7504
|
+
} finally {
|
|
7505
|
+
updateRow(provider, { fetchingModels: false });
|
|
7506
|
+
}
|
|
7507
|
+
};
|
|
7508
|
+
const clearProviderKey = async (provider) => {
|
|
7509
|
+
const keyRef = cloudCredentialRef(provider);
|
|
7510
|
+
if (keyRef === void 0) return;
|
|
7511
|
+
if (typeof props.credentials.unset !== "function") {
|
|
7512
|
+
updateRow(provider, {
|
|
7513
|
+
message: t("clearKeyUnsupported"),
|
|
7514
|
+
messageIsError: true
|
|
7515
|
+
});
|
|
7516
|
+
return;
|
|
7517
|
+
}
|
|
7518
|
+
updateRow(provider, {
|
|
7519
|
+
saving: true,
|
|
7520
|
+
message: "",
|
|
7521
|
+
messageIsError: false
|
|
7522
|
+
});
|
|
7523
|
+
try {
|
|
7524
|
+
const response = await props.credentials.unset(keyRef);
|
|
7525
|
+
if (!response.ok) throw new Error(response.error?.message ?? t("clearKeyFailed"));
|
|
7526
|
+
updateRow(provider, {
|
|
7527
|
+
keyStatus: "missing",
|
|
7528
|
+
keyInput: "",
|
|
7529
|
+
testResult: void 0,
|
|
7530
|
+
message: t("keyCleared"),
|
|
7531
|
+
messageIsError: false
|
|
7532
|
+
});
|
|
6769
7533
|
} catch (cause) {
|
|
6770
|
-
|
|
7534
|
+
updateRow(provider, {
|
|
7535
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
7536
|
+
messageIsError: true
|
|
7537
|
+
});
|
|
6771
7538
|
} finally {
|
|
6772
|
-
|
|
7539
|
+
updateRow(provider, { saving: false });
|
|
6773
7540
|
}
|
|
6774
7541
|
};
|
|
6775
|
-
const
|
|
6776
|
-
|
|
7542
|
+
const testResultText = (result) => {
|
|
7543
|
+
if (result === void 0) return "";
|
|
7544
|
+
if (result.ok) return t("testOk");
|
|
7545
|
+
if (result.reason === "missing-key") return t("badgeMissing");
|
|
7546
|
+
if (result.reason === "unauthorized") return t("testUnauthorized");
|
|
7547
|
+
return `${t("testFailed")}${result.message !== void 0 && result.message.length > 0 ? `: ${result.message}` : ""}`;
|
|
7548
|
+
};
|
|
7549
|
+
const badgeOf = (provider) => {
|
|
7550
|
+
if (provider === "comfyui") return {
|
|
7551
|
+
text: t("comfyuiNoKey"),
|
|
7552
|
+
className: "dsh-ig-badge dsh-ig-badge-neutral"
|
|
7553
|
+
};
|
|
7554
|
+
const status = rows[provider].keyStatus;
|
|
7555
|
+
if (status === "checking") return {
|
|
7556
|
+
text: t("badgeChecking"),
|
|
7557
|
+
className: "dsh-ig-badge dsh-ig-badge-neutral dsh-ig-badge-checking"
|
|
7558
|
+
};
|
|
7559
|
+
if (status === "configured") return {
|
|
7560
|
+
text: t("badgeConfigured"),
|
|
7561
|
+
className: "dsh-ig-badge dsh-ig-badge-ok"
|
|
7562
|
+
};
|
|
7563
|
+
if (status === "missing") return {
|
|
7564
|
+
text: t("badgeMissing"),
|
|
7565
|
+
className: "dsh-ig-badge dsh-ig-badge-missing"
|
|
7566
|
+
};
|
|
7567
|
+
return {
|
|
7568
|
+
text: t("badgeUnknown"),
|
|
7569
|
+
className: "dsh-ig-badge dsh-ig-badge-neutral"
|
|
7570
|
+
};
|
|
7571
|
+
};
|
|
6777
7572
|
const importWorkflow = async (event) => {
|
|
6778
7573
|
const file = event.target.files?.[0];
|
|
6779
7574
|
event.target.value = "";
|
|
6780
7575
|
if (file === void 0) return;
|
|
6781
|
-
|
|
7576
|
+
updateRow("comfyui", {
|
|
7577
|
+
message: "",
|
|
7578
|
+
messageIsError: false
|
|
7579
|
+
});
|
|
6782
7580
|
try {
|
|
6783
7581
|
if (file.size > 5242880) throw new Error(t("workflowTooLarge"));
|
|
6784
7582
|
const json = await file.text();
|
|
6785
7583
|
validateComfyUIWorkflowJson(json);
|
|
6786
|
-
const name = uniqueComfyUIWorkflowName(file.name, workflows.map((entry) => entry.name));
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
7584
|
+
const name = uniqueComfyUIWorkflowName(file.name, rows.comfyui.workflows.map((entry) => entry.name));
|
|
7585
|
+
setRows((current) => ({
|
|
7586
|
+
...current,
|
|
7587
|
+
comfyui: {
|
|
7588
|
+
...current.comfyui,
|
|
7589
|
+
workflows: [...current.comfyui.workflows, {
|
|
7590
|
+
name,
|
|
7591
|
+
json
|
|
7592
|
+
}],
|
|
7593
|
+
activeWorkflow: current.comfyui.activeWorkflow.length > 0 ? current.comfyui.activeWorkflow : name
|
|
7594
|
+
}
|
|
7595
|
+
}));
|
|
7596
|
+
updateRow("comfyui", {
|
|
7597
|
+
message: t("workflowImported", { name }),
|
|
7598
|
+
messageIsError: false
|
|
7599
|
+
});
|
|
6793
7600
|
} catch (cause) {
|
|
6794
|
-
|
|
7601
|
+
updateRow("comfyui", {
|
|
7602
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
7603
|
+
messageIsError: true
|
|
7604
|
+
});
|
|
6795
7605
|
}
|
|
6796
7606
|
};
|
|
6797
7607
|
/** Renaming the active entry keeps the active selection following its new name. */
|
|
6798
7608
|
const renameWorkflow = (index, name) => {
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
7609
|
+
setRows((current) => {
|
|
7610
|
+
const previous = current.comfyui.workflows[index];
|
|
7611
|
+
const workflows = current.comfyui.workflows.map((entry, position) => position === index ? {
|
|
7612
|
+
...entry,
|
|
7613
|
+
name
|
|
7614
|
+
} : entry);
|
|
7615
|
+
const activeWorkflow = previous !== void 0 && previous.name === current.comfyui.activeWorkflow ? name : current.comfyui.activeWorkflow;
|
|
7616
|
+
return {
|
|
7617
|
+
...current,
|
|
7618
|
+
comfyui: {
|
|
7619
|
+
...current.comfyui,
|
|
7620
|
+
workflows,
|
|
7621
|
+
activeWorkflow
|
|
7622
|
+
}
|
|
7623
|
+
};
|
|
7624
|
+
});
|
|
6805
7625
|
};
|
|
6806
7626
|
/** Removing the active entry moves the selection to the first remaining workflow. */
|
|
6807
7627
|
const removeWorkflow = (index) => {
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
7628
|
+
setRows((current) => {
|
|
7629
|
+
const previous = current.comfyui.workflows[index];
|
|
7630
|
+
const workflows = current.comfyui.workflows.filter((_entry, position) => position !== index);
|
|
7631
|
+
const activeWorkflow = previous !== void 0 && previous.name === current.comfyui.activeWorkflow ? workflows[0]?.name ?? "" : current.comfyui.activeWorkflow;
|
|
7632
|
+
return {
|
|
7633
|
+
...current,
|
|
7634
|
+
comfyui: {
|
|
7635
|
+
...current.comfyui,
|
|
7636
|
+
workflows,
|
|
7637
|
+
activeWorkflow
|
|
7638
|
+
}
|
|
7639
|
+
};
|
|
7640
|
+
});
|
|
6812
7641
|
};
|
|
6813
7642
|
/** Editing one entry's preset leaves the rest of the entry untouched. */
|
|
6814
7643
|
const setWorkflowPreset = (index, presetPrompt) => {
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
7644
|
+
setRows((current) => {
|
|
7645
|
+
const workflows = current.comfyui.workflows.map((entry, position) => position === index ? {
|
|
7646
|
+
...entry,
|
|
7647
|
+
presetPrompt
|
|
7648
|
+
} : entry);
|
|
7649
|
+
return {
|
|
7650
|
+
...current,
|
|
7651
|
+
comfyui: {
|
|
7652
|
+
...current.comfyui,
|
|
7653
|
+
workflows
|
|
7654
|
+
}
|
|
7655
|
+
};
|
|
7656
|
+
});
|
|
6819
7657
|
};
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
7658
|
+
/** Workspace checkbox persists immediately, like every other toggle on this card. */
|
|
7659
|
+
const toggleSaveToWorkspace = (next) => {
|
|
7660
|
+
setSaveToWorkspace(next);
|
|
7661
|
+
setWorkspaceMessage("");
|
|
7662
|
+
setWorkspaceMessageIsError(false);
|
|
7663
|
+
props.scope.set("saveToWorkspace", next).catch((cause) => {
|
|
7664
|
+
setSaveToWorkspace(snapshot.value?.saveToWorkspace ?? true);
|
|
7665
|
+
setWorkspaceMessage(cause instanceof Error ? cause.message : String(cause));
|
|
7666
|
+
setWorkspaceMessageIsError(true);
|
|
7667
|
+
});
|
|
7668
|
+
};
|
|
7669
|
+
/** Folder input persists on Enter or blur; no save button needed. */
|
|
7670
|
+
const commitWorkspaceFolder = () => {
|
|
7671
|
+
const next = workspaceFolder.trim();
|
|
7672
|
+
if (next === (snapshot.value?.workspaceFolder ?? "dsh-image-gen")) return;
|
|
7673
|
+
setWorkspaceMessage("");
|
|
7674
|
+
setWorkspaceMessageIsError(false);
|
|
7675
|
+
props.scope.set("workspaceFolder", next).then(() => {
|
|
7676
|
+
setWorkspaceMessage(t("saved"));
|
|
7677
|
+
}).catch((cause) => {
|
|
7678
|
+
setWorkspaceFolder(snapshot.value?.workspaceFolder ?? "dsh-image-gen");
|
|
7679
|
+
setWorkspaceMessage(cause instanceof Error ? cause.message : String(cause));
|
|
7680
|
+
setWorkspaceMessageIsError(true);
|
|
7681
|
+
});
|
|
7682
|
+
};
|
|
7683
|
+
/** The pill toggle saves immediately, like the default-provider radio. */
|
|
7684
|
+
const toggleShowPill = (next) => {
|
|
7685
|
+
setShowPill(next);
|
|
7686
|
+
setUiMessage("");
|
|
7687
|
+
setUiMessageIsError(false);
|
|
7688
|
+
props.scope.set("showProviderPill", next).catch((cause) => {
|
|
7689
|
+
setShowPill(snapshot.value?.showProviderPill === true);
|
|
7690
|
+
setUiMessage(cause instanceof Error ? cause.message : String(cause));
|
|
7691
|
+
setUiMessageIsError(true);
|
|
7692
|
+
});
|
|
7693
|
+
};
|
|
7694
|
+
const renderCloudBody = (provider) => {
|
|
7695
|
+
const row = rows[provider];
|
|
7696
|
+
const keyRef = cloudCredentialRef(provider) ?? "";
|
|
7697
|
+
const keyReadOnly = row.keyInfo?.writable === false;
|
|
7698
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
7699
|
+
className: "dsh-ig-provider-body",
|
|
7700
|
+
children: (0, react_jsx_runtime.jsxs)("form", {
|
|
7701
|
+
onSubmit: (event) => {
|
|
7702
|
+
event.preventDefault();
|
|
7703
|
+
saveProviderRow(provider);
|
|
7704
|
+
},
|
|
7705
|
+
children: [
|
|
7706
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
7707
|
+
className: "dsh-ig-field",
|
|
7708
|
+
children: [
|
|
7709
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7710
|
+
className: "dsh-ig-label",
|
|
7711
|
+
children: t("apiKeyLabel", { provider: providerLabels[provider] })
|
|
7712
|
+
}),
|
|
7713
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
7714
|
+
className: "dsh-ig-input",
|
|
7715
|
+
type: "password",
|
|
7716
|
+
autoComplete: "off",
|
|
7717
|
+
value: row.keyInput,
|
|
7718
|
+
onChange: (event) => {
|
|
7719
|
+
updateRow(provider, { keyInput: event.target.value });
|
|
7720
|
+
},
|
|
7721
|
+
placeholder: row.keyStatus === "configured" ? t("apiKeyPlaceholder") : "",
|
|
7722
|
+
disabled: !snapshot.writable || keyReadOnly
|
|
7723
|
+
}),
|
|
7724
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7725
|
+
className: "dsh-ig-hint",
|
|
7726
|
+
children: keyReadOnly ? t("keyReadOnly", { source: row.keyInfo?.source ?? "" }) : t("apiKeyHint", { key: keyRef })
|
|
7727
|
+
})
|
|
7728
|
+
]
|
|
7729
|
+
}),
|
|
7730
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
7731
|
+
className: "dsh-ig-field",
|
|
7732
|
+
children: [
|
|
7733
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7734
|
+
className: "dsh-ig-label",
|
|
7735
|
+
children: t("endpoint")
|
|
7736
|
+
}),
|
|
7737
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
7738
|
+
className: "dsh-ig-input-group",
|
|
7739
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
7740
|
+
className: "dsh-ig-input",
|
|
7741
|
+
type: "url",
|
|
7742
|
+
value: row.baseURL,
|
|
7743
|
+
onChange: (event) => {
|
|
7744
|
+
updateRow(provider, { baseURL: event.target.value });
|
|
7745
|
+
},
|
|
7746
|
+
required: true,
|
|
7747
|
+
disabled: !snapshot.writable
|
|
7748
|
+
}), provider !== "openai-compat" ? (0, react_jsx_runtime.jsx)("button", {
|
|
7749
|
+
type: "button",
|
|
7750
|
+
className: "dsh-ig-btn-reset",
|
|
7751
|
+
title: t("resetTitle"),
|
|
7752
|
+
onClick: () => {
|
|
7753
|
+
updateRow(provider, { baseURL: DEFAULT_BASE_URLS[provider] });
|
|
7754
|
+
},
|
|
7755
|
+
disabled: !snapshot.writable,
|
|
7756
|
+
children: t("reset")
|
|
7757
|
+
}) : null]
|
|
7758
|
+
}),
|
|
7759
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7760
|
+
className: "dsh-ig-hint",
|
|
7761
|
+
children: t(CLOUD_HINT_KEYS[provider])
|
|
7762
|
+
})
|
|
7763
|
+
]
|
|
7764
|
+
}),
|
|
7765
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
7766
|
+
className: "dsh-ig-field",
|
|
7767
|
+
children: [
|
|
7768
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7769
|
+
className: "dsh-ig-label",
|
|
7770
|
+
children: t("model")
|
|
7771
|
+
}),
|
|
7772
|
+
modelPullSupported(provider) ? (0, react_jsx_runtime.jsxs)("div", {
|
|
7773
|
+
className: "dsh-ig-input-group",
|
|
7774
|
+
children: [
|
|
7775
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
7776
|
+
className: "dsh-ig-input",
|
|
7777
|
+
value: row.model,
|
|
7778
|
+
onChange: (event) => {
|
|
7779
|
+
updateRow(provider, { model: event.target.value });
|
|
7780
|
+
},
|
|
7781
|
+
list: `dsh-ig-${provider}-model-options`,
|
|
7782
|
+
required: provider !== "openai-compat",
|
|
7783
|
+
disabled: !snapshot.writable
|
|
7784
|
+
}),
|
|
7785
|
+
(0, react_jsx_runtime.jsx)("datalist", {
|
|
7786
|
+
id: `dsh-ig-${provider}-model-options`,
|
|
7787
|
+
children: row.modelOptions.map((id) => (0, react_jsx_runtime.jsx)("option", { value: id }, id))
|
|
7788
|
+
}),
|
|
7789
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
7790
|
+
type: "button",
|
|
7791
|
+
className: "dsh-ig-btn-secondary",
|
|
7792
|
+
disabled: row.fetchingModels || !snapshot.writable,
|
|
7793
|
+
onClick: () => {
|
|
7794
|
+
fetchProviderModels(provider);
|
|
7795
|
+
},
|
|
7796
|
+
children: row.fetchingModels ? t("fetchingModels") : t("fetchModels")
|
|
7797
|
+
})
|
|
7798
|
+
]
|
|
7799
|
+
}) : (0, react_jsx_runtime.jsx)("input", {
|
|
7800
|
+
className: "dsh-ig-input",
|
|
7801
|
+
value: row.model,
|
|
7802
|
+
onChange: (event) => {
|
|
7803
|
+
updateRow(provider, { model: event.target.value });
|
|
7804
|
+
},
|
|
7805
|
+
required: true,
|
|
7806
|
+
disabled: !snapshot.writable
|
|
7807
|
+
}),
|
|
7808
|
+
modelPullSupported(provider) ? row.modelFetchMessage.length > 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
7809
|
+
className: `dsh-ig-hint${row.modelFetchIsError ? " dsh-ig-hint-error" : ""}`,
|
|
7810
|
+
role: "status",
|
|
7811
|
+
children: row.modelFetchMessage
|
|
7812
|
+
}) : (0, react_jsx_runtime.jsx)("span", {
|
|
7813
|
+
className: "dsh-ig-hint",
|
|
7814
|
+
children: t("fetchModelsHint")
|
|
7815
|
+
}) : null
|
|
7816
|
+
]
|
|
7817
|
+
}),
|
|
7818
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
7819
|
+
className: "dsh-ig-row-actions",
|
|
7820
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
7821
|
+
className: `dsh-ig-status${row.messageIsError ? " dsh-ig-status-error" : ""}`,
|
|
7822
|
+
role: "status",
|
|
7823
|
+
children: row.message || testResultText(row.testResult)
|
|
7824
|
+
}), (0, react_jsx_runtime.jsxs)("span", {
|
|
7825
|
+
className: "dsh-ig-row-buttons",
|
|
7826
|
+
children: [
|
|
7827
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
7828
|
+
type: "button",
|
|
7829
|
+
className: "dsh-ig-btn-secondary",
|
|
7830
|
+
disabled: row.testing,
|
|
7831
|
+
onClick: () => {
|
|
7832
|
+
testConnection(provider);
|
|
7833
|
+
},
|
|
7834
|
+
children: row.testing ? t("testing") : t("testConnection")
|
|
7835
|
+
}),
|
|
7836
|
+
row.keyStatus === "configured" && !keyReadOnly ? (0, react_jsx_runtime.jsx)("button", {
|
|
7837
|
+
type: "button",
|
|
7838
|
+
className: "dsh-ig-btn-secondary dsh-ig-btn-danger",
|
|
7839
|
+
disabled: row.saving,
|
|
7840
|
+
onClick: () => {
|
|
7841
|
+
clearProviderKey(provider);
|
|
7842
|
+
},
|
|
7843
|
+
children: t("clearKey")
|
|
7844
|
+
}) : null,
|
|
7845
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
7846
|
+
className: "dsh-ig-save",
|
|
7847
|
+
type: "submit",
|
|
7848
|
+
disabled: row.saving || !snapshot.writable,
|
|
7849
|
+
children: row.saving ? t("saving") : t("save")
|
|
7850
|
+
})
|
|
7851
|
+
]
|
|
7852
|
+
})]
|
|
7853
|
+
})
|
|
7854
|
+
]
|
|
7855
|
+
})
|
|
7856
|
+
});
|
|
7857
|
+
};
|
|
7858
|
+
const renderComfyUIBody = () => {
|
|
7859
|
+
const row = rows.comfyui;
|
|
7860
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
7861
|
+
className: "dsh-ig-provider-body",
|
|
7862
|
+
children: (0, react_jsx_runtime.jsxs)("form", {
|
|
7863
|
+
onSubmit: (event) => {
|
|
7864
|
+
event.preventDefault();
|
|
7865
|
+
saveProviderRow("comfyui");
|
|
7866
|
+
},
|
|
7867
|
+
children: [
|
|
7868
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
7869
|
+
className: "dsh-ig-field",
|
|
7870
|
+
children: [
|
|
7871
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7872
|
+
className: "dsh-ig-label",
|
|
7873
|
+
children: t("endpoint")
|
|
7874
|
+
}),
|
|
7875
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
7876
|
+
className: "dsh-ig-input-group",
|
|
7877
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
7878
|
+
className: "dsh-ig-input",
|
|
7879
|
+
type: "url",
|
|
7880
|
+
value: row.baseURL,
|
|
7881
|
+
onChange: (event) => {
|
|
7882
|
+
updateRow("comfyui", { baseURL: event.target.value });
|
|
7883
|
+
},
|
|
7884
|
+
required: true,
|
|
7885
|
+
disabled: !snapshot.writable
|
|
7886
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
7887
|
+
type: "button",
|
|
7888
|
+
className: "dsh-ig-btn-reset",
|
|
7889
|
+
title: t("resetTitle"),
|
|
7890
|
+
onClick: () => {
|
|
7891
|
+
updateRow("comfyui", { baseURL: DEFAULT_BASE_URLS.comfyui });
|
|
7892
|
+
},
|
|
7893
|
+
disabled: !snapshot.writable,
|
|
7894
|
+
children: t("reset")
|
|
7895
|
+
})]
|
|
7896
|
+
}),
|
|
7897
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7898
|
+
className: "dsh-ig-hint",
|
|
7899
|
+
children: t("endpointHintComfyUI")
|
|
7900
|
+
})
|
|
7901
|
+
]
|
|
7902
|
+
}),
|
|
7903
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
7904
|
+
className: "dsh-ig-field",
|
|
7905
|
+
children: [
|
|
7906
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7907
|
+
className: "dsh-ig-label",
|
|
7908
|
+
children: t("workflow")
|
|
7909
|
+
}),
|
|
7910
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
7911
|
+
className: "dsh-ig-file-row",
|
|
7912
|
+
children: [(0, react_jsx_runtime.jsxs)("label", {
|
|
7913
|
+
className: "dsh-ig-file-button",
|
|
7914
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
7915
|
+
className: "dsh-ig-file-input",
|
|
7916
|
+
type: "file",
|
|
7917
|
+
accept: ".json,application/json",
|
|
7918
|
+
onChange: (event) => {
|
|
7919
|
+
importWorkflow(event);
|
|
7920
|
+
}
|
|
7921
|
+
}), t("workflowImport")]
|
|
7922
|
+
}), row.workflows.length === 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
7923
|
+
className: "dsh-ig-file-name",
|
|
7924
|
+
children: t("workflowMissing")
|
|
7925
|
+
}) : null]
|
|
7926
|
+
}),
|
|
7927
|
+
row.workflows.length > 0 ? (0, react_jsx_runtime.jsx)("ul", {
|
|
7928
|
+
className: "dsh-ig-workflow-list",
|
|
7929
|
+
children: row.workflows.map((entry, index) => (0, react_jsx_runtime.jsxs)("li", {
|
|
7930
|
+
className: "dsh-ig-workflow-row",
|
|
7931
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
7932
|
+
className: "dsh-ig-workflow-main",
|
|
7933
|
+
children: [
|
|
7934
|
+
(0, react_jsx_runtime.jsx)("label", {
|
|
7935
|
+
className: "dsh-ig-workflow-active",
|
|
7936
|
+
title: t("workflowActiveTitle"),
|
|
7937
|
+
children: (0, react_jsx_runtime.jsx)("input", {
|
|
7938
|
+
type: "radio",
|
|
7939
|
+
name: "dsh-ig-active-workflow",
|
|
7940
|
+
"aria-label": t("workflowActiveTitle"),
|
|
7941
|
+
checked: entry.name === row.activeWorkflow,
|
|
7942
|
+
onChange: () => {
|
|
7943
|
+
updateRow("comfyui", { activeWorkflow: entry.name });
|
|
7944
|
+
}
|
|
7945
|
+
})
|
|
7946
|
+
}),
|
|
7947
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
7948
|
+
className: "dsh-ig-input dsh-ig-workflow-name",
|
|
7949
|
+
value: entry.name,
|
|
7950
|
+
title: entry.name,
|
|
7951
|
+
onChange: (event) => {
|
|
7952
|
+
renameWorkflow(index, event.target.value);
|
|
7953
|
+
}
|
|
7954
|
+
}),
|
|
7955
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
7956
|
+
type: "button",
|
|
7957
|
+
className: "dsh-ig-btn-reset",
|
|
7958
|
+
onClick: () => {
|
|
7959
|
+
removeWorkflow(index);
|
|
7960
|
+
},
|
|
7961
|
+
children: t("workflowRemove")
|
|
7962
|
+
})
|
|
7963
|
+
]
|
|
7964
|
+
}), (0, react_jsx_runtime.jsx)("input", {
|
|
7965
|
+
className: "dsh-ig-input dsh-ig-workflow-preset",
|
|
7966
|
+
value: entry.presetPrompt ?? "",
|
|
7967
|
+
placeholder: t("workflowPresetPlaceholder"),
|
|
7968
|
+
title: t("workflowPresetTitle"),
|
|
7969
|
+
onChange: (event) => {
|
|
7970
|
+
setWorkflowPreset(index, event.target.value);
|
|
7971
|
+
}
|
|
7972
|
+
})]
|
|
7973
|
+
}, String(index)))
|
|
7974
|
+
}) : null,
|
|
7975
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7976
|
+
className: "dsh-ig-hint",
|
|
7977
|
+
children: t("workflowHint")
|
|
7978
|
+
})
|
|
7979
|
+
]
|
|
7980
|
+
}),
|
|
7981
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
7982
|
+
className: "dsh-ig-field",
|
|
7983
|
+
children: [
|
|
7984
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
7985
|
+
className: "dsh-ig-label",
|
|
7986
|
+
children: t("timeout")
|
|
7987
|
+
}),
|
|
7988
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
7989
|
+
className: "dsh-ig-input",
|
|
7990
|
+
type: "number",
|
|
7991
|
+
min: "1",
|
|
7992
|
+
max: "3600",
|
|
7993
|
+
step: "1",
|
|
7994
|
+
value: row.timeoutSeconds,
|
|
7995
|
+
onChange: (event) => {
|
|
7996
|
+
updateRow("comfyui", { timeoutSeconds: Number(event.target.value) });
|
|
7997
|
+
},
|
|
7998
|
+
required: true,
|
|
7999
|
+
disabled: !snapshot.writable
|
|
8000
|
+
}),
|
|
8001
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
8002
|
+
className: "dsh-ig-hint",
|
|
8003
|
+
children: t("timeoutHint")
|
|
8004
|
+
})
|
|
8005
|
+
]
|
|
8006
|
+
}),
|
|
8007
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
8008
|
+
className: "dsh-ig-row-actions",
|
|
8009
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
8010
|
+
className: `dsh-ig-status${row.messageIsError ? " dsh-ig-status-error" : ""}`,
|
|
8011
|
+
role: "status",
|
|
8012
|
+
children: row.message || testResultText(row.testResult)
|
|
8013
|
+
}), (0, react_jsx_runtime.jsxs)("span", {
|
|
8014
|
+
className: "dsh-ig-row-buttons",
|
|
8015
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
8016
|
+
type: "button",
|
|
8017
|
+
className: "dsh-ig-btn-secondary",
|
|
8018
|
+
disabled: row.testing,
|
|
8019
|
+
onClick: () => {
|
|
8020
|
+
testConnection("comfyui");
|
|
8021
|
+
},
|
|
8022
|
+
children: row.testing ? t("testing") : t("testConnection")
|
|
8023
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
8024
|
+
className: "dsh-ig-save",
|
|
8025
|
+
type: "submit",
|
|
8026
|
+
disabled: row.saving || !snapshot.writable || row.workflows.length === 0,
|
|
8027
|
+
children: row.saving ? t("saving") : t("save")
|
|
8028
|
+
})]
|
|
8029
|
+
})]
|
|
8030
|
+
})
|
|
8031
|
+
]
|
|
8032
|
+
})
|
|
8033
|
+
});
|
|
8034
|
+
};
|
|
8035
|
+
const renderProviderRow = (provider) => {
|
|
8036
|
+
const row = rows[provider];
|
|
8037
|
+
const badge = badgeOf(provider);
|
|
8038
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
8039
|
+
className: `dsh-ig-provider-row ${row.expanded ? "dsh-ig-provider-row-open" : ""}`,
|
|
8040
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
8041
|
+
type: "button",
|
|
8042
|
+
className: "dsh-ig-provider-head",
|
|
8043
|
+
"aria-expanded": row.expanded,
|
|
8044
|
+
onClick: () => {
|
|
8045
|
+
updateRow(provider, { expanded: !row.expanded });
|
|
8046
|
+
},
|
|
8047
|
+
children: [
|
|
8048
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
8049
|
+
className: "dsh-ig-provider-name",
|
|
8050
|
+
children: providerLabels[provider]
|
|
8051
|
+
}),
|
|
8052
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
8053
|
+
className: badge.className,
|
|
8054
|
+
title: badge.text,
|
|
8055
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
8056
|
+
className: "dsh-ig-badge-dot",
|
|
8057
|
+
"aria-hidden": "true"
|
|
8058
|
+
}), badge.text]
|
|
8059
|
+
}),
|
|
8060
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
8061
|
+
className: `dsh-ig-provider-chevron ${row.expanded ? "dsh-ig-provider-chevron-open" : ""}`,
|
|
8062
|
+
"aria-hidden": "true",
|
|
8063
|
+
children: (0, react_jsx_runtime.jsx)("svg", {
|
|
8064
|
+
width: "12",
|
|
8065
|
+
height: "12",
|
|
8066
|
+
viewBox: "0 0 16 16",
|
|
8067
|
+
fill: "none",
|
|
8068
|
+
stroke: "currentColor",
|
|
8069
|
+
strokeWidth: "2",
|
|
8070
|
+
strokeLinecap: "round",
|
|
8071
|
+
strokeLinejoin: "round",
|
|
8072
|
+
children: (0, react_jsx_runtime.jsx)("path", { d: "M4 6l4 4 4-4" })
|
|
8073
|
+
})
|
|
8074
|
+
})
|
|
8075
|
+
]
|
|
8076
|
+
}), row.expanded ? provider === "comfyui" ? renderComfyUIBody() : renderCloudBody(provider) : null]
|
|
8077
|
+
}, provider);
|
|
8078
|
+
};
|
|
8079
|
+
return (0, react_jsx_runtime.jsxs)("li", {
|
|
8080
|
+
className: `dsh-ig-card ${open ? "dsh-ig-card-open" : ""}`,
|
|
8081
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
8082
|
+
type: "button",
|
|
8083
|
+
className: "dsh-ig-head",
|
|
8084
|
+
"aria-expanded": open,
|
|
8085
|
+
onClick: () => {
|
|
8086
|
+
setOpen((value) => !value);
|
|
8087
|
+
},
|
|
8088
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
8089
|
+
className: "dsh-ig-head-text",
|
|
8090
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
8091
|
+
className: "dsh-ig-title",
|
|
8092
|
+
children: t("title")
|
|
8093
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
8094
|
+
className: "dsh-ig-desc",
|
|
8095
|
+
children: t("description")
|
|
8096
|
+
})]
|
|
8097
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
6839
8098
|
className: `dsh-ig-chevron ${open ? "dsh-ig-chevron-open" : ""}`,
|
|
6840
8099
|
"aria-hidden": "true",
|
|
6841
8100
|
children: (0, react_jsx_runtime.jsx)("svg", {
|
|
@@ -6850,280 +8109,147 @@ window.__ModuleLoader__.load({
|
|
|
6850
8109
|
children: (0, react_jsx_runtime.jsx)("path", { d: "M4 6l4 4 4-4" })
|
|
6851
8110
|
})
|
|
6852
8111
|
})]
|
|
6853
|
-
}), open ? (0, react_jsx_runtime.jsxs)("
|
|
8112
|
+
}), open ? (0, react_jsx_runtime.jsxs)("div", {
|
|
6854
8113
|
className: "dsh-ig-body",
|
|
6855
|
-
onSubmit: (event) => {
|
|
6856
|
-
save(event);
|
|
6857
|
-
},
|
|
6858
8114
|
children: [
|
|
6859
|
-
(0, react_jsx_runtime.
|
|
6860
|
-
className: "dsh-ig-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
className: "dsh-ig-label",
|
|
6864
|
-
children: t("provider")
|
|
6865
|
-
}),
|
|
6866
|
-
(0, react_jsx_runtime.jsxs)("select", {
|
|
6867
|
-
className: "dsh-ig-input",
|
|
6868
|
-
value: provider,
|
|
6869
|
-
onChange: (event) => {
|
|
6870
|
-
const next = event.target.value;
|
|
6871
|
-
setProvider(next);
|
|
6872
|
-
setModel(modelOf(next, snapshot.value));
|
|
6873
|
-
setBaseURL(baseURLOf(next, snapshot.value));
|
|
6874
|
-
setKey("");
|
|
6875
|
-
},
|
|
6876
|
-
children: [
|
|
6877
|
-
(0, react_jsx_runtime.jsx)("option", {
|
|
6878
|
-
value: "google",
|
|
6879
|
-
children: t("providerGoogle")
|
|
6880
|
-
}),
|
|
6881
|
-
(0, react_jsx_runtime.jsx)("option", {
|
|
6882
|
-
value: "openai",
|
|
6883
|
-
children: t("providerOpenAI")
|
|
6884
|
-
}),
|
|
6885
|
-
(0, react_jsx_runtime.jsx)("option", {
|
|
6886
|
-
value: "seedream",
|
|
6887
|
-
children: t("providerSeedream")
|
|
6888
|
-
}),
|
|
6889
|
-
(0, react_jsx_runtime.jsx)("option", {
|
|
6890
|
-
value: "dashscope",
|
|
6891
|
-
children: t("providerDashScope")
|
|
6892
|
-
}),
|
|
6893
|
-
(0, react_jsx_runtime.jsx)("option", {
|
|
6894
|
-
value: "comfyui",
|
|
6895
|
-
children: t("providerComfyUI")
|
|
6896
|
-
})
|
|
6897
|
-
]
|
|
6898
|
-
}),
|
|
6899
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
6900
|
-
className: "dsh-ig-hint",
|
|
6901
|
-
children: providerLabels[provider]
|
|
6902
|
-
})
|
|
6903
|
-
]
|
|
6904
|
-
}),
|
|
6905
|
-
provider !== "comfyui" ? (0, react_jsx_runtime.jsxs)("label", {
|
|
6906
|
-
className: "dsh-ig-field",
|
|
6907
|
-
children: [
|
|
6908
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
6909
|
-
className: "dsh-ig-label",
|
|
6910
|
-
children: t("apiKeyLabel", { provider: providerLabels[provider] })
|
|
6911
|
-
}),
|
|
6912
|
-
(0, react_jsx_runtime.jsx)("input", {
|
|
6913
|
-
className: "dsh-ig-input",
|
|
6914
|
-
type: "password",
|
|
6915
|
-
autoComplete: "off",
|
|
6916
|
-
value: key,
|
|
6917
|
-
onChange: (event) => {
|
|
6918
|
-
setKey(event.target.value);
|
|
6919
|
-
},
|
|
6920
|
-
placeholder: configured ? t("apiKeyPlaceholder") : ""
|
|
6921
|
-
}),
|
|
6922
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
6923
|
-
className: "dsh-ig-hint",
|
|
6924
|
-
children: t("apiKeyHint", { key: KEY_REF[provider] ?? "" })
|
|
6925
|
-
})
|
|
6926
|
-
]
|
|
8115
|
+
!snapshot.writable ? (0, react_jsx_runtime.jsx)("p", {
|
|
8116
|
+
className: "dsh-ig-status dsh-ig-status-readonly",
|
|
8117
|
+
role: "note",
|
|
8118
|
+
children: t("settingsReadOnly")
|
|
6927
8119
|
}) : null,
|
|
6928
|
-
(0, react_jsx_runtime.jsxs)("
|
|
8120
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
6929
8121
|
className: "dsh-ig-field",
|
|
6930
8122
|
children: [
|
|
6931
8123
|
(0, react_jsx_runtime.jsx)("span", {
|
|
6932
8124
|
className: "dsh-ig-label",
|
|
6933
|
-
children: t("
|
|
8125
|
+
children: t("defaultProvider")
|
|
6934
8126
|
}),
|
|
6935
|
-
(0, react_jsx_runtime.
|
|
6936
|
-
className: "dsh-ig-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
},
|
|
6952
|
-
children: t("reset")
|
|
6953
|
-
})]
|
|
8127
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
8128
|
+
className: "dsh-ig-radios",
|
|
8129
|
+
role: "radiogroup",
|
|
8130
|
+
"aria-label": t("defaultProvider"),
|
|
8131
|
+
children: IMAGE_PROVIDERS.map((provider) => (0, react_jsx_runtime.jsxs)("label", {
|
|
8132
|
+
className: `dsh-ig-radio${defaultProvider === provider ? " dsh-ig-radio-checked" : ""}`,
|
|
8133
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
8134
|
+
type: "radio",
|
|
8135
|
+
name: "dsh-ig-default-provider",
|
|
8136
|
+
checked: defaultProvider === provider,
|
|
8137
|
+
onChange: () => {
|
|
8138
|
+
selectDefaultProvider(provider);
|
|
8139
|
+
},
|
|
8140
|
+
disabled: !snapshot.writable
|
|
8141
|
+
}), providerLabels[provider]]
|
|
8142
|
+
}, provider))
|
|
6954
8143
|
}),
|
|
6955
8144
|
(0, react_jsx_runtime.jsx)("span", {
|
|
6956
8145
|
className: "dsh-ig-hint",
|
|
6957
|
-
children:
|
|
6958
|
-
})
|
|
8146
|
+
children: t("defaultProviderHint")
|
|
8147
|
+
}),
|
|
8148
|
+
providerMessage.length > 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
8149
|
+
className: `dsh-ig-status${providerMessageIsError ? " dsh-ig-status-error" : ""}`,
|
|
8150
|
+
role: "status",
|
|
8151
|
+
children: providerMessage
|
|
8152
|
+
}) : null
|
|
6959
8153
|
]
|
|
6960
8154
|
}),
|
|
6961
|
-
|
|
6962
|
-
className: "dsh-ig-
|
|
6963
|
-
children:
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
className: "dsh-ig-input",
|
|
6968
|
-
value: model,
|
|
6969
|
-
onChange: (event) => {
|
|
6970
|
-
setModel(event.target.value);
|
|
6971
|
-
},
|
|
6972
|
-
required: true
|
|
6973
|
-
})]
|
|
6974
|
-
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
6975
|
-
className: "dsh-ig-field",
|
|
8155
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
8156
|
+
className: "dsh-ig-providers",
|
|
8157
|
+
children: IMAGE_PROVIDERS.map((provider) => renderProviderRow(provider))
|
|
8158
|
+
}),
|
|
8159
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
8160
|
+
className: "dsh-ig-section",
|
|
6976
8161
|
children: [
|
|
6977
8162
|
(0, react_jsx_runtime.jsx)("span", {
|
|
6978
|
-
className: "dsh-ig-
|
|
6979
|
-
children: t("
|
|
8163
|
+
className: "dsh-ig-section-title",
|
|
8164
|
+
children: t("workspaceSection")
|
|
6980
8165
|
}),
|
|
6981
8166
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
6982
|
-
className: "dsh-ig-
|
|
8167
|
+
className: "dsh-ig-field",
|
|
6983
8168
|
children: [(0, react_jsx_runtime.jsxs)("label", {
|
|
6984
|
-
className: "dsh-ig-
|
|
8169
|
+
className: "dsh-ig-check-row",
|
|
6985
8170
|
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
accept: ".json,application/json",
|
|
8171
|
+
type: "checkbox",
|
|
8172
|
+
checked: saveToWorkspace,
|
|
6989
8173
|
onChange: (event) => {
|
|
6990
|
-
|
|
6991
|
-
}
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
8174
|
+
toggleSaveToWorkspace(event.target.checked);
|
|
8175
|
+
},
|
|
8176
|
+
disabled: !snapshot.writable
|
|
8177
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
8178
|
+
className: "dsh-ig-label",
|
|
8179
|
+
children: t("saveToWorkspace")
|
|
8180
|
+
})]
|
|
8181
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
8182
|
+
className: "dsh-ig-hint",
|
|
8183
|
+
children: t("saveToWorkspaceHint")
|
|
8184
|
+
})]
|
|
6997
8185
|
}),
|
|
6998
|
-
|
|
6999
|
-
className: "dsh-ig-
|
|
7000
|
-
children:
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
children: (0, react_jsx_runtime.jsx)("input", {
|
|
7009
|
-
type: "radio",
|
|
7010
|
-
name: "dsh-ig-active-workflow",
|
|
7011
|
-
"aria-label": t("workflowActiveTitle"),
|
|
7012
|
-
checked: entry.name === activeWorkflow,
|
|
7013
|
-
onChange: () => {
|
|
7014
|
-
setActiveWorkflow(entry.name);
|
|
7015
|
-
}
|
|
7016
|
-
})
|
|
7017
|
-
}),
|
|
7018
|
-
(0, react_jsx_runtime.jsx)("input", {
|
|
7019
|
-
className: "dsh-ig-input dsh-ig-workflow-name",
|
|
7020
|
-
value: entry.name,
|
|
7021
|
-
title: entry.name,
|
|
7022
|
-
onChange: (event) => {
|
|
7023
|
-
renameWorkflow(index, event.target.value);
|
|
7024
|
-
}
|
|
7025
|
-
}),
|
|
7026
|
-
(0, react_jsx_runtime.jsx)("button", {
|
|
7027
|
-
type: "button",
|
|
7028
|
-
className: "dsh-ig-btn-reset",
|
|
7029
|
-
onClick: () => {
|
|
7030
|
-
removeWorkflow(index);
|
|
7031
|
-
},
|
|
7032
|
-
children: t("workflowRemove")
|
|
7033
|
-
})
|
|
7034
|
-
]
|
|
7035
|
-
}), (0, react_jsx_runtime.jsx)("input", {
|
|
7036
|
-
className: "dsh-ig-input dsh-ig-workflow-preset",
|
|
7037
|
-
value: entry.presetPrompt ?? "",
|
|
7038
|
-
placeholder: t("workflowPresetPlaceholder"),
|
|
7039
|
-
title: t("workflowPresetTitle"),
|
|
8186
|
+
saveToWorkspace ? (0, react_jsx_runtime.jsxs)("label", {
|
|
8187
|
+
className: "dsh-ig-field",
|
|
8188
|
+
children: [
|
|
8189
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
8190
|
+
className: "dsh-ig-label",
|
|
8191
|
+
children: t("folder")
|
|
8192
|
+
}),
|
|
8193
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
8194
|
+
className: "dsh-ig-input",
|
|
8195
|
+
value: workspaceFolder,
|
|
7040
8196
|
onChange: (event) => {
|
|
7041
|
-
|
|
7042
|
-
}
|
|
7043
|
-
|
|
7044
|
-
|
|
8197
|
+
setWorkspaceFolder(event.target.value);
|
|
8198
|
+
},
|
|
8199
|
+
onBlur: () => {
|
|
8200
|
+
commitWorkspaceFolder();
|
|
8201
|
+
},
|
|
8202
|
+
onKeyDown: (event) => {
|
|
8203
|
+
if (event.key === "Enter") commitWorkspaceFolder();
|
|
8204
|
+
},
|
|
8205
|
+
placeholder: "dsh-image-gen",
|
|
8206
|
+
disabled: !snapshot.writable
|
|
8207
|
+
}),
|
|
8208
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
8209
|
+
className: "dsh-ig-hint",
|
|
8210
|
+
children: t("folderHint")
|
|
8211
|
+
})
|
|
8212
|
+
]
|
|
7045
8213
|
}) : null,
|
|
7046
|
-
(0, react_jsx_runtime.jsx)("
|
|
7047
|
-
className: "dsh-ig-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
}), (0, react_jsx_runtime.jsxs)("label", {
|
|
7052
|
-
className: "dsh-ig-field",
|
|
7053
|
-
children: [
|
|
7054
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
7055
|
-
className: "dsh-ig-label",
|
|
7056
|
-
children: t("timeout")
|
|
7057
|
-
}),
|
|
7058
|
-
(0, react_jsx_runtime.jsx)("input", {
|
|
7059
|
-
className: "dsh-ig-input",
|
|
7060
|
-
type: "number",
|
|
7061
|
-
min: "1",
|
|
7062
|
-
max: "3600",
|
|
7063
|
-
step: "1",
|
|
7064
|
-
value: timeoutSeconds,
|
|
7065
|
-
onChange: (event) => {
|
|
7066
|
-
setTimeoutSeconds(Number(event.target.value));
|
|
7067
|
-
},
|
|
7068
|
-
required: true
|
|
7069
|
-
}),
|
|
7070
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
7071
|
-
className: "dsh-ig-hint",
|
|
7072
|
-
children: t("timeoutHint")
|
|
7073
|
-
})
|
|
8214
|
+
workspaceMessage.length > 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
8215
|
+
className: `dsh-ig-status${workspaceMessageIsError ? " dsh-ig-status-error" : ""}`,
|
|
8216
|
+
role: "status",
|
|
8217
|
+
children: workspaceMessage
|
|
8218
|
+
}) : null
|
|
7074
8219
|
]
|
|
7075
|
-
})] }),
|
|
7076
|
-
(0, react_jsx_runtime.jsxs)("div", {
|
|
7077
|
-
className: "dsh-ig-field",
|
|
7078
|
-
children: [(0, react_jsx_runtime.jsxs)("label", {
|
|
7079
|
-
className: "dsh-ig-check-row",
|
|
7080
|
-
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
7081
|
-
type: "checkbox",
|
|
7082
|
-
checked: saveToWorkspace,
|
|
7083
|
-
onChange: (event) => {
|
|
7084
|
-
setSaveToWorkspace(event.target.checked);
|
|
7085
|
-
}
|
|
7086
|
-
}), (0, react_jsx_runtime.jsx)("span", {
|
|
7087
|
-
className: "dsh-ig-label",
|
|
7088
|
-
children: t("saveToWorkspace")
|
|
7089
|
-
})]
|
|
7090
|
-
}), (0, react_jsx_runtime.jsx)("span", {
|
|
7091
|
-
className: "dsh-ig-hint",
|
|
7092
|
-
children: t("saveToWorkspaceHint")
|
|
7093
|
-
})]
|
|
7094
8220
|
}),
|
|
7095
|
-
saveToWorkspace ? (0, react_jsx_runtime.jsxs)("label", {
|
|
7096
|
-
className: "dsh-ig-field",
|
|
7097
|
-
children: [
|
|
7098
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
7099
|
-
className: "dsh-ig-label",
|
|
7100
|
-
children: t("folder")
|
|
7101
|
-
}),
|
|
7102
|
-
(0, react_jsx_runtime.jsx)("input", {
|
|
7103
|
-
className: "dsh-ig-input",
|
|
7104
|
-
value: workspaceFolder,
|
|
7105
|
-
onChange: (event) => {
|
|
7106
|
-
setWorkspaceFolder(event.target.value);
|
|
7107
|
-
},
|
|
7108
|
-
placeholder: "dsh-image-gen"
|
|
7109
|
-
}),
|
|
7110
|
-
(0, react_jsx_runtime.jsx)("span", {
|
|
7111
|
-
className: "dsh-ig-hint",
|
|
7112
|
-
children: t("folderHint")
|
|
7113
|
-
})
|
|
7114
|
-
]
|
|
7115
|
-
}) : null,
|
|
7116
8221
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
7117
|
-
className: "dsh-ig-
|
|
7118
|
-
children: [(0, react_jsx_runtime.jsx)("
|
|
7119
|
-
className:
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
8222
|
+
className: "dsh-ig-section",
|
|
8223
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
8224
|
+
className: "dsh-ig-section-title",
|
|
8225
|
+
children: t("uiSection")
|
|
8226
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
8227
|
+
className: "dsh-ig-field",
|
|
8228
|
+
children: [
|
|
8229
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
8230
|
+
className: "dsh-ig-check-row",
|
|
8231
|
+
children: [(0, react_jsx_runtime.jsx)("input", {
|
|
8232
|
+
type: "checkbox",
|
|
8233
|
+
checked: showPill,
|
|
8234
|
+
onChange: (event) => {
|
|
8235
|
+
toggleShowPill(event.target.checked);
|
|
8236
|
+
},
|
|
8237
|
+
disabled: !snapshot.writable
|
|
8238
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
8239
|
+
className: "dsh-ig-label",
|
|
8240
|
+
children: t("showPill")
|
|
8241
|
+
})]
|
|
8242
|
+
}),
|
|
8243
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
8244
|
+
className: "dsh-ig-hint",
|
|
8245
|
+
children: t("showPillHint")
|
|
8246
|
+
}),
|
|
8247
|
+
uiMessage.length > 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
8248
|
+
className: `dsh-ig-status${uiMessageIsError ? " dsh-ig-status-error" : ""}`,
|
|
8249
|
+
role: "status",
|
|
8250
|
+
children: uiMessage
|
|
8251
|
+
}) : null
|
|
8252
|
+
]
|
|
7127
8253
|
})]
|
|
7128
8254
|
})
|
|
7129
8255
|
]
|
|
@@ -7674,11 +8800,11 @@ window.__ModuleLoader__.load({
|
|
|
7674
8800
|
};
|
|
7675
8801
|
}
|
|
7676
8802
|
function modelOf(provider, value) {
|
|
7677
|
-
const stored = provider === "
|
|
8803
|
+
const stored = provider === "comfyui" ? activeComfyUIWorkflow(value ?? {})?.name : value?.[CLOUD_MODEL_FIELDS[provider]];
|
|
7678
8804
|
return typeof stored === "string" && stored.length > 0 ? stored : DEFAULT_MODELS[provider];
|
|
7679
8805
|
}
|
|
7680
8806
|
function baseURLOf(provider, value) {
|
|
7681
|
-
const stored = provider === "
|
|
8807
|
+
const stored = provider === "comfyui" ? value?.comfyuiBaseURL : value?.[CLOUD_URL_FIELDS[provider]];
|
|
7682
8808
|
return typeof stored === "string" && stored.length > 0 ? stored : DEFAULT_BASE_URLS[provider];
|
|
7683
8809
|
}
|
|
7684
8810
|
//#endregion
|