@goodandready/dsh-image-gen 0.10.21 → 0.10.23
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 +12 -0
- package/README.ru.md +12 -0
- package/README.zh.md +12 -0
- package/lib/client.js +177 -192
- package/lib/index.js +37 -32
- package/lib/providers.js +96 -50
- package/lib/resolve-image.js +1 -1
- package/lib/tools/generation.js +9 -9
- package/lib/updater.js +338 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,18 @@
|
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
+
## 🚀 Updates v0.10.23: In-App Auto-Updater, Settings Synchronization, Active Probes & Language Purity (#232)
|
|
45
|
+
* **One-Click In-App Auto-Updater**: Direct 1-click update support inside the plugin Settings Card (`UpdaterSection`) backed by `/api/dsh-image-gen/update`. Fetches the npm registry for release manifests, verifies semver differences, and securely triggers `dsh plugin add @goodandready/dsh-image-gen@latest` restricted to loopback and private LAN connections.
|
|
46
|
+
* **1:1 Settings Synchronization**: Fully synchronized host `Config` schema in `lib/index.js` with client UI fields (`lib/client.js`), exposing `autoEnhancePrompt` and `defaultStylePreset` under the `✨ Enhancer` tab.
|
|
47
|
+
* **Active Diagnostic Probes**: Added real HTTP network probes in `testProviderConnection` for Replicate (`/v1/models`), Google Gemini (`/v1beta/models`), and ByteDance Seedream with timeout protection and live roundtrip latency tracking.
|
|
48
|
+
* **Strict Multi-Language Compliance**: Pure standard `en` and `zh` localization bundles embedded in core package; modularized Russian language support via `goodandready/dsh-russian-lang` per DSH plugin guidelines. Exactly 0 Cyrillic characters in product code (`lib/`).
|
|
49
|
+
* **WAI-ARIA Accessibility Hardening**: Enhanced tab navigation and input form validation with `role="tablist"`, `role="tab"`, `aria-selected`, `aria-controls`, `role="tabpanel"`, `aria-describedby`, and `role="alert"`.
|
|
50
|
+
|
|
51
|
+
## 🚀 Updates v0.10.22: Referential Stability & React Error #185 Infinite Loop Fix (#230)
|
|
52
|
+
* **Settings Card Referential Stability**: Resolved React Error #185 (`Maximum update depth exceeded`) in `FalSettingsCardController` and `CardForm.prototype.bind`. Store snapshots are referentially cached during render cycles (`Object.is(prev, next) === true`), completely preventing infinite re-render loops in React 18 / `useSyncExternalStore`.
|
|
53
|
+
* **Deep DSH Store Integration**: Added seamless runtime integration with `@deepseek-ai/dsh-client-store` (`runtime.createSnapshotStore`) paired with a robust standalone snapshot caching fallback.
|
|
54
|
+
* **Automated Regression Test Suite**: Added dedicated referential identity test in `test/client-syntax.test.mjs` verifying snapshot immutability across repeated reads, single-notification publish triggers, and clean listener lifecycle.
|
|
55
|
+
|
|
44
56
|
## 🚀 Updates v0.10.21: Variations Workbench, Smart Aspect Ratio Crop & Brand Asset Pack (#228)
|
|
45
57
|
* **Variations & Style Remix Workbench**: Interactive visual drawer embedded directly in `FalImageCard` and Gallery. Fine-tune variations with a continuous creativity / denoising strength slider (0.05 to 0.95), preset quick buttons ("Subtle 0.25", "Creative 0.65"), and prompt modifier guidance.
|
|
46
58
|
* **Intelligent Aspect-Ratio Canvas Cropper & Resizer (`smart_crop_image`)**: Instant lossless aspect ratio framing for social and responsive surfaces (`1:1`, `16:9`, `9:16`, `4:3`, `3:2`, `2:3`) supporting focal heuristics (`auto_focus`, `center`, `rule_of_thirds`, `letterbox`) via zero-dependency pure Node.js SVG vector raster wrapper.
|
package/README.ru.md
CHANGED
|
@@ -34,6 +34,18 @@
|
|
|
34
34
|
</div>
|
|
35
35
|
|
|
36
36
|
---
|
|
37
|
+
## 🚀 Обновления v0.10.23: Встроенное автообновление, синхронизация настроек, диагностические пробы и чистота языка (#232)
|
|
38
|
+
* **Встроенное обновление в 1 клик**: Прямая проверка и обновление плагина прямо из карточки настроек (`UpdaterSection`) через эндпоинт `/api/dsh-image-gen/update`. Опрашивает реестр npm, сравнивает semver-версии и безопасно запускает установку через `dsh plugin add` с защитой по loopback и доверенной локальной сети (RFC 1918).
|
|
39
|
+
* **Синхронизация настроек 1:1**: Полное выравнивание схемы хоста `Config` в `lib/index.js` и полей UI `FIELDS` в `lib/client.js` — во вкладку «✨ Промпт и стили» добавлены тумблеры `autoEnhancePrompt` и выпадающий список `defaultStylePreset`.
|
|
40
|
+
* **Активные диагностические пробы**: Добавлены реальные сетевые проверки в `testProviderConnection` для Replicate (`/v1/models`), Google Gemini (`/v1beta/models`) и ByteDance Seedream с защитой по тайм-ауту и замером сетевой задержки.
|
|
41
|
+
* **Строгое соответствие стандарту мультиязычности**: Чистые стандартные словари `en` и `zh` в ядре плагина; русские переводы модульно вынесены в `goodandready/dsh-russian-lang` в соответствии с правилами DSH. Ровно 0 символов кириллицы в исходном коде (`lib/`).
|
|
42
|
+
* **Доступность интерфейса (WAI-ARIA A11y)**: Реализована разметка вкладок и валидации форм с атрибутами `role="tablist"`, `role="tab"`, `aria-selected`, `aria-controls`, `role="tabpanel"`, `aria-describedby` и `role="alert"`.
|
|
43
|
+
|
|
44
|
+
## 🚀 Обновления v0.10.22: Стабилизация состояния карточки настроек и устранение React Error #185 (#230)
|
|
45
|
+
* **Референциальная стабильность карточки настроек**: Устранена критическая ошибка React #185 (`Maximum update depth exceeded`) в `FalSettingsCardController` и `CardForm.prototype.bind`. Снимки состояния кэшируются по ссылке (`Object.is(prev, next) === true`) во время циклов рендера, полностью предотвращая бесконечные циклы перерисовки в React 18 / `useSyncExternalStore`.
|
|
46
|
+
* **Глубокая интеграция со стором DSH**: Добавлена бесшовная поддержка официального `@deepseek-ai/dsh-client-store` (`runtime.createSnapshotStore`) с автономным отказоустойчивым кэширующим fallback-режимом.
|
|
47
|
+
* **Автоматические регрессионные тесты**: Добавлен специализированный тест стабильности ссылок в `test/client-syntax.test.mjs`, контролирующий идентичность снимков при последовательных чтениях, атомарность уведомлений и корректную отписку.
|
|
48
|
+
|
|
37
49
|
## 🚀 Обновления v0.10.21: Верстак вариаций, умный кроппер и экспорт бренд-ассетов (#228)
|
|
38
50
|
* **Интерактивный верстак вариаций и ремиксов (Remix Workbench)**: Встроенная панель в `FalImageCard` и галерее генераций. Настройка силы вариаций ползунком креативности (0.05–0.95), быстрые пресеты («Тонкие правки 0.25», «Креатив 0.65») и текстовое до-руливание стилем.
|
|
39
51
|
* **Умное кадрирование под стандарты пропорций (`smart_crop_image`)**: Мгновенный пересчет и кадрирование под соцсети и баннеры (`1:1`, `16:9`, `9:16`, `4:3`, `3:2`, `2:3`) с режимами центрирования, третей (`rule_of_thirds`), умного фокуса и рамки (`letterbox`) на чистом SVG без внешних бинарников.
|
package/README.zh.md
CHANGED
|
@@ -47,6 +47,18 @@
|
|
|
47
47
|
|
|
48
48
|
---
|
|
49
49
|
|
|
50
|
+
## 🚀 更新 v0.10.23: 应用内一键更新、设置同步、真实探针与语言规范 (#232)
|
|
51
|
+
* **应用内一键自动更新**: 设置卡片内新增「插件更新」模块(`UpdaterSection`),配合 `/api/dsh-image-gen/update` 接口。自动查询 npm 官方注册表,对比语义化版本号,并在本地回环或私有局域网安全授权下执行 `dsh plugin add @goodandready/dsh-image-gen@latest`。
|
|
52
|
+
* **1:1 核心配置与界面设置同步**: 严格对齐 `lib/index.js` 宿主 `Config` 与 `lib/client.js` 界面字段,在「✨ 提示词增强」标签页下完整呈现 `autoEnhancePrompt`(智能自动增强提示词)与 `defaultStylePreset`(默认风格预设)。
|
|
53
|
+
* **真实网络诊断探针**: 在 `testProviderConnection` 中为 Replicate (`/v1/models`)、Google Gemini (`/v1beta/models`) 及字节跳动 Seedream 增加带超时保护的真实 HTTP 网络探测与延迟往返测速。
|
|
54
|
+
* **严格多语言纯度标准**: 核心代码完全遵照 DSH 插件规范,内置纯净完整的 `en` 和 `zh` 词典;俄语支持通过 `goodandready/dsh-russian-lang` 独立注册。`lib/` 源码中完全清理非拉丁字符。
|
|
55
|
+
* **WAI-ARIA 无障碍访问支持**: 为标签页切换与表单错误提示加入 `role="tablist"`, `role="tab"`, `aria-selected`, `aria-controls`, `role="tabpanel"`, `aria-describedby` 和 `role="alert"`。
|
|
56
|
+
|
|
57
|
+
## 🚀 更新 v0.10.22: 设置卡片状态引用稳定性与修复 React Error #185 无限循环 (#230)
|
|
58
|
+
* **设置卡片状态引用稳定性**: 修复了 `FalSettingsCardController` 和 `CardForm.prototype.bind` 中引发的 React Error #185(`Maximum update depth exceeded`)。快照在渲染周期内进行引用缓存(`Object.is(prev, next) === true`),彻底杜绝 React 18 / `useSyncExternalStore` 的无限重新渲染死循环。
|
|
59
|
+
* **深度 DSH 运行时集成**: 无缝集成官方 `@deepseek-ai/dsh-client-store`(`runtime.createSnapshotStore`),并提供零依赖的高性能独立快照缓存兜底。
|
|
60
|
+
* **自动化回归测试集**: 在 `test/client-syntax.test.mjs` 中引入针对引用一致性的专项测试,严密校验多次连续读取的一致性、单次发布通知机制与监听器注销完整性。
|
|
61
|
+
|
|
50
62
|
## 🚀 更新 v0.10.21: 变体工作台、智能比例裁切与品牌资源包导出 (#228)
|
|
51
63
|
* **交互式变体与风格重混工作台 (Remix Workbench)**: 直接集成在 `FalImageCard` 和图库中的交互抽屉。支持连续创意度/去噪强度滑块 (0.05 到 0.95)、预设快捷按钮(“微调 0.25”、“强创意 0.65”)及提示词引导。
|
|
52
64
|
* **智能比例无损画布裁切器 (`smart_crop_image`)**: 快速裁切适配各大社交与设计标准比例 (`1:1`, `16:9`, `9:16`, `4:3`, `3:2`, `2:3`),支持自动对焦、三分法构图 (`rule_of_thirds`) 与黑边留白 (`letterbox`)。
|
package/lib/client.js
CHANGED
|
@@ -17,12 +17,20 @@ window.__ModuleLoader__.load({
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
let runtime = null
|
|
21
|
+
for (const id of ['@deepseek-ai/dsh-client-store', '@deepseek-ai/dsh-client-runtime/client']) {
|
|
22
|
+
try {
|
|
23
|
+
runtime = require(id)
|
|
24
|
+
if (runtime && typeof runtime.createSnapshotStore === 'function') break
|
|
25
|
+
} catch (_) {}
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
const NS = 'dsh-image-gen'
|
|
21
29
|
const SETTINGS_NS = 'dsh-image-gen'
|
|
22
30
|
const TITLE = 'Image Studio'
|
|
23
31
|
const SUBTITLE = 'Multi-provider AI image generation, editing, upscale & vectorization.'
|
|
24
32
|
|
|
25
|
-
//
|
|
33
|
+
// DSH UI primitives chevron icon with fallback SVG.
|
|
26
34
|
let ChevronIcon = null
|
|
27
35
|
try {
|
|
28
36
|
const primitives = require('@deepseek-ai/dsh-client-ui-primitives')
|
|
@@ -266,6 +274,8 @@ window.__ModuleLoader__.load({
|
|
|
266
274
|
{ field: 'subscriptionQuality', spec: selectField('subscriptionQuality', ['', 'low', 'medium', 'high']), kind: 'select', options: ['', 'low', 'medium', 'high'], labelKey: 'f.subscriptionQuality', hintKey: 'f.subscriptionQualityHint', when: ['codex', 'grok'], tab: 'provider' },
|
|
267
275
|
|
|
268
276
|
// Enhancer & Style
|
|
277
|
+
{ field: 'autoEnhancePrompt', spec: booleanField('autoEnhancePrompt'), kind: 'select', options: ['true', 'false'], labelKey: 'f.autoEnhancePrompt', hintKey: 'f.autoEnhancePromptHint', tab: 'enhancer' },
|
|
278
|
+
{ field: 'defaultStylePreset', spec: selectField('defaultStylePreset', STYLE_PRESET_OPTIONS), kind: 'select', options: STYLE_PRESET_OPTIONS, labelKey: 'f.defaultStylePreset', hintKey: 'f.defaultStylePresetHint', tab: 'enhancer' },
|
|
269
279
|
{ field: 'enhancePrompt', spec: booleanField('enhancePrompt'), kind: 'select', options: ['true', 'false'], labelKey: 'f.enhancePrompt', hintKey: 'f.enhancePromptHint', tab: 'enhancer' },
|
|
270
280
|
{ field: 'enableLlmEnhancer', spec: booleanField('enableLlmEnhancer'), kind: 'select', options: ['true', 'false'], labelKey: 'f.enableLlmEnhancer', hintKey: 'f.enableLlmEnhancerHint', tab: 'enhancer' },
|
|
271
281
|
{ field: 'enhanceModel', spec: textField('enhanceModel'), kind: 'text', labelKey: 'f.enhanceModel', hintKey: 'f.enhanceModelHint', placeholderKey: 'p.enhanceModel', tab: 'enhancer' },
|
|
@@ -298,11 +308,22 @@ window.__ModuleLoader__.load({
|
|
|
298
308
|
}
|
|
299
309
|
}
|
|
300
310
|
bind(project) {
|
|
311
|
+
if (runtime && typeof runtime.createSnapshotStore === 'function') {
|
|
312
|
+
const store = runtime.createSnapshotStore(project())
|
|
313
|
+
this.listeners.add(() => store.set(project()))
|
|
314
|
+
return store
|
|
315
|
+
}
|
|
316
|
+
let cached = project()
|
|
317
|
+
const storeListeners = new Set()
|
|
318
|
+
this.listeners.add(() => {
|
|
319
|
+
cached = project()
|
|
320
|
+
for (const listener of storeListeners) listener()
|
|
321
|
+
})
|
|
301
322
|
return {
|
|
302
|
-
getSnapshot: () =>
|
|
323
|
+
getSnapshot: () => cached,
|
|
303
324
|
subscribe: (cb) => {
|
|
304
|
-
|
|
305
|
-
return () =>
|
|
325
|
+
storeListeners.add(cb)
|
|
326
|
+
return () => storeListeners.delete(cb)
|
|
306
327
|
},
|
|
307
328
|
}
|
|
308
329
|
}
|
|
@@ -494,16 +515,128 @@ window.__ModuleLoader__.load({
|
|
|
494
515
|
className: invalid ? 'ig-input ig-input-invalid' : 'ig-input',
|
|
495
516
|
type: 'text',
|
|
496
517
|
...(entry.kind === 'number' ? { inputMode: 'numeric' } : {}),
|
|
518
|
+
'aria-invalid': invalid ? true : undefined,
|
|
519
|
+
'aria-describedby': invalid ? id + '-err' : undefined,
|
|
497
520
|
value: state.text,
|
|
498
521
|
placeholder: entry.placeholderKey ? t(entry.placeholderKey) : '',
|
|
499
522
|
disabled,
|
|
500
523
|
onChange: (e) => onEdit(e.target.value),
|
|
501
524
|
}),
|
|
502
|
-
react.createElement('p', {
|
|
525
|
+
react.createElement('p', {
|
|
526
|
+
id: invalid ? id + '-err' : undefined,
|
|
527
|
+
role: invalid ? 'alert' : undefined,
|
|
528
|
+
className: invalid ? 'ig-field-err' : 'ig-field-hint',
|
|
529
|
+
}, invalid ? fieldProps.invalidLabel : hint)
|
|
503
530
|
)
|
|
504
531
|
}
|
|
505
532
|
|
|
506
533
|
|
|
534
|
+
|
|
535
|
+
// -------------------------------------------------------------- Updater Section
|
|
536
|
+
function UpdaterSection(props) {
|
|
537
|
+
const t = props.t || ((k) => k)
|
|
538
|
+
const [status, setStatus] = react.useState(null)
|
|
539
|
+
const [loading, setLoading] = react.useState(false)
|
|
540
|
+
const [updating, setUpdating] = react.useState(false)
|
|
541
|
+
const [msg, setMsg] = react.useState(null)
|
|
542
|
+
|
|
543
|
+
const checkUpdate = react.useCallback(async () => {
|
|
544
|
+
setLoading(true)
|
|
545
|
+
setMsg(null)
|
|
546
|
+
try {
|
|
547
|
+
const res = await fetch('/api/dsh-image-gen/update', {
|
|
548
|
+
headers: { accept: 'application/json' },
|
|
549
|
+
cache: 'no-store',
|
|
550
|
+
})
|
|
551
|
+
if (!res.ok) throw new Error('HTTP ' + res.status)
|
|
552
|
+
const data = await res.json()
|
|
553
|
+
setStatus(data)
|
|
554
|
+
} catch (e) {
|
|
555
|
+
setMsg({ ok: false, text: (t('updater.failed') || 'Update check failed: ') + (e?.message || String(e)) })
|
|
556
|
+
} finally {
|
|
557
|
+
setLoading(false)
|
|
558
|
+
}
|
|
559
|
+
}, [t])
|
|
560
|
+
|
|
561
|
+
const onUpdateNow = async () => {
|
|
562
|
+
setUpdating(true)
|
|
563
|
+
setMsg(null)
|
|
564
|
+
try {
|
|
565
|
+
const res = await fetch('/api/dsh-image-gen/update', {
|
|
566
|
+
method: 'POST',
|
|
567
|
+
headers: {
|
|
568
|
+
'x-dsh-plugin-update': '1',
|
|
569
|
+
'content-type': 'application/json',
|
|
570
|
+
},
|
|
571
|
+
})
|
|
572
|
+
const data = await res.json()
|
|
573
|
+
if (!res.ok) throw new Error(data?.error || 'HTTP ' + res.status)
|
|
574
|
+
setStatus(data)
|
|
575
|
+
setMsg({ ok: true, text: t('updater.success') || 'Plugin updated successfully! Restart DSH to apply.' })
|
|
576
|
+
} catch (e) {
|
|
577
|
+
setMsg({ ok: false, text: e?.message || String(e) })
|
|
578
|
+
} finally {
|
|
579
|
+
setUpdating(false)
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
react.useEffect(() => {
|
|
584
|
+
checkUpdate()
|
|
585
|
+
}, [checkUpdate])
|
|
586
|
+
|
|
587
|
+
const currentVer = status?.currentVersion || '0.10.22'
|
|
588
|
+
const latestVer = status?.latestVersion
|
|
589
|
+
const updateAvailable = Boolean(status?.updateAvailable && latestVer && latestVer !== currentVer)
|
|
590
|
+
|
|
591
|
+
return react.createElement(
|
|
592
|
+
'div',
|
|
593
|
+
{ className: 'ig-stat-box', style: { gap: '10px', marginTop: '12px' } },
|
|
594
|
+
react.createElement(
|
|
595
|
+
'div',
|
|
596
|
+
{ style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: '8px' } },
|
|
597
|
+
react.createElement(
|
|
598
|
+
'div',
|
|
599
|
+
{ style: { display: 'flex', alignItems: 'center', gap: '8px' } },
|
|
600
|
+
react.createElement('span', { style: { fontSize: '13px', fontWeight: 600, color: 'var(--dsw-alias-label-primary)' } }, '🔄 ' + t('updater.title')),
|
|
601
|
+
react.createElement('span', { className: 'ig-badge ' + (updateAvailable ? 'ig-badge-warn' : 'ig-badge-ok') },
|
|
602
|
+
updateAvailable ? 'v' + latestVer + ' available' : 'v' + currentVer + ' (' + t('updater.upToDate') + ')'
|
|
603
|
+
)
|
|
604
|
+
),
|
|
605
|
+
react.createElement(
|
|
606
|
+
'div',
|
|
607
|
+
{ style: { display: 'flex', gap: '8px' } },
|
|
608
|
+
updateAvailable
|
|
609
|
+
? react.createElement(
|
|
610
|
+
'button',
|
|
611
|
+
{
|
|
612
|
+
type: 'button',
|
|
613
|
+
className: 'ig-btn ig-btn-primary',
|
|
614
|
+
style: { padding: '4px 10px', fontSize: '12px' },
|
|
615
|
+
onClick: onUpdateNow,
|
|
616
|
+
disabled: updating || loading,
|
|
617
|
+
},
|
|
618
|
+
updating ? (t('updater.updating') || 'Updating…') : (t('updater.updateNow') || 'Update now').replace('{version}', latestVer)
|
|
619
|
+
)
|
|
620
|
+
: null,
|
|
621
|
+
react.createElement(
|
|
622
|
+
'button',
|
|
623
|
+
{
|
|
624
|
+
type: 'button',
|
|
625
|
+
className: 'ig-btn',
|
|
626
|
+
style: { padding: '4px 10px', fontSize: '12px' },
|
|
627
|
+
onClick: checkUpdate,
|
|
628
|
+
disabled: loading || updating,
|
|
629
|
+
},
|
|
630
|
+
loading ? (t('updater.checking') || 'Checking…') : (t('updater.check') || 'Check updates')
|
|
631
|
+
)
|
|
632
|
+
)
|
|
633
|
+
),
|
|
634
|
+
msg
|
|
635
|
+
? react.createElement('div', { className: msg.ok ? 'ig-alert-ok' : 'ig-alert-bad', style: { padding: '6px 10px', fontSize: '12px' } }, msg.text)
|
|
636
|
+
: null
|
|
637
|
+
)
|
|
638
|
+
}
|
|
639
|
+
|
|
507
640
|
// -------------------------------------------------------------- Diagnostics Panel
|
|
508
641
|
function DiagnosticsPanel(props) {
|
|
509
642
|
const t = props.t || ((k) => k)
|
|
@@ -1046,13 +1179,17 @@ window.__ModuleLoader__.load({
|
|
|
1046
1179
|
// Tab Navigation
|
|
1047
1180
|
react.createElement(
|
|
1048
1181
|
'div',
|
|
1049
|
-
{ className: 'ig-tabs' },
|
|
1182
|
+
{ className: 'ig-tabs', role: 'tablist', 'aria-label': 'Settings Sections' },
|
|
1050
1183
|
tabs.map((tab) =>
|
|
1051
1184
|
react.createElement(
|
|
1052
1185
|
'button',
|
|
1053
1186
|
{
|
|
1054
1187
|
key: tab.id,
|
|
1188
|
+
id: 'tab-btn-' + tab.id,
|
|
1055
1189
|
type: 'button',
|
|
1190
|
+
role: 'tab',
|
|
1191
|
+
'aria-selected': activeTab === tab.id,
|
|
1192
|
+
'aria-controls': 'tab-panel-' + tab.id,
|
|
1056
1193
|
className: activeTab === tab.id ? 'ig-tab-btn ig-tab-btn-active' : 'ig-tab-btn',
|
|
1057
1194
|
onClick: () => setActiveTab(tab.id),
|
|
1058
1195
|
},
|
|
@@ -1063,7 +1200,13 @@ window.__ModuleLoader__.load({
|
|
|
1063
1200
|
// Active Tab Fields
|
|
1064
1201
|
react.createElement(
|
|
1065
1202
|
'div',
|
|
1066
|
-
{
|
|
1203
|
+
{
|
|
1204
|
+
id: 'tab-panel-' + activeTab,
|
|
1205
|
+
role: 'tabpanel',
|
|
1206
|
+
'aria-labelledby': 'tab-btn-' + activeTab,
|
|
1207
|
+
style: { display: 'flex', flexDirection: 'column', gap: '8px' },
|
|
1208
|
+
},
|
|
1209
|
+
activeTab === 'general' ? react.createElement(UpdaterSection, { t }) : null,
|
|
1067
1210
|
currentTabFields.map((entry) =>
|
|
1068
1211
|
react.createElement(Field, {
|
|
1069
1212
|
key: entry.field,
|
|
@@ -1488,6 +1631,23 @@ window.__ModuleLoader__.load({
|
|
|
1488
1631
|
'f.subscriptionQuality': 'Subscription Quality',
|
|
1489
1632
|
'f.subscriptionQualityHint': 'Target quality profile when using Codex or Grok subscriptions.',
|
|
1490
1633
|
|
|
1634
|
+
'f.autoEnhancePrompt': 'Auto Enhance Prompt',
|
|
1635
|
+
'f.autoEnhancePromptHint': 'Enrich prompts with photography, lighting, and composition quality tokens.',
|
|
1636
|
+
'f.defaultStylePreset': 'Default Style Preset',
|
|
1637
|
+
'f.defaultStylePresetHint': 'Default style preset applied to generations (e.g. cinematic, anime, photorealistic).',
|
|
1638
|
+
'p.defaultStylePreset': 'none',
|
|
1639
|
+
|
|
1640
|
+
'updater.title': 'Plugin Updates',
|
|
1641
|
+
'updater.check': 'Check updates',
|
|
1642
|
+
'updater.checking': 'Checking…',
|
|
1643
|
+
'updater.current': 'Current version',
|
|
1644
|
+
'updater.latest': 'Latest version',
|
|
1645
|
+
'updater.upToDate': 'Up to date',
|
|
1646
|
+
'updater.updateNow': 'Update to v{version}',
|
|
1647
|
+
'updater.updating': 'Updating…',
|
|
1648
|
+
'updater.success': 'Plugin updated successfully! Please restart DSH service.',
|
|
1649
|
+
'updater.failed': 'Update check failed: ',
|
|
1650
|
+
|
|
1491
1651
|
'f.enhancePrompt': 'LLM Prompt Enhancer',
|
|
1492
1652
|
'f.enhancePromptHint': 'Expand concise prompts with rich artistic details before generation.',
|
|
1493
1653
|
'f.enableLlmEnhancer': 'Enable LLM Enhancer (Legacy)',
|
|
@@ -1675,6 +1835,16 @@ window.__ModuleLoader__.load({
|
|
|
1675
1835
|
'f.defaultStylePresetHint': '生成图像时应用的默认艺术或摄影风格(如 cinematic, anime 等)。',
|
|
1676
1836
|
'p.defaultStylePreset': 'none',
|
|
1677
1837
|
|
|
1838
|
+
'updater.title': '插件更新',
|
|
1839
|
+
'updater.check': '检查更新',
|
|
1840
|
+
'updater.checking': '正在检查…',
|
|
1841
|
+
'updater.current': '当前版本',
|
|
1842
|
+
'updater.latest': '最新版本',
|
|
1843
|
+
'updater.upToDate': '已是最新',
|
|
1844
|
+
'updater.updateNow': '一键更新至 v{version}',
|
|
1845
|
+
'updater.updating': '正在更新…',
|
|
1846
|
+
'updater.success': '插件更新成功!请重启 DSH 服务以生效。',
|
|
1847
|
+
'updater.failed': '更新检查失败:',
|
|
1678
1848
|
'f.enhancePrompt': 'LLM 提示词扩展',
|
|
1679
1849
|
'f.enhancePromptHint': '在生成前由会话模型自动丰富短提示词细节。',
|
|
1680
1850
|
'f.enableLlmEnhancer': '启用 LLM 提示词增强 (Legacy)',
|
|
@@ -1711,190 +1881,6 @@ window.__ModuleLoader__.load({
|
|
|
1711
1881
|
'p.cacheTtlDays': '0',
|
|
1712
1882
|
}
|
|
1713
1883
|
|
|
1714
|
-
const ru = {
|
|
1715
|
-
'settings.navLabel': 'Image Studio',
|
|
1716
|
-
'settings.title': 'Генерация изображений',
|
|
1717
|
-
'settings.description': 'Мультипровайдерная студия: генерация, инпейнтинг, вариации, апскейл и векторизация.',
|
|
1718
|
-
'settings.unavailable': 'Настройки плагина инициализируются. Они появятся автоматически через несколько секунд.',
|
|
1719
|
-
'settings.unsaved': 'Несохранённые изменения',
|
|
1720
|
-
'settings.saving': 'Сохранение…',
|
|
1721
|
-
'settings.save': 'Сохранить настройки',
|
|
1722
|
-
'settings.discard': 'Сбросить изменения',
|
|
1723
|
-
'settings.saveFailed': 'Не удалось сохранить настройки. Проверьте параметры и попробуйте снова.',
|
|
1724
|
-
'settings.readOnly': 'Настройки доступны только для чтения.',
|
|
1725
|
-
'settings.overridden': 'переопределено',
|
|
1726
|
-
'settings.reset': 'Сбросить к умолчанию',
|
|
1727
|
-
'settings.invalidNumber': 'Введите корректное число',
|
|
1728
|
-
'settings.collapse': 'Свернуть',
|
|
1729
|
-
'settings.expand': 'Развернуть',
|
|
1730
|
-
'settings.credentialHint': 'Ключи API хранятся в DSH Credentials (~/.dsh/.credentials.yaml) и не попадают в файлы конфигурации.',
|
|
1731
|
-
|
|
1732
|
-
'tab.general': 'Основные',
|
|
1733
|
-
'tab.provider': 'Провайдер',
|
|
1734
|
-
'tab.enhancer': 'Промпт и стили',
|
|
1735
|
-
'tab.safety': 'Безопасность и бюджет',
|
|
1736
|
-
'tab.cache': 'Кэш и хранение',
|
|
1737
|
-
|
|
1738
|
-
'stat.active_provider': 'Активный провайдер',
|
|
1739
|
-
'stat.format_size': 'Параметры по умолчанию',
|
|
1740
|
-
'stat.safety_status': 'Защита и Loop Guard',
|
|
1741
|
-
'stat.budget_cache': 'Бюджет и кэширование',
|
|
1742
|
-
|
|
1743
|
-
'card.generating': 'Генерация изображения…',
|
|
1744
|
-
'card.failed': 'Ошибка генерации',
|
|
1745
|
-
'card.image': 'Результат Image Studio',
|
|
1746
|
-
'card.unknownError': 'Неизвестная ошибка во время создания изображения.',
|
|
1747
|
-
'card.sizePrefix': 'Размер',
|
|
1748
|
-
'card.seedPrefix': 'Сид',
|
|
1749
|
-
'card.actionReroll': 'Перегенерировать картинку',
|
|
1750
|
-
'card.actionUpscale': 'Увеличить разрешение',
|
|
1751
|
-
'card.actionRemoveBg': 'Удалить фон',
|
|
1752
|
-
'card.reroll': 'Реролл',
|
|
1753
|
-
'card.upscale': 'Апскейл 2x/4x',
|
|
1754
|
-
'card.removeBg': 'Без фона',
|
|
1755
|
-
'card.copyPrompt': 'Копировать промпт',
|
|
1756
|
-
'card.origPrompt': 'Исходный промпт',
|
|
1757
|
-
|
|
1758
|
-
'f.enabled': 'Главный выключатель',
|
|
1759
|
-
'f.enabledHint': 'Включение или отключение всех инструментов генерации картинок.',
|
|
1760
|
-
'f.provider': 'Провайдер генерации',
|
|
1761
|
-
'f.providerHint': 'Сервис, выполняющий непосредственное создание изображений.',
|
|
1762
|
-
'f.inherit': 'По умолчанию / наследовать',
|
|
1763
|
-
'f.needFal': 'Требуется ключ FAL API',
|
|
1764
|
-
'f.needCustom': 'Требуется OpenAI-совместимый эндпоинт',
|
|
1765
|
-
'f.needCodex': 'Встроенная подписка Codex',
|
|
1766
|
-
'f.needGrok': 'Встроенная подписка Grok',
|
|
1767
|
-
'f.needLocal': 'Локальный ComfyUI или Automatic1111',
|
|
1768
|
-
'f.needSeedream': 'Требуется ключ SeaDream API',
|
|
1769
|
-
'f.needGemini': 'Требуется ключ Google Gemini API',
|
|
1770
|
-
'f.needReplicate': 'Требуется токен Replicate API',
|
|
1771
|
-
|
|
1772
|
-
'f.defaultSize': 'Соотношение сторон по умолчанию',
|
|
1773
|
-
'f.defaultSizeHint': 'Разрешение и пропорции кадра, когда параметр image_size не передан.',
|
|
1774
|
-
'f.defaultFormat': 'Формат файла',
|
|
1775
|
-
'f.defaultFormatHint': 'Формат сохранения результатов (PNG, JPEG или WEBP).',
|
|
1776
|
-
'f.deliverAs': 'Способ доставки',
|
|
1777
|
-
'f.deliverAsHint': 'Способ передачи: "link" (безопасно для текстовых моделей) или "image" (для vision-моделей).',
|
|
1778
|
-
'f.outputDir': 'Каталог сохранения',
|
|
1779
|
-
'f.outputDirHint': 'Путь к папке сохранения сгенерированных файлов на диске.',
|
|
1780
|
-
'p.outputDir': 'generated/images',
|
|
1781
|
-
'f.historyLimit': 'Лимит истории',
|
|
1782
|
-
'f.historyLimitHint': 'Максимальное число последних генераций, удерживаемых в памяти.',
|
|
1783
|
-
'p.historyLimit': '50',
|
|
1784
|
-
|
|
1785
|
-
'f.model': 'Модель FAL',
|
|
1786
|
-
'f.modelHint': 'Идентификатор модели на сервисе FAL (например, fal-ai/flux-2/klein/9b).',
|
|
1787
|
-
'p.model': 'fal-ai/flux-2/klein/9b',
|
|
1788
|
-
'f.apiKeyEnv': 'Ключ FAL (credential-ref)',
|
|
1789
|
-
'f.apiKeyEnvHint': 'Ссылка на ключ доступа FAL в хранилище credentials.',
|
|
1790
|
-
'p.apiKeyEnv': 'FAL_API_KEY',
|
|
1791
|
-
'f.baseURL': 'Базовый URL FAL',
|
|
1792
|
-
'f.baseURLHint': 'Адрес сервиса очередей FAL.',
|
|
1793
|
-
'p.baseURL': 'https://queue.fal.run',
|
|
1794
|
-
'f.pollIntervalMs': 'Интервал опроса (мс)',
|
|
1795
|
-
'f.pollIntervalMsHint': 'Периодичность проверки статуса при асинхронной генерации.',
|
|
1796
|
-
'p.pollIntervalMs': '2000',
|
|
1797
|
-
'f.timeoutMs': 'Таймаут (мс)',
|
|
1798
|
-
'f.timeoutMsHint': 'Предельное время ожидания генерации до возврата ошибки.',
|
|
1799
|
-
'p.timeoutMs': '180000',
|
|
1800
|
-
|
|
1801
|
-
'f.customBaseURL': 'URL стороннего API',
|
|
1802
|
-
'f.customBaseURLHint': 'Адрес OpenAI-совместимого эндпоинта (например, https://api.openai.com/v1).',
|
|
1803
|
-
'p.customBaseURL': 'https://api.openai.com/v1',
|
|
1804
|
-
'f.customModel': 'Модель стороннего API',
|
|
1805
|
-
'f.customModelHint': 'Имя модели для отправки в сторонний API.',
|
|
1806
|
-
'p.customModel': 'dall-e-3',
|
|
1807
|
-
'f.customKeyEnv': 'Ключ стороннего API',
|
|
1808
|
-
'f.customKeyEnvHint': 'Имя ссылки на ключ для стороннего API.',
|
|
1809
|
-
'p.customKeyEnv': 'OPENAI_API_KEY',
|
|
1810
|
-
'f.customSize': 'Фиксированный размер',
|
|
1811
|
-
'f.customSizeHint': 'Точный размер кадра для стороннего API (например, 1024x1024).',
|
|
1812
|
-
'p.customSize': '1024x1024',
|
|
1813
|
-
|
|
1814
|
-
'f.replicateModel': 'Модель Replicate',
|
|
1815
|
-
'f.replicateModelHint': 'Идентификатор модели на Replicate.',
|
|
1816
|
-
'p.replicateModel': 'black-forest-labs/flux-schnell',
|
|
1817
|
-
'f.replicateKeyEnv': 'Ключ Replicate',
|
|
1818
|
-
'f.replicateKeyEnvHint': 'Имя ссылки на API-токен Replicate.',
|
|
1819
|
-
'p.replicateKeyEnv': 'REPLICATE_API_TOKEN',
|
|
1820
|
-
|
|
1821
|
-
'f.seedreamModel': 'Модель SeaDream',
|
|
1822
|
-
'f.seedreamModelHint': 'Идентификатор модели ByteDance SeaDream.',
|
|
1823
|
-
'p.seedreamModel': 'seedream-4.0',
|
|
1824
|
-
'f.seedreamKeyEnv': 'Ключ SeaDream',
|
|
1825
|
-
'f.seedreamKeyEnvHint': 'Имя ссылки на ключ API SeaDream.',
|
|
1826
|
-
'p.seedreamKeyEnv': 'SEEDREAM_API_KEY',
|
|
1827
|
-
'f.seedreamBaseURL': 'Базовый URL SeaDream',
|
|
1828
|
-
'f.seedreamBaseURLHint': 'Адрес API SeaDream (ByteDance/Volcengine Ark).',
|
|
1829
|
-
'p.seedreamBaseURL': 'https://api.bytedanceapi.com/v1',
|
|
1830
|
-
|
|
1831
|
-
'f.geminiModel': 'Модель Gemini',
|
|
1832
|
-
'f.geminiModelHint': 'Идентификатор модели генерации Google Gemini.',
|
|
1833
|
-
'p.geminiModel': 'gemini-2.0-flash-exp-image-generation',
|
|
1834
|
-
'f.geminiKeyEnv': 'Ключ Gemini',
|
|
1835
|
-
'f.geminiKeyEnvHint': 'Имя ссылки на ключ Google Gemini API.',
|
|
1836
|
-
'p.geminiKeyEnv': 'GEMINI_API_KEY',
|
|
1837
|
-
|
|
1838
|
-
'f.localKind': 'Тип локального движка',
|
|
1839
|
-
'f.localKindHint': 'Выбор между ComfyUI API и Automatic1111 WebUI.',
|
|
1840
|
-
'f.localBaseURL': 'Адрес локального сервера',
|
|
1841
|
-
'f.localBaseURLHint': 'Адрес локального сервера (ComfyUI: 8188, A1111: 7860).',
|
|
1842
|
-
'p.localBaseURL': 'http://127.0.0.1:8188',
|
|
1843
|
-
'f.localModel': 'Модель / Чекпоинт',
|
|
1844
|
-
'f.localModelHint': 'Имя чекпоинта или воркфлоу ComfyUI.',
|
|
1845
|
-
'p.localModel': 'v1-5-pruned-emaonly.safetensors',
|
|
1846
|
-
'f.localSteps': 'Шаги сэмплирования',
|
|
1847
|
-
'f.localStepsHint': 'Количество шагов генерации.',
|
|
1848
|
-
'p.localSteps': '20',
|
|
1849
|
-
'f.localCfg': 'Шкала CFG',
|
|
1850
|
-
'f.localCfgHint': 'Сила следования промпту.',
|
|
1851
|
-
'p.localCfg': '7',
|
|
1852
|
-
'f.localComfyUrl': 'Локальный ComfyUI URL (Legacy)',
|
|
1853
|
-
'f.localComfyUrlHint': 'Прямой адрес ComfyUI.',
|
|
1854
|
-
'p.localComfyUrl': 'http://127.0.0.1:8188',
|
|
1855
|
-
'f.localA1111Url': 'Локальный A1111 URL (Legacy)',
|
|
1856
|
-
'f.localA1111UrlHint': 'Прямой адрес Automatic1111.',
|
|
1857
|
-
'p.localA1111Url': 'http://127.0.0.1:7860',
|
|
1858
|
-
|
|
1859
|
-
'f.subscriptionQuality': 'Качество подписки',
|
|
1860
|
-
'f.subscriptionQualityHint': 'Профиль качества для провайдеров Codex и Grok.',
|
|
1861
|
-
|
|
1862
|
-
'f.enhancePrompt': 'LLM-улучшение промпта',
|
|
1863
|
-
'f.enhancePromptHint': 'Автоматическое обогащение коротких запросов художественными деталями.',
|
|
1864
|
-
'f.enableLlmEnhancer': 'Включить LLM Enhancer (Legacy)',
|
|
1865
|
-
'f.enableLlmEnhancerHint': 'Устаревший переключатель улучшения промптов.',
|
|
1866
|
-
'f.enhanceModel': 'Модель улучшения',
|
|
1867
|
-
'f.enhanceModelHint': 'Модель для расширения промптов (пусто = основная модель чата).',
|
|
1868
|
-
'p.enhanceModel': 'Пусто для основной модели чата',
|
|
1869
|
-
'f.enhanceBelowChars': 'Порог длины промпта',
|
|
1870
|
-
'f.enhanceBelowCharsHint': 'Промпты длиннее этого количества символов не расширяются.',
|
|
1871
|
-
'p.enhanceBelowChars': '200',
|
|
1872
|
-
'f.stylePreset': 'Художественный стиль',
|
|
1873
|
-
'f.stylePresetHint': 'Автоматический суффикс стиля для всех создаваемых изображений.',
|
|
1874
|
-
|
|
1875
|
-
'f.qualityGate': 'Контроль качества (Quality Gate)',
|
|
1876
|
-
'f.qualityGateHint': 'Автоматическая проверка кадров и скрытый реролл при дефектах или пустом кадре.',
|
|
1877
|
-
'f.dailyBudgetUsd': 'Дневной бюджет ($ USD)',
|
|
1878
|
-
'f.dailyBudgetUsdHint': 'Предельный лимит затрат в сутки по всем графическим инструментам (0 = без лимита).',
|
|
1879
|
-
'p.dailyBudgetUsd': '0.00',
|
|
1880
|
-
'f.loopGuardLimit': 'Защита от циклов (Loop Guard)',
|
|
1881
|
-
'f.loopGuardLimitHint': 'Максимум последовательных генераций подряд без участия пользователя (0 = выкл).',
|
|
1882
|
-
'p.loopGuardLimit': '3',
|
|
1883
|
-
|
|
1884
|
-
'f.diskCache': 'Дисковый кэш по хэшу',
|
|
1885
|
-
'f.diskCacheHint': 'Мгновенная выдача (<50 мс) и нулевая стоимость для повторных идентичных генераций.',
|
|
1886
|
-
'f.cacheBySeed': 'Кэш по сиду и промпту',
|
|
1887
|
-
'f.cacheBySeedHint': 'Возвращать кэш при полном совпадении сида и текста промпта.',
|
|
1888
|
-
'f.cacheByPrompt': 'Кэш по тексту промпта',
|
|
1889
|
-
'f.cacheByPromptHint': 'Возвращать кэш при повторении того же текста промпта.',
|
|
1890
|
-
'f.pruneDays': 'Срок хранения файлов (дни)',
|
|
1891
|
-
'f.pruneDaysHint': 'Автоматическое удаление файлов и записей старше указанного числа дней (0 = бессрочно).',
|
|
1892
|
-
'p.pruneDays': '0',
|
|
1893
|
-
'f.cacheTtlDays': 'Срок хранения кэша (Legacy)',
|
|
1894
|
-
'f.cacheTtlDaysHint': 'Устаревшее имя параметра срока хранения.',
|
|
1895
|
-
'p.cacheTtlDays': '0',
|
|
1896
|
-
}
|
|
1897
|
-
|
|
1898
1884
|
// -------------------------------------------------------------- Registration & Apply
|
|
1899
1885
|
const inject = ['slots', 'settingsScope', 'locale', 'sessions']
|
|
1900
1886
|
|
|
@@ -1902,7 +1888,6 @@ window.__ModuleLoader__.load({
|
|
|
1902
1888
|
if (ctx.locale && typeof ctx.locale.define === 'function') {
|
|
1903
1889
|
ctx.locale.define('en', NS, en)
|
|
1904
1890
|
ctx.locale.define('zh', NS, zh)
|
|
1905
|
-
ctx.locale.define('ru', NS, ru)
|
|
1906
1891
|
}
|
|
1907
1892
|
|
|
1908
1893
|
let card
|