dsh-image-gen 0.2.6 → 0.3.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 +172 -172
- package/README.md +182 -182
- package/README.zh-CN.md +172 -172
- package/lib/client.js +2809 -300
- package/lib/client.js.map +1 -1
- package/lib/index.js +579 -108
- package/lib/types/client/browser-image-utils.d.ts +10 -0
- package/lib/types/client/conversation-image-revisions.d.ts +25 -0
- package/lib/types/client/conversation-regenerate.d.ts +11 -0
- package/lib/types/client/gallery-store.d.ts +19 -0
- package/lib/types/client/gallery-view.d.ts +27 -5
- package/lib/types/client/image-cache.d.ts +26 -0
- package/lib/types/client/studio-style.d.ts +1 -0
- package/lib/types/client/studio-view.d.ts +30 -0
- package/lib/types/image-route.d.ts +0 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/shared.d.ts +71 -0
- package/lib/types/studio-route.d.ts +12 -0
- package/lib/types/studio.d.ts +8 -0
- package/lib/types/workspace-save.d.ts +3 -0
- package/package.json +8 -10
- package/skills/install-dsh-image-gen/SKILL.md +22 -22
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared browser image and DOM helpers for client views.
|
|
3
|
+
* Completely decoupled from gallery-view and studio-view to prevent circular dependencies.
|
|
4
|
+
*/
|
|
5
|
+
/** Copy an image Blob to the OS clipboard, converting to PNG if required by the browser. */
|
|
6
|
+
export declare function copyImageBlob(blob: Blob): Promise<boolean>;
|
|
7
|
+
/** Safely trigger a browser file download by mounting an anchor element into the DOM. */
|
|
8
|
+
export declare function downloadBlobUrl(url: string, filename: string): void;
|
|
9
|
+
/** Human-readable relative time formatter supporting zh and en. */
|
|
10
|
+
export declare function formatRelativeTime(timestamp: number, lang: 'zh' | 'en'): string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
2
|
+
import type { CloudImageProvider } from '../shared.js';
|
|
3
|
+
/** One regenerated version displayed in place of an original conversation image. */
|
|
4
|
+
export interface ConversationImageRevision {
|
|
5
|
+
attachment: ImageAttachmentRef;
|
|
6
|
+
prompt: string;
|
|
7
|
+
provider: CloudImageProvider;
|
|
8
|
+
model: string;
|
|
9
|
+
output: string;
|
|
10
|
+
createdAt: number;
|
|
11
|
+
ratio: string;
|
|
12
|
+
quality: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ConversationImageRevisionChain {
|
|
15
|
+
originId: string;
|
|
16
|
+
/** Zero selects the immutable conversation image; revisions use one-based positions. */
|
|
17
|
+
currentIndex: number;
|
|
18
|
+
revisions: ConversationImageRevision[];
|
|
19
|
+
}
|
|
20
|
+
/** Read the locally persisted replacement history for one immutable conversation image. */
|
|
21
|
+
export declare function loadConversationImageRevisionChain(originId: string): ConversationImageRevisionChain;
|
|
22
|
+
/** Append a generated version and make it the version shown by the conversation card. */
|
|
23
|
+
export declare function appendConversationImageRevision(originId: string, revision: ConversationImageRevision): ConversationImageRevisionChain;
|
|
24
|
+
/** Select an earlier or later version without altering the underlying conversation event. */
|
|
25
|
+
export declare function selectConversationImageRevision(originId: string, requestedIndex: number): ConversationImageRevisionChain;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type StudioGenerateRequest } from '../shared.js';
|
|
2
|
+
export interface RegeneratableImage {
|
|
3
|
+
provider: string;
|
|
4
|
+
model: string;
|
|
5
|
+
output?: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
/** Build the workbench request that reproduces a conversation image with an edited prompt. */
|
|
8
|
+
export declare function conversationRegenerateRequest(image: RegeneratableImage, prompt: string, remembered?: {
|
|
9
|
+
ratio: string;
|
|
10
|
+
quality: string;
|
|
11
|
+
} | undefined): StudioGenerateRequest;
|
|
@@ -23,6 +23,12 @@ export interface GalleryItem {
|
|
|
23
23
|
isFavorite?: boolean | undefined;
|
|
24
24
|
/** Custom tags or collection markers */
|
|
25
25
|
tags?: string[] | undefined;
|
|
26
|
+
/** Workspace filesystem path where the image was generated/saved */
|
|
27
|
+
workspacePath?: string | undefined;
|
|
28
|
+
/** Workspace ID if known */
|
|
29
|
+
workspaceId?: string | undefined;
|
|
30
|
+
/** Conversation session ID where the image was generated */
|
|
31
|
+
sessionId?: string | undefined;
|
|
26
32
|
}
|
|
27
33
|
type GalleryListener = () => void;
|
|
28
34
|
/**
|
|
@@ -58,4 +64,17 @@ export declare function bulkDeleteGalleryItems(ids: string[]): Promise<void>;
|
|
|
58
64
|
* Clear all gallery records and reset tombstones.
|
|
59
65
|
*/
|
|
60
66
|
export declare function clearGallery(): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Standardize path format across Windows and POSIX (lowercase, forward slashes, no trailing slash).
|
|
69
|
+
*/
|
|
70
|
+
export declare function normalizeWorkspacePath(rawPath: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* Determine if a gallery item belongs to the given workspace context.
|
|
73
|
+
* Compares workspaceId, sessionId membership, workspacePath, and savedTo file path prefix.
|
|
74
|
+
*/
|
|
75
|
+
export declare function isItemInWorkspace(item: GalleryItem, workspace?: {
|
|
76
|
+
workspaceId?: string | undefined;
|
|
77
|
+
path?: string | undefined;
|
|
78
|
+
sessionIds?: readonly string[] | undefined;
|
|
79
|
+
} | null): boolean;
|
|
61
80
|
export {};
|
|
@@ -10,7 +10,7 @@ export interface LocaleService {
|
|
|
10
10
|
};
|
|
11
11
|
subscribe(fn: () => void): () => void;
|
|
12
12
|
}
|
|
13
|
-
export type TabKey = 'gallery' | 'studio' | 'favorites'
|
|
13
|
+
export type TabKey = 'gallery' | 'studio' | 'favorites';
|
|
14
14
|
export type SortKey = 'newest' | 'oldest';
|
|
15
15
|
declare const DICT: {
|
|
16
16
|
readonly zh: {
|
|
@@ -28,6 +28,8 @@ declare const DICT: {
|
|
|
28
28
|
readonly filterAllModels: "全部模型";
|
|
29
29
|
readonly filterAllRatios: "全部比例";
|
|
30
30
|
readonly searchPlaceholder: "搜索 Prompt、标签…";
|
|
31
|
+
readonly filterCurrentWorkspace: "仅看此工作区";
|
|
32
|
+
readonly filterCurrentWorkspaceHint: "只展示属于当前工作区的生图记录与物理文件";
|
|
31
33
|
readonly sortNewest: "最新生成";
|
|
32
34
|
readonly sortOldest: "最早生成";
|
|
33
35
|
readonly totalCount: "共 {count} 张生成图片";
|
|
@@ -46,6 +48,13 @@ declare const DICT: {
|
|
|
46
48
|
readonly download: "下载图片";
|
|
47
49
|
readonly copyImg: "复制图片";
|
|
48
50
|
readonly copyPpt: "复制 Prompt";
|
|
51
|
+
readonly regenerate: "重新生成";
|
|
52
|
+
readonly regenerateTitle: "重新生成图片";
|
|
53
|
+
readonly regenerateHint: "可按需修改 Prompt,基于当前模型和比例在画廊生成一张新图片。";
|
|
54
|
+
readonly confirmRegenerate: "开始生成";
|
|
55
|
+
readonly regenerating: "正在重新生成…";
|
|
56
|
+
readonly regenerateSuccess: "已生成新图片并收录到画廊";
|
|
57
|
+
readonly regenerateFailed: "重新生成失败";
|
|
49
58
|
readonly delete: "从画廊删除";
|
|
50
59
|
readonly confirmDelete: "确定要从画廊中删除这张图片吗?(不会影响原聊天记录)";
|
|
51
60
|
readonly deleted: "已从画廊删除";
|
|
@@ -100,6 +109,8 @@ declare const DICT: {
|
|
|
100
109
|
readonly filterAllModels: "All Models";
|
|
101
110
|
readonly filterAllRatios: "All Ratios";
|
|
102
111
|
readonly searchPlaceholder: "Search prompt, tags…";
|
|
112
|
+
readonly filterCurrentWorkspace: "Current workspace only";
|
|
113
|
+
readonly filterCurrentWorkspaceHint: "Only show images belonging to the active workspace";
|
|
103
114
|
readonly sortNewest: "Newest first";
|
|
104
115
|
readonly sortOldest: "Oldest first";
|
|
105
116
|
readonly totalCount: "{count} images total";
|
|
@@ -118,6 +129,13 @@ declare const DICT: {
|
|
|
118
129
|
readonly download: "Download";
|
|
119
130
|
readonly copyImg: "Copy Image";
|
|
120
131
|
readonly copyPpt: "Copy Prompt";
|
|
132
|
+
readonly regenerate: "Regenerate";
|
|
133
|
+
readonly regenerateTitle: "Regenerate Image";
|
|
134
|
+
readonly regenerateHint: "Edit prompt if needed. A new image will be generated and added to the gallery.";
|
|
135
|
+
readonly confirmRegenerate: "Generate";
|
|
136
|
+
readonly regenerating: "Regenerating…";
|
|
137
|
+
readonly regenerateSuccess: "New image generated and added to gallery";
|
|
138
|
+
readonly regenerateFailed: "Regeneration failed";
|
|
121
139
|
readonly delete: "Delete from gallery";
|
|
122
140
|
readonly confirmDelete: "Are you sure you want to remove this image from the gallery? (Chat history will not be affected)";
|
|
123
141
|
readonly deleted: "Deleted from gallery";
|
|
@@ -159,8 +177,12 @@ declare const DICT: {
|
|
|
159
177
|
};
|
|
160
178
|
};
|
|
161
179
|
export type DictKey = keyof typeof DICT.zh;
|
|
162
|
-
export
|
|
180
|
+
export interface GalleryViewTabProps {
|
|
163
181
|
locale?: LocaleService;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
182
|
+
sessionId?: string;
|
|
183
|
+
useSession?: (selector: (state: any) => any) => any;
|
|
184
|
+
useSessions?: (selector: (state: any) => any) => any;
|
|
185
|
+
useWorkspaces?: (selector: (state: any) => any) => any;
|
|
186
|
+
}
|
|
187
|
+
export declare const GalleryViewTab: FC<GalleryViewTabProps>;
|
|
188
|
+
export { copyImageBlob } from './browser-image-utils.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded in-memory attachment image cache for client views.
|
|
3
|
+
*
|
|
4
|
+
* Enforces dual constraints (max items + max bytes) with LRU eviction.
|
|
5
|
+
* The background fetch lifecycle is decoupled from individual consumer signals,
|
|
6
|
+
* preventing a canceled thumbnail from aborting the shared blob request.
|
|
7
|
+
*/
|
|
8
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
9
|
+
export declare const MAX_CACHE_COUNT = 30;
|
|
10
|
+
export declare const MAX_CACHE_BYTES: number;
|
|
11
|
+
/**
|
|
12
|
+
* Fetch or reuse an image Blob by attachment ID.
|
|
13
|
+
* Refreshes LRU recency on hit and enforces count/byte limits on arrival.
|
|
14
|
+
*/
|
|
15
|
+
export declare function fetchAttachmentBlob(attachment: ImageAttachmentRef): Promise<Blob>;
|
|
16
|
+
/** Check if an attachment Blob is already cached in memory. */
|
|
17
|
+
export declare function getCachedAttachmentBlob(attachmentId: string | ImageAttachmentRef['attachmentId']): Promise<Blob> | undefined;
|
|
18
|
+
/** Evict one item from memory cache (e.g. when deleted from gallery). */
|
|
19
|
+
export declare function evictAttachmentCache(attachmentId: string | ImageAttachmentRef['attachmentId']): void;
|
|
20
|
+
/** Clear all in-memory image caches. */
|
|
21
|
+
export declare function clearAttachmentCache(): void;
|
|
22
|
+
/** Get current cache size metrics (useful for assertions and health monitoring). */
|
|
23
|
+
export declare function getCacheMetrics(): {
|
|
24
|
+
count: number;
|
|
25
|
+
bytes: number;
|
|
26
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const STUDIO_STYLE = "\n.dsh-ig-gallery-page-body.is-workbench{flex:1 1 0;height:100%;min-height:0;padding:0;overflow:hidden;display:flex;flex-direction:column}\n.dsh-ig-workbench{--ig-blue:#2f64f5;--ig-line:color-mix(in srgb,currentColor 11%,transparent);--ig-soft:color-mix(in srgb,currentColor 4%,transparent);position:relative;display:flex;flex-direction:column;min-height:0;height:100%;overflow:hidden;padding:10px 12px 12px;color:var(--foreground,#182033);box-sizing:border-box;background:radial-gradient(circle at 60% -20%,rgba(63,104,246,.07),transparent 30%)}\n.dsh-ig-workbench *{box-sizing:border-box}.dsh-ig-workbench button,.dsh-ig-workbench select,.dsh-ig-workbench textarea{font:inherit;color:inherit}\n.dsh-ig-workbench-grid{display:grid;grid-template-columns:minmax(190px,238px) minmax(0,1fr) minmax(286px,340px);grid-template-rows:minmax(0,1fr);min-height:0;height:0;flex:1 1 0;border:1px solid var(--ig-line);border-radius:12px;overflow:hidden;background:var(--background,#fff);box-shadow:0 12px 32px rgba(30,42,76,.05);transition:grid-template-columns .2s ease}\n.dsh-ig-workbench-grid.is-sidebar-collapsed{grid-template-columns:minmax(0,1fr) minmax(286px,340px)}\n.dsh-ig-recent-panel,.dsh-ig-generate-panel{min-width:0;min-height:0;overflow:hidden;background:color-mix(in srgb,var(--background,#fff) 96%,#f5f7fb)}.dsh-ig-recent-panel{display:flex;flex-direction:column;border-right:1px solid var(--ig-line)}\n.dsh-ig-panel-title{height:48px;flex:0 0 48px;padding:0 12px 0 14px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--ig-line);font-size:13px;font-weight:650}\n.dsh-ig-count-badge{font-size:11px;min-width:22px;text-align:center;padding:2px 6px;border-radius:999px;background:var(--ig-soft);color:#7b8498;font-weight:500}\n.dsh-ig-collapse-btn{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:6px;background:transparent;color:#717b90;cursor:pointer;transition:all .15s}\n.dsh-ig-collapse-btn:hover{border-color:var(--ig-line);background:var(--ig-soft);color:var(--foreground,#182033)}\n.dsh-ig-recent-scroll{flex:1 1 0;height:0;padding:8px;overflow-x:hidden;overflow-y:auto;min-height:0}.dsh-ig-recent-empty{min-height:180px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:10px;color:#929bad;text-align:center;font-size:12px}\n.dsh-ig-recent-item{display:grid;grid-template-columns:70px minmax(0,1fr);gap:10px;width:100%;padding:8px;border:1px solid transparent;border-radius:9px;background:transparent;text-align:left;cursor:pointer;transition:background .16s,border-color .16s,transform .16s}.dsh-ig-recent-item:hover{background:var(--ig-soft);transform:translateY(-1px)}.dsh-ig-recent-item.is-active{border-color:#89a7ff;background:rgba(47,100,245,.075);box-shadow:inset 3px 0 0 var(--ig-blue)}.dsh-ig-recent-thumb{width:70px;height:70px;border-radius:7px;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#eef1f7;color:#929bad}.dsh-ig-recent-thumb img{width:100%;height:100%;object-fit:cover}.dsh-ig-recent-item>div:last-child{min-width:0;padding:1px 0}.dsh-ig-recent-item strong{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;font-size:12.5px;line-height:19px;font-weight:630}.dsh-ig-recent-item span,.dsh-ig-recent-item small{display:block;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;color:#828b9e;font-size:10.5px;line-height:16px}\n.dsh-ig-load-more{width:100%;height:32px;margin:8px 0;display:flex;align-items:center;justify-content:center;border:1px dashed var(--ig-line);border-radius:7px;background:transparent;font-size:11px;color:#6b758b;cursor:pointer;transition:background .15s,color .15s}.dsh-ig-load-more:hover{background:var(--ig-soft);color:var(--ig-blue);border-color:#a2b9f6}\n.dsh-ig-mini-btn{height:22px;padding:0 7px;display:inline-flex;align-items:center;gap:3px;border:1px solid var(--ig-line);border-radius:5px;background:var(--background,#fff);font-size:10.5px;font-weight:500;color:var(--foreground,#242f44);cursor:pointer;transition:all .15s}.dsh-ig-mini-btn:hover{border-color:#9bb4f5;color:var(--ig-blue);background:rgba(47,100,245,.06)}\n.dsh-ig-canvas-column{min-width:0;min-height:0;height:100%;overflow:hidden;display:flex;flex-direction:column;background:color-mix(in srgb,var(--background,#fff) 97%,#e8edf7)}\n.dsh-ig-canvas-toolbar{height:46px;flex:0 0 46px;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 14px;border-bottom:1px solid var(--ig-line)}\n.dsh-ig-canvas-toolbar-left,.dsh-ig-canvas-toolbar-right{display:flex;align-items:center;gap:6px}\n.dsh-ig-canvas-toolbar button{height:30px;min-width:30px;padding:0 9px;display:inline-flex;align-items:center;justify-content:center;gap:5px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);color:var(--foreground,#242f44);font-size:11.5px;font-weight:500;cursor:pointer;transition:border-color .15s,background .15s,color .15s}\n.dsh-ig-canvas-toolbar button:hover{border-color:#9bb4f5;background:rgba(47,100,245,.05);color:var(--ig-blue)}\n.dsh-ig-canvas-toolbar button.is-active{border-color:#8ba8f8;background:rgba(47,100,245,.08);color:var(--ig-blue);font-weight:550}\n.dsh-ig-zoom-display{font-size:11px;min-width:38px;text-align:center;color:#64748b;user-select:none;font-variant-numeric:tabular-nums}\n.dsh-ig-status-badge-wrap{position:relative;display:inline-flex;align-items:center}\n.dsh-ig-status-badge{height:30px;display:inline-flex;align-items:center;gap:7px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);cursor:pointer;user-select:none;transition:border-color .15s,background .15s,box-shadow .15s}\n.dsh-ig-status-badge:hover{border-color:#9bb4f5;background:rgba(47,100,245,.04)}\n.dsh-ig-status-dot{width:7px;height:7px;min-width:7px;max-width:7px;border-radius:50%;flex-shrink:0;box-sizing:border-box}\n.dsh-ig-status-dot.is-ready{background:#10b981;box-shadow:0 0 0 2px rgba(16,185,129,.2)}\n.dsh-ig-status-dot.is-muted{background:#ef4444;box-shadow:0 0 0 2px rgba(239,68,68,.2)}\n.dsh-ig-status-text{font-size:11.5px;font-weight:500;color:var(--foreground,#242f44);line-height:1}\n.dsh-ig-status-arrow{color:#94a3b8;transition:transform .15s,color .15s}\n.dsh-ig-status-badge-wrap:hover .dsh-ig-status-arrow{transform:rotate(180deg);color:var(--ig-blue)}\n.dsh-ig-status-popover{position:absolute;left:0;top:calc(100% + 6px);width:260px;background:var(--background,#fff);border:1px solid var(--ig-line);border-radius:9px;box-shadow:0 12px 36px rgba(20,28,45,.14);padding:10px 12px;z-index:40;opacity:0;pointer-events:none;transform:translateY(4px);transition:opacity .15s cubic-bezier(.16,1,.3,1),transform .15s cubic-bezier(.16,1,.3,1)}\n.dsh-ig-status-badge-wrap:hover .dsh-ig-status-popover{opacity:1;pointer-events:auto;transform:translateY(0)}\n.dsh-ig-status-popover-title{display:flex;align-items:center;justify-content:space-between;font-size:10px;font-weight:650;color:#8590a6;margin-bottom:8px;letter-spacing:.02em;text-transform:uppercase}\n.dsh-ig-status-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}\n.dsh-ig-status-list li{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 8px;border-radius:6px;transition:background .12s}\n.dsh-ig-status-list li.is-configured{background:rgba(16,185,129,.05);border:1px solid rgba(16,185,129,.12)}\n.dsh-ig-status-list li.is-missing{background:rgba(239,68,68,.04);border:1px solid rgba(239,68,68,.12);opacity:.75}\n.dsh-ig-status-item-name{display:flex;flex-direction:column;min-width:0}\n.dsh-ig-status-item-name strong{font-size:11.5px;font-weight:600;color:var(--foreground,#182033);line-height:16px}\n.dsh-ig-status-item-name small{font-size:9.5px;color:#7c869a;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:145px;line-height:14px}\n.dsh-ig-status-item-tag{font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;flex-shrink:0}\n.is-configured .dsh-ig-status-item-tag{color:#059669;background:rgba(16,185,129,.14)}\n.is-missing .dsh-ig-status-item-tag{color:#dc2626;background:rgba(239,68,68,.14)}\n.dsh-ig-canvas{position:relative;flex:1 1 0;height:0;min-height:0;display:flex;align-items:center;justify-content:center;overflow:hidden;padding:24px;touch-action:none;user-select:none;cursor:grab;background-image:linear-gradient(45deg,rgba(114,128,156,.035) 25%,transparent 25%),linear-gradient(-45deg,rgba(114,128,156,.035) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(114,128,156,.035) 75%),linear-gradient(-45deg,transparent 75%,rgba(114,128,156,.035) 75%);background-size:24px 24px;background-position:0 0,0 12px,12px -12px,-12px 0}\n.dsh-ig-canvas.is-dragging{cursor:grabbing!important}\n.dsh-ig-canvas img{display:block;max-width:100%;max-height:100%;width:auto;height:auto;border-radius:10px;box-shadow:0 14px 45px rgba(25,35,63,.18);user-select:none;-webkit-user-drag:none;pointer-events:auto}\n.dsh-ig-canvas-empty,.dsh-ig-generating-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px;color:#929bad;font-size:12px;padding:26px;cursor:default}\n.dsh-ig-generating-state strong{font-size:15px;color:var(--foreground,#182033)}.dsh-ig-generating-state span{font-size:11px}.dsh-ig-generation-orbit{width:66px;height:66px;border-radius:50%;display:grid;place-items:center;color:var(--ig-blue);background:rgba(47,100,245,.09);box-shadow:0 0 0 10px rgba(47,100,245,.035);animation:dshIgPulse 1.8s ease-in-out infinite}\n.dsh-ig-result-strip{flex:0 0 auto;min-height:52px;padding:8px 14px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--ig-line)}.dsh-ig-result-strip>span{font-size:12px;font-weight:650}.dsh-ig-result-strip>div,.dsh-ig-result-actions>div{display:flex;gap:7px}.dsh-ig-result-strip button,.dsh-ig-result-actions button{height:32px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--background,#fff);font-size:11px;cursor:pointer}.dsh-ig-result-strip button:hover,.dsh-ig-result-actions button:hover{border-color:#9fb2ed;color:var(--ig-blue)}.dsh-ig-result-actions{flex:0 0 auto;min-height:54px;padding:8px 14px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--ig-line)}.dsh-ig-result-actions p{margin:0;min-width:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:11.5px;line-height:18px;color:#596277}.dsh-ig-result-meta{flex:0 0 auto;min-height:32px;padding:6px 14px;display:flex;gap:13px;align-items:center;flex-wrap:wrap;border-top:1px solid var(--ig-line);font-size:10px;color:#8790a3}.dsh-ig-result-meta span+span:before{content:'\u00B7';margin-right:13px}\n.dsh-ig-generate-panel{height:100%;display:flex;flex-direction:column;border-left:1px solid var(--ig-line);overflow:hidden}.dsh-ig-panel-tabs{height:48px;flex:0 0 48px;display:grid;grid-template-columns:1fr 1fr;border-bottom:1px solid var(--ig-line);padding:0 14px}.dsh-ig-panel-tabs button{position:relative;border:0;background:transparent;font-size:12px;color:#7c8598;cursor:pointer}.dsh-ig-panel-tabs button.is-active{color:var(--ig-blue);font-weight:650}.dsh-ig-panel-tabs button.is-active:after{content:'';position:absolute;left:20%;right:20%;bottom:-1px;height:2px;background:var(--ig-blue);border-radius:2px 2px 0 0}.dsh-ig-generator-form{flex:1 1 0;height:0;padding:15px;display:flex;flex-direction:column;gap:15px;overflow-x:hidden;overflow-y:auto;min-height:0}.dsh-ig-mode-switch{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-ig-mode-switch button{height:39px;border:1px solid var(--ig-line);border-radius:8px;background:var(--background,#fff);display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;cursor:pointer}.dsh-ig-mode-switch button.is-active{border-color:#789bff;color:var(--ig-blue);background:rgba(47,100,245,.065);box-shadow:inset 0 0 0 1px rgba(47,100,245,.1)}\n.dsh-ig-field{position:relative;display:flex;flex-direction:column;gap:7px}.dsh-ig-field>label,.dsh-ig-field-label label{font-size:11.5px;font-weight:630}.dsh-ig-field>label span{font-weight:400;color:#929bad}.dsh-ig-field-label{display:flex;align-items:center;justify-content:space-between}.dsh-ig-field-label b{color:#e14d4d}.dsh-ig-field-label button{border:0;background:transparent;color:#798397;font-size:10.5px;cursor:pointer}.dsh-ig-field textarea{width:100%;height:112px;padding:11px 12px 22px;resize:vertical;border:1px solid var(--ig-line);border-radius:9px;background:var(--background,#fff);font-size:12px;line-height:19px;outline:none}.dsh-ig-field textarea:focus{border-color:var(--ig-blue);box-shadow:0 0 0 3px rgba(47,100,245,.09)}.dsh-ig-field>small{position:absolute;right:9px;bottom:7px;color:#9aa2b2;font-size:9.5px}.dsh-ig-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:9px}.dsh-ig-field-select{display:flex;flex-direction:column;gap:6px;min-width:0}.dsh-ig-field-select>span{font-size:11px;font-weight:620}.dsh-ig-field-select select{width:100%;height:36px;padding:0 26px 0 9px;border:1px solid var(--ig-line);border-radius:8px;background:var(--background,#fff);font-size:11px;outline:none;text-overflow:ellipsis}.dsh-ig-field-select select:focus{border-color:var(--ig-blue)}\n.dsh-ig-upload{height:92px;border:1px dashed #bcc6d9;border-radius:9px;background:rgba(255,255,255,.45);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;color:#7d879b;cursor:pointer}.dsh-ig-upload strong{font-size:11px;font-weight:570}.dsh-ig-upload small{font-size:9.5px}.dsh-ig-upload:hover,.dsh-ig-upload.is-dragging{border-color:var(--ig-blue);background:rgba(47,100,245,.05);color:var(--ig-blue)}\n.dsh-ig-reference-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));gap:8px}\n.dsh-ig-reference-card{position:relative;aspect-ratio:1;border-radius:8px;overflow:hidden;background:#eef1f7;border:1px solid var(--ig-line)}\n.dsh-ig-reference-card img{width:100%;height:100%;object-fit:cover}\n.dsh-ig-reference-card button{position:absolute;right:4px;top:4px;width:18px;height:18px;border:0;border-radius:50%;display:grid;place-items:center;background:rgba(20,28,45,.75);color:#fff;cursor:pointer;padding:0;transition:background .15s}\n.dsh-ig-reference-card button:hover{background:#ef4444}\n.dsh-ig-reference-add{aspect-ratio:1;border:1px dashed #bcc6d9;border-radius:8px;background:rgba(255,255,255,.45);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;color:#7d879b;cursor:pointer;font-size:10px;transition:border-color .15s,color .15s,background .15s}\n.dsh-ig-reference-add:hover{border-color:var(--ig-blue);background:rgba(47,100,245,.05);color:var(--ig-blue)}\n.dsh-ig-reference-preview{position:relative;height:108px;border-radius:9px;overflow:hidden;background:#eef1f7}.dsh-ig-reference-preview img{width:100%;height:100%;object-fit:contain}.dsh-ig-reference-preview button{position:absolute;right:7px;top:7px;width:25px;height:25px;border:0;border-radius:50%;display:grid;place-items:center;background:rgba(20,28,45,.72);color:#fff;cursor:pointer}\n.dsh-ig-inline-note,.dsh-ig-form-error{padding:9px 10px;border-radius:7px;font-size:10.5px;line-height:16px}.dsh-ig-inline-note{background:#fff8e7;color:#8b671c;border:1px solid #f1dfae}.dsh-ig-form-error{background:#fff1f1;color:#b63737;border:1px solid #f2caca}.dsh-ig-form-loading{height:70px;display:grid;place-items:center;color:var(--ig-blue)}\n.dsh-ig-config-error{padding:14px;display:flex;flex-direction:column;align-items:center;gap:10px;background:#fff1f1;border:1px solid #f2caca;border-radius:8px;color:#b63737;font-size:11.5px;text-align:center}.dsh-ig-config-error p{margin:0;line-height:17px}.dsh-ig-config-error button{height:30px;display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:1px solid #e0a8a8;border-radius:6px;background:#fff;color:#b63737;font-size:11.5px;font-weight:600;cursor:pointer}.dsh-ig-config-error button:hover{background:#ffebeb}\n.dsh-ig-generate-button{height:42px;flex:0 0 auto;border:0;border-radius:8px;background:linear-gradient(135deg,#386cf6,#2758e7);color:#fff!important;display:flex;align-items:center;justify-content:center;gap:8px;font-size:12px;font-weight:650;cursor:pointer;box-shadow:0 8px 18px rgba(47,100,245,.22);transition:transform .16s,box-shadow .16s}.dsh-ig-generate-button:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 10px 24px rgba(47,100,245,.28)}.dsh-ig-generate-button:disabled{opacity:.55;cursor:not-allowed;box-shadow:none}\n.dsh-ig-generate-button.is-cancel{background:linear-gradient(135deg,#ef4444,#dc2626);box-shadow:0 8px 18px rgba(239,68,68,.25)}.dsh-ig-generate-button.is-cancel:hover{background:linear-gradient(135deg,#dc2626,#b91c1c);box-shadow:0 10px 24px rgba(239,68,68,.35)}\n.dsh-ig-details{padding:16px;margin:0;overflow:auto}.dsh-ig-details>div{padding:12px 0;border-bottom:1px solid var(--ig-line)}.dsh-ig-details dt{font-size:10.5px;color:#8992a4;margin-bottom:5px}.dsh-ig-details dd{margin:0;font-size:11.5px;line-height:18px;word-break:break-word}.dsh-ig-details-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;height:220px;padding:20px;color:#929bad;font-size:11px;text-align:center}\n.dsh-ig-workbench-modal-backdrop{position:fixed;inset:0;background:rgba(15,23,42,.45);backdrop-filter:blur(3px);z-index:999;display:grid;place-items:center;padding:16px}\n.dsh-ig-workbench-modal-box{width:100%;max-width:380px;background:var(--background,#fff);border-radius:12px;padding:20px;box-shadow:0 20px 48px rgba(0,0,0,.22);display:flex;flex-direction:column;gap:14px}\n.dsh-ig-workbench-modal-header{display:flex;align-items:center;gap:10px}\n.dsh-ig-workbench-modal-header strong{font-size:14px;font-weight:650;color:#b91c1c}\n.dsh-ig-workbench-modal-desc{font-size:12px;line-height:18px;color:#555f77;margin:0}\n.dsh-ig-workbench-modal-option{display:flex;align-items:center;gap:8px;font-size:11.5px;color:#4b5563;cursor:pointer}\n.dsh-ig-workbench-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:4px}\n.dsh-ig-workbench-modal-actions button{height:32px;padding:0 14px;border-radius:7px;font-size:11.5px;font-weight:600;cursor:pointer}\n.dsh-ig-workbench-modal-cancel{border:1px solid var(--ig-line);background:var(--background,#fff);color:#6b7280}\n.dsh-ig-workbench-modal-cancel:hover{background:#f3f4f6}\n.dsh-ig-workbench-modal-danger{border:0;background:#dc2626;color:#fff}\n.dsh-ig-workbench-modal-danger:hover{background:#b91c1c}\n@keyframes dshIgPulse{50%{transform:scale(1.06);box-shadow:0 0 0 16px rgba(47,100,245,.025)}}\n.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}\n@keyframes dshIgFade{from{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%,0)}}\n@media(max-width:1120px){.dsh-ig-workbench-grid{grid-template-columns:190px minmax(360px,1fr) 300px}.dsh-ig-result-actions button span{display:none}}\n@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}}\n@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}}\n@media(prefers-reduced-motion:reduce){.dsh-ig-workbench *{scroll-behavior:auto!important;animation-duration:.01ms!important;transition-duration:.01ms!important}}\n.dsh-ig-workspace-filter-label{height:30px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line,rgba(0,0,0,.1));border-radius:7px;background:var(--background,#fff);font-size:11.5px;color:var(--foreground,#242f44);cursor:pointer;user-select:none;transition:border-color .15s,background .15s}\n.dsh-ig-workspace-filter-label:hover{border-color:#9bb4f5;background:rgba(47,100,245,.04)}\n.dsh-ig-workspace-checkbox{cursor:pointer;accent-color:#2f64f5;width:13.5px;height:13.5px;margin:0}\n.dsh-ig-workspace-filter-text{font-weight:500;white-space:nowrap}\n.dsh-ig-workspace-filter-badge{font-size:10px;font-weight:600;padding:1px 6px;border-radius:999px;background:color-mix(in srgb,currentColor 7%,transparent);color:#64748b;font-variant-numeric:tabular-nums}\n";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
3
|
+
export interface LocaleService {
|
|
4
|
+
subscribe(cb: () => void): () => void;
|
|
5
|
+
getSnapshot(): {
|
|
6
|
+
active?: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export interface StudioReferenceItem {
|
|
10
|
+
id: string;
|
|
11
|
+
attachment?: ImageAttachmentRef;
|
|
12
|
+
file?: File;
|
|
13
|
+
previewUrl: string;
|
|
14
|
+
}
|
|
15
|
+
export interface StudioWorkspaceProps {
|
|
16
|
+
workspaceId?: string | undefined;
|
|
17
|
+
path?: string | undefined;
|
|
18
|
+
title?: string | undefined;
|
|
19
|
+
sessionIds?: readonly string[] | undefined;
|
|
20
|
+
}
|
|
21
|
+
export declare const StudioView: FC<{
|
|
22
|
+
locale?: LocaleService | undefined;
|
|
23
|
+
workspace?: StudioWorkspaceProps | null | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function useAttachmentImage(attachment: ImageAttachmentRef | undefined, shouldLoad?: boolean): {
|
|
26
|
+
url: string | null;
|
|
27
|
+
blob: Blob | null;
|
|
28
|
+
loading: boolean;
|
|
29
|
+
};
|
|
30
|
+
export declare function fileToBase64(file: File): Promise<string>;
|
|
@@ -9,7 +9,6 @@ export interface ImageRouteDeps {
|
|
|
9
9
|
/** Dependencies required by the delete route. */
|
|
10
10
|
export interface DeleteRouteDeps {
|
|
11
11
|
deleteWorkspaceImage(filePath: string): Promise<boolean>;
|
|
12
|
-
deleteWorkspaceImageByAttachmentId(attachmentId: string): Promise<boolean>;
|
|
13
12
|
}
|
|
14
13
|
/** Serve one verified durable image reference to a same-origin browser request. */
|
|
15
14
|
export declare function serveImage(req: IncomingMessage, res: ServerResponse, deps: ImageRouteDeps): Promise<void>;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Context } from '@deepseek-ai/cordis';
|
|
|
3
3
|
import { Config } from './config.js';
|
|
4
4
|
export { Config } from './config.js';
|
|
5
5
|
export { IMAGE_ROUTE, DELETE_ROUTE, imageAttachmentFromMeta } from './image-route.js';
|
|
6
|
+
export { STUDIO_ROUTE } from './shared.js';
|
|
6
7
|
export declare const name = "dsh-image-gen";
|
|
7
8
|
export declare const inject: string[];
|
|
8
9
|
export declare function apply(ctx: Context, config?: Config): void;
|
package/lib/types/shared.d.ts
CHANGED
|
@@ -1,13 +1,84 @@
|
|
|
1
1
|
/** Values shared by the Host and browser Bundle faces. */
|
|
2
|
+
import type { ImageAttachmentRef, ImageMediaType } from '@deepseek-ai/dsh-attachment';
|
|
2
3
|
/** Browser route used by the generated-image card. */
|
|
3
4
|
export declare const IMAGE_ROUTE = "/plugins/dsh-image-gen/image";
|
|
4
5
|
/** Browser route used for deleting generated images and workspace files. */
|
|
5
6
|
export declare const DELETE_ROUTE = "/plugins/dsh-image-gen/delete";
|
|
7
|
+
/** Same-origin route used by the browser image workbench. */
|
|
8
|
+
export declare const STUDIO_ROUTE = "/plugins/dsh-image-gen/studio";
|
|
6
9
|
/** Namespace persisted through DSH Settings. */
|
|
7
10
|
export declare const IMAGE_GENERATION_NAMESPACE = "image-generation";
|
|
8
11
|
/** Supported providers. */
|
|
9
12
|
export declare const IMAGE_PROVIDERS: readonly ["google", "openai", "seedream", "dashscope", "comfyui"];
|
|
10
13
|
export type ImageProvider = typeof IMAGE_PROVIDERS[number];
|
|
14
|
+
/** Providers supported by the first browser workbench release. */
|
|
15
|
+
export declare const CLOUD_IMAGE_PROVIDERS: readonly ["google", "openai", "seedream", "dashscope"];
|
|
16
|
+
export type CloudImageProvider = typeof CLOUD_IMAGE_PROVIDERS[number];
|
|
17
|
+
/** One selectable output option exposed by a provider profile. */
|
|
18
|
+
export interface StudioOption {
|
|
19
|
+
value: string;
|
|
20
|
+
label: string;
|
|
21
|
+
}
|
|
22
|
+
/** Browser-safe provider description. Credentials and endpoints never cross this boundary. */
|
|
23
|
+
export interface StudioProviderProfile {
|
|
24
|
+
provider: CloudImageProvider;
|
|
25
|
+
label: string;
|
|
26
|
+
model: string;
|
|
27
|
+
configured: boolean;
|
|
28
|
+
supportsEditing: boolean;
|
|
29
|
+
ratioOptions: StudioOption[];
|
|
30
|
+
qualityOptions: StudioOption[];
|
|
31
|
+
defaultRatio: string;
|
|
32
|
+
defaultQuality: string;
|
|
33
|
+
}
|
|
34
|
+
/** Lightweight workspace description exposed to the client for scoping. */
|
|
35
|
+
export interface StudioWorkspaceInfo {
|
|
36
|
+
workspaceId: string;
|
|
37
|
+
path: string;
|
|
38
|
+
title: string;
|
|
39
|
+
sessionIds: string[];
|
|
40
|
+
}
|
|
41
|
+
/** Read model and capability state for the workbench without exposing secrets. */
|
|
42
|
+
export interface StudioConfigResponse {
|
|
43
|
+
providers: StudioProviderProfile[];
|
|
44
|
+
activeProvider: CloudImageProvider;
|
|
45
|
+
workspaceRoot?: string | undefined;
|
|
46
|
+
workspaces?: StudioWorkspaceInfo[] | undefined;
|
|
47
|
+
}
|
|
48
|
+
/** A browser-uploaded reference image used for one editing request. */
|
|
49
|
+
export interface StudioEncodedReference {
|
|
50
|
+
mediaType: ImageMediaType;
|
|
51
|
+
data: string;
|
|
52
|
+
name?: string;
|
|
53
|
+
}
|
|
54
|
+
/** A durable image reference selected from the existing gallery. */
|
|
55
|
+
export interface StudioAttachmentReference {
|
|
56
|
+
attachment: ImageAttachmentRef;
|
|
57
|
+
}
|
|
58
|
+
export type StudioReference = StudioEncodedReference | StudioAttachmentReference;
|
|
59
|
+
/** One browser workbench generation or editing request. */
|
|
60
|
+
export interface StudioGenerateRequest {
|
|
61
|
+
mode: 'generate' | 'edit';
|
|
62
|
+
provider: CloudImageProvider;
|
|
63
|
+
model: string;
|
|
64
|
+
prompt: string;
|
|
65
|
+
ratio: string;
|
|
66
|
+
quality: string;
|
|
67
|
+
reference?: StudioReference;
|
|
68
|
+
references?: StudioReference[];
|
|
69
|
+
workspaceRoot?: string | undefined;
|
|
70
|
+
}
|
|
71
|
+
/** One completed workbench request. */
|
|
72
|
+
export interface StudioGenerateResponse {
|
|
73
|
+
attachment: ImageAttachmentRef;
|
|
74
|
+
provider: CloudImageProvider;
|
|
75
|
+
model: string;
|
|
76
|
+
prompt: string;
|
|
77
|
+
output: string;
|
|
78
|
+
createdAt: number;
|
|
79
|
+
elapsedMs: number;
|
|
80
|
+
savedTo?: string | undefined;
|
|
81
|
+
}
|
|
11
82
|
/** Default endpoints and base URLs. */
|
|
12
83
|
export declare const DEFAULT_GOOGLE_ENDPOINT = "https://generativelanguage.googleapis.com/v1beta/interactions";
|
|
13
84
|
export declare const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Same-origin HTTP bridge used by the browser image workbench. */
|
|
2
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
|
+
import { type StudioConfigResponse, type StudioGenerateRequest, type StudioGenerateResponse } from './shared.js';
|
|
4
|
+
export interface StudioRouteDeps {
|
|
5
|
+
describe(): Promise<StudioConfigResponse>;
|
|
6
|
+
generate(input: StudioGenerateRequest, signal: AbortSignal): Promise<StudioGenerateResponse>;
|
|
7
|
+
maxBodyBytes: number;
|
|
8
|
+
}
|
|
9
|
+
/** Serve workbench capabilities and generation requests without exposing provider credentials. */
|
|
10
|
+
export declare function serveStudio(req: IncomingMessage, res: ServerResponse, deps: StudioRouteDeps): Promise<void>;
|
|
11
|
+
/** Strictly validate the small untrusted workbench wire contract. */
|
|
12
|
+
export declare function parseStudioGenerateRequest(value: unknown): StudioGenerateRequest;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { type Config } from './config.js';
|
|
3
|
+
import { type CloudImageProvider, type StudioConfigResponse, type StudioGenerateRequest, type StudioGenerateResponse, type StudioProviderProfile } from './shared.js';
|
|
4
|
+
/** Return only browser-safe capability data. */
|
|
5
|
+
export declare function describeStudio(ctx: Context, config: Config): Promise<StudioConfigResponse>;
|
|
6
|
+
/** Execute one validated browser workbench request using the existing provider adapters. */
|
|
7
|
+
export declare function generateFromStudio(ctx: Context, config: Config, input: StudioGenerateRequest, signal: AbortSignal, fallbackWorkspaceRoot?: string | undefined): Promise<StudioGenerateResponse>;
|
|
8
|
+
export declare function studioProfile(config: Config, provider: CloudImageProvider, configured: boolean): StudioProviderProfile;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { StudioWorkspaceInfo } from './shared.js';
|
|
1
2
|
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
2
3
|
/**
|
|
3
4
|
* Build the deterministic file name for a generated image:
|
|
@@ -52,6 +53,8 @@ export declare function saveImageToWorkspace(options: {
|
|
|
52
53
|
}): Promise<string>;
|
|
53
54
|
/** Discover all DSH workspace paths recorded in local application storage. */
|
|
54
55
|
export declare function getDshWorkspaceRoots(): Promise<string[]>;
|
|
56
|
+
/** Discover detailed workspace records from DSH workspace.json storage. */
|
|
57
|
+
export declare function getDshWorkspacesFull(): Promise<StudioWorkspaceInfo[]>;
|
|
55
58
|
/**
|
|
56
59
|
* Safely delete a generated image file from workspace disk by its path.
|
|
57
60
|
* Enforces strict safety gates:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-image-gen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
@@ -54,13 +54,6 @@
|
|
|
54
54
|
"platform": "web"
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
|
-
"scripts": {
|
|
58
|
-
"typecheck": "tsc --noEmit",
|
|
59
|
-
"build": "tsc && tsdown",
|
|
60
|
-
"prepare": "pnpm run build",
|
|
61
|
-
"test": "vitest run",
|
|
62
|
-
"pack:check": "pnpm pack --dry-run"
|
|
63
|
-
},
|
|
64
57
|
"engines": {
|
|
65
58
|
"node": "^22.19.0 || >=24.0.0"
|
|
66
59
|
},
|
|
@@ -130,8 +123,13 @@
|
|
|
130
123
|
"unrun": "^0.3.1",
|
|
131
124
|
"vitest": "^4.1.8"
|
|
132
125
|
},
|
|
133
|
-
"packageManager": "pnpm@11.7.0",
|
|
134
126
|
"dependencies": {
|
|
135
127
|
"lucide-react": "^1.38.0"
|
|
128
|
+
},
|
|
129
|
+
"scripts": {
|
|
130
|
+
"typecheck": "tsc --noEmit",
|
|
131
|
+
"build": "tsc && tsdown",
|
|
132
|
+
"test": "vitest run",
|
|
133
|
+
"pack:check": "pnpm pack --dry-run"
|
|
136
134
|
}
|
|
137
|
-
}
|
|
135
|
+
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: install-dsh-image-gen
|
|
3
|
-
description: Install, configure, verify, or remove the dsh-image-gen Bundle in a DeepSeek Harness Web profile. Use when a user wants Google, OpenAI-compatible relay, Seedream, DashScope, or local ComfyUI image generation in DSH, cannot find the Image generation settings card, or needs help testing generate_image.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Install DSH Image Gen
|
|
7
|
-
|
|
8
|
-
1. Confirm `dsh` runs and record `dsh --version`.
|
|
9
|
-
2. Ask which Web profile to change if the user did not name one. Default to `web` only when that profile already exists.
|
|
10
|
-
3. Install the pinned package or repository spec the user provides:
|
|
11
|
-
|
|
12
|
-
```sh
|
|
13
|
-
dsh plugin --profile <profile> add <package-or-git-spec>
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
4. If pnpm blocks the Git dependency's `prepare` script, explain that the allowance executes repository code during installation. Add only the exact package key pnpm reports to the profile's `pnpm-workspace.yaml`, then retry after the user approves.
|
|
17
|
-
5. Verify `dsh --profile <profile> --dump-config` contains the `dsh-image-gen` layer and `image-gen` row.
|
|
18
|
-
6. Start the profile. If port 3080 is already in use, identify the existing DSH process before stopping anything.
|
|
19
|
-
7. In Settings > Plugins > Plugin configuration > Image generation, select a cloud Provider and save its API key, or select Local ComfyUI, enter its URL, and import a ComfyUI API Format workflow JSON containing `{{prompt}}`. Never print, read back, or commit a key.
|
|
20
|
-
8. Test with “生成一张戴墨镜的赛博朋克猫图片”. Confirm one `generate_image` call succeeds and its image renders in the conversation.
|
|
21
|
-
|
|
22
|
-
For removal, run `dsh plugin --profile <profile> remove dsh-image-gen`. Do not delete the user's credentials unless they explicitly request it.
|
|
1
|
+
---
|
|
2
|
+
name: install-dsh-image-gen
|
|
3
|
+
description: Install, configure, verify, or remove the dsh-image-gen Bundle in a DeepSeek Harness Web profile. Use when a user wants Google, OpenAI-compatible relay, Seedream, DashScope, or local ComfyUI image generation in DSH, cannot find the Image generation settings card, or needs help testing generate_image.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Install DSH Image Gen
|
|
7
|
+
|
|
8
|
+
1. Confirm `dsh` runs and record `dsh --version`.
|
|
9
|
+
2. Ask which Web profile to change if the user did not name one. Default to `web` only when that profile already exists.
|
|
10
|
+
3. Install the pinned package or repository spec the user provides:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
dsh plugin --profile <profile> add <package-or-git-spec>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
4. If pnpm blocks the Git dependency's `prepare` script, explain that the allowance executes repository code during installation. Add only the exact package key pnpm reports to the profile's `pnpm-workspace.yaml`, then retry after the user approves.
|
|
17
|
+
5. Verify `dsh --profile <profile> --dump-config` contains the `dsh-image-gen` layer and `image-gen` row.
|
|
18
|
+
6. Start the profile. If port 3080 is already in use, identify the existing DSH process before stopping anything.
|
|
19
|
+
7. In Settings > Plugins > Plugin configuration > Image generation, select a cloud Provider and save its API key, or select Local ComfyUI, enter its URL, and import a ComfyUI API Format workflow JSON containing `{{prompt}}`. Never print, read back, or commit a key.
|
|
20
|
+
8. Test with “生成一张戴墨镜的赛博朋克猫图片”. Confirm one `generate_image` call succeeds and its image renders in the conversation.
|
|
21
|
+
|
|
22
|
+
For removal, run `dsh plugin --profile <profile> remove dsh-image-gen`. Do not delete the user's credentials unless they explicitly request it.
|