@goodandready/dsh-image-gen 0.11.38 → 0.11.40
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/capabilities.js +433 -0
- package/lib/client.js +10 -0
- package/lib/comfy-catalog.js +433 -0
- package/lib/config-schema.js +10 -0
- package/lib/index.js +76 -0
- package/lib/project-profiles.js +234 -0
- package/lib/providers/backends/local.js +35 -1
- package/lib/recipes.js +410 -0
- package/lib/register-tools.js +22 -1
- package/lib/tools/capabilities.js +139 -0
- package/lib/tools/project-profiles.js +139 -0
- package/lib/tools/recipes.js +250 -0
- package/package.json +1 -1
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability Registry and Model Selector (#434)
|
|
3
|
+
* Provides comprehensive capability mapping, strict pre-flight validation,
|
|
4
|
+
* cost estimation, and recommendation for task-specific models and providers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const CAPABILITY_REGISTRY = [
|
|
8
|
+
// Fal.ai models
|
|
9
|
+
{
|
|
10
|
+
provider: 'fal',
|
|
11
|
+
modelId: 'fal-ai/flux/dev',
|
|
12
|
+
displayName: 'FLUX.1 [dev]',
|
|
13
|
+
capabilities: ['txt2img', 'img2img', 'inpaint', 'high_res', 'text_rendering'],
|
|
14
|
+
maxResolution: 2048,
|
|
15
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4', '21:9'],
|
|
16
|
+
features: {
|
|
17
|
+
textRendering: true,
|
|
18
|
+
facePreservation: false,
|
|
19
|
+
maskInpainting: true,
|
|
20
|
+
referenceConditioning: false,
|
|
21
|
+
controlnet: false,
|
|
22
|
+
},
|
|
23
|
+
estimatedCostUSD: 0.025,
|
|
24
|
+
pricingSource: 'fal.ai/pricing (2026-09)',
|
|
25
|
+
verifiedDate: '2026-09-15',
|
|
26
|
+
tier: 'pro',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
provider: 'fal',
|
|
30
|
+
modelId: 'fal-ai/flux/schnell',
|
|
31
|
+
displayName: 'FLUX.1 [schnell]',
|
|
32
|
+
capabilities: ['txt2img', 'text_rendering'],
|
|
33
|
+
maxResolution: 1024,
|
|
34
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4'],
|
|
35
|
+
features: {
|
|
36
|
+
textRendering: true,
|
|
37
|
+
facePreservation: false,
|
|
38
|
+
maskInpainting: false,
|
|
39
|
+
referenceConditioning: false,
|
|
40
|
+
controlnet: false,
|
|
41
|
+
},
|
|
42
|
+
estimatedCostUSD: 0.003,
|
|
43
|
+
pricingSource: 'fal.ai/pricing (2026-09)',
|
|
44
|
+
verifiedDate: '2026-09-15',
|
|
45
|
+
tier: 'economy',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
provider: 'fal',
|
|
49
|
+
modelId: 'fal-ai/flux-general/image-to-image',
|
|
50
|
+
displayName: 'FLUX.1 Image-to-Image',
|
|
51
|
+
capabilities: ['img2img', 'reference'],
|
|
52
|
+
maxResolution: 1536,
|
|
53
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4'],
|
|
54
|
+
features: {
|
|
55
|
+
textRendering: true,
|
|
56
|
+
facePreservation: false,
|
|
57
|
+
maskInpainting: false,
|
|
58
|
+
referenceConditioning: true,
|
|
59
|
+
controlnet: false,
|
|
60
|
+
},
|
|
61
|
+
estimatedCostUSD: 0.03,
|
|
62
|
+
pricingSource: 'fal.ai/pricing (2026-09)',
|
|
63
|
+
verifiedDate: '2026-09-15',
|
|
64
|
+
tier: 'pro',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
provider: 'fal',
|
|
68
|
+
modelId: 'fal-ai/recraft-v3',
|
|
69
|
+
displayName: 'Recraft v3',
|
|
70
|
+
capabilities: ['txt2img', 'vector', 'text_rendering', 'high_res'],
|
|
71
|
+
maxResolution: 2048,
|
|
72
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4'],
|
|
73
|
+
features: {
|
|
74
|
+
textRendering: true,
|
|
75
|
+
facePreservation: false,
|
|
76
|
+
maskInpainting: false,
|
|
77
|
+
referenceConditioning: false,
|
|
78
|
+
controlnet: false,
|
|
79
|
+
},
|
|
80
|
+
estimatedCostUSD: 0.04,
|
|
81
|
+
pricingSource: 'fal.ai/pricing (2026-09)',
|
|
82
|
+
verifiedDate: '2026-09-15',
|
|
83
|
+
tier: 'pro',
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
// Google Gemini Imagen models
|
|
87
|
+
{
|
|
88
|
+
provider: 'gemini',
|
|
89
|
+
modelId: 'imagen-3.0-generate-002',
|
|
90
|
+
displayName: 'Google Imagen 3.0',
|
|
91
|
+
capabilities: ['txt2img', 'text_rendering', 'high_res'],
|
|
92
|
+
maxResolution: 2048,
|
|
93
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4'],
|
|
94
|
+
features: {
|
|
95
|
+
textRendering: true,
|
|
96
|
+
facePreservation: false,
|
|
97
|
+
maskInpainting: false,
|
|
98
|
+
referenceConditioning: false,
|
|
99
|
+
controlnet: false,
|
|
100
|
+
},
|
|
101
|
+
estimatedCostUSD: 0.03,
|
|
102
|
+
pricingSource: 'ai.google.dev (2026-09)',
|
|
103
|
+
verifiedDate: '2026-09-01',
|
|
104
|
+
tier: 'pro',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
provider: 'gemini',
|
|
108
|
+
modelId: 'imagen-3.0-capability-001',
|
|
109
|
+
displayName: 'Google Imagen 3.0 Editing',
|
|
110
|
+
capabilities: ['txt2img', 'img2img', 'inpaint', 'outpaint'],
|
|
111
|
+
maxResolution: 1536,
|
|
112
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4'],
|
|
113
|
+
features: {
|
|
114
|
+
textRendering: true,
|
|
115
|
+
facePreservation: false,
|
|
116
|
+
maskInpainting: true,
|
|
117
|
+
referenceConditioning: true,
|
|
118
|
+
controlnet: false,
|
|
119
|
+
},
|
|
120
|
+
estimatedCostUSD: 0.035,
|
|
121
|
+
pricingSource: 'ai.google.dev (2026-09)',
|
|
122
|
+
verifiedDate: '2026-09-01',
|
|
123
|
+
tier: 'pro',
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
// Replicate models
|
|
127
|
+
{
|
|
128
|
+
provider: 'replicate',
|
|
129
|
+
modelId: 'black-forest-labs/flux-1.1-pro',
|
|
130
|
+
displayName: 'Replicate FLUX 1.1 Pro',
|
|
131
|
+
capabilities: ['txt2img', 'text_rendering', 'high_res'],
|
|
132
|
+
maxResolution: 2048,
|
|
133
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4', '21:9'],
|
|
134
|
+
features: {
|
|
135
|
+
textRendering: true,
|
|
136
|
+
facePreservation: false,
|
|
137
|
+
maskInpainting: false,
|
|
138
|
+
referenceConditioning: false,
|
|
139
|
+
controlnet: false,
|
|
140
|
+
},
|
|
141
|
+
estimatedCostUSD: 0.04,
|
|
142
|
+
pricingSource: 'replicate.com/pricing',
|
|
143
|
+
verifiedDate: '2026-09-10',
|
|
144
|
+
tier: 'pro',
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
provider: 'replicate',
|
|
148
|
+
modelId: 'stability-ai/sdxl',
|
|
149
|
+
displayName: 'Replicate SDXL',
|
|
150
|
+
capabilities: ['txt2img', 'img2img', 'inpaint'],
|
|
151
|
+
maxResolution: 1024,
|
|
152
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4'],
|
|
153
|
+
features: {
|
|
154
|
+
textRendering: false,
|
|
155
|
+
facePreservation: false,
|
|
156
|
+
maskInpainting: true,
|
|
157
|
+
referenceConditioning: true,
|
|
158
|
+
controlnet: false,
|
|
159
|
+
},
|
|
160
|
+
estimatedCostUSD: 0.018,
|
|
161
|
+
pricingSource: 'replicate.com/pricing',
|
|
162
|
+
verifiedDate: '2026-09-10',
|
|
163
|
+
tier: 'economy',
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// Local (ComfyUI / Stable Diffusion / A1111)
|
|
167
|
+
{
|
|
168
|
+
provider: 'local',
|
|
169
|
+
modelId: 'sdxl_base',
|
|
170
|
+
displayName: 'Local ComfyUI SDXL Base',
|
|
171
|
+
capabilities: ['txt2img', 'img2img', 'inpaint', 'high_res', 'face_preservation', 'controlnet'],
|
|
172
|
+
maxResolution: 2048,
|
|
173
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4', '21:9'],
|
|
174
|
+
features: {
|
|
175
|
+
textRendering: false,
|
|
176
|
+
facePreservation: true,
|
|
177
|
+
maskInpainting: true,
|
|
178
|
+
referenceConditioning: true,
|
|
179
|
+
controlnet: true,
|
|
180
|
+
},
|
|
181
|
+
estimatedCostUSD: 0.0,
|
|
182
|
+
pricingSource: 'local-hardware (0 USD)',
|
|
183
|
+
verifiedDate: '2026-10-01',
|
|
184
|
+
tier: 'free',
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
provider: 'local',
|
|
188
|
+
modelId: 'flux_local',
|
|
189
|
+
displayName: 'Local ComfyUI FLUX',
|
|
190
|
+
capabilities: ['txt2img', 'img2img', 'text_rendering', 'high_res'],
|
|
191
|
+
maxResolution: 2048,
|
|
192
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16', '4:3', '3:4', '21:9'],
|
|
193
|
+
features: {
|
|
194
|
+
textRendering: true,
|
|
195
|
+
facePreservation: false,
|
|
196
|
+
maskInpainting: false,
|
|
197
|
+
referenceConditioning: false,
|
|
198
|
+
controlnet: false,
|
|
199
|
+
},
|
|
200
|
+
estimatedCostUSD: 0.0,
|
|
201
|
+
pricingSource: 'local-hardware (0 USD)',
|
|
202
|
+
verifiedDate: '2026-10-01',
|
|
203
|
+
tier: 'free',
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
// Seedream backend
|
|
207
|
+
{
|
|
208
|
+
provider: 'seedream',
|
|
209
|
+
modelId: 'seedream-v2',
|
|
210
|
+
displayName: 'Seedream v2',
|
|
211
|
+
capabilities: ['txt2img', 'img2img'],
|
|
212
|
+
maxResolution: 1024,
|
|
213
|
+
supportedAspectRatios: ['1:1', '16:9', '9:16'],
|
|
214
|
+
features: {
|
|
215
|
+
textRendering: false,
|
|
216
|
+
facePreservation: false,
|
|
217
|
+
maskInpainting: false,
|
|
218
|
+
referenceConditioning: false,
|
|
219
|
+
controlnet: false,
|
|
220
|
+
},
|
|
221
|
+
estimatedCostUSD: 0.015,
|
|
222
|
+
pricingSource: 'seedream API',
|
|
223
|
+
verifiedDate: '2026-08-20',
|
|
224
|
+
tier: 'economy',
|
|
225
|
+
},
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Returns the entire capability registry with metadata.
|
|
230
|
+
*/
|
|
231
|
+
export function getCapabilityRegistry() {
|
|
232
|
+
return [...CAPABILITY_REGISTRY]
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Filter models based on required operations and features.
|
|
237
|
+
* Unknown capabilities are strictly treated as unsupported.
|
|
238
|
+
*/
|
|
239
|
+
export function filterModelsByCapabilities(requirements = {}, options = {}) {
|
|
240
|
+
const {
|
|
241
|
+
operations = [],
|
|
242
|
+
textRendering = false,
|
|
243
|
+
facePreservation = false,
|
|
244
|
+
maskInpainting = false,
|
|
245
|
+
referenceConditioning = false,
|
|
246
|
+
controlnet = false,
|
|
247
|
+
minResolution = 0,
|
|
248
|
+
aspectRatio = null,
|
|
249
|
+
} = requirements
|
|
250
|
+
|
|
251
|
+
const maxCost = requirements.maxCost ?? requirements.maxCostUSD ?? Infinity
|
|
252
|
+
|
|
253
|
+
const configuredProviders = Array.isArray(options.configuredProviders)
|
|
254
|
+
? options.configuredProviders
|
|
255
|
+
: (Array.isArray(requirements.configuredProviders) ? requirements.configuredProviders : null)
|
|
256
|
+
|
|
257
|
+
return CAPABILITY_REGISTRY.map((model) => {
|
|
258
|
+
const missing = []
|
|
259
|
+
|
|
260
|
+
if (configuredProviders && !configuredProviders.includes(model.provider)) {
|
|
261
|
+
missing.push(`provider_unconfigured:${model.provider}`)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
for (const op of operations) {
|
|
265
|
+
if (!model.capabilities.includes(op)) {
|
|
266
|
+
missing.push(`operation:${op}`)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (textRendering && !model.features.textRendering) {
|
|
271
|
+
missing.push('feature:textRendering')
|
|
272
|
+
}
|
|
273
|
+
if (facePreservation && !model.features.facePreservation) {
|
|
274
|
+
missing.push('feature:facePreservation')
|
|
275
|
+
}
|
|
276
|
+
if (maskInpainting && !model.features.maskInpainting) {
|
|
277
|
+
missing.push('feature:maskInpainting')
|
|
278
|
+
}
|
|
279
|
+
if (referenceConditioning && !model.features.referenceConditioning) {
|
|
280
|
+
missing.push('feature:referenceConditioning')
|
|
281
|
+
}
|
|
282
|
+
if (controlnet && !model.features.controlnet) {
|
|
283
|
+
missing.push('feature:controlnet')
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (minResolution > 0 && model.maxResolution < minResolution) {
|
|
287
|
+
missing.push(`resolution:${model.maxResolution}<${minResolution}`)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (aspectRatio && !model.supportedAspectRatios.includes(aspectRatio)) {
|
|
291
|
+
missing.push(`aspectRatio:${aspectRatio}`)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (model.estimatedCostUSD > maxCost) {
|
|
295
|
+
missing.push(`cost:${model.estimatedCostUSD}>${maxCost}`)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
...model,
|
|
300
|
+
compatible: missing.length === 0,
|
|
301
|
+
missingCapabilities: missing,
|
|
302
|
+
}
|
|
303
|
+
})
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Evaluates requirements and recommends the best model.
|
|
308
|
+
*/
|
|
309
|
+
export function recommendModelForTask(requirements = {}, options = {}) {
|
|
310
|
+
const evaluated = filterModelsByCapabilities(requirements, options)
|
|
311
|
+
const compatible = evaluated.filter((m) => m.compatible)
|
|
312
|
+
|
|
313
|
+
if (compatible.length === 0) {
|
|
314
|
+
const partial = [...evaluated].sort((a, b) => a.missingCapabilities.length - b.missingCapabilities.length)
|
|
315
|
+
return {
|
|
316
|
+
ok: false,
|
|
317
|
+
recommended: null,
|
|
318
|
+
message: 'No model in registry completely satisfies all specified task requirements.',
|
|
319
|
+
alternatives: partial.slice(0, 3).map((m) => ({
|
|
320
|
+
provider: m.provider,
|
|
321
|
+
modelId: m.modelId,
|
|
322
|
+
displayName: m.displayName,
|
|
323
|
+
missing: m.missingCapabilities,
|
|
324
|
+
estimatedCostUSD: m.estimatedCostUSD,
|
|
325
|
+
})),
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Rank compatible models:
|
|
330
|
+
// 1. Configured providers preferred
|
|
331
|
+
// 2. Cost-effectiveness
|
|
332
|
+
// 3. Higher max resolution
|
|
333
|
+
compatible.sort((a, b) => {
|
|
334
|
+
if (a.estimatedCostUSD !== b.estimatedCostUSD) {
|
|
335
|
+
return a.estimatedCostUSD - b.estimatedCostUSD
|
|
336
|
+
}
|
|
337
|
+
return b.maxResolution - a.maxResolution
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
const best = compatible[0]
|
|
341
|
+
const reasons = []
|
|
342
|
+
if (best.estimatedCostUSD === 0) reasons.push('Zero API cost (local backend)')
|
|
343
|
+
else reasons.push(`Estimated cost: $${best.estimatedCostUSD.toFixed(3)}`)
|
|
344
|
+
if (best.features.textRendering && requirements.textRendering) reasons.push('Native high-precision text rendering')
|
|
345
|
+
if (best.features.facePreservation && requirements.facePreservation) reasons.push('Facial identity retention supported')
|
|
346
|
+
if (best.features.maskInpainting && requirements.maskInpainting) reasons.push('Pixel-accurate mask inpainting supported')
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
ok: true,
|
|
350
|
+
recommended: best,
|
|
351
|
+
recommendationReason: reasons.join('; '),
|
|
352
|
+
allCompatibleCount: compatible.length,
|
|
353
|
+
alternatives: compatible.slice(1, 4).map((m) => ({
|
|
354
|
+
provider: m.provider,
|
|
355
|
+
modelId: m.modelId,
|
|
356
|
+
displayName: m.displayName,
|
|
357
|
+
estimatedCostUSD: m.estimatedCostUSD,
|
|
358
|
+
})),
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Pre-flight validation before provider dispatch (#434).
|
|
364
|
+
* Rejects unsupported capabilities BEFORE submitting to provider to avoid wasting credits or losing inputs.
|
|
365
|
+
*/
|
|
366
|
+
export function validateModelCapability(provider, modelId, requestedFeatures = {}) {
|
|
367
|
+
const model = CAPABILITY_REGISTRY.find(
|
|
368
|
+
(m) => m.provider === provider && (m.modelId === modelId || !modelId)
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
if (!model) {
|
|
372
|
+
// Unknown model/provider: return strict unknown warning
|
|
373
|
+
return {
|
|
374
|
+
valid: false,
|
|
375
|
+
status: 'unknown_model',
|
|
376
|
+
reason: `Provider "${provider}" with model "${modelId || 'default'}" is not documented in capability registry.`,
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const {
|
|
381
|
+
operation,
|
|
382
|
+
requiresMask,
|
|
383
|
+
requiresReference,
|
|
384
|
+
requiresFacePreservation,
|
|
385
|
+
requiresTextRender,
|
|
386
|
+
} = requestedFeatures
|
|
387
|
+
|
|
388
|
+
if (operation && !model.capabilities.includes(operation)) {
|
|
389
|
+
return {
|
|
390
|
+
valid: false,
|
|
391
|
+
status: 'unsupported_operation',
|
|
392
|
+
reason: `Operation "${operation}" is not supported by model "${model.displayName}" (${model.provider}).`,
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (requiresMask && !model.features.maskInpainting) {
|
|
397
|
+
return {
|
|
398
|
+
valid: false,
|
|
399
|
+
status: 'unsupported_feature',
|
|
400
|
+
reason: `Mask inpainting is requested but not supported by "${model.displayName}". Discarding mask would corrupt generation.`,
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (requiresReference && !model.features.referenceConditioning && !model.capabilities.includes('img2img')) {
|
|
405
|
+
return {
|
|
406
|
+
valid: false,
|
|
407
|
+
status: 'unsupported_feature',
|
|
408
|
+
reason: `Reference image conditioning is requested but not supported by "${model.displayName}".`,
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (requiresFacePreservation && !model.features.facePreservation) {
|
|
413
|
+
return {
|
|
414
|
+
valid: false,
|
|
415
|
+
status: 'unsupported_feature',
|
|
416
|
+
reason: `Face preservation identity transfer is requested but not supported by "${model.displayName}".`,
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (requiresTextRender && !model.features.textRendering) {
|
|
421
|
+
return {
|
|
422
|
+
valid: false,
|
|
423
|
+
status: 'unsupported_feature',
|
|
424
|
+
reason: `High-fidelity text rendering is required but "${model.displayName}" lacks native text layout capabilities.`,
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
valid: true,
|
|
430
|
+
status: 'supported',
|
|
431
|
+
model,
|
|
432
|
+
}
|
|
433
|
+
}
|
package/lib/client.js
CHANGED
|
@@ -360,6 +360,7 @@ window.__ModuleLoader__.load({
|
|
|
360
360
|
{ field: 'toolsetProcessing', spec: booleanField('toolsetProcessing'), kind: 'select', options: ['true', 'false'], labelKey: 'f.toolsetProcessing', hintKey: 'f.toolsetProcessingHint', tab: 'general' },
|
|
361
361
|
{ field: 'toolsetFrontend', spec: booleanField('toolsetFrontend'), kind: 'select', options: ['true', 'false'], labelKey: 'f.toolsetFrontend', hintKey: 'f.toolsetFrontendHint', tab: 'general' },
|
|
362
362
|
{ field: 'toolsetCreative', spec: booleanField('toolsetCreative'), kind: 'select', options: ['true', 'false'], labelKey: 'f.toolsetCreative', hintKey: 'f.toolsetCreativeHint', tab: 'general' },
|
|
363
|
+
{ field: 'activeProjectProfile', spec: selectField('activeProjectProfile', ['', 'cyberpunk_neon', 'minimal_nordic', 'corporate_editorial']), kind: 'select', options: ['', 'cyberpunk_neon', 'minimal_nordic', 'corporate_editorial'], labelKey: 'f.activeProjectProfile', hintKey: 'f.activeProjectProfileHint', tab: 'general' },
|
|
363
364
|
|
|
364
365
|
// Provider: FAL
|
|
365
366
|
{ field: 'model', spec: textField('model'), kind: 'text', labelKey: 'f.model', hintKey: 'f.modelHint', placeholderKey: 'p.model', when: ['fal'], tab: 'provider' },
|
|
@@ -396,6 +397,7 @@ window.__ModuleLoader__.load({
|
|
|
396
397
|
// Backward-compat aliases for tests
|
|
397
398
|
{ field: 'localComfyUrl', spec: textField('localComfyUrl'), kind: 'text', labelKey: 'f.localComfyUrl', hintKey: 'f.localComfyUrlHint', placeholderKey: 'p.localComfyUrl', when: ['local'], tab: 'provider' },
|
|
398
399
|
{ field: 'localA1111Url', spec: textField('localA1111Url'), kind: 'text', labelKey: 'f.localA1111Url', hintKey: 'f.localA1111UrlHint', placeholderKey: 'p.localA1111Url', when: ['local'], tab: 'provider' },
|
|
400
|
+
{ field: 'comfyTemplate', spec: selectField('comfyTemplate', ['', 'txt2img_sdxl', 'img2img_sdxl', 'face_instantid', 'upscale_esrgan']), kind: 'select', options: ['', 'txt2img_sdxl', 'img2img_sdxl', 'face_instantid', 'upscale_esrgan'], labelKey: 'f.comfyTemplate', hintKey: 'f.comfyTemplateHint', when: ['local'], tab: 'provider' },
|
|
399
401
|
{ field: 'comfyWorkflowJson', spec: jsonField('comfyWorkflowJson'), kind: 'text', labelKey: 'f.comfyWorkflowJson', hintKey: 'f.comfyWorkflowJsonHint', placeholderKey: 'p.comfyWorkflowJson', when: ['local'], tab: 'provider' },
|
|
400
402
|
|
|
401
403
|
// Provider: Codex / Grok
|
|
@@ -2875,6 +2877,10 @@ window.__ModuleLoader__.load({
|
|
|
2875
2877
|
'vault.search': 'Search prompt or tags...',
|
|
2876
2878
|
'vault.seed': 'Seed',
|
|
2877
2879
|
'vault.title': 'Asset Browser & Vault',
|
|
2880
|
+
'f.comfyTemplate': 'ComfyUI Workflow Template',
|
|
2881
|
+
'f.comfyTemplateHint': 'Pre-vetted workflow template (e.g. SDXL txt2img, img2img, InstantID face transfer, RealESRGAN upscaler).',
|
|
2882
|
+
'f.activeProjectProfile': 'Active Project Profile',
|
|
2883
|
+
'f.activeProjectProfileHint': 'Select a saved visual profile (palette, style, format) to consistently apply across generations (#435).',
|
|
2878
2884
|
}
|
|
2879
2885
|
const zh = {
|
|
2880
2886
|
'card.actionRemoveBg': '移除背景',
|
|
@@ -3182,6 +3188,10 @@ window.__ModuleLoader__.load({
|
|
|
3182
3188
|
'vault.search': '搜索提示词或标签...',
|
|
3183
3189
|
'vault.seed': '种子',
|
|
3184
3190
|
'vault.title': '图像素材库与浏览器',
|
|
3191
|
+
'f.comfyTemplate': 'ComfyUI 工作流模板',
|
|
3192
|
+
'f.comfyTemplateHint': '经过验证的预设工作流模板(例如 SDXL 文生图、图生图、InstantID 人脸迁移、RealESRGAN 放大器)。',
|
|
3193
|
+
'f.activeProjectProfile': '活动项目视觉配置',
|
|
3194
|
+
'f.activeProjectProfileHint': '选择已保存的项目视觉配置(调色板、风格、格式),跨多次生成统一应用 (#435)。',
|
|
3185
3195
|
}
|
|
3186
3196
|
// Dual compatibility with DSH 0.1.5-rc.3 (settingsScope) and 0.1.6+ (configForms) (#291, #295)
|
|
3187
3197
|
const inject = ['slots', 'locale', 'sessions']
|