dsh-image-gen 0.2.4 → 0.2.6
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 +2 -2
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/lib/client.js +1812 -492
- package/lib/client.js.map +1 -1
- package/lib/index.js +394 -52
- package/lib/types/client/gallery-store.d.ts +21 -3
- package/lib/types/client/gallery-view.d.ts +105 -10
- package/lib/types/client/image-result-node.d.ts +18 -1
- package/lib/types/client/index.d.ts +3 -1
- package/lib/types/comfyui-workflow.d.ts +13 -2
- package/lib/types/comfyui.d.ts +22 -5
- package/lib/types/config.d.ts +15 -6
- package/lib/types/image-route.d.ts +8 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/types/shared.d.ts +33 -0
- package/lib/types/workspace-save.d.ts +21 -0
- package/package.json +7 -3
|
@@ -12,9 +12,17 @@ export interface GalleryItem {
|
|
|
12
12
|
provider: ImageProvider;
|
|
13
13
|
model: string;
|
|
14
14
|
createdAt: number;
|
|
15
|
-
aspectRatio?: string;
|
|
16
|
-
imageSize?: string;
|
|
17
|
-
output?: string;
|
|
15
|
+
aspectRatio?: string | undefined;
|
|
16
|
+
imageSize?: string | undefined;
|
|
17
|
+
output?: string | undefined;
|
|
18
|
+
/** Workflow seed reported by the ComfyUI provider. Optional so records written by older versions stay readable; the object store is schemaless, so no IndexedDB version bump is needed. */
|
|
19
|
+
seed?: number | undefined;
|
|
20
|
+
/** Saved file path on workspace disk if savedTo was returned */
|
|
21
|
+
savedTo?: string | undefined;
|
|
22
|
+
/** Whether this item is marked as favorite */
|
|
23
|
+
isFavorite?: boolean | undefined;
|
|
24
|
+
/** Custom tags or collection markers */
|
|
25
|
+
tags?: string[] | undefined;
|
|
18
26
|
}
|
|
19
27
|
type GalleryListener = () => void;
|
|
20
28
|
/**
|
|
@@ -24,6 +32,7 @@ export declare function subscribeGallery(listener: GalleryListener): () => void;
|
|
|
24
32
|
/**
|
|
25
33
|
* Save or update a gallery record by attachmentId.
|
|
26
34
|
* Skipped if the item was previously deleted (tombstoned).
|
|
35
|
+
* Preserves existing isFavorite, tags, and original createdAt on re-renders.
|
|
27
36
|
*/
|
|
28
37
|
export declare function saveGalleryItem(item: Omit<GalleryItem, 'createdAt'> & {
|
|
29
38
|
createdAt?: number;
|
|
@@ -32,10 +41,19 @@ export declare function saveGalleryItem(item: Omit<GalleryItem, 'createdAt'> & {
|
|
|
32
41
|
* Retrieve all gallery records sorted by createdAt descending.
|
|
33
42
|
*/
|
|
34
43
|
export declare function getGalleryItems(): Promise<GalleryItem[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Toggle favorite status of a gallery item.
|
|
46
|
+
* Returns the new favorite status (true if favorited, false if unfavorited).
|
|
47
|
+
*/
|
|
48
|
+
export declare function toggleFavoriteGalleryItem(id: string): Promise<boolean>;
|
|
35
49
|
/**
|
|
36
50
|
* Delete a single gallery record by ID and record a tombstone.
|
|
37
51
|
*/
|
|
38
52
|
export declare function deleteGalleryItem(id: string): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Bulk delete multiple gallery records by IDs and record tombstones in a single transaction.
|
|
55
|
+
*/
|
|
56
|
+
export declare function bulkDeleteGalleryItems(ids: string[]): Promise<void>;
|
|
39
57
|
/**
|
|
40
58
|
* Clear all gallery records and reset tombstones.
|
|
41
59
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Native Workspace Gallery View Component for DSH `conversation.view` slot.
|
|
3
|
-
* Fully i18n-reactive (Chinese & English)
|
|
2
|
+
* Native Workspace Gallery & Studio View Component for DSH `conversation.view` slot.
|
|
3
|
+
* Fully i18n-reactive (Chinese & English) with modular tabs, multi-dimensional filters,
|
|
4
|
+
* responsive image grid, and placeholder routes.
|
|
4
5
|
*/
|
|
5
6
|
import { type FC } from 'react';
|
|
6
7
|
export interface LocaleService {
|
|
@@ -9,22 +10,38 @@ export interface LocaleService {
|
|
|
9
10
|
};
|
|
10
11
|
subscribe(fn: () => void): () => void;
|
|
11
12
|
}
|
|
13
|
+
export type TabKey = 'gallery' | 'studio' | 'favorites' | 'compare' | 'tasks';
|
|
14
|
+
export type SortKey = 'newest' | 'oldest';
|
|
12
15
|
declare const DICT: {
|
|
13
16
|
readonly zh: {
|
|
14
|
-
readonly
|
|
15
|
-
readonly
|
|
16
|
-
readonly
|
|
17
|
+
readonly tabGallery: "图库";
|
|
18
|
+
readonly tabStudio: "工作台";
|
|
19
|
+
readonly tabFavorites: "收藏";
|
|
20
|
+
readonly tabCompare: "对比";
|
|
21
|
+
readonly tabTasks: "任务";
|
|
22
|
+
readonly filterAllProviders: "全部提供商";
|
|
17
23
|
readonly filterGoogle: "Google Gemini";
|
|
18
24
|
readonly filterOpenAI: "OpenAI / 中转站";
|
|
19
25
|
readonly filterSeedream: "字节 Seedream";
|
|
20
26
|
readonly filterDashScope: "阿里 DashScope";
|
|
27
|
+
readonly filterComfyUI: "本地 ComfyUI";
|
|
28
|
+
readonly filterAllModels: "全部模型";
|
|
29
|
+
readonly filterAllRatios: "全部比例";
|
|
30
|
+
readonly searchPlaceholder: "搜索 Prompt、标签…";
|
|
31
|
+
readonly sortNewest: "最新生成";
|
|
32
|
+
readonly sortOldest: "最早生成";
|
|
33
|
+
readonly totalCount: "共 {count} 张生成图片";
|
|
21
34
|
readonly emptyTitle: "暂无生图记录";
|
|
22
35
|
readonly emptyDesc: "在对话中让 Agent 生图后,生成的图片会自动收录到这里。";
|
|
36
|
+
readonly favEmptyTitle: "暂无收藏图片";
|
|
37
|
+
readonly favEmptyDesc: "在图库中点击卡片右下角的 ♡ 按钮,即可将喜爱的图片收录到这里。";
|
|
23
38
|
readonly noMatchTitle: "未找到匹配结果";
|
|
24
|
-
readonly noMatchDesc: "
|
|
39
|
+
readonly noMatchDesc: "尝试更换搜索关键词或调整筛选条件。";
|
|
25
40
|
readonly copiedPrompt: "已复制 Prompt";
|
|
26
41
|
readonly copiedImage: "已复制图片";
|
|
27
42
|
readonly copyFailed: "复制失败";
|
|
43
|
+
readonly favoriteAdded: "已添加到收藏";
|
|
44
|
+
readonly favoriteRemoved: "已取消收藏";
|
|
28
45
|
readonly preview: "查看大图";
|
|
29
46
|
readonly download: "下载图片";
|
|
30
47
|
readonly copyImg: "复制图片";
|
|
@@ -35,22 +52,68 @@ declare const DICT: {
|
|
|
35
52
|
readonly model: "模型";
|
|
36
53
|
readonly prompt: "Prompt";
|
|
37
54
|
readonly close: "关闭 (Esc)";
|
|
55
|
+
readonly prevImage: "上一张 (←)";
|
|
56
|
+
readonly nextImage: "下一张 (→)";
|
|
57
|
+
readonly manage: "批量删除";
|
|
58
|
+
readonly exitManage: "退出选择";
|
|
59
|
+
readonly selectedCount: "已选 {n} 项";
|
|
60
|
+
readonly selectAll: "全选";
|
|
61
|
+
readonly invertSelect: "反选";
|
|
62
|
+
readonly clearSelect: "清空";
|
|
63
|
+
readonly batchDelete: "批量删除";
|
|
64
|
+
readonly batchDeleteTitle: "确认批量删除选中的 {count} 张图片?";
|
|
65
|
+
readonly batchDeleteTitleSingle: "确认从画廊中删除这张图片?";
|
|
66
|
+
readonly batchDeleteDesc: "将从画廊历史记录中移除所选图片。";
|
|
67
|
+
readonly deleteWorkspaceFilesOpt: "同时清理工作区磁盘物理文件(不可恢复)";
|
|
68
|
+
readonly cancel: "取消";
|
|
69
|
+
readonly confirmBatchDelete: "确认删除 ({count})";
|
|
70
|
+
readonly confirmDeleteSingle: "确认删除";
|
|
71
|
+
readonly batchDeletedToast: "已删除 {count} 张图片";
|
|
72
|
+
readonly batchDeletedWithFilesToast: "已删除 {count} 张图片,并清理了 {files} 个工作区文件";
|
|
73
|
+
readonly deleteFailedFileLocked: "已删除 {count} 张图片,但有 {files} 个文件因被系统占用未能删除";
|
|
74
|
+
readonly deleteFailedDatabase: "删除失败:本地数据库操作异常";
|
|
75
|
+
readonly justNow: "刚刚";
|
|
76
|
+
readonly minutesAgo: "{n} 分钟前";
|
|
77
|
+
readonly hoursAgo: "{n} 小时前";
|
|
78
|
+
readonly daysAgo: "{n} 天前";
|
|
79
|
+
readonly studioTitle: "AI 图像工作台 (Studio)";
|
|
80
|
+
readonly studioDesc: "工作台模块正在紧锣密鼓开发中。在此你将体验大图精修、变体生成 (Variations)、参数重调并一键将生成结果无缝插回 DSH 正在进行的对话。";
|
|
81
|
+
readonly studioTip: "💡 提示:目前你可以在“图库”中点击任意图片,在弹窗中进行查看、复制与下载。";
|
|
82
|
+
readonly compareTitle: "多模型横向对比 (Compare)";
|
|
83
|
+
readonly compareDesc: "支持单个 Prompt 一键同时调度 Gemini、Seedream、DashScope 及本地 ComfyUI 模型并排生成,直观横评画质与细节。";
|
|
84
|
+
readonly tasksTitle: "异步任务队列 (Tasks)";
|
|
85
|
+
readonly tasksDesc: "集中管理后台批量生图、多模型并发生成与本地 ComfyUI 耗时任务。支持状态追踪、失败重试与执行耗时分析。";
|
|
86
|
+
readonly comingSoonBadge: "即将推出";
|
|
38
87
|
};
|
|
39
88
|
readonly en: {
|
|
40
|
-
readonly
|
|
41
|
-
readonly
|
|
42
|
-
readonly
|
|
89
|
+
readonly tabGallery: "Gallery";
|
|
90
|
+
readonly tabStudio: "Studio";
|
|
91
|
+
readonly tabFavorites: "Favorites";
|
|
92
|
+
readonly tabCompare: "Compare";
|
|
93
|
+
readonly tabTasks: "Tasks";
|
|
94
|
+
readonly filterAllProviders: "All Providers";
|
|
43
95
|
readonly filterGoogle: "Google Gemini";
|
|
44
96
|
readonly filterOpenAI: "OpenAI / Relay";
|
|
45
97
|
readonly filterSeedream: "ByteDance Seedream";
|
|
46
98
|
readonly filterDashScope: "Aliyun DashScope";
|
|
99
|
+
readonly filterComfyUI: "Local ComfyUI";
|
|
100
|
+
readonly filterAllModels: "All Models";
|
|
101
|
+
readonly filterAllRatios: "All Ratios";
|
|
102
|
+
readonly searchPlaceholder: "Search prompt, tags…";
|
|
103
|
+
readonly sortNewest: "Newest first";
|
|
104
|
+
readonly sortOldest: "Oldest first";
|
|
105
|
+
readonly totalCount: "{count} images total";
|
|
47
106
|
readonly emptyTitle: "No images generated yet";
|
|
48
107
|
readonly emptyDesc: "Images generated during conversations will automatically appear here.";
|
|
108
|
+
readonly favEmptyTitle: "No favorite images yet";
|
|
109
|
+
readonly favEmptyDesc: "Click the ♡ button on any card in the gallery to collect your favorite images here.";
|
|
49
110
|
readonly noMatchTitle: "No matching images";
|
|
50
|
-
readonly noMatchDesc: "Try a different search keyword or
|
|
111
|
+
readonly noMatchDesc: "Try a different search keyword or adjust filter criteria.";
|
|
51
112
|
readonly copiedPrompt: "Prompt copied";
|
|
52
113
|
readonly copiedImage: "Image copied";
|
|
53
114
|
readonly copyFailed: "Copy failed";
|
|
115
|
+
readonly favoriteAdded: "Added to favorites";
|
|
116
|
+
readonly favoriteRemoved: "Removed from favorites";
|
|
54
117
|
readonly preview: "Full Preview";
|
|
55
118
|
readonly download: "Download";
|
|
56
119
|
readonly copyImg: "Copy Image";
|
|
@@ -61,6 +124,38 @@ declare const DICT: {
|
|
|
61
124
|
readonly model: "Model";
|
|
62
125
|
readonly prompt: "Prompt";
|
|
63
126
|
readonly close: "Close (Esc)";
|
|
127
|
+
readonly prevImage: "Previous (←)";
|
|
128
|
+
readonly nextImage: "Next (→)";
|
|
129
|
+
readonly manage: "Batch Delete";
|
|
130
|
+
readonly exitManage: "Done";
|
|
131
|
+
readonly selectedCount: "{n} selected";
|
|
132
|
+
readonly selectAll: "Select All";
|
|
133
|
+
readonly invertSelect: "Invert";
|
|
134
|
+
readonly clearSelect: "Clear";
|
|
135
|
+
readonly batchDelete: "Batch Delete";
|
|
136
|
+
readonly batchDeleteTitle: "Delete {count} selected images?";
|
|
137
|
+
readonly batchDeleteTitleSingle: "Delete this image from gallery?";
|
|
138
|
+
readonly batchDeleteDesc: "These images will be removed from your gallery history.";
|
|
139
|
+
readonly deleteWorkspaceFilesOpt: "Also delete files from workspace disk (cannot be undone)";
|
|
140
|
+
readonly cancel: "Cancel";
|
|
141
|
+
readonly confirmBatchDelete: "Delete ({count})";
|
|
142
|
+
readonly confirmDeleteSingle: "Delete";
|
|
143
|
+
readonly batchDeletedToast: "Deleted {count} images";
|
|
144
|
+
readonly batchDeletedWithFilesToast: "Deleted {count} images and cleaned {files} workspace files";
|
|
145
|
+
readonly deleteFailedFileLocked: "Deleted {count} images, but {files} files could not be deleted (busy/locked)";
|
|
146
|
+
readonly deleteFailedDatabase: "Failed to delete: local database error";
|
|
147
|
+
readonly justNow: "Just now";
|
|
148
|
+
readonly minutesAgo: "{n}m ago";
|
|
149
|
+
readonly hoursAgo: "{n}h ago";
|
|
150
|
+
readonly daysAgo: "{n}d ago";
|
|
151
|
+
readonly studioTitle: "AI Image Studio";
|
|
152
|
+
readonly studioDesc: "Studio workbench is under active development. Fine-tune prompts, generate variations (2x/4x), and inject images directly into DSH chat.";
|
|
153
|
+
readonly studioTip: "💡 Tip: You can currently click any image in the Gallery to preview, copy, or download it.";
|
|
154
|
+
readonly compareTitle: "Model Comparison (Compare)";
|
|
155
|
+
readonly compareDesc: "Side-by-side multi-model benchmarking coming soon. Test Gemini, Seedream, DashScope, and ComfyUI with a single prompt.";
|
|
156
|
+
readonly tasksTitle: "Task Queue (Tasks)";
|
|
157
|
+
readonly tasksDesc: "Centralized view for batch generation, asynchronous ComfyUI runs, live progress tracking, and retry controls.";
|
|
158
|
+
readonly comingSoonBadge: "Coming Soon";
|
|
64
159
|
};
|
|
65
160
|
};
|
|
66
161
|
export type DictKey = keyof typeof DICT.zh;
|
|
@@ -8,6 +8,8 @@ export interface ImageResultPresentation {
|
|
|
8
8
|
readonly model: string;
|
|
9
9
|
readonly output: string;
|
|
10
10
|
readonly savedTo?: string;
|
|
11
|
+
/** Workflow seed reported by the ComfyUI provider, when available. */
|
|
12
|
+
readonly seed?: number;
|
|
11
13
|
}
|
|
12
14
|
interface ImageResultState {
|
|
13
15
|
readonly turn: number;
|
|
@@ -46,8 +48,23 @@ interface ConversationNodeDefinitionLike<State> {
|
|
|
46
48
|
}, match: MatchLike): State;
|
|
47
49
|
buildViewNode(context: ContextLike<State>): Record<string, unknown> | null;
|
|
48
50
|
}
|
|
49
|
-
/**
|
|
51
|
+
/** Options controlling where the artifact anchors as its Turn progresses. */
|
|
52
|
+
export interface ImageResultNodeOptions {
|
|
53
|
+
/**
|
|
54
|
+
* Whether the host transcript view folds completed-Turn process content
|
|
55
|
+
* (Compact mode). Omission or a thrown/unavailable read falls back to
|
|
56
|
+
* Compact-safe anchoring, which keeps the artifact always visible.
|
|
57
|
+
*/
|
|
58
|
+
readonly isCompactTranscript?: () => boolean;
|
|
59
|
+
}
|
|
60
|
+
/** Default definition: unknown transcript mode falls back to Compact-safe anchoring. */
|
|
50
61
|
export declare const imageResultDefinition: ConversationNodeDefinitionLike<ImageResultState>;
|
|
62
|
+
/**
|
|
63
|
+
* One image result row per Turn, anchored at its own tool/result position while
|
|
64
|
+
* the Turn runs, then optionally re-anchored beside the final answer once the
|
|
65
|
+
* Turn closes (only needed under the folding Compact transcript view).
|
|
66
|
+
*/
|
|
67
|
+
export declare function createImageResultDefinition(options?: ImageResultNodeOptions): ConversationNodeDefinitionLike<ImageResultState>;
|
|
51
68
|
/** Parse the plugin-owned durable presentation metadata from a Tool result event. */
|
|
52
69
|
export declare function imageResultFromMeta(value: unknown): ImageResultPresentation | undefined;
|
|
53
70
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import type { SettingsScope } from '@deepseek-ai/dsh-client-runtime/client';
|
|
3
3
|
import type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
4
|
-
import { type ImageProvider } from '../shared.js';
|
|
4
|
+
import { type ComfyUIWorkflowEntry, type ImageProvider } from '../shared.js';
|
|
5
5
|
import { type LocaleService } from './gallery-view.js';
|
|
6
6
|
import { type ImageResultPresentation } from './image-result-node.js';
|
|
7
7
|
type Provider = ImageProvider;
|
|
@@ -16,6 +16,8 @@ interface ImageSettings {
|
|
|
16
16
|
dashscopeEndpoint?: string;
|
|
17
17
|
dashscopeModel?: string;
|
|
18
18
|
comfyuiBaseURL?: string;
|
|
19
|
+
comfyuiWorkflows?: ComfyUIWorkflowEntry[];
|
|
20
|
+
comfyuiActiveWorkflow?: string;
|
|
19
21
|
comfyuiWorkflowJson?: string;
|
|
20
22
|
comfyuiWorkflowName?: string;
|
|
21
23
|
comfyuiTimeoutMs?: number;
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
export declare const COMFYUI_PROMPT_PLACEHOLDER = "{{prompt}}";
|
|
2
2
|
export declare const COMFYUI_SEED_PLACEHOLDER = "{{seed}}";
|
|
3
|
+
export declare const COMFYUI_IMAGE_PLACEHOLDER = "{{image}}";
|
|
3
4
|
type JsonRecord = Record<string, unknown>;
|
|
4
5
|
/** Validate imported JSON without exposing workflow graph details to callers. */
|
|
5
6
|
export declare function validateComfyUIWorkflowJson(workflowJson: string): void;
|
|
6
|
-
/**
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Parse, clone, and inject one prompt plus an optional randomized seed.
|
|
9
|
+
*
|
|
10
|
+
* Prompt and seed placeholders are replaced inside any string so existing
|
|
11
|
+
* workflows that embed them in longer text keep working. The image
|
|
12
|
+
* placeholder is stricter: it only matches a dedicated `inputs.image` field
|
|
13
|
+
* whose value is exactly the placeholder, and at most one may exist, because
|
|
14
|
+
* the field must carry a single uploaded file name.
|
|
15
|
+
*/
|
|
16
|
+
export declare function prepareComfyUIWorkflow(workflowJson: string, prompt: string, seed?: number, image?: string): JsonRecord;
|
|
17
|
+
/** Random seed in the 32-bit range ComfyUI samplers accept. */
|
|
18
|
+
export declare function randomSeed(): number;
|
|
8
19
|
export {};
|
package/lib/types/comfyui.d.ts
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
|
-
/** ComfyUI text-to-image
|
|
1
|
+
/** ComfyUI text-to-image and image-to-image adapters using an imported API-format workflow. */
|
|
2
2
|
import type { ImageMediaType } from '@deepseek-ai/dsh-attachment';
|
|
3
3
|
export interface GeneratedComfyUIImage {
|
|
4
4
|
data: Uint8Array;
|
|
5
5
|
mediaType: ImageMediaType;
|
|
6
|
+
/** Concrete seed injected into the workflow, surfaced for provenance metadata. */
|
|
7
|
+
seed: number;
|
|
6
8
|
}
|
|
7
|
-
/**
|
|
8
|
-
export
|
|
9
|
+
/** Source image bytes a ComfyUI workflow accepts through its image input. */
|
|
10
|
+
export interface ComfyUISourceImage {
|
|
11
|
+
data: Uint8Array;
|
|
12
|
+
mediaType: ImageMediaType;
|
|
13
|
+
}
|
|
14
|
+
interface ComfyUIJobInput {
|
|
9
15
|
baseURL: string;
|
|
16
|
+
timeoutMs: number;
|
|
17
|
+
signal: AbortSignal;
|
|
18
|
+
}
|
|
19
|
+
/** Run one ComfyUI text-to-image workflow and return its first final image. */
|
|
20
|
+
export declare function generateComfyUIImage(input: ComfyUIJobInput & {
|
|
10
21
|
workflowJson: string;
|
|
11
22
|
prompt: string;
|
|
12
|
-
timeoutMs: number;
|
|
13
23
|
maxBytes: number;
|
|
14
|
-
signal: AbortSignal;
|
|
15
24
|
}): Promise<GeneratedComfyUIImage>;
|
|
25
|
+
/** Upload one source image, run the workflow, and return its first final image. */
|
|
26
|
+
export declare function editComfyUIImage(input: ComfyUIJobInput & {
|
|
27
|
+
workflowJson: string;
|
|
28
|
+
prompt: string;
|
|
29
|
+
sourceImage: ComfyUISourceImage;
|
|
30
|
+
maxBytes: number;
|
|
31
|
+
}): Promise<GeneratedComfyUIImage>;
|
|
32
|
+
export {};
|
package/lib/types/config.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** User-facing configuration for supported image providers. */
|
|
2
2
|
import z from '@deepseek-ai/schemastery';
|
|
3
|
-
import { DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, IMAGE_PROVIDERS, type ImageProvider } from './shared.js';
|
|
4
|
-
export { DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, IMAGE_PROVIDERS, type ImageProvider, };
|
|
3
|
+
import { DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, IMAGE_PROVIDERS, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ComfyUIWorkflowEntry, type ImageProvider } from './shared.js';
|
|
4
|
+
export { DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, IMAGE_PROVIDERS, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ComfyUIWorkflowEntry, type ImageProvider, };
|
|
5
5
|
/** Default workspace subfolder that receives generated image files. */
|
|
6
6
|
export declare const DEFAULT_WORKSPACE_FOLDER = "dsh-image-gen";
|
|
7
7
|
/** Google API credential reference. */
|
|
@@ -29,9 +29,13 @@ export interface Config {
|
|
|
29
29
|
dashscopeEndpoint?: string;
|
|
30
30
|
dashscopeModel?: string;
|
|
31
31
|
comfyuiBaseURL?: string;
|
|
32
|
-
/** ComfyUI
|
|
32
|
+
/** Named ComfyUI workflows managed by the Web settings page. */
|
|
33
|
+
comfyuiWorkflows?: ComfyUIWorkflowEntry[];
|
|
34
|
+
/** Name of the workflow ComfyUI calls use by default. */
|
|
35
|
+
comfyuiActiveWorkflow?: string;
|
|
36
|
+
/** Legacy single-workflow storage; synced to the active entry for downgrades. */
|
|
33
37
|
comfyuiWorkflowJson?: string;
|
|
34
|
-
/** Original imported file name
|
|
38
|
+
/** Original imported file name of the legacy single workflow. */
|
|
35
39
|
comfyuiWorkflowName?: string;
|
|
36
40
|
comfyuiTimeoutMs?: number;
|
|
37
41
|
/** Also write every generated image as a file under the session workspace. */
|
|
@@ -70,7 +74,12 @@ export declare function resolveProvider(config: Config): {
|
|
|
70
74
|
} | {
|
|
71
75
|
provider: 'comfyui';
|
|
72
76
|
baseURL: string;
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
workflows: ComfyUIWorkflowEntry[];
|
|
78
|
+
workflow?: ComfyUIWorkflowEntry;
|
|
75
79
|
timeoutMs: number;
|
|
76
80
|
};
|
|
81
|
+
/** The workflow a ComfyUI call runs: the requested name when given, else the active one. */
|
|
82
|
+
export declare function selectComfyUIWorkflow(active: {
|
|
83
|
+
workflows: ComfyUIWorkflowEntry[];
|
|
84
|
+
workflow?: ComfyUIWorkflowEntry;
|
|
85
|
+
}, requested?: string): ComfyUIWorkflowEntry;
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
/** Same-origin HTTP bridge from the Web result card to the Attachment service. */
|
|
2
2
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
3
|
import type { ImageAttachmentRef, StoredImageAttachment } from '@deepseek-ai/dsh-attachment';
|
|
4
|
-
export { IMAGE_ROUTE } from './shared.js';
|
|
4
|
+
export { IMAGE_ROUTE, DELETE_ROUTE } from './shared.js';
|
|
5
5
|
/** Dependencies required by the image route. */
|
|
6
6
|
export interface ImageRouteDeps {
|
|
7
7
|
readImage(ref: ImageAttachmentRef): Promise<StoredImageAttachment>;
|
|
8
8
|
}
|
|
9
|
+
/** Dependencies required by the delete route. */
|
|
10
|
+
export interface DeleteRouteDeps {
|
|
11
|
+
deleteWorkspaceImage(filePath: string): Promise<boolean>;
|
|
12
|
+
deleteWorkspaceImageByAttachmentId(attachmentId: string): Promise<boolean>;
|
|
13
|
+
}
|
|
9
14
|
/** Serve one verified durable image reference to a same-origin browser request. */
|
|
10
15
|
export declare function serveImage(req: IncomingMessage, res: ServerResponse, deps: ImageRouteDeps): Promise<void>;
|
|
16
|
+
/** Safely delete one or more generated image files from the workspace disk. */
|
|
17
|
+
export declare function serveDelete(req: IncomingMessage, res: ServerResponse, deps: DeleteRouteDeps): Promise<void>;
|
|
11
18
|
/** Validate the persisted reference carried by a tool presentation. */
|
|
12
19
|
export declare function imageAttachmentFromMeta(meta: unknown): ImageAttachmentRef | undefined;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
3
|
import { Config } from './config.js';
|
|
4
4
|
export { Config } from './config.js';
|
|
5
|
-
export { IMAGE_ROUTE, imageAttachmentFromMeta } from './image-route.js';
|
|
5
|
+
export { IMAGE_ROUTE, DELETE_ROUTE, imageAttachmentFromMeta } from './image-route.js';
|
|
6
6
|
export declare const name = "dsh-image-gen";
|
|
7
7
|
export declare const inject: string[];
|
|
8
8
|
export declare function apply(ctx: Context, config?: Config): void;
|
package/lib/types/shared.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** Values shared by the Host and browser Bundle faces. */
|
|
2
2
|
/** Browser route used by the generated-image card. */
|
|
3
3
|
export declare const IMAGE_ROUTE = "/plugins/dsh-image-gen/image";
|
|
4
|
+
/** Browser route used for deleting generated images and workspace files. */
|
|
5
|
+
export declare const DELETE_ROUTE = "/plugins/dsh-image-gen/delete";
|
|
4
6
|
/** Namespace persisted through DSH Settings. */
|
|
5
7
|
export declare const IMAGE_GENERATION_NAMESPACE = "image-generation";
|
|
6
8
|
/** Supported providers. */
|
|
@@ -20,5 +22,36 @@ export declare const DEFAULT_GOOGLE_MODEL = "gemini-3.1-flash-image";
|
|
|
20
22
|
export declare const DEFAULT_OPENAI_MODEL = "gpt-image-2";
|
|
21
23
|
export declare const DEFAULT_SEEDREAM_MODEL = "doubao-seedream-5-0-260128";
|
|
22
24
|
export declare const DEFAULT_DASHSCOPE_MODEL = "qwen-image-3.0";
|
|
25
|
+
/** One named ComfyUI API-format workflow imported through settings. */
|
|
26
|
+
export interface ComfyUIWorkflowEntry {
|
|
27
|
+
/** Unique human-readable label; used as the result model and by tool calls. */
|
|
28
|
+
name: string;
|
|
29
|
+
/** API-format workflow JSON with {{prompt}} / {{seed}} and optional {{image}} placeholders. */
|
|
30
|
+
json: string;
|
|
31
|
+
/** Optional preset prepended to the user prompt on every call of this workflow. */
|
|
32
|
+
presetPrompt?: string;
|
|
33
|
+
}
|
|
34
|
+
/** Raw ComfyUI workflow fields as persisted through DSH Settings. */
|
|
35
|
+
export interface ComfyUIWorkflowSource {
|
|
36
|
+
/** Named workflows managed by the Web settings page. */
|
|
37
|
+
comfyuiWorkflows?: readonly ComfyUIWorkflowEntry[];
|
|
38
|
+
/** Name of the entry ComfyUI calls use by default. */
|
|
39
|
+
comfyuiActiveWorkflow?: string;
|
|
40
|
+
/** Legacy single-workflow storage; synced to the active entry for downgrades. */
|
|
41
|
+
comfyuiWorkflowJson?: string;
|
|
42
|
+
comfyuiWorkflowName?: string;
|
|
43
|
+
}
|
|
44
|
+
/** Named workflows, falling back to the legacy single-workflow fields when the list is empty. */
|
|
45
|
+
export declare function resolveComfyUIWorkflows(source: ComfyUIWorkflowSource): ComfyUIWorkflowEntry[];
|
|
46
|
+
/** The workflow ComfyUI calls use by default: the configured active name, else the first entry. */
|
|
47
|
+
export declare function activeComfyUIWorkflow(source: ComfyUIWorkflowSource): ComfyUIWorkflowEntry | undefined;
|
|
48
|
+
/** Derive a workflow label that does not collide with the given existing names. */
|
|
49
|
+
export declare function uniqueComfyUIWorkflowName(name: string, existing: readonly string[]): string;
|
|
50
|
+
/**
|
|
51
|
+
* Combine a workflow's preset with the user prompt: preset first, user second,
|
|
52
|
+
* joined by one comma — never doubled when the preset already ends in a
|
|
53
|
+
* separator, and reduced to the non-empty side when the other is blank.
|
|
54
|
+
*/
|
|
55
|
+
export declare function mergeComfyUIPrompt(preset: string | undefined, user: string): string;
|
|
23
56
|
export declare const DEFAULT_MODELS: Record<ImageProvider, string>;
|
|
24
57
|
export declare const DEFAULT_BASE_URLS: Record<ImageProvider, string>;
|
|
@@ -50,3 +50,24 @@ export declare function saveImageToWorkspace(options: {
|
|
|
50
50
|
data: Uint8Array;
|
|
51
51
|
signal?: AbortSignal;
|
|
52
52
|
}): Promise<string>;
|
|
53
|
+
/** Discover all DSH workspace paths recorded in local application storage. */
|
|
54
|
+
export declare function getDshWorkspaceRoots(): Promise<string[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Safely delete a generated image file from workspace disk by its path.
|
|
57
|
+
* Enforces strict safety gates:
|
|
58
|
+
* 1. Base name must match generated image pattern (`image-<hex>.<ext>`) to avoid touching user files.
|
|
59
|
+
* 2. Path must be a regular file and NOT a symbolic link.
|
|
60
|
+
* 3. Real canonical path's basename must also match the pattern.
|
|
61
|
+
* 4. Real canonical path must reside within an allowed workspace root (or process.cwd()).
|
|
62
|
+
*/
|
|
63
|
+
export declare function deleteImageFromWorkspace(filePath: string, allowedWorkspaceRoots?: Iterable<string>): Promise<boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* Safely find and delete a generated image file by its attachment ID within a single workspace root.
|
|
66
|
+
* Strictly checks sha256:64hex format and avoids scanning unrelated workspaces.
|
|
67
|
+
* Only used as fallback for historical images where savedTo was not persisted.
|
|
68
|
+
*/
|
|
69
|
+
export declare function deleteImageByAttachmentIdFromWorkspace(attachmentId: string, options?: {
|
|
70
|
+
workspaceRoot?: string | undefined;
|
|
71
|
+
folder?: string | undefined;
|
|
72
|
+
allowedWorkspaceRoots?: Iterable<string> | undefined;
|
|
73
|
+
}): Promise<boolean>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-image-gen",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Bring ChatGPT-like image generation to DeepSeek Harness — Gemini, OpenAI, Seedream, DashScope, local ComfyUI & more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "shanliuling",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"@deepseek-ai/dsh-credentials": "0.1.1-rc.2",
|
|
120
120
|
"@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
|
|
121
121
|
"@deepseek-ai/dsh-llm": "0.1.1-rc.2",
|
|
122
|
-
"@deepseek-ai/dsh-settings": "0.1.
|
|
122
|
+
"@deepseek-ai/dsh-settings": "0.1.2-alpha.2",
|
|
123
123
|
"@deepseek-ai/dsh-tools": "0.1.1-rc.2",
|
|
124
124
|
"@deepseek-ai/schemastery": "3.18.1",
|
|
125
125
|
"@types/node": "^22.20.0",
|
|
@@ -127,7 +127,11 @@
|
|
|
127
127
|
"react": "^18.2.0",
|
|
128
128
|
"tsdown": "^0.22.2",
|
|
129
129
|
"typescript": "^6.0.3",
|
|
130
|
+
"unrun": "^0.3.1",
|
|
130
131
|
"vitest": "^4.1.8"
|
|
131
132
|
},
|
|
132
|
-
"packageManager": "pnpm@11.7.0"
|
|
133
|
+
"packageManager": "pnpm@11.7.0",
|
|
134
|
+
"dependencies": {
|
|
135
|
+
"lucide-react": "^1.38.0"
|
|
136
|
+
}
|
|
133
137
|
}
|