@dsh-plus/image-studio 0.1.7 → 0.1.9
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/lib/client.js +56 -35
- package/lib/index.d.ts +22 -22
- package/lib/index.js +1 -1
- package/package.json +2 -2
- package/src/client/api.ts +7 -1
- package/src/client/panel/generator.tsx +31 -7
- package/src/client/panel/uploads.tsx +7 -4
- package/src/config.ts +39 -35
- package/src/service.ts +2 -2
package/lib/client.js
CHANGED
|
@@ -338,28 +338,24 @@ window.__ModuleLoader__.load({
|
|
|
338
338
|
}
|
|
339
339
|
//#endregion
|
|
340
340
|
//#region ../shared/src/client/fetch.ts
|
|
341
|
-
|
|
342
|
-
* 同源自定义端点的最小 fetch 封装(各插件 client/api.ts 的公共收编版)。
|
|
343
|
-
* 仅同源(credentials: same-origin),错误统一抛 Error(body.error)。
|
|
344
|
-
* @module @dsh-plus/shared/client/fetch
|
|
345
|
-
*/
|
|
346
|
-
async function parse(res) {
|
|
341
|
+
async function parse(res, guard) {
|
|
347
342
|
const body = await res.json();
|
|
348
343
|
if (!res.ok) throw new Error(body.error ?? `HTTP ${res.status}`);
|
|
344
|
+
if (guard !== void 0 && !guard(body)) throw new Error(`响应结构不符合预期(${res.url})`);
|
|
349
345
|
return body;
|
|
350
346
|
}
|
|
351
347
|
/** GET 同源 JSON 端点。 */
|
|
352
|
-
async function getJson(route) {
|
|
353
|
-
return parse(await fetch(route, { credentials: "same-origin" }));
|
|
348
|
+
async function getJson(route, guard) {
|
|
349
|
+
return parse(await fetch(route, { credentials: "same-origin" }), guard);
|
|
354
350
|
}
|
|
355
351
|
/** POST 同源 JSON 端点(body 可省略)。 */
|
|
356
|
-
async function postJson(route, body) {
|
|
352
|
+
async function postJson(route, body, guard) {
|
|
357
353
|
return parse(await fetch(route, {
|
|
358
354
|
method: "POST",
|
|
359
355
|
credentials: "same-origin",
|
|
360
356
|
headers: { "content-type": "application/json" },
|
|
361
|
-
body
|
|
362
|
-
}));
|
|
357
|
+
...body === void 0 ? {} : { body: JSON.stringify(body) }
|
|
358
|
+
}), guard);
|
|
363
359
|
}
|
|
364
360
|
//#endregion
|
|
365
361
|
//#region ../shared/src/client/fields.tsx
|
|
@@ -929,9 +925,14 @@ ${extra}
|
|
|
929
925
|
function cancelTask(taskId) {
|
|
930
926
|
return postJson(`${BASE}/tasks/${taskId}/cancel`);
|
|
931
927
|
}
|
|
928
|
+
/** 画廊列表应答形状守卫:items 需为数组(渲染期直接 map)。 */
|
|
929
|
+
function isGalleryList(value) {
|
|
930
|
+
if (typeof value !== "object" || value === null) return false;
|
|
931
|
+
return Array.isArray(value.items);
|
|
932
|
+
}
|
|
932
933
|
/** 画廊列表。 */
|
|
933
934
|
function fetchGallery() {
|
|
934
|
-
return getJson(`${BASE}/gallery
|
|
935
|
+
return getJson(`${BASE}/gallery`, isGalleryList);
|
|
935
936
|
}
|
|
936
937
|
/** 删除画廊条目。 */
|
|
937
938
|
function deleteGalleryItem(itemId) {
|
|
@@ -2616,6 +2617,14 @@ ${extra}
|
|
|
2616
2617
|
function presetId(prefix) {
|
|
2617
2618
|
return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
2618
2619
|
}
|
|
2620
|
+
/** 单选上传结果 → 遮罩引用(无成功条目时保持原值)。 */
|
|
2621
|
+
function uploadRef(entries) {
|
|
2622
|
+
const first = entries[0];
|
|
2623
|
+
return first === void 0 ? null : {
|
|
2624
|
+
kind: "upload",
|
|
2625
|
+
id: first.id
|
|
2626
|
+
};
|
|
2627
|
+
}
|
|
2619
2628
|
function GeneratorForm(props) {
|
|
2620
2629
|
const { t, endpoint, catalog, protocols, presets, gallery, scope, api } = props;
|
|
2621
2630
|
const [providerId, setProviderId] = (0, react.useState)("");
|
|
@@ -2980,40 +2989,52 @@ ${extra}
|
|
|
2980
2989
|
className: "ims-hint",
|
|
2981
2990
|
children: t("sources.count").replace("{n}", String(sources.length))
|
|
2982
2991
|
}),
|
|
2983
|
-
uploads.error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
2984
|
-
className: "ims-status ims-statusError",
|
|
2985
|
-
role: "alert",
|
|
2986
|
-
children: [t("upload.failed"), uploads.error]
|
|
2987
|
-
}) : null,
|
|
2988
2992
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
2989
2993
|
className: "ims-blockTitle",
|
|
2990
2994
|
children: t("sources.mask")
|
|
2991
2995
|
}),
|
|
2992
2996
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2993
2997
|
className: "ims-sources",
|
|
2994
|
-
children: [
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
2998
|
+
children: [
|
|
2999
|
+
mask !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3000
|
+
className: "ims-thumb",
|
|
3001
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
3002
|
+
src: refUrl(mask),
|
|
3003
|
+
alt: ""
|
|
3004
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3005
|
+
type: "button",
|
|
3006
|
+
className: "ims-thumbRemove",
|
|
3007
|
+
"aria-label": t("sources.maskClear"),
|
|
3008
|
+
onClick: () => setMask(null),
|
|
3009
|
+
children: "×"
|
|
3010
|
+
})]
|
|
3011
|
+
}) : null,
|
|
3012
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3000
3013
|
type: "button",
|
|
3001
|
-
className: "ims-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3014
|
+
className: "ims-thumbAdd",
|
|
3015
|
+
onClick: () => setPicker("mask"),
|
|
3016
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconLayers, { size: 18 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("sources.maskPick") })]
|
|
3017
|
+
}),
|
|
3018
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(UploadButton, {
|
|
3019
|
+
t,
|
|
3020
|
+
uploads,
|
|
3021
|
+
multiple: false,
|
|
3022
|
+
accept: "image/png",
|
|
3023
|
+
className: "ims-thumbAdd",
|
|
3024
|
+
onUploaded: (entries) => setMask(uploadRef(entries)),
|
|
3025
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 18 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("upload.pick") })]
|
|
3026
|
+
})
|
|
3027
|
+
]
|
|
3012
3028
|
}),
|
|
3013
3029
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3014
3030
|
className: "ims-hint",
|
|
3015
3031
|
children: t("sources.maskHint")
|
|
3016
|
-
})
|
|
3032
|
+
}),
|
|
3033
|
+
uploads.error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
3034
|
+
className: "ims-status ims-statusError",
|
|
3035
|
+
role: "alert",
|
|
3036
|
+
children: [t("upload.failed"), uploads.error]
|
|
3037
|
+
}) : null
|
|
3017
3038
|
]
|
|
3018
3039
|
}) : null
|
|
3019
3040
|
]
|
package/lib/index.d.ts
CHANGED
|
@@ -1,26 +1,6 @@
|
|
|
1
1
|
import z from "@deepseek-ai/schemastery";
|
|
2
2
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
3
3
|
//#region src/config.d.ts
|
|
4
|
-
declare const Config: z<Schemastery.ObjectS<{
|
|
5
|
-
promptPresets: z<unknown[], any[]>;
|
|
6
|
-
paramPresets: z<unknown[], any[]>;
|
|
7
|
-
providerPresets: z<unknown[], any[]>;
|
|
8
|
-
maxConcurrent: z<number, number>;
|
|
9
|
-
requestTimeoutMs: z<number, number>;
|
|
10
|
-
proxy: z<string, string>;
|
|
11
|
-
galleryMaxItems: z<number, number>;
|
|
12
|
-
uploadTtlHours: z<number, number>;
|
|
13
|
-
}>, Schemastery.ObjectT<{
|
|
14
|
-
promptPresets: z<unknown[], any[]>;
|
|
15
|
-
paramPresets: z<unknown[], any[]>;
|
|
16
|
-
providerPresets: z<unknown[], any[]>;
|
|
17
|
-
maxConcurrent: z<number, number>;
|
|
18
|
-
requestTimeoutMs: z<number, number>;
|
|
19
|
-
proxy: z<string, string>;
|
|
20
|
-
galleryMaxItems: z<number, number>;
|
|
21
|
-
uploadTtlHours: z<number, number>;
|
|
22
|
-
}>>;
|
|
23
|
-
type ImageStudioConfig = Schemastery.TypeT<typeof Config>;
|
|
24
4
|
/** 提示词预设(解析后视图)。 */
|
|
25
5
|
interface PromptPresetEntry {
|
|
26
6
|
id: string;
|
|
@@ -44,6 +24,26 @@ interface ProviderPresetEntry {
|
|
|
44
24
|
credentialRef: string;
|
|
45
25
|
extraHeaders: Record<string, string>;
|
|
46
26
|
}
|
|
27
|
+
declare const Config: z<Schemastery.ObjectS<{
|
|
28
|
+
promptPresets: z<PromptPresetEntry[], PromptPresetEntry[]>;
|
|
29
|
+
paramPresets: z<ParamPresetEntry[], ParamPresetEntry[]>;
|
|
30
|
+
providerPresets: z<ProviderPresetEntry[], ProviderPresetEntry[]>;
|
|
31
|
+
maxConcurrent: z<number, number>;
|
|
32
|
+
requestTimeoutMs: z<number, number>;
|
|
33
|
+
proxy: z<string, string>;
|
|
34
|
+
galleryMaxItems: z<number, number>;
|
|
35
|
+
uploadTtlHours: z<number, number>;
|
|
36
|
+
}>, Schemastery.ObjectT<{
|
|
37
|
+
promptPresets: z<PromptPresetEntry[], PromptPresetEntry[]>;
|
|
38
|
+
paramPresets: z<ParamPresetEntry[], ParamPresetEntry[]>;
|
|
39
|
+
providerPresets: z<ProviderPresetEntry[], ProviderPresetEntry[]>;
|
|
40
|
+
maxConcurrent: z<number, number>;
|
|
41
|
+
requestTimeoutMs: z<number, number>;
|
|
42
|
+
proxy: z<string, string>;
|
|
43
|
+
galleryMaxItems: z<number, number>;
|
|
44
|
+
uploadTtlHours: z<number, number>;
|
|
45
|
+
}>>;
|
|
46
|
+
type ImageStudioConfig = Schemastery.TypeT<typeof Config>;
|
|
47
47
|
//#endregion
|
|
48
48
|
//#region src/provider/types.d.ts
|
|
49
49
|
/**
|
|
@@ -320,7 +320,7 @@ declare function credentialRefNameOf(presetId: string): string;
|
|
|
320
320
|
* @module image-studio/errors
|
|
321
321
|
*/
|
|
322
322
|
/** 全部错误码(封闭集合,新增协议/端点行为时按需扩充)。 */
|
|
323
|
-
declare const ERROR_CODES: readonly [
|
|
323
|
+
declare const ERROR_CODES: readonly ['unknown-protocol', 'unknown-endpoint', 'invalid-request', 'unknown-source', 'unknown-task', 'task-not-runnable', 'credential-unavailable', 'settings-unavailable', 'unsupported-media', 'upload-too-large', 'provider-error'];
|
|
324
324
|
type ErrorCode = (typeof ERROR_CODES)[number];
|
|
325
325
|
declare class ImageStudioError extends Error {
|
|
326
326
|
readonly code: ErrorCode;
|
|
@@ -474,7 +474,7 @@ declare function validateParamSpecs(specs: unknown): ParamSpecMap;
|
|
|
474
474
|
//#endregion
|
|
475
475
|
//#region src/index.d.ts
|
|
476
476
|
declare const name = "dsh-plus-image-studio";
|
|
477
|
-
declare const inject: readonly [
|
|
477
|
+
declare const inject: readonly ['credentials'];
|
|
478
478
|
declare module '@deepseek-ai/cordis' {
|
|
479
479
|
interface Context {
|
|
480
480
|
imageStudio: ImageStudioService;
|
package/lib/index.js
CHANGED
|
@@ -27,7 +27,7 @@ const PromptPreset = z.object({
|
|
|
27
27
|
const ParamPreset = z.object({
|
|
28
28
|
id: z.string().required().description("预设 id"),
|
|
29
29
|
name: z.string().required().description("预设名称"),
|
|
30
|
-
endpoint: z.
|
|
30
|
+
endpoint: z.union([z.const("generation"), z.const("edit")]).required().description("适用端点:generation | edit"),
|
|
31
31
|
/** 参数表结构由 params/spec 校验,settings 层存原始 JSON。 */
|
|
32
32
|
paramSpecs: z.any().required().description("参数开关表(ParamSpecMap JSON)")
|
|
33
33
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-plus/image-studio",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "dsh-plus service+ui plugin: 图像工作室——OpenAI Images 协议文生图/图生图,全参数开关化,双预设体系,并发生图任务与可二次编辑画廊",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"https-proxy-agent": "^9.1.0",
|
|
23
|
-
"@dsh-plus/shared": "0.1.
|
|
23
|
+
"@dsh-plus/shared": "0.1.16"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"@deepseek-ai/cordis": "^4.0.2",
|
package/src/client/api.ts
CHANGED
|
@@ -38,9 +38,15 @@ export function cancelTask(taskId: string): Promise<{ ok: boolean }> {
|
|
|
38
38
|
return postJson(`${BASE}/tasks/${taskId}/cancel`)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/** 画廊列表应答形状守卫:items 需为数组(渲染期直接 map)。 */
|
|
42
|
+
function isGalleryList(value: unknown): value is GalleryListWire {
|
|
43
|
+
if (typeof value !== 'object' || value === null) return false
|
|
44
|
+
return Array.isArray((value as { items?: unknown }).items)
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
/** 画廊列表。 */
|
|
42
48
|
export function fetchGallery(): Promise<GalleryListWire> {
|
|
43
|
-
return getJson(`${BASE}/gallery
|
|
49
|
+
return getJson(`${BASE}/gallery`, isGalleryList)
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
/** 画廊条目详情(含参数回放)。 */
|
|
@@ -15,7 +15,13 @@ import {
|
|
|
15
15
|
type Scope,
|
|
16
16
|
} from '@dsh-plus/shared/client'
|
|
17
17
|
import { type ReactElement, useEffect, useMemo, useRef, useState } from 'react'
|
|
18
|
-
import type {
|
|
18
|
+
import type {
|
|
19
|
+
GenerateRequest,
|
|
20
|
+
PresetsWire,
|
|
21
|
+
ProvidersWire,
|
|
22
|
+
SourceRef,
|
|
23
|
+
UploadEntry,
|
|
24
|
+
} from '../../dto.ts'
|
|
19
25
|
import type { GalleryItem } from '../../gallery/store.ts'
|
|
20
26
|
import { MAX_SOURCE_IMAGES } from '../../limits.ts'
|
|
21
27
|
import type { ParamEntry } from '../../params/catalog.ts'
|
|
@@ -66,6 +72,12 @@ function presetId(prefix: string): string {
|
|
|
66
72
|
return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`
|
|
67
73
|
}
|
|
68
74
|
|
|
75
|
+
/** 单选上传结果 → 遮罩引用(无成功条目时保持原值)。 */
|
|
76
|
+
function uploadRef(entries: UploadEntry[]): SourceRef | null {
|
|
77
|
+
const first = entries[0]
|
|
78
|
+
return first === undefined ? null : { kind: 'upload', id: first.id }
|
|
79
|
+
}
|
|
80
|
+
|
|
69
81
|
export function GeneratorForm(props: GeneratorProps): ReactElement {
|
|
70
82
|
const { t, endpoint, catalog, protocols, presets, gallery, scope, api } = props
|
|
71
83
|
const [providerId, setProviderId] = useState('')
|
|
@@ -433,12 +445,6 @@ export function GeneratorForm(props: GeneratorProps): ReactElement {
|
|
|
433
445
|
</UploadButton>
|
|
434
446
|
</div>
|
|
435
447
|
<p className="ims-hint">{t('sources.count').replace('{n}', String(sources.length))}</p>
|
|
436
|
-
{uploads.error !== null ? (
|
|
437
|
-
<p className="ims-status ims-statusError" role="alert">
|
|
438
|
-
{t('upload.failed')}
|
|
439
|
-
{uploads.error}
|
|
440
|
-
</p>
|
|
441
|
-
) : null}
|
|
442
448
|
<h3 className="ims-blockTitle">{t('sources.mask')}</h3>
|
|
443
449
|
<div className="ims-sources">
|
|
444
450
|
{mask !== null ? (
|
|
@@ -458,8 +464,26 @@ export function GeneratorForm(props: GeneratorProps): ReactElement {
|
|
|
458
464
|
<IconLayers size={18} />
|
|
459
465
|
<span>{t('sources.maskPick')}</span>
|
|
460
466
|
</button>
|
|
467
|
+
<UploadButton
|
|
468
|
+
t={t}
|
|
469
|
+
uploads={uploads}
|
|
470
|
+
multiple={false}
|
|
471
|
+
// 遮罩必须 PNG(官方要求带透明通道),文件选择器先行收窄。
|
|
472
|
+
accept="image/png"
|
|
473
|
+
className="ims-thumbAdd"
|
|
474
|
+
onUploaded={(entries) => setMask(uploadRef(entries))}
|
|
475
|
+
>
|
|
476
|
+
<IconPlusOutline16 size={18} />
|
|
477
|
+
<span>{t('upload.pick')}</span>
|
|
478
|
+
</UploadButton>
|
|
461
479
|
</div>
|
|
462
480
|
<p className="ims-hint">{t('sources.maskHint')}</p>
|
|
481
|
+
{uploads.error !== null ? (
|
|
482
|
+
<p className="ims-status ims-statusError" role="alert">
|
|
483
|
+
{t('upload.failed')}
|
|
484
|
+
{uploads.error}
|
|
485
|
+
</p>
|
|
486
|
+
) : null}
|
|
463
487
|
</section>
|
|
464
488
|
) : null}
|
|
465
489
|
</div>
|
|
@@ -77,10 +77,13 @@ interface UploadButtonProps {
|
|
|
77
77
|
onUploaded(entries: UploadEntry[]): void
|
|
78
78
|
/** 允许多选(源图)或单选(遮罩)。 */
|
|
79
79
|
multiple: boolean
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
/**
|
|
81
|
+
* 允许的文件类型(缺省四类位图;遮罩场景传 image/png)。
|
|
82
|
+
* 并上 undefined:调用方按 `multiple ? undefined : 'image/png'` 直接透传。
|
|
83
|
+
*/
|
|
84
|
+
accept?: string | undefined
|
|
85
|
+
disabled?: boolean | undefined
|
|
86
|
+
className?: string | undefined
|
|
84
87
|
children: ReactNode
|
|
85
88
|
}
|
|
86
89
|
|
package/src/config.ts
CHANGED
|
@@ -12,26 +12,56 @@ import { SETTINGS_NS as NS_LITERAL } from './ns.ts'
|
|
|
12
12
|
/** settings 命名空间(字面量即合法命名空间,编译期校验)。 */
|
|
13
13
|
export const SETTINGS_NS = NS_LITERAL
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
/** 提示词预设(解析后视图)。 */
|
|
16
|
+
export interface PromptPresetEntry {
|
|
17
|
+
id: string
|
|
18
|
+
name: string
|
|
19
|
+
text: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** 参数预设(解析后视图)。 */
|
|
23
|
+
export interface ParamPresetEntry {
|
|
24
|
+
id: string
|
|
25
|
+
name: string
|
|
26
|
+
endpoint: 'generation' | 'edit'
|
|
27
|
+
paramSpecs: unknown
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** 提供商预设(解析后视图)。 */
|
|
31
|
+
export interface ProviderPresetEntry {
|
|
32
|
+
id: string
|
|
33
|
+
name: string
|
|
34
|
+
protocol: string
|
|
35
|
+
baseUrl: string
|
|
36
|
+
model: string
|
|
37
|
+
credentialRef: string
|
|
38
|
+
extraHeaders: Record<string, string>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 显式标注而非 `any`:z.object() 推断类型含 cosmokit 的 `& Dict` 索引签名,
|
|
42
|
+
// 直接导出会触发 TS2883(inferred type cannot be named / not portable)并使
|
|
43
|
+
// tsdown 的 dts 生成失败。标注成具名契约后既保住类型、又让产物可移植——
|
|
44
|
+
// 退回 `any` 会让三个预设数组元素全部退化为 any。
|
|
45
|
+
const PromptPreset: z<PromptPresetEntry, PromptPresetEntry> = z.object({
|
|
19
46
|
id: z.string().required().description('预设 id(稳定标识,删除级联引用)'),
|
|
20
47
|
name: z.string().required().description('预设名称'),
|
|
21
48
|
text: z.string().required().description('提示词模板'),
|
|
22
49
|
})
|
|
23
50
|
|
|
24
|
-
|
|
25
|
-
const ParamPreset: any = z.object({
|
|
51
|
+
const ParamPreset: z<ParamPresetEntry, ParamPresetEntry> = z.object({
|
|
26
52
|
id: z.string().required().description('预设 id'),
|
|
27
53
|
name: z.string().required().description('预设名称'),
|
|
28
|
-
|
|
54
|
+
// 用字面量联合而非 z.string():endpoint 只有两个合法取值,收窄后与
|
|
55
|
+
// ParamPresetEntry['endpoint'] 对齐,拼错端点会在编译期暴露。
|
|
56
|
+
endpoint: z
|
|
57
|
+
.union([z.const('generation'), z.const('edit')])
|
|
58
|
+
.required()
|
|
59
|
+
.description('适用端点:generation | edit'),
|
|
29
60
|
/** 参数表结构由 params/spec 校验,settings 层存原始 JSON。 */
|
|
30
61
|
paramSpecs: z.any().required().description('参数开关表(ParamSpecMap JSON)'),
|
|
31
62
|
})
|
|
32
63
|
|
|
33
|
-
|
|
34
|
-
const ProviderPreset: any = z.object({
|
|
64
|
+
const ProviderPreset: z<ProviderPresetEntry, ProviderPresetEntry> = z.object({
|
|
35
65
|
id: z.string().required().description('预设 id'),
|
|
36
66
|
name: z.string().required().description('预设名称'),
|
|
37
67
|
protocol: z.string().required().description('协议 id(如 openai-images)'),
|
|
@@ -68,29 +98,3 @@ export const Config = z.object({
|
|
|
68
98
|
})
|
|
69
99
|
|
|
70
100
|
export type ImageStudioConfig = Schemastery.TypeT<typeof Config>
|
|
71
|
-
|
|
72
|
-
/** 提示词预设(解析后视图)。 */
|
|
73
|
-
export interface PromptPresetEntry {
|
|
74
|
-
id: string
|
|
75
|
-
name: string
|
|
76
|
-
text: string
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** 参数预设(解析后视图)。 */
|
|
80
|
-
export interface ParamPresetEntry {
|
|
81
|
-
id: string
|
|
82
|
-
name: string
|
|
83
|
-
endpoint: 'generation' | 'edit'
|
|
84
|
-
paramSpecs: unknown
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** 提供商预设(解析后视图)。 */
|
|
88
|
-
export interface ProviderPresetEntry {
|
|
89
|
-
id: string
|
|
90
|
-
name: string
|
|
91
|
-
protocol: string
|
|
92
|
-
baseUrl: string
|
|
93
|
-
model: string
|
|
94
|
-
credentialRef: string
|
|
95
|
-
extraHeaders: Record<string, string>
|
|
96
|
-
}
|
package/src/service.ts
CHANGED
|
@@ -126,11 +126,11 @@ export class ImageStudioService extends Service {
|
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
private paramPresets(): ParamPresetEntry[] {
|
|
129
|
-
return this.current().paramPresets
|
|
129
|
+
return this.current().paramPresets
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
private providerPresets(): ProviderPresetEntry[] {
|
|
133
|
-
return this.current().providerPresets
|
|
133
|
+
return this.current().providerPresets
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/** 预设快照(端点投影)。 */
|