@goodandready/dsh-image-gen 0.8.0 → 0.8.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 +1 -1
- package/lib/client.js +33 -17
- package/lib/index.js +24 -1
- package/lib/providers.js +8 -0
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2026 dsh-
|
|
3
|
+
Copyright (c) 2026 dsh-image-gen contributors
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/lib/client.js
CHANGED
|
@@ -796,30 +796,46 @@ window.__ModuleLoader__.load({
|
|
|
796
796
|
FalImageCard,
|
|
797
797
|
),
|
|
798
798
|
)
|
|
799
|
-
//
|
|
800
|
-
//
|
|
799
|
+
// Карточка во вкладке «Настройки плагинов» вместо строки в боковом
|
|
800
|
+
// списке: список плоский и перестал помещаться, а карточки вкладки
|
|
801
|
+
// сворачиваются. Ключ слота обязан равняться пространству настроек:
|
|
802
|
+
// вкладка перебирает именно их, с чужим ключом карточка исчезла бы молча.
|
|
803
|
+
// Заголовок, пояснение и сворачивание рисует сама карточка — ядро даёт
|
|
804
|
+
// только рамку списка.
|
|
801
805
|
//
|
|
802
|
-
//
|
|
803
|
-
//
|
|
804
|
-
//
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
//
|
|
808
|
-
// Заодно отпадает возня с keyed-слотом: settings.section принимает id на
|
|
809
|
-
// всех версиях ядра, и держать сразу id и key больше не нужно.
|
|
810
|
-
ctx.slots.inject('settings.section', () =>
|
|
806
|
+
// Запасной путь: слот объявлен пакетом настроек ядра. Если в сборке его
|
|
807
|
+
// нет, регистрация бросает — тогда остаётся прежний раздел в боковом
|
|
808
|
+
// списке, чтобы настройки не пропали.
|
|
809
|
+
let placedInPluginsTab = false
|
|
810
|
+
try {
|
|
811
811
|
ctx.slots.register(
|
|
812
812
|
{
|
|
813
|
-
name: 'settings.
|
|
814
|
-
|
|
815
|
-
order: 34,
|
|
813
|
+
name: 'settings.plugin.item',
|
|
814
|
+
key: SETTINGS_NS,
|
|
816
815
|
locale: NS,
|
|
817
|
-
label: () => t('settings.navLabel'),
|
|
818
816
|
inject: () => cardOnce().inject(),
|
|
819
817
|
},
|
|
820
818
|
FalSettingsCard,
|
|
821
|
-
)
|
|
822
|
-
|
|
819
|
+
)
|
|
820
|
+
placedInPluginsTab = true
|
|
821
|
+
} catch (noPluginItemSlot) {
|
|
822
|
+
placedInPluginsTab = false
|
|
823
|
+
}
|
|
824
|
+
if (!placedInPluginsTab) {
|
|
825
|
+
ctx.slots.inject('settings.section', () =>
|
|
826
|
+
ctx.slots.register(
|
|
827
|
+
{
|
|
828
|
+
name: 'settings.section',
|
|
829
|
+
id: '@goodandready/dsh-image-gen',
|
|
830
|
+
order: 34,
|
|
831
|
+
locale: NS,
|
|
832
|
+
label: () => t('settings.navLabel'),
|
|
833
|
+
inject: () => cardOnce().inject(),
|
|
834
|
+
},
|
|
835
|
+
FalSettingsCard,
|
|
836
|
+
),
|
|
837
|
+
)
|
|
838
|
+
}
|
|
823
839
|
}
|
|
824
840
|
exports.apply = apply
|
|
825
841
|
exports.inject = inject
|
package/lib/index.js
CHANGED
|
@@ -21,11 +21,12 @@ import {
|
|
|
21
21
|
IMAGE_SIZES,
|
|
22
22
|
OUTPUT_FORMATS,
|
|
23
23
|
PROVIDER_KEYS,
|
|
24
|
+
buildSidecar,
|
|
24
25
|
makeProviders,
|
|
25
26
|
normalizeMediaType,
|
|
26
27
|
} from './providers.js'
|
|
27
28
|
|
|
28
|
-
export { IMAGE_SIZES, OUTPUT_FORMATS, PROVIDER_KEYS, normalizeMediaType }
|
|
29
|
+
export { IMAGE_SIZES, OUTPUT_FORMATS, PROVIDER_KEYS, buildSidecar, normalizeMediaType }
|
|
29
30
|
|
|
30
31
|
export const name = 'dsh-image-gen'
|
|
31
32
|
|
|
@@ -335,6 +336,10 @@ export function apply(ctx, config) {
|
|
|
335
336
|
{ prompt: args.prompt, size, format, seed: args.seed, signal: exec.signal },
|
|
336
337
|
)
|
|
337
338
|
const generated = await providers[provider]()
|
|
339
|
+
// Подписочные провайдеры (codex/grok) отдают {ok:false, reason} вместо исключения:
|
|
340
|
+
// отказ должен дойти до модели текстом. Без проверки execute шёл дальше с пустыми
|
|
341
|
+
// байтами, и пользователь получал битую карточку вместо внятного отказа.
|
|
342
|
+
if (generated && generated.ok === false) throw new Error(generated.reason)
|
|
338
343
|
const bytes = generated.bytes
|
|
339
344
|
|
|
340
345
|
const mediaType = generated.mediaType
|
|
@@ -355,6 +360,24 @@ export function apply(ctx, config) {
|
|
|
355
360
|
await mkdir(outDir, { recursive: true })
|
|
356
361
|
const filePath = path.join(outDir, name)
|
|
357
362
|
await writeFile(filePath, bytes)
|
|
363
|
+
// Sidecar: рядом с картинкой — метаданные генерации. Каталог становится
|
|
364
|
+
// самодокументируемым (галерея/повтор/диагностика читают их без БД).
|
|
365
|
+
await writeFile(
|
|
366
|
+
path.join(outDir, `${stem}.json`),
|
|
367
|
+
JSON.stringify(buildSidecar({
|
|
368
|
+
prompt: args.prompt,
|
|
369
|
+
size,
|
|
370
|
+
format,
|
|
371
|
+
seed: generated.seed,
|
|
372
|
+
provider,
|
|
373
|
+
deliverAs,
|
|
374
|
+
width: generated.width || attachment.width,
|
|
375
|
+
height: generated.height || attachment.height,
|
|
376
|
+
mediaType,
|
|
377
|
+
attachmentId: attachment.attachmentId,
|
|
378
|
+
url: deliverAs === 'image' && generated.sourceUrl ? generated.sourceUrl : localUrl,
|
|
379
|
+
}), null, 2),
|
|
380
|
+
)
|
|
358
381
|
|
|
359
382
|
// The plugin's own route outlives the fal.media link, and the card
|
|
360
383
|
// needs the reference anyway to verify the bytes.
|
package/lib/providers.js
CHANGED
|
@@ -65,6 +65,14 @@ export function normalizeMediaType(contentType, fallbackFormat) {
|
|
|
65
65
|
return 'image/png'
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/** Метаданные одной генерации для sidecar-файла рядом с картинкой. */
|
|
69
|
+
export function buildSidecar({
|
|
70
|
+
prompt, size, format, seed, provider, deliverAs,
|
|
71
|
+
width, height, mediaType, attachmentId, url, createdAt = new Date().toISOString(),
|
|
72
|
+
}) {
|
|
73
|
+
return { prompt, size, format, seed, provider, deliverAs, width, height, mediaType, attachmentId, url, createdAt }
|
|
74
|
+
}
|
|
75
|
+
|
|
68
76
|
/** Submit a generation job to the FAL queue. */
|
|
69
77
|
export async function submitJob(fetchImpl, baseURL, model, key, body, signal) {
|
|
70
78
|
const res = await fetchImpl(`${baseURL}/${model}`, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-image-gen",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
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",
|