@goodandready/dsh-image-gen 0.10.8 → 0.10.10
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.md +7 -0
- package/README.ru.md +7 -0
- package/lib/client.js +147 -108
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,6 +83,13 @@
|
|
|
83
83
|
* **FAL Credential Aliasing**: seamless fallback between `FAL_API_KEY` and `FAL_KEY` in credentials and environment.
|
|
84
84
|
* **Subscription Aspect Ratio Mapping**: maps aspect ratios (`16:9`, `3:2`, `9:16`, `2:3`) to appropriate subscription dimensions (`1536x1024` / `1024x1536`) instead of falling back to default square `1024x1024`.
|
|
85
85
|
|
|
86
|
+
|
|
87
|
+
### 🚀 What's New in v0.10.10 (#201, #203)
|
|
88
|
+
* **Settings GUI Stabilization (#201)**: Fixed `booleanField` spec in client runtime that prevented the settings configuration pane from rendering in DSH Web UI. All configuration fields (providers, model identifiers, API credentials, style presets, LLM enhancer, timeouts, cache retention) render cleanly.
|
|
89
|
+
* **Streamlined Settings UI (#203)**: Removed the bulky in-settings history gallery to keep the configuration panel focused, fast, and organized.
|
|
90
|
+
* **Comprehensive Localization (#201)**: Added 100% dictionary coverage for all provider credentials, endpoints, and field hints in English and Russian.
|
|
91
|
+
* **Robust Slot Mounting**: Implemented `registerFirst` helper with graceful fallback between `settings.plugin.item` and `settings.section`.
|
|
92
|
+
|
|
86
93
|
## 🎨 Supported Generation Backends
|
|
87
94
|
|
|
88
95
|
* **`fal`** (Default): FAL.ai queue for FLUX.1, SDXL, Clarity Upscaler, and BiRefNet.
|
package/README.ru.md
CHANGED
|
@@ -129,6 +129,13 @@ graph LR
|
|
|
129
129
|
- **Оптимизация компонентов (#139)**: из `FalImageCard` удалён неиспользуемый мёртвый стейт.
|
|
130
130
|
- **100% интернационализация (#140)**: устранены захардкоженные русские строки, добавлены переводы на русский, английский и китайский языки.
|
|
131
131
|
|
|
132
|
+
|
|
133
|
+
### 🚀 Что нового в v0.10.10 (#201, #203)
|
|
134
|
+
* **Стабилизация окна настроек GUI (#201)**: Исправлена спецификация `booleanField` в клиентском коде, вызывавшая падение рендера карточки настроек плагина в DSH Web UI. Форма настроек теперь открывается штатно со всеми полями, селекторами провайдеров, моделями, ссылками на ключи и пресетами.
|
|
135
|
+
* **Очистка интерфейса настроек (#203)**: Из окна настроек убрана встроенная галерея истории генераций, загромождавшая карточку настроек.
|
|
136
|
+
* **Полная локализация (#201)**: Добавлены все недостающие строки переводов и подсказок на русском и английском языках для всех поддерживаемых провайдеров.
|
|
137
|
+
* **Надёжная регистрация слотов**: Реализован `registerFirst` с плавным откатом между `settings.plugin.item` и `settings.section`.
|
|
138
|
+
|
|
132
139
|
## 🎨 Поддерживаемые провайдеры генерации
|
|
133
140
|
|
|
134
141
|
* **`fal`** *(дефолт)*: Сверхбыстрая очередь FAL.ai (`FLUX.1-schnell`, `FLUX-dev`, `SDXL`, BiRefNet, Clarity Upscaler).
|
package/lib/client.js
CHANGED
|
@@ -82,12 +82,7 @@ window.__ModuleLoader__.load({
|
|
|
82
82
|
'.fal_input:disabled,.fal_select:disabled{opacity:.6}' +
|
|
83
83
|
'.fal_hint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px}' +
|
|
84
84
|
'.fal_invalid{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}' +
|
|
85
|
-
'.fal_sep{height:1px;background:var(--dsw-alias-border-l2);margin:2px 0 0}'
|
|
86
|
-
'.fal_gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;margin-top:12px}' +
|
|
87
|
-
'.fal_galleryItem{display:flex;flex-direction:column;gap:4px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;overflow:hidden}' +
|
|
88
|
-
'.fal_galleryImg{width:100%;height:90px;object-fit:cover;display:block}' +
|
|
89
|
-
'.fal_galleryMeta{font-size:11px;color:var(--dsw-alias-label-secondary);padding:4px 6px}' +
|
|
90
|
-
'.fal_galleryEmpty{color:var(--dsw-alias-label-secondary);font-size:12px;margin-top:12px}'
|
|
85
|
+
'.fal_sep{height:1px;background:var(--dsw-alias-border-l2);margin:2px 0 0}'
|
|
91
86
|
const tagId = 'dsh-image-gen/settings-card.module.css'
|
|
92
87
|
if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css=' + JSON.stringify(tagId) + ']') === null) {
|
|
93
88
|
const tag = document.createElement('style')
|
|
@@ -124,11 +119,6 @@ window.__ModuleLoader__.load({
|
|
|
124
119
|
save: 'fal_save',
|
|
125
120
|
select: 'fal_select',
|
|
126
121
|
sep: 'fal_sep',
|
|
127
|
-
gallery: 'fal_gallery',
|
|
128
|
-
galleryItem: 'fal_galleryItem',
|
|
129
|
-
galleryImg: 'fal_galleryImg',
|
|
130
|
-
galleryMeta: 'fal_galleryMeta',
|
|
131
|
-
galleryEmpty: 'fal_galleryEmpty',
|
|
132
122
|
}
|
|
133
123
|
|
|
134
124
|
// -------------------------------------------------------------- chrome
|
|
@@ -136,7 +126,7 @@ window.__ModuleLoader__.load({
|
|
|
136
126
|
function PluginSettingsCard(props) {
|
|
137
127
|
// Карточка живёт в собственном разделе настроек и на странице одна, так
|
|
138
128
|
// что открыта сразу: свёрнутая выглядела бы как пустая страница.
|
|
139
|
-
const [open, setOpen] = react.useState(
|
|
129
|
+
const [open, setOpen] = react.useState(props.defaultOpen ?? true)
|
|
140
130
|
const { state } = props
|
|
141
131
|
// Раньше здесь было `return null`, и раздел оказывался пустым, если хост
|
|
142
132
|
// ещё не объявил настройки. Пустая страница ничего не объясняет — лучше
|
|
@@ -464,7 +454,17 @@ window.__ModuleLoader__.load({
|
|
|
464
454
|
const PROVIDERS = ['fal', 'custom', 'codex', 'grok', 'local', 'seedream', 'gemini', 'replicate']
|
|
465
455
|
|
|
466
456
|
/** Field specs in display order. */
|
|
467
|
-
const booleanField = (
|
|
457
|
+
const booleanField = (field) => ({
|
|
458
|
+
field,
|
|
459
|
+
type: 'boolean',
|
|
460
|
+
format: (value) => (typeof value === 'boolean' ? String(value) : (value === 'true' || value === 'false' ? value : '')),
|
|
461
|
+
parse: (text) => {
|
|
462
|
+
if (text === '') return { kind: 'clear' }
|
|
463
|
+
if (text === 'true') return { kind: 'set', value: true }
|
|
464
|
+
if (text === 'false') return { kind: 'set', value: false }
|
|
465
|
+
return void 0
|
|
466
|
+
},
|
|
467
|
+
})
|
|
468
468
|
const STYLE_PRESET_OPTIONS = ['', 'cinematic', 'anime', 'digital_art', 'photographic', 'fantasy', 'isometric', 'cyberpunk', 'watercolor', 'origami', 'oil_painting', 'pixel_art', 'logo']
|
|
469
469
|
|
|
470
470
|
const FIELDS = [
|
|
@@ -511,7 +511,6 @@ window.__ModuleLoader__.load({
|
|
|
511
511
|
{ field: 'deliverAs', spec: selectField('deliverAs', DELIVERY_MODES), kind: 'select', options: DELIVERY_MODES, labelKey: 'f.deliverAs', hintKey: 'f.deliverAsHint' },
|
|
512
512
|
{ field: 'outputDir', spec: textField('outputDir'), kind: 'text', labelKey: 'f.outputDir', hintKey: 'f.outputDirHint', placeholderKey: 'p.outputDir' },
|
|
513
513
|
{ field: 'cacheTtlDays', spec: numberField('cacheTtlDays'), kind: 'number', labelKey: 'f.cacheTtlDays', hintKey: 'f.cacheTtlDaysHint', placeholderKey: 'p.cacheTtlDays' },
|
|
514
|
-
{ field: 'maxHistoryEntries', spec: numberField('maxHistoryEntries'), kind: 'number', labelKey: 'f.maxHistoryEntries', hintKey: 'f.maxHistoryEntriesHint', placeholderKey: 'p.maxHistoryEntries' },
|
|
515
514
|
]
|
|
516
515
|
|
|
517
516
|
function Field(props) {
|
|
@@ -539,66 +538,11 @@ window.__ModuleLoader__.load({
|
|
|
539
538
|
return react_jsx_runtime.jsx(ValueField, { ...base, numeric: entry.kind === 'number', placeholder: entry.placeholderKey ? t(entry.placeholderKey) : '' })
|
|
540
539
|
}
|
|
541
540
|
|
|
542
|
-
/** Render the plugin settings card. */
|
|
543
|
-
/** Галерея истории генераций: тянет /history и рендерит миниатюры. */
|
|
544
|
-
function HistoryGallery(props) {
|
|
545
|
-
const [entries, setEntries] = react.useState([])
|
|
546
|
-
const [loading, setLoading] = react.useState(true)
|
|
547
|
-
const [filter, setFilter] = react.useState('')
|
|
548
|
-
react.useEffect(() => {
|
|
549
|
-
let cancelled = false
|
|
550
|
-
fetch('/dsh-image-gen/history')
|
|
551
|
-
.then((r) => r.json())
|
|
552
|
-
.then((data) => { if (!cancelled) { setEntries(Array.isArray(data) ? data : []); setLoading(false) } })
|
|
553
|
-
.catch(() => { if (!cancelled) setLoading(false) })
|
|
554
|
-
return () => { cancelled = true }
|
|
555
|
-
}, [])
|
|
556
|
-
const t = props.t
|
|
557
|
-
if (loading) return react_jsx_runtime.jsx('p', { className: cssDefault.galleryEmpty, children: t('history.loading') })
|
|
558
|
-
if (!entries.length) return react_jsx_runtime.jsx('p', { className: cssDefault.galleryEmpty, children: t('history.empty') })
|
|
559
|
-
const providers = [...new Set(entries.map((e) => e.provider).filter(Boolean))]
|
|
560
|
-
const filtered = filter ? entries.filter((e) => e.provider === filter) : entries
|
|
561
|
-
return react_jsx_runtime.jsxs('div', {
|
|
562
|
-
className: cssDefault.gallery,
|
|
563
|
-
children: [
|
|
564
|
-
react_jsx_runtime.jsx('select', {
|
|
565
|
-
className: cssDefault.select,
|
|
566
|
-
value: filter,
|
|
567
|
-
onChange: (e) => setFilter(e.target.value),
|
|
568
|
-
children: [
|
|
569
|
-
react_jsx_runtime.jsx('option', { value: '', children: t('history.all') }),
|
|
570
|
-
providers.map((p) => react_jsx_runtime.jsx('option', { value: p, children: p }, p)),
|
|
571
|
-
],
|
|
572
|
-
}),
|
|
573
|
-
filtered.map((e) =>
|
|
574
|
-
react_jsx_runtime.jsxs('a', {
|
|
575
|
-
className: cssDefault.galleryItem,
|
|
576
|
-
key: e.path,
|
|
577
|
-
href: e.thumbnailUrl || '#',
|
|
578
|
-
target: '_blank',
|
|
579
|
-
rel: 'noreferrer',
|
|
580
|
-
children: [
|
|
581
|
-
e.thumbnailUrl ? react_jsx_runtime.jsx('img', { className: cssDefault.galleryImg, src: e.thumbnailUrl, alt: e.prompt || '', loading: 'lazy' }) : null,
|
|
582
|
-
react_jsx_runtime.jsx('div', { className: cssDefault.galleryMeta, children: `${e.provider || ''} · ${e.size || ''}` }),
|
|
583
|
-
e.seed !== undefined ? react_jsx_runtime.jsx('button', {
|
|
584
|
-
type: 'button',
|
|
585
|
-
className: 'fal-repeat',
|
|
586
|
-
onClick: (ev) => {
|
|
587
|
-
ev.preventDefault()
|
|
588
|
-
ev.stopPropagation()
|
|
589
|
-
try { navigator.clipboard.writeText(String(e.seed)) } catch (err) { /* нет доступа к буферу */ }
|
|
590
|
-
},
|
|
591
|
-
}, `seed ${e.seed}`) : null,
|
|
592
|
-
],
|
|
593
|
-
}),
|
|
594
|
-
),
|
|
595
|
-
],
|
|
596
|
-
})
|
|
597
|
-
}
|
|
598
|
-
|
|
599
541
|
function FalSettingsCard(props) {
|
|
600
|
-
const
|
|
601
|
-
const state = props.useFalSettingsCard
|
|
542
|
+
const t = props.t || ((k) => k)
|
|
543
|
+
const state = (typeof props.useFalSettingsCard === 'function'
|
|
544
|
+
? props.useFalSettingsCard((snapshot) => snapshot)
|
|
545
|
+
: null) || props.state || { available: true, writable: true, provider: { text: 'fal' } }
|
|
602
546
|
const disabled = !state.writable
|
|
603
547
|
const currentProvider = (state.provider && state.provider.text) || 'fal'
|
|
604
548
|
const visibleFields = FIELDS.filter((entry) => !entry.when || entry.when.includes(currentProvider))
|
|
@@ -616,7 +560,7 @@ window.__ModuleLoader__.load({
|
|
|
616
560
|
onSave: props.save,
|
|
617
561
|
onDiscard: props.discard,
|
|
618
562
|
children: [
|
|
619
|
-
react_jsx_runtime.jsx('p', { className: cssDefault.hint, children: t('settings.credentialHint') }),
|
|
563
|
+
react_jsx_runtime.jsx('p', { className: cssDefault.hint, key: 'credHint', children: t('settings.credentialHint') }),
|
|
620
564
|
visibleFields.map((entry) =>
|
|
621
565
|
react_jsx_runtime.jsx(
|
|
622
566
|
Field,
|
|
@@ -625,15 +569,12 @@ window.__ModuleLoader__.load({
|
|
|
625
569
|
state: state[entry.field] ?? { text: '', overridden: false, invalid: false },
|
|
626
570
|
fieldProps,
|
|
627
571
|
t,
|
|
628
|
-
onEdit: (text) => props.edit(entry.field, text),
|
|
629
|
-
onReset: () => props.resetField(entry.field),
|
|
572
|
+
onEdit: (text) => props.edit && props.edit(entry.field, text),
|
|
573
|
+
onReset: () => props.resetField && props.resetField(entry.field),
|
|
630
574
|
},
|
|
631
575
|
entry.field,
|
|
632
576
|
),
|
|
633
577
|
),
|
|
634
|
-
react_jsx_runtime.jsx('div', { className: cssDefault.sep, key: 'hsep' }),
|
|
635
|
-
react_jsx_runtime.jsx('p', { className: cssDefault.hint, key: 'hlabel', children: t('history.title') }),
|
|
636
|
-
react_jsx_runtime.jsx(HistoryGallery, { t, key: 'history' }),
|
|
637
578
|
],
|
|
638
579
|
})
|
|
639
580
|
}
|
|
@@ -680,6 +621,53 @@ window.__ModuleLoader__.load({
|
|
|
680
621
|
'settings.saving': 'Saving…',
|
|
681
622
|
'settings.saveFailed': 'Save failed',
|
|
682
623
|
'f.inherit': 'Inherit (default)',
|
|
624
|
+
'f.enabled': 'Enabled',
|
|
625
|
+
'f.enabledHint': 'Master switch: enable or disable the generate_image tool.',
|
|
626
|
+
'f.needFal': 'requires FAL API key',
|
|
627
|
+
'f.needCustom': 'requires custom endpoint URL',
|
|
628
|
+
'f.needCodex': 'uses Codex subscription session',
|
|
629
|
+
'f.needGrok': 'uses Grok subscription session',
|
|
630
|
+
'f.needLocal': 'connects to local ComfyUI/A1111',
|
|
631
|
+
'f.needSeedream': 'requires SeaDream API key',
|
|
632
|
+
'f.needGemini': 'requires Gemini API key',
|
|
633
|
+
'f.needReplicate': 'requires Replicate API token',
|
|
634
|
+
'f.replicateModel': 'Model (Replicate)',
|
|
635
|
+
'f.replicateModelHint': 'Replicate model identifier, e.g. black-forest-labs/flux-schnell.',
|
|
636
|
+
'f.replicateKeyEnv': 'API key reference (Replicate)',
|
|
637
|
+
'f.replicateKeyEnvHint': 'Credential reference / env var holding the Replicate API token.',
|
|
638
|
+
'p.replicateModel': 'Example: black-forest-labs/flux-schnell',
|
|
639
|
+
'p.replicateKeyEnv': 'Example: REPLICATE_API_TOKEN',
|
|
640
|
+
'f.seedreamModel': 'Model (SeaDream)',
|
|
641
|
+
'f.seedreamModelHint': 'SeaDream model identifier.',
|
|
642
|
+
'f.seedreamKeyEnv': 'API key reference (SeaDream)',
|
|
643
|
+
'f.seedreamKeyEnvHint': 'Credential reference / env var holding the SeaDream API key.',
|
|
644
|
+
'f.seedreamBaseURL': 'Base URL (SeaDream)',
|
|
645
|
+
'f.seedreamBaseURLHint': 'SeaDream endpoint URL (Volcengine Ark API).',
|
|
646
|
+
'p.seedreamModel': 'Example: Doubao-SeaDream-3.0',
|
|
647
|
+
'p.seedreamKeyEnv': 'Example: SEADREAM_API_KEY',
|
|
648
|
+
'p.seedreamBaseURL': 'Example: https://ark.cn-beijing.volces.com/api/v3',
|
|
649
|
+
'f.geminiModel': 'Model (Gemini)',
|
|
650
|
+
'f.geminiModelHint': 'Gemini Imagen model identifier.',
|
|
651
|
+
'f.geminiKeyEnv': 'API key reference (Gemini)',
|
|
652
|
+
'f.geminiKeyEnvHint': 'Credential reference / env var holding the Gemini API key.',
|
|
653
|
+
'p.geminiModel': 'Example: imagen-3.0-generate-002',
|
|
654
|
+
'p.geminiKeyEnv': 'Example: GEMINI_API_KEY',
|
|
655
|
+
'f.localComfyUrl': 'ComfyUI URL',
|
|
656
|
+
'f.localComfyUrlHint': 'Base URL of local ComfyUI server.',
|
|
657
|
+
'p.localComfyUrl': 'Example: http://127.0.0.1:8188',
|
|
658
|
+
'f.localA1111Url': 'Automatic1111 URL',
|
|
659
|
+
'f.localA1111UrlHint': 'Base URL of local Automatic1111 / SD WebUI.',
|
|
660
|
+
'p.localA1111Url': 'Example: http://127.0.0.1:7860',
|
|
661
|
+
'f.stylePreset': 'Default style preset',
|
|
662
|
+
'f.stylePresetHint': 'Style preset automatically applied if the tool call does not specify one.',
|
|
663
|
+
'f.enableLlmEnhancer': 'LLM prompt enhancer',
|
|
664
|
+
'f.enableLlmEnhancerHint': 'Automatically refine and expand prompts before generation using session LLM.',
|
|
665
|
+
'f.cacheTtlDays': 'Cache retention (days)',
|
|
666
|
+
'f.cacheTtlDaysHint': 'How many days downloaded images are stored in cache before cleanup.',
|
|
667
|
+
'p.cacheTtlDays': 'Example: 7',
|
|
668
|
+
'f.maxHistoryEntries': 'Max history entries',
|
|
669
|
+
'f.maxHistoryEntriesHint': 'Maximum number of items shown in generation history gallery.',
|
|
670
|
+
'p.maxHistoryEntries': 'Example: 50',
|
|
683
671
|
'f.provider': 'Provider',
|
|
684
672
|
'f.providerHint': 'fal — the FAL queue configured below. custom — any OpenAI-compatible API, configured further down. '
|
|
685
673
|
+ 'codex and grok — through a subscription you are logged into, no key needed here.',
|
|
@@ -743,6 +731,53 @@ window.__ModuleLoader__.load({
|
|
|
743
731
|
'settings.saving': 'Сохранение…',
|
|
744
732
|
'settings.saveFailed': 'Не удалось сохранить',
|
|
745
733
|
'f.inherit': 'Унаследовать (по умолчанию)',
|
|
734
|
+
'f.enabled': 'Включено',
|
|
735
|
+
'f.enabledHint': 'Главный переключатель: включить или отключить инструмент generate_image.',
|
|
736
|
+
'f.needFal': 'требуется ключ API FAL',
|
|
737
|
+
'f.needCustom': 'требуется базовый URL API',
|
|
738
|
+
'f.needCodex': 'использует сессию подписки Codex',
|
|
739
|
+
'f.needGrok': 'использует сессию подписки Grok',
|
|
740
|
+
'f.needLocal': 'подключается к локальному ComfyUI/A1111',
|
|
741
|
+
'f.needSeedream': 'требуется ключ API SeaDream',
|
|
742
|
+
'f.needGemini': 'требуется ключ API Gemini',
|
|
743
|
+
'f.needReplicate': 'требуется токен API Replicate',
|
|
744
|
+
'f.replicateModel': 'Модель (Replicate)',
|
|
745
|
+
'f.replicateModelHint': 'Идентификатор модели Replicate, например black-forest-labs/flux-schnell.',
|
|
746
|
+
'f.replicateKeyEnv': 'Ссылка на ключ (Replicate)',
|
|
747
|
+
'f.replicateKeyEnvHint': 'Имя credential-ссылки / переменной окружения с токеном Replicate.',
|
|
748
|
+
'p.replicateModel': 'Пример: black-forest-labs/flux-schnell',
|
|
749
|
+
'p.replicateKeyEnv': 'Пример: REPLICATE_API_TOKEN',
|
|
750
|
+
'f.seedreamModel': 'Модель (SeaDream)',
|
|
751
|
+
'f.seedreamModelHint': 'Идентификатор модели SeaDream.',
|
|
752
|
+
'f.seedreamKeyEnv': 'Ссылка на ключ (SeaDream)',
|
|
753
|
+
'f.seedreamKeyEnvHint': 'Имя credential-ссылки / переменной окружения с ключом SeaDream.',
|
|
754
|
+
'f.seedreamBaseURL': 'Базовый URL (SeaDream)',
|
|
755
|
+
'f.seedreamBaseURLHint': 'Базовый URL API SeaDream (Volcengine Ark).',
|
|
756
|
+
'p.seedreamModel': 'Пример: Doubao-SeaDream-3.0',
|
|
757
|
+
'p.seedreamKeyEnv': 'Пример: SEADREAM_API_KEY',
|
|
758
|
+
'p.seedreamBaseURL': 'Пример: https://ark.cn-beijing.volces.com/api/v3',
|
|
759
|
+
'f.geminiModel': 'Модель (Gemini)',
|
|
760
|
+
'f.geminiModelHint': 'Идентификатор модели Gemini Imagen.',
|
|
761
|
+
'f.geminiKeyEnv': 'Ссылка на ключ (Gemini)',
|
|
762
|
+
'f.geminiKeyEnvHint': 'Имя credential-ссылки / переменной окружения с ключом Gemini.',
|
|
763
|
+
'p.geminiModel': 'Пример: imagen-3.0-generate-002',
|
|
764
|
+
'p.geminiKeyEnv': 'Пример: GEMINI_API_KEY',
|
|
765
|
+
'f.localComfyUrl': 'URL ComfyUI',
|
|
766
|
+
'f.localComfyUrlHint': 'Базовый URL локального сервера ComfyUI.',
|
|
767
|
+
'p.localComfyUrl': 'Пример: http://127.0.0.1:8188',
|
|
768
|
+
'f.localA1111Url': 'URL Automatic1111',
|
|
769
|
+
'f.localA1111UrlHint': 'Базовый URL локального SD WebUI / Automatic1111.',
|
|
770
|
+
'p.localA1111Url': 'Пример: http://127.0.0.1:7860',
|
|
771
|
+
'f.stylePreset': 'Стилевой пресет по умолчанию',
|
|
772
|
+
'f.stylePresetHint': 'Пресет стилизации, применяемый если инструмент вызван без указания стиля.',
|
|
773
|
+
'f.enableLlmEnhancer': 'Улучшение промпта через LLM',
|
|
774
|
+
'f.enableLlmEnhancerHint': 'Автоматически детализировать и улучшать промпты через чат-модель перед генерацией.',
|
|
775
|
+
'f.cacheTtlDays': 'Срок хранения кэша (дней)',
|
|
776
|
+
'f.cacheTtlDaysHint': 'Сколько дней скачанные картинки хранятся в кэше до очистки.',
|
|
777
|
+
'p.cacheTtlDays': 'Пример: 7',
|
|
778
|
+
'f.maxHistoryEntries': 'Максимум записей в истории',
|
|
779
|
+
'f.maxHistoryEntriesHint': 'Максимальное количество картинок в галерее истории генераций.',
|
|
780
|
+
'p.maxHistoryEntries': 'Пример: 50',
|
|
746
781
|
'f.provider': 'Провайдер',
|
|
747
782
|
'f.providerHint': 'fal — очередь FAL, настроенная ниже. custom — любой OpenAI-совместимый API, настраивается дальше. '
|
|
748
783
|
+ 'codex и grok — через подписку, в которую вы вошли; ключ здесь не нужен.',
|
|
@@ -1226,36 +1261,40 @@ function FalImageCard(props) {
|
|
|
1226
1261
|
// Запасной путь: слот объявлен пакетом настроек ядра. Если в сборке его
|
|
1227
1262
|
// нет, регистрация бросает — тогда остаётся прежний раздел в боковом
|
|
1228
1263
|
// списке, чтобы настройки не пропали.
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
}
|
|
1244
|
-
if (!placedInPluginsTab) {
|
|
1245
|
-
ctx.slots.inject('settings.section', () =>
|
|
1246
|
-
ctx.slots.register(
|
|
1247
|
-
{
|
|
1248
|
-
name: 'settings.section',
|
|
1249
|
-
id: '@goodandready/dsh-image-gen',
|
|
1250
|
-
order: 34,
|
|
1251
|
-
locale: NS,
|
|
1252
|
-
label: () => t('settings.navLabel'),
|
|
1253
|
-
inject: () => cardOnce().inject(),
|
|
1254
|
-
},
|
|
1255
|
-
FalSettingsCard,
|
|
1256
|
-
),
|
|
1257
|
-
)
|
|
1264
|
+
function registerFirst(ctx, candidates, component) {
|
|
1265
|
+
if (!ctx || !ctx.slots) return undefined
|
|
1266
|
+
for (const entry of candidates) {
|
|
1267
|
+
try {
|
|
1268
|
+
if (typeof ctx.slots?.has === 'function' && !ctx.slots.has(entry.name)) {
|
|
1269
|
+
continue
|
|
1270
|
+
}
|
|
1271
|
+
let ok = false
|
|
1272
|
+
ctx.slots.inject(entry.name, () => {
|
|
1273
|
+
ctx.slots.register(entry, component)
|
|
1274
|
+
ok = true
|
|
1275
|
+
})
|
|
1276
|
+
if (ok) return entry.name
|
|
1277
|
+
} catch {}
|
|
1258
1278
|
}
|
|
1279
|
+
return undefined
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
registerFirst(ctx, [
|
|
1283
|
+
{
|
|
1284
|
+
name: 'settings.plugin.item',
|
|
1285
|
+
key: SETTINGS_NS,
|
|
1286
|
+
locale: NS,
|
|
1287
|
+
inject: () => cardOnce().inject(),
|
|
1288
|
+
},
|
|
1289
|
+
{
|
|
1290
|
+
name: 'settings.section',
|
|
1291
|
+
id: '@goodandready/dsh-image-gen',
|
|
1292
|
+
order: 34,
|
|
1293
|
+
locale: NS,
|
|
1294
|
+
label: () => t('settings.navLabel'),
|
|
1295
|
+
inject: () => cardOnce().inject(),
|
|
1296
|
+
},
|
|
1297
|
+
], FalSettingsCard)
|
|
1259
1298
|
}
|
|
1260
1299
|
exports.apply = apply
|
|
1261
1300
|
exports.inject = inject
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-image-gen",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.10",
|
|
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",
|