@goodandready/dsh-image-gen 0.11.34 → 0.11.35
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/config-schema.js +19 -9
- package/lib/index.js +3 -2
- package/lib/providers.js +21 -14
- package/package.json +1 -1
package/lib/config-schema.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// lib/config-schema.js — Zod configuration schema and normalization helpers (#317)
|
|
2
2
|
|
|
3
3
|
import z from '@deepseek-ai/schemastery'
|
|
4
|
-
import { IMAGE_SIZES, OUTPUT_FORMATS, PROVIDER_KEYS } from './
|
|
4
|
+
import { IMAGE_SIZES, OUTPUT_FORMATS, PROVIDER_KEYS } from './provider-utils.js'
|
|
5
5
|
|
|
6
6
|
// Polyfill for .volatile() schema annotation if runtime schemastery lacks it (#295)
|
|
7
7
|
if (typeof z.prototype?.volatile !== 'function') {
|
|
@@ -343,15 +343,25 @@ export function isVolatileRef(value) {
|
|
|
343
343
|
return !!value && typeof value === 'object' && !Array.isArray(value) && typeof value.get === 'function'
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
346
|
+
/**
|
|
347
|
+
* Deeply unwrap Cosmokit/Schemastery Volatile boxes into plain primitives/objects/arrays (#282, #417).
|
|
348
|
+
*/
|
|
349
|
+
export function plainConfig(value) {
|
|
350
|
+
if (value === null || value === undefined) return value
|
|
351
|
+
if (typeof value === 'function') return plainConfig(value())
|
|
352
|
+
if (isVolatileRef(value)) return plainConfig(value.get())
|
|
353
|
+
if (Array.isArray(value)) return value.map(plainConfig)
|
|
354
|
+
if (typeof value === 'object') {
|
|
355
|
+
if (Buffer.isBuffer(value) || value instanceof Date || value instanceof RegExp || value instanceof URL) {
|
|
356
|
+
return value
|
|
357
|
+
}
|
|
358
|
+
const out = {}
|
|
359
|
+
for (const [k, v] of Object.entries(value)) {
|
|
360
|
+
out[k] = plainConfig(v)
|
|
361
|
+
}
|
|
362
|
+
return out
|
|
353
363
|
}
|
|
354
|
-
return
|
|
364
|
+
return value
|
|
355
365
|
}
|
|
356
366
|
|
|
357
367
|
export function volatileConfig(cfg) {
|
package/lib/index.js
CHANGED
|
@@ -367,13 +367,14 @@ export function apply(ctx, rawConfig) {
|
|
|
367
367
|
try {
|
|
368
368
|
const u = new URL(req.url, 'http://localhost')
|
|
369
369
|
const qProvider = u.searchParams.get('provider')
|
|
370
|
+
const effectiveCfg = live()
|
|
370
371
|
const provider = (typeof qProvider === 'string' && qProvider.trim())
|
|
371
|
-
|| (typeof
|
|
372
|
+
|| (typeof effectiveCfg?.provider === 'string' && effectiveCfg.provider.trim())
|
|
372
373
|
|| 'fal'
|
|
373
374
|
const deps = {
|
|
374
375
|
fetchImpl: fetch,
|
|
375
376
|
resolveKey: (ref) => resolveApiKey(ctx, ref),
|
|
376
|
-
cfg:
|
|
377
|
+
cfg: effectiveCfg,
|
|
377
378
|
ctx,
|
|
378
379
|
}
|
|
379
380
|
const result = await testProviderConnection(deps, provider)
|
package/lib/providers.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import sharp from 'sharp'
|
|
2
|
+
import { plainConfig } from './config-schema.js'
|
|
2
3
|
import { CURATED_STYLES, normalizeStyleKey } from './prompt-polisher.js'
|
|
3
4
|
/**
|
|
4
5
|
* Returns candidate API key names considering known aliases (e.g. FAL_API_KEY <-> FAL_KEY).
|
|
@@ -221,16 +222,17 @@ export async function saveAttachmentSafe(ctx, { bytes, mediaType, name }) {
|
|
|
221
222
|
|
|
222
223
|
|
|
223
224
|
export function makeProviders(deps, job) {
|
|
224
|
-
const
|
|
225
|
+
const safeDeps = deps?.cfg ? { ...deps, cfg: plainConfig(deps.cfg) } : deps
|
|
226
|
+
const subscription = createSubscriptionGenerator(safeDeps, job)
|
|
225
227
|
return {
|
|
226
|
-
fal: createFalGenerator(
|
|
227
|
-
custom: createCustomGenerator(
|
|
228
|
+
fal: createFalGenerator(safeDeps, job),
|
|
229
|
+
custom: createCustomGenerator(safeDeps, job),
|
|
228
230
|
codex: subscription('codex'),
|
|
229
231
|
grok: subscription('grok'),
|
|
230
|
-
local: createLocalGenerator(
|
|
231
|
-
seedream: createSeedreamGenerator(
|
|
232
|
-
gemini: createGeminiGenerator(
|
|
233
|
-
replicate: createReplicateGenerator(
|
|
232
|
+
local: createLocalGenerator(safeDeps, job),
|
|
233
|
+
seedream: createSeedreamGenerator(safeDeps, job),
|
|
234
|
+
gemini: createGeminiGenerator(safeDeps, job),
|
|
235
|
+
replicate: createReplicateGenerator(safeDeps, job),
|
|
234
236
|
}
|
|
235
237
|
}
|
|
236
238
|
|
|
@@ -279,7 +281,8 @@ export function embedPngMetadata(pngBytes, metadata = {}) {
|
|
|
279
281
|
return Buffer.concat([buf.subarray(0, insertPos), chunk, buf.subarray(insertPos)])
|
|
280
282
|
}
|
|
281
283
|
|
|
282
|
-
export async function removeBackgroundFal({ fetchImpl, resolveKey, cfg }, { imageBytes, mediaType = 'image/png', model = 'fal-ai/birefnet', signal }) {
|
|
284
|
+
export async function removeBackgroundFal({ fetchImpl, resolveKey, cfg: rawCfg }, { imageBytes, mediaType = 'image/png', model = 'fal-ai/birefnet', signal }) {
|
|
285
|
+
const cfg = plainConfig(rawCfg)
|
|
283
286
|
const key = await resolveKey(cfg.apiKeyEnv)
|
|
284
287
|
const base64 = Buffer.isBuffer(imageBytes) ? imageBytes.toString('base64') : Buffer.from(imageBytes).toString('base64')
|
|
285
288
|
const dataUrl = `data:${mediaType};base64,${base64}`
|
|
@@ -297,7 +300,8 @@ export async function removeBackgroundFal({ fetchImpl, resolveKey, cfg }, { imag
|
|
|
297
300
|
return { bytes, mediaType: 'image/png', width: img.width || 0, height: img.height || 0, sourceUrl: img.url }
|
|
298
301
|
}
|
|
299
302
|
|
|
300
|
-
export async function upscaleImageFal({ fetchImpl, resolveKey, cfg }, { imageBytes, mediaType = 'image/png', scale = 2, creativity, prompt, model = 'fal-ai/clarity-upscaler', signal }) {
|
|
303
|
+
export async function upscaleImageFal({ fetchImpl, resolveKey, cfg: rawCfg }, { imageBytes, mediaType = 'image/png', scale = 2, creativity, prompt, model = 'fal-ai/clarity-upscaler', signal }) {
|
|
304
|
+
const cfg = plainConfig(rawCfg)
|
|
301
305
|
const key = await resolveKey(cfg.apiKeyEnv)
|
|
302
306
|
const base64 = Buffer.isBuffer(imageBytes) ? imageBytes.toString('base64') : Buffer.from(imageBytes).toString('base64')
|
|
303
307
|
const dataUrl = `data:${mediaType};base64,${base64}`
|
|
@@ -579,8 +583,9 @@ export async function blendImagesFal({ fetchImpl, resolveKey, cfg }, { images, w
|
|
|
579
583
|
/** Direct image editing (inpainting / img2img) via selected provider. */
|
|
580
584
|
/** @internal — direct provider call path for integration tests */
|
|
581
585
|
export async function editImageDirect(deps, job) {
|
|
582
|
-
const
|
|
583
|
-
const
|
|
586
|
+
const safeDeps = deps?.cfg ? { ...deps, cfg: plainConfig(deps.cfg) } : deps
|
|
587
|
+
const providers = makeProviders(safeDeps, job)
|
|
588
|
+
const providerKey = (typeof job?.provider === 'string' && job.provider.trim()) || (typeof safeDeps?.cfg?.provider === 'string' && safeDeps.cfg.provider.trim()) || (typeof safeDeps?.cfg?.defaultProvider === 'string' && safeDeps.cfg.defaultProvider.trim()) || 'fal'
|
|
584
589
|
const fn = providers[providerKey] || providers.fal || providers.custom
|
|
585
590
|
if (!fn) throw new Error(`Provider "${providerKey}" does not support image editing`)
|
|
586
591
|
return fn(job.seed, job.prompt)
|
|
@@ -589,11 +594,12 @@ export async function editImageDirect(deps, job) {
|
|
|
589
594
|
/** Direct image variation via selected provider. */
|
|
590
595
|
/** @internal — direct provider call path for integration tests */
|
|
591
596
|
export async function varyImageDirect(deps, job) {
|
|
592
|
-
const
|
|
597
|
+
const safeDeps = deps?.cfg ? { ...deps, cfg: plainConfig(deps.cfg) } : deps
|
|
598
|
+
const providers = makeProviders(safeDeps, {
|
|
593
599
|
...job,
|
|
594
600
|
strength: job.variationStrength ?? job.strength ?? 0.35,
|
|
595
601
|
})
|
|
596
|
-
const providerKey = (typeof job?.provider === 'string' && job.provider.trim()) || (typeof
|
|
602
|
+
const providerKey = (typeof job?.provider === 'string' && job.provider.trim()) || (typeof safeDeps?.cfg?.provider === 'string' && safeDeps.cfg.provider.trim()) || (typeof safeDeps?.cfg?.defaultProvider === 'string' && safeDeps.cfg.defaultProvider.trim()) || 'fal'
|
|
597
603
|
const fn = providers[providerKey] || providers.fal || providers.custom
|
|
598
604
|
if (!fn) throw new Error(`Provider "${providerKey}" does not support image variations`)
|
|
599
605
|
return fn(job.seed, job.prompt)
|
|
@@ -628,7 +634,8 @@ export function toLosslessJson(val) {
|
|
|
628
634
|
* Returns { ok: boolean, latencyMs: number, message: string }.
|
|
629
635
|
*/
|
|
630
636
|
export async function testProviderConnection(deps, providerId) {
|
|
631
|
-
const { fetchImpl = fetch, resolveKey
|
|
637
|
+
const { fetchImpl = fetch, resolveKey } = deps || {}
|
|
638
|
+
const cfg = plainConfig(deps?.cfg)
|
|
632
639
|
const start = Date.now()
|
|
633
640
|
const rawProvider = (typeof providerId === 'string' && providerId.trim())
|
|
634
641
|
|| (typeof cfg?.provider === 'string' && cfg.provider.trim())
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-image-gen",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.35",
|
|
4
4
|
"description": "Image generation for DeepSeek Harness: a generate_image tool with pluggable providers — the FAL queue, any OpenAI-compatible images API, or a ChatGPT/Grok subscription with no API key at all. The picture is shown inline in the conversation; the model receives either a link (works with any chat model) or the image itself (needs dsh-vision-bridge or a vision-capable model).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|