@dickpy/dsh-imagegen 1.4.0 → 1.5.1
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/LICENSE +201 -201
- package/README.md +270 -124
- package/cordis.patch.yml +8 -8
- package/docs/images/ecommerce-mode.png +0 -0
- package/docs/images/image-generation-studio-three-column.png +0 -0
- package/docs/images/imagegen-overview.png +0 -0
- package/docs/videos/agent-chat-edit.gif +0 -0
- package/docs/videos/agent-chat-edit.mp4 +0 -0
- package/lib/client.js +1873 -431
- package/lib/client.js.map +1 -1
- package/lib/index.js +355 -116
- package/package.json +77 -70
- package/src/agent-image-tools.ts +447 -418
- package/src/client/ImageGenPanel.tsx +1243 -348
- package/src/client/SettingsCard.tsx +936 -936
- package/src/client/TemplateLibrary.tsx +336 -336
- package/src/client/api.ts +203 -193
- package/src/client/channels-form.ts +263 -263
- package/src/client/controller.ts +46 -46
- package/src/client/conversation-sync.ts +14 -14
- package/src/client/css-modules.d.ts +5 -5
- package/src/client/helpers.ts +33 -33
- package/src/client/image-toolview.module.css +73 -73
- package/src/client/image-toolview.tsx +34 -28
- package/src/client/index.ts +25 -24
- package/src/client/locales.ts +156 -28
- package/src/client/mount.tsx +117 -117
- package/src/client/panel.module.css +1243 -455
- package/src/client/settings-card.module.css +1023 -1023
- package/src/client/settings-form.ts +337 -336
- package/src/client/settings-scope.ts +302 -298
- package/src/client/sidebar-entry.ts +190 -190
- package/src/client/templates.module.css +453 -453
- package/src/edit-image-command.ts +110 -0
- package/src/engine.ts +520 -520
- package/src/gallery-store.ts +306 -286
- package/src/generation-runtime.ts +84 -79
- package/src/history-store.ts +270 -250
- package/src/image-format.ts +11 -11
- package/src/image-models.ts +19 -19
- package/src/index.ts +337 -318
- package/src/model-catalog.ts +115 -115
- package/src/presets.ts +71 -71
- package/src/prompt-enhancer.ts +137 -137
- package/src/protocol.ts +380 -338
- package/src/routes.ts +966 -916
- package/src/settings-compat.ts +60 -0
- package/src/task-queue.ts +113 -113
- package/src/templates/cases.json +10196 -10196
- package/src/templates-store.ts +278 -278
- package/src/updater.ts +117 -117
- package/docs/images/agent-chat-edit.png +0 -0
- package/docs/images/agent-chat-generate.png +0 -0
- package/docs/images/agent-chat-poster-workflow.png +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Compatibility helpers for the dsh-settings API transition. */
|
|
2
|
+
|
|
3
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
4
|
+
import * as settingsModule from '@deepseek-ai/dsh-settings'
|
|
5
|
+
import type { SettingsNamespace, SettingsSectionHooks } from '@deepseek-ai/dsh-settings'
|
|
6
|
+
import type z from 'schemastery'
|
|
7
|
+
|
|
8
|
+
type SettingsModuleCompat = {
|
|
9
|
+
settingsNamespace?: (value: string) => SettingsNamespace
|
|
10
|
+
installSettingsSection?: <T>(
|
|
11
|
+
ctx: Context,
|
|
12
|
+
ns: SettingsNamespace,
|
|
13
|
+
schema: z<T>,
|
|
14
|
+
entry: T,
|
|
15
|
+
hooks: SettingsSectionHooks<T>,
|
|
16
|
+
) => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface SettingsProviderCompat {
|
|
20
|
+
installSection?: <T>(
|
|
21
|
+
owner: Context,
|
|
22
|
+
ns: SettingsNamespace,
|
|
23
|
+
schema: z<T>,
|
|
24
|
+
entry: T,
|
|
25
|
+
hooks: SettingsSectionHooks<T>,
|
|
26
|
+
) => void
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const compatModule = settingsModule as unknown as SettingsModuleCompat
|
|
30
|
+
|
|
31
|
+
/** Brand namespaces where the installed settings package still exposes it. */
|
|
32
|
+
export function settingsNamespaceCompat(value: string): SettingsNamespace {
|
|
33
|
+
return compatModule.settingsNamespace?.(value) ?? value as SettingsNamespace
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Register an optional settings section across the rc.7 and alpha.2 APIs.
|
|
38
|
+
* rc.7 exposes a module helper; alpha.2 moves the helper onto the provider.
|
|
39
|
+
*/
|
|
40
|
+
export function installSettingsSectionCompat<T>(
|
|
41
|
+
ctx: Context,
|
|
42
|
+
ns: SettingsNamespace,
|
|
43
|
+
schema: z<T>,
|
|
44
|
+
entry: T,
|
|
45
|
+
hooks: SettingsSectionHooks<T>,
|
|
46
|
+
): void {
|
|
47
|
+
const legacyInstaller = compatModule.installSettingsSection
|
|
48
|
+
if (legacyInstaller !== undefined) {
|
|
49
|
+
legacyInstaller(ctx, ns, schema, entry, hooks)
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
ctx.inject(['settings'], (sctx) => {
|
|
54
|
+
const provider = sctx.get('settings') as unknown as SettingsProviderCompat
|
|
55
|
+
if (provider.installSection === undefined) {
|
|
56
|
+
throw new TypeError('dsh-settings does not expose installSection')
|
|
57
|
+
}
|
|
58
|
+
provider.installSection(ctx, ns, schema, entry, hooks)
|
|
59
|
+
})
|
|
60
|
+
}
|
package/src/task-queue.ts
CHANGED
|
@@ -1,113 +1,113 @@
|
|
|
1
|
-
/** In-memory, host-resident image generation queue. */
|
|
2
|
-
|
|
3
|
-
import { randomUUID } from 'node:crypto'
|
|
4
|
-
import type { GenerateRequest, GenerateResult, GenerationTask } from './protocol.ts'
|
|
5
|
-
|
|
6
|
-
export type GenerationTaskListener = (task: GenerationTask) => void
|
|
7
|
-
|
|
8
|
-
export class GenerationTaskQueue {
|
|
9
|
-
private readonly tasks: GenerationTask[] = []
|
|
10
|
-
private readonly controllers = new Map<string, AbortController>()
|
|
11
|
-
private readonly listeners = new Set<GenerationTaskListener>()
|
|
12
|
-
private running = 0
|
|
13
|
-
private serialRunning = false
|
|
14
|
-
|
|
15
|
-
constructor(
|
|
16
|
-
private readonly run: (request: GenerateRequest, signal: AbortSignal) => Promise<GenerateResult>,
|
|
17
|
-
private readonly concurrency = 1,
|
|
18
|
-
) {}
|
|
19
|
-
|
|
20
|
-
list(): GenerationTask[] {
|
|
21
|
-
return this.tasks.map(task => this.snapshot(task))
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Observe queue state changes. Listener failures never disrupt generation. */
|
|
25
|
-
subscribe(listener: GenerationTaskListener): () => void {
|
|
26
|
-
this.listeners.add(listener)
|
|
27
|
-
return () => { this.listeners.delete(listener) }
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
submit(request: GenerateRequest): GenerationTask {
|
|
31
|
-
const task: GenerationTask = { id: randomUUID(), request: { ...request }, status: 'queued', createdAt: Date.now() }
|
|
32
|
-
this.tasks.unshift(task)
|
|
33
|
-
this.publish(task)
|
|
34
|
-
this.drain()
|
|
35
|
-
return this.snapshot(task)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
cancel(id: string): GenerationTask | undefined {
|
|
39
|
-
const task = this.tasks.find(item => item.id === id)
|
|
40
|
-
if (task === undefined || task.status === 'completed' || task.status === 'failed' || task.status === 'cancelled') return task
|
|
41
|
-
task.status = 'cancelled'
|
|
42
|
-
task.finishedAt = Date.now()
|
|
43
|
-
this.controllers.get(id)?.abort()
|
|
44
|
-
this.publish(task)
|
|
45
|
-
this.drain()
|
|
46
|
-
return this.snapshot(task)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
retry(id: string): GenerationTask | undefined {
|
|
50
|
-
const previous = this.tasks.find(item => item.id === id)
|
|
51
|
-
return previous === undefined ? undefined : this.submit(previous.request)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
private drain(): void {
|
|
55
|
-
while (this.running < Math.max(1, this.concurrency)) {
|
|
56
|
-
const task = this.tasks.find(item => item.status === 'queued'
|
|
57
|
-
&& (this.running === 0 || (item.request.comparisonId !== undefined && !this.serialRunning)))
|
|
58
|
-
if (task === undefined) return
|
|
59
|
-
this.running += 1
|
|
60
|
-
if (task.request.comparisonId === undefined) this.serialRunning = true
|
|
61
|
-
void this.runTask(task).finally(() => {
|
|
62
|
-
this.running -= 1
|
|
63
|
-
if (task.request.comparisonId === undefined) this.serialRunning = false
|
|
64
|
-
this.drain()
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private async runTask(task: GenerationTask): Promise<void> {
|
|
70
|
-
task.status = 'running'
|
|
71
|
-
task.startedAt = Date.now()
|
|
72
|
-
this.publish(task)
|
|
73
|
-
const controller = new AbortController()
|
|
74
|
-
this.controllers.set(task.id, controller)
|
|
75
|
-
try {
|
|
76
|
-
const result = await this.run(task.request, controller.signal)
|
|
77
|
-
if (this.tasks.find(item => item.id === task.id)?.status !== 'cancelled') {
|
|
78
|
-
task.status = 'completed'
|
|
79
|
-
task.result = result
|
|
80
|
-
task.finishedAt = Date.now()
|
|
81
|
-
this.publish(task)
|
|
82
|
-
}
|
|
83
|
-
} catch (error) {
|
|
84
|
-
if (this.tasks.find(item => item.id === task.id)?.status !== 'cancelled') {
|
|
85
|
-
task.status = 'failed'
|
|
86
|
-
task.error = error instanceof Error ? error.message : String(error)
|
|
87
|
-
task.finishedAt = Date.now()
|
|
88
|
-
this.publish(task)
|
|
89
|
-
}
|
|
90
|
-
} finally {
|
|
91
|
-
this.controllers.delete(task.id)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
private publish(task: GenerationTask): void {
|
|
96
|
-
const snapshot = this.snapshot(task)
|
|
97
|
-
for (const listener of this.listeners) {
|
|
98
|
-
try {
|
|
99
|
-
listener(snapshot)
|
|
100
|
-
} catch {
|
|
101
|
-
// Observers must not be able to interrupt the queue pump.
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private snapshot(task: GenerationTask): GenerationTask {
|
|
107
|
-
return {
|
|
108
|
-
...task,
|
|
109
|
-
request: { ...task.request },
|
|
110
|
-
...task.result === undefined ? {} : { result: task.result },
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
1
|
+
/** In-memory, host-resident image generation queue. */
|
|
2
|
+
|
|
3
|
+
import { randomUUID } from 'node:crypto'
|
|
4
|
+
import type { GenerateRequest, GenerateResult, GenerationTask } from './protocol.ts'
|
|
5
|
+
|
|
6
|
+
export type GenerationTaskListener = (task: GenerationTask) => void
|
|
7
|
+
|
|
8
|
+
export class GenerationTaskQueue {
|
|
9
|
+
private readonly tasks: GenerationTask[] = []
|
|
10
|
+
private readonly controllers = new Map<string, AbortController>()
|
|
11
|
+
private readonly listeners = new Set<GenerationTaskListener>()
|
|
12
|
+
private running = 0
|
|
13
|
+
private serialRunning = false
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
private readonly run: (request: GenerateRequest, signal: AbortSignal) => Promise<GenerateResult>,
|
|
17
|
+
private readonly concurrency = 1,
|
|
18
|
+
) {}
|
|
19
|
+
|
|
20
|
+
list(): GenerationTask[] {
|
|
21
|
+
return this.tasks.map(task => this.snapshot(task))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Observe queue state changes. Listener failures never disrupt generation. */
|
|
25
|
+
subscribe(listener: GenerationTaskListener): () => void {
|
|
26
|
+
this.listeners.add(listener)
|
|
27
|
+
return () => { this.listeners.delete(listener) }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
submit(request: GenerateRequest): GenerationTask {
|
|
31
|
+
const task: GenerationTask = { id: randomUUID(), request: { ...request }, status: 'queued', createdAt: Date.now() }
|
|
32
|
+
this.tasks.unshift(task)
|
|
33
|
+
this.publish(task)
|
|
34
|
+
this.drain()
|
|
35
|
+
return this.snapshot(task)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
cancel(id: string): GenerationTask | undefined {
|
|
39
|
+
const task = this.tasks.find(item => item.id === id)
|
|
40
|
+
if (task === undefined || task.status === 'completed' || task.status === 'failed' || task.status === 'cancelled') return task
|
|
41
|
+
task.status = 'cancelled'
|
|
42
|
+
task.finishedAt = Date.now()
|
|
43
|
+
this.controllers.get(id)?.abort()
|
|
44
|
+
this.publish(task)
|
|
45
|
+
this.drain()
|
|
46
|
+
return this.snapshot(task)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
retry(id: string): GenerationTask | undefined {
|
|
50
|
+
const previous = this.tasks.find(item => item.id === id)
|
|
51
|
+
return previous === undefined ? undefined : this.submit(previous.request)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private drain(): void {
|
|
55
|
+
while (this.running < Math.max(1, this.concurrency)) {
|
|
56
|
+
const task = this.tasks.find(item => item.status === 'queued'
|
|
57
|
+
&& (this.running === 0 || (item.request.comparisonId !== undefined && !this.serialRunning)))
|
|
58
|
+
if (task === undefined) return
|
|
59
|
+
this.running += 1
|
|
60
|
+
if (task.request.comparisonId === undefined) this.serialRunning = true
|
|
61
|
+
void this.runTask(task).finally(() => {
|
|
62
|
+
this.running -= 1
|
|
63
|
+
if (task.request.comparisonId === undefined) this.serialRunning = false
|
|
64
|
+
this.drain()
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private async runTask(task: GenerationTask): Promise<void> {
|
|
70
|
+
task.status = 'running'
|
|
71
|
+
task.startedAt = Date.now()
|
|
72
|
+
this.publish(task)
|
|
73
|
+
const controller = new AbortController()
|
|
74
|
+
this.controllers.set(task.id, controller)
|
|
75
|
+
try {
|
|
76
|
+
const result = await this.run(task.request, controller.signal)
|
|
77
|
+
if (this.tasks.find(item => item.id === task.id)?.status !== 'cancelled') {
|
|
78
|
+
task.status = 'completed'
|
|
79
|
+
task.result = result
|
|
80
|
+
task.finishedAt = Date.now()
|
|
81
|
+
this.publish(task)
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (this.tasks.find(item => item.id === task.id)?.status !== 'cancelled') {
|
|
85
|
+
task.status = 'failed'
|
|
86
|
+
task.error = error instanceof Error ? error.message : String(error)
|
|
87
|
+
task.finishedAt = Date.now()
|
|
88
|
+
this.publish(task)
|
|
89
|
+
}
|
|
90
|
+
} finally {
|
|
91
|
+
this.controllers.delete(task.id)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private publish(task: GenerationTask): void {
|
|
96
|
+
const snapshot = this.snapshot(task)
|
|
97
|
+
for (const listener of this.listeners) {
|
|
98
|
+
try {
|
|
99
|
+
listener(snapshot)
|
|
100
|
+
} catch {
|
|
101
|
+
// Observers must not be able to interrupt the queue pump.
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private snapshot(task: GenerationTask): GenerationTask {
|
|
107
|
+
return {
|
|
108
|
+
...task,
|
|
109
|
+
request: { ...task.request },
|
|
110
|
+
...task.result === undefined ? {} : { result: task.result },
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|