@goodandready/dsh-image-gen 0.10.3 → 0.10.4
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 +8 -0
- package/README.ru.md +8 -0
- package/README.zh.md +8 -0
- package/lib/client.js +57 -30
- package/lib/index.js +5 -2
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -55,6 +55,14 @@
|
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
58
|
+
|
|
59
|
+
## 🚀 Updates in v0.10.4: Cordis Lifecycle, Full Settings GUI, and i18n
|
|
60
|
+
- **Cordis Lifecycle (#136)**: wrapped all 7 tool registrations in `ctx.effect` for proper disposal on reload.
|
|
61
|
+
- **Settings GUI Completeness (#137)**: exposed fields for Replicate, SeaDream, Gemini, Local ComfyUI/A1111, style presets, and LLM enhancer.
|
|
62
|
+
- **Package Manifest (#138)**: declared kernel `peerDependencies` (`host-webserver`, `settings`, `llm`, `system-prompt`).
|
|
63
|
+
- **React Cleanup (#139)**: removed dead state hooks from `FalImageCard`.
|
|
64
|
+
- **Complete Localization (#140)**: eliminated hardcoded strings, wiring comprehensive dictionaries for en, ru, and zh.
|
|
65
|
+
|
|
58
66
|
## 🎨 Supported Generation Backends
|
|
59
67
|
|
|
60
68
|
* **`fal`** (Default): FAL.ai queue for FLUX.1, SDXL, Clarity Upscaler, and BiRefNet.
|
package/README.ru.md
CHANGED
|
@@ -111,6 +111,14 @@ graph LR
|
|
|
111
111
|
|
|
112
112
|
---
|
|
113
113
|
|
|
114
|
+
|
|
115
|
+
## 🚀 Обновления v0.10.4: жизненный цикл Cordis, полнота настроек и интернационализация
|
|
116
|
+
- **Жизненный цикл Cordis (#136)**: регистрация всех 7 инструментов обёрнута в `ctx.effect` для штатной отписки при перезагрузке плагина.
|
|
117
|
+
- **Полнота настроек в GUI (#137)**: в карточку настроек добавлены поля для Replicate, SeaDream, Gemini, Local ComfyUI/A1111, пресетов стилей и LLM-улучшителя.
|
|
118
|
+
- **Манифест зависимостей (#138)**: в `peerDependencies` задекларированы все используемые службы ядра (`host-webserver`, `settings`, `llm`, `system-prompt`).
|
|
119
|
+
- **Оптимизация компонентов (#139)**: из `FalImageCard` удалён неиспользуемый мёртвый стейт.
|
|
120
|
+
- **100% интернационализация (#140)**: устранены захардкоженные русские строки, добавлены переводы на русский, английский и китайский языки.
|
|
121
|
+
|
|
114
122
|
## 🎨 Поддерживаемые провайдеры генерации
|
|
115
123
|
|
|
116
124
|
* **`fal`** *(дефолт)*: Сверхбыстрая очередь FAL.ai (`FLUX.1-schnell`, `FLUX-dev`, `SDXL`, BiRefNet, Clarity Upscaler).
|
package/README.zh.md
CHANGED
|
@@ -37,6 +37,14 @@
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
+
|
|
41
|
+
## 🚀 v0.10.4 更新:Cordis 生命周期、完整设置界面与国际化
|
|
42
|
+
- **Cordis 生命周期 (#136)**:将所有 7 个工具注册包装在 `ctx.effect` 中,以便在热重载时正常释放。
|
|
43
|
+
- **设置界面完整性 (#137)**:添加了 Replicate、SeaDream、Gemini、本地 ComfyUI/A1111、风格预设和 LLM 增强器的配置字段。
|
|
44
|
+
- **包清单依赖 (#138)**:在 `peerDependencies` 中补齐了内核服务依赖。
|
|
45
|
+
- **React 组件优化 (#139)**:从 `FalImageCard` 中移除了未使用的无用状态。
|
|
46
|
+
- **全面国际化 (#140)**:消除了硬编码文本,为中、英、俄语提供完整翻译。
|
|
47
|
+
|
|
40
48
|
## 📦 安装
|
|
41
49
|
|
|
42
50
|
```bash
|
package/lib/client.js
CHANGED
|
@@ -465,22 +465,53 @@ window.__ModuleLoader__.load({
|
|
|
465
465
|
|
|
466
466
|
/** Field specs in display order. */
|
|
467
467
|
const booleanField = (name) => ({ name, type: 'boolean', parse: (v) => v === 'true' || v === true, format: (v) => String(!!v) })
|
|
468
|
+
const STYLE_PRESET_OPTIONS = ['', 'cinematic', 'anime', 'digital_art', 'photographic', 'fantasy', 'isometric', 'cyberpunk', 'watercolor', 'origami', 'oil_painting', 'pixel_art', 'logo']
|
|
469
|
+
|
|
468
470
|
const FIELDS = [
|
|
469
471
|
{ field: 'enabled', spec: booleanField('enabled'), kind: 'select', options: ['true', 'false'], labelKey: 'f.enabled', hintKey: 'f.enabledHint' },
|
|
470
|
-
{ field: 'provider', spec: selectField('provider', PROVIDERS), kind: 'select', options: PROVIDERS, labelKey: 'f.provider', hintKey: 'f.providerHint', providerNeeds: { fal: '
|
|
472
|
+
{ field: 'provider', spec: selectField('provider', PROVIDERS), kind: 'select', options: PROVIDERS, labelKey: 'f.provider', hintKey: 'f.providerHint', providerNeeds: { fal: 'f.needFal', custom: 'f.needCustom', codex: 'f.needCodex', grok: 'f.needGrok', local: 'f.needLocal', seedream: 'f.needSeedream', gemini: 'f.needGemini', replicate: 'f.needReplicate' } },
|
|
473
|
+
|
|
474
|
+
// FAL
|
|
471
475
|
{ field: 'model', spec: textField('model'), kind: 'text', labelKey: 'f.model', hintKey: 'f.modelHint', placeholderKey: 'p.model', when: ['fal'] },
|
|
472
476
|
{ field: 'apiKeyEnv', spec: textField('apiKeyEnv'), kind: 'text', labelKey: 'f.apiKeyEnv', hintKey: 'f.apiKeyEnvHint', placeholderKey: 'p.apiKeyEnv', when: ['fal'] },
|
|
473
477
|
{ field: 'baseURL', spec: textField('baseURL'), kind: 'text', labelKey: 'f.baseURL', hintKey: 'f.baseURLHint', placeholderKey: 'p.baseURL', when: ['fal'] },
|
|
474
|
-
{ field: 'defaultSize', spec: selectField('defaultSize', IMAGE_SIZES), kind: 'select', options: IMAGE_SIZES, labelKey: 'f.defaultSize', hintKey: 'f.defaultSizeHint', sizePixels: SIZE_PIXELS },
|
|
475
|
-
{ field: 'defaultFormat', spec: selectField('defaultFormat', OUTPUT_FORMATS), kind: 'select', options: OUTPUT_FORMATS, labelKey: 'f.defaultFormat', hintKey: 'f.defaultFormatHint' },
|
|
476
478
|
{ field: 'pollIntervalMs', spec: numberField('pollIntervalMs'), kind: 'number', labelKey: 'f.pollIntervalMs', hintKey: 'f.pollIntervalMsHint', placeholderKey: 'p.pollIntervalMs', when: ['fal'] },
|
|
477
479
|
{ field: 'timeoutMs', spec: numberField('timeoutMs'), kind: 'number', labelKey: 'f.timeoutMs', hintKey: 'f.timeoutMsHint', placeholderKey: 'p.timeoutMs', when: ['fal'] },
|
|
478
|
-
|
|
480
|
+
|
|
481
|
+
// Custom
|
|
479
482
|
{ field: 'customBaseURL', spec: textField('customBaseURL'), kind: 'text', labelKey: 'f.customBaseURL', hintKey: 'f.customBaseURLHint', placeholderKey: 'p.customBaseURL', when: ['custom'] },
|
|
480
483
|
{ field: 'customModel', spec: textField('customModel'), kind: 'text', labelKey: 'f.customModel', hintKey: 'f.customModelHint', placeholderKey: 'p.customModel', when: ['custom'] },
|
|
481
484
|
{ field: 'customKeyEnv', spec: textField('customKeyEnv'), kind: 'text', labelKey: 'f.customKeyEnv', hintKey: 'f.customKeyEnvHint', placeholderKey: 'p.customKeyEnv', when: ['custom'] },
|
|
482
485
|
{ field: 'customSize', spec: textField('customSize'), kind: 'text', labelKey: 'f.customSize', hintKey: 'f.customSizeHint', placeholderKey: 'p.customSize', when: ['custom'] },
|
|
486
|
+
|
|
487
|
+
// Replicate
|
|
488
|
+
{ field: 'replicateModel', spec: textField('replicateModel'), kind: 'text', labelKey: 'f.replicateModel', hintKey: 'f.replicateModelHint', placeholderKey: 'p.replicateModel', when: ['replicate'] },
|
|
489
|
+
{ field: 'replicateKeyEnv', spec: textField('replicateKeyEnv'), kind: 'text', labelKey: 'f.replicateKeyEnv', hintKey: 'f.replicateKeyEnvHint', placeholderKey: 'p.replicateKeyEnv', when: ['replicate'] },
|
|
490
|
+
|
|
491
|
+
// SeaDream
|
|
492
|
+
{ field: 'seedreamModel', spec: textField('seedreamModel'), kind: 'text', labelKey: 'f.seedreamModel', hintKey: 'f.seedreamModelHint', placeholderKey: 'p.seedreamModel', when: ['seedream'] },
|
|
493
|
+
{ field: 'seedreamKeyEnv', spec: textField('seedreamKeyEnv'), kind: 'text', labelKey: 'f.seedreamKeyEnv', hintKey: 'f.seedreamKeyEnvHint', placeholderKey: 'p.seedreamKeyEnv', when: ['seedream'] },
|
|
494
|
+
{ field: 'seedreamBaseURL', spec: textField('seedreamBaseURL'), kind: 'text', labelKey: 'f.seedreamBaseURL', hintKey: 'f.seedreamBaseURLHint', placeholderKey: 'p.seedreamBaseURL', when: ['seedream'] },
|
|
495
|
+
|
|
496
|
+
// Gemini
|
|
497
|
+
{ field: 'geminiModel', spec: textField('geminiModel'), kind: 'text', labelKey: 'f.geminiModel', hintKey: 'f.geminiModelHint', placeholderKey: 'p.geminiModel', when: ['gemini'] },
|
|
498
|
+
{ field: 'geminiKeyEnv', spec: textField('geminiKeyEnv'), kind: 'text', labelKey: 'f.geminiKeyEnv', hintKey: 'f.geminiKeyEnvHint', placeholderKey: 'p.geminiKeyEnv', when: ['gemini'] },
|
|
499
|
+
|
|
500
|
+
// Local ComfyUI / A1111
|
|
501
|
+
{ field: 'localComfyUrl', spec: textField('localComfyUrl'), kind: 'text', labelKey: 'f.localComfyUrl', hintKey: 'f.localComfyUrlHint', placeholderKey: 'p.localComfyUrl', when: ['local'] },
|
|
502
|
+
{ field: 'localA1111Url', spec: textField('localA1111Url'), kind: 'text', labelKey: 'f.localA1111Url', hintKey: 'f.localA1111UrlHint', placeholderKey: 'p.localA1111Url', when: ['local'] },
|
|
503
|
+
|
|
504
|
+
// Common Style & LLM Enhancer
|
|
505
|
+
{ field: 'stylePreset', spec: selectField('stylePreset', STYLE_PRESET_OPTIONS), kind: 'select', options: STYLE_PRESET_OPTIONS, labelKey: 'f.stylePreset', hintKey: 'f.stylePresetHint' },
|
|
506
|
+
{ field: 'enableLlmEnhancer', spec: booleanField('enableLlmEnhancer'), kind: 'select', options: ['true', 'false'], labelKey: 'f.enableLlmEnhancer', hintKey: 'f.enableLlmEnhancerHint' },
|
|
507
|
+
|
|
508
|
+
// Output & Defaults
|
|
509
|
+
{ field: 'defaultSize', spec: selectField('defaultSize', IMAGE_SIZES), kind: 'select', options: IMAGE_SIZES, labelKey: 'f.defaultSize', hintKey: 'f.defaultSizeHint', sizePixels: SIZE_PIXELS },
|
|
510
|
+
{ field: 'defaultFormat', spec: selectField('defaultFormat', OUTPUT_FORMATS), kind: 'select', options: OUTPUT_FORMATS, labelKey: 'f.defaultFormat', hintKey: 'f.defaultFormatHint' },
|
|
511
|
+
{ field: 'deliverAs', spec: selectField('deliverAs', DELIVERY_MODES), kind: 'select', options: DELIVERY_MODES, labelKey: 'f.deliverAs', hintKey: 'f.deliverAsHint' },
|
|
483
512
|
{ field: 'outputDir', spec: textField('outputDir'), kind: 'text', labelKey: 'f.outputDir', hintKey: 'f.outputDirHint', placeholderKey: 'p.outputDir' },
|
|
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' },
|
|
484
515
|
]
|
|
485
516
|
|
|
486
517
|
function Field(props) {
|
|
@@ -501,7 +532,7 @@ window.__ModuleLoader__.load({
|
|
|
501
532
|
}
|
|
502
533
|
if (entry.kind === 'select') {
|
|
503
534
|
const px = entry.sizePixels && entry.sizePixels[state.text] ? ` — ${entry.sizePixels[state.text]}` : ''
|
|
504
|
-
const need = entry.providerNeeds && entry.providerNeeds[state.text] ? ` (
|
|
535
|
+
const need = entry.providerNeeds && entry.providerNeeds[state.text] ? ` (${t(entry.providerNeeds[state.text])})` : ''
|
|
505
536
|
const hint = base.hint + px + need
|
|
506
537
|
return react_jsx_runtime.jsx(SelectField, { ...base, hint, options: entry.options, inheritLabel: t('f.inherit') })
|
|
507
538
|
}
|
|
@@ -828,19 +859,17 @@ function FalImageCard(props) {
|
|
|
828
859
|
prompt = raw ? (JSON.parse(raw).prompt || '') : ''
|
|
829
860
|
} catch (e) { prompt = '' }
|
|
830
861
|
|
|
862
|
+
const t = props.t || ((k) => k)
|
|
831
863
|
const repeatText = (() => {
|
|
832
864
|
const parts = [String(args.prompt || '').trim()]
|
|
833
865
|
const size = args.image_size || args.size
|
|
834
866
|
const seed = args.seed
|
|
835
|
-
if (size) parts.push(
|
|
836
|
-
if (seed !== undefined) parts.push(
|
|
867
|
+
if (size) parts.push(`${t('card.sizePrefix')}: ${size}`)
|
|
868
|
+
if (seed !== undefined) parts.push(`${t('card.seedPrefix')}: ${seed}`)
|
|
837
869
|
return parts.filter(Boolean).join(', ')
|
|
838
870
|
})()
|
|
839
871
|
|
|
840
872
|
const [editing, setEditing] = react.useState(false)
|
|
841
|
-
const [inpaintOpen, setInpaintOpen] = react.useState(false)
|
|
842
|
-
const [compareSlider, setCompareSlider] = react.useState(50)
|
|
843
|
-
const [showCompare, setShowCompare] = react.useState(false)
|
|
844
873
|
const [editText, setEditText] = react.useState('')
|
|
845
874
|
|
|
846
875
|
const onEditPrompt = () => {
|
|
@@ -862,8 +891,6 @@ function FalImageCard(props) {
|
|
|
862
891
|
}
|
|
863
892
|
|
|
864
893
|
const [copied, setCopied] = react.useState(false)
|
|
865
|
-
const canvasRef = react.useRef(null)
|
|
866
|
-
const [drawing, setDrawing] = react.useState(false)
|
|
867
894
|
|
|
868
895
|
const sendActionPrompt = async (text) => {
|
|
869
896
|
try {
|
|
@@ -893,23 +920,23 @@ function FalImageCard(props) {
|
|
|
893
920
|
|
|
894
921
|
const onReroll = () => {
|
|
895
922
|
const nextSeed = (typeof args.seed === 'number' ? args.seed + 1 : Math.floor(Math.random() * 100000))
|
|
896
|
-
sendActionPrompt(
|
|
923
|
+
sendActionPrompt(`${t('card.actionReroll')} (${nextSeed}): ${prompt || repeatText}`)
|
|
897
924
|
}
|
|
898
925
|
|
|
899
926
|
const onUpscale = () => {
|
|
900
927
|
const ref = parsed.attachment ? parsed.attachment.attachmentId : (parsed.url || '')
|
|
901
|
-
sendActionPrompt(
|
|
928
|
+
sendActionPrompt(`${t('card.actionUpscale')}: upscale_image(image: "${ref}")`)
|
|
902
929
|
}
|
|
903
930
|
|
|
904
931
|
const onRemoveBg = () => {
|
|
905
932
|
const ref = parsed.attachment ? parsed.attachment.attachmentId : (parsed.url || '')
|
|
906
|
-
sendActionPrompt(
|
|
933
|
+
sendActionPrompt(`${t('card.actionRemoveBg')}: remove_background(image: "${ref}")`)
|
|
907
934
|
}
|
|
908
935
|
|
|
909
936
|
|
|
910
937
|
|
|
911
938
|
const head = react.createElement('div', { className: 'fal-head' },
|
|
912
|
-
running ? '
|
|
939
|
+
running ? t('card.generating') : failed ? t('card.failed') : t('card.image'))
|
|
913
940
|
|
|
914
941
|
// «Повторить генерацию»: отправляет в чат новое сообщение с теми же
|
|
915
942
|
// промптом и параметрами, извлечёнными из исходного вызова инструмента.
|
|
@@ -933,10 +960,10 @@ function FalImageCard(props) {
|
|
|
933
960
|
const body = []
|
|
934
961
|
if (prompt) body.push(react.createElement('div', { className: 'fal-prompt', key: 'p' }, prompt))
|
|
935
962
|
if (args.originalPrompt && args.originalPrompt !== prompt) {
|
|
936
|
-
body.push(react.createElement('div', { className: 'fal-meta', key: 'orig' },
|
|
963
|
+
body.push(react.createElement('div', { className: 'fal-meta', key: 'orig' }, `${t('card.origPrompt')}: ${args.originalPrompt}`))
|
|
937
964
|
}
|
|
938
965
|
if (failed) {
|
|
939
|
-
body.push(react.createElement('div', { className: 'fal-err', key: 'e' }, parsed.text || '
|
|
966
|
+
body.push(react.createElement('div', { className: 'fal-err', key: 'e' }, parsed.text || t('card.unknownError')))
|
|
940
967
|
} else if (!parsed.attachment && parsed.url) {
|
|
941
968
|
body.push(react.createElement('img', {
|
|
942
969
|
key: 'i',
|
|
@@ -990,7 +1017,7 @@ function FalImageCard(props) {
|
|
|
990
1017
|
type: 'button',
|
|
991
1018
|
className: 'fal-action-btn',
|
|
992
1019
|
onClick: onReroll,
|
|
993
|
-
title: '
|
|
1020
|
+
title: t('card.rerollTitle')
|
|
994
1021
|
}, '🔄 Re-roll'))
|
|
995
1022
|
|
|
996
1023
|
btns.push(react.createElement('button', {
|
|
@@ -998,7 +1025,7 @@ function FalImageCard(props) {
|
|
|
998
1025
|
type: 'button',
|
|
999
1026
|
className: 'fal-action-btn',
|
|
1000
1027
|
onClick: onUpscale,
|
|
1001
|
-
title: '
|
|
1028
|
+
title: t('card.upscaleTitle')
|
|
1002
1029
|
}, '🔍 2x Upscale'))
|
|
1003
1030
|
|
|
1004
1031
|
btns.push(react.createElement('button', {
|
|
@@ -1006,7 +1033,7 @@ function FalImageCard(props) {
|
|
|
1006
1033
|
type: 'button',
|
|
1007
1034
|
className: 'fal-action-btn',
|
|
1008
1035
|
onClick: onRemoveBg,
|
|
1009
|
-
title: '
|
|
1036
|
+
title: t('card.removeBgTitle')
|
|
1010
1037
|
}, '✂️ Remove BG'))
|
|
1011
1038
|
|
|
1012
1039
|
if (prompt) {
|
|
@@ -1015,8 +1042,8 @@ function FalImageCard(props) {
|
|
|
1015
1042
|
type: 'button',
|
|
1016
1043
|
className: 'fal-action-btn',
|
|
1017
1044
|
onClick: onCopyPrompt,
|
|
1018
|
-
title: '
|
|
1019
|
-
}, copied ? '
|
|
1045
|
+
title: t('card.copyPromptTitle')
|
|
1046
|
+
}, copied ? t('card.copied') : t('card.copyPrompt')))
|
|
1020
1047
|
}
|
|
1021
1048
|
|
|
1022
1049
|
if (args.seed !== undefined) {
|
|
@@ -1025,8 +1052,8 @@ function FalImageCard(props) {
|
|
|
1025
1052
|
type: 'button',
|
|
1026
1053
|
className: 'fal-action-btn',
|
|
1027
1054
|
onClick: onCopySeed,
|
|
1028
|
-
title: '
|
|
1029
|
-
}, `🎲
|
|
1055
|
+
title: t('card.copySeedTitle')
|
|
1056
|
+
}, `🎲 ${t('card.seedPrefix')}: ${args.seed}`))
|
|
1030
1057
|
}
|
|
1031
1058
|
|
|
1032
1059
|
body.push(react.createElement('div', { key: 'action-row', className: 'fal-btn-row' }, btns))
|
|
@@ -1042,7 +1069,7 @@ function FalImageCard(props) {
|
|
|
1042
1069
|
type: 'button',
|
|
1043
1070
|
className: 'fal-repeat',
|
|
1044
1071
|
onClick: repeat,
|
|
1045
|
-
}, '
|
|
1072
|
+
}, t('card.repeatGen')))
|
|
1046
1073
|
}
|
|
1047
1074
|
if (!running && !failed) {
|
|
1048
1075
|
if (editing) {
|
|
@@ -1051,7 +1078,7 @@ function FalImageCard(props) {
|
|
|
1051
1078
|
type: 'text',
|
|
1052
1079
|
className: 'fal-input',
|
|
1053
1080
|
value: editText,
|
|
1054
|
-
placeholder: prompt || '
|
|
1081
|
+
placeholder: prompt || t('card.newPromptPlaceholder'),
|
|
1055
1082
|
onChange: (e) => setEditText(e.target.value),
|
|
1056
1083
|
}))
|
|
1057
1084
|
body.push(react.createElement('button', {
|
|
@@ -1071,14 +1098,14 @@ function FalImageCard(props) {
|
|
|
1071
1098
|
setEditing(false)
|
|
1072
1099
|
setEditText('')
|
|
1073
1100
|
},
|
|
1074
|
-
}, '
|
|
1101
|
+
}, t('card.send')))
|
|
1075
1102
|
} else {
|
|
1076
1103
|
body.push(react.createElement('button', {
|
|
1077
1104
|
key: 'edit',
|
|
1078
1105
|
type: 'button',
|
|
1079
1106
|
className: 'fal-repeat',
|
|
1080
1107
|
onClick: () => { setEditText(prompt || ''); setEditing(true) },
|
|
1081
|
-
}, '
|
|
1108
|
+
}, t('card.editPrompt')))
|
|
1082
1109
|
}
|
|
1083
1110
|
}
|
|
1084
1111
|
if (!running && !failed && downloadUrl) {
|
|
@@ -1087,7 +1114,7 @@ function FalImageCard(props) {
|
|
|
1087
1114
|
className: 'fal-repeat',
|
|
1088
1115
|
href: downloadUrl,
|
|
1089
1116
|
download: 'generated-image.png',
|
|
1090
|
-
}, '
|
|
1117
|
+
}, t('card.download')))
|
|
1091
1118
|
}
|
|
1092
1119
|
|
|
1093
1120
|
return react.createElement('div', { className: 'fal-card' }, head, body)
|
package/lib/index.js
CHANGED
|
@@ -534,7 +534,9 @@ export function apply(ctx, config) {
|
|
|
534
534
|
},
|
|
535
535
|
}), 'dsh-image-gen: history route')
|
|
536
536
|
|
|
537
|
-
ctx.
|
|
537
|
+
// Регистрация инструментов обёрнута в ctx.effect для соблюдения жизненного цикла Cordis (#136)
|
|
538
|
+
ctx.effect(() => {
|
|
539
|
+
ctx.tools.register(
|
|
538
540
|
defineTool({
|
|
539
541
|
name: 'generate_image',
|
|
540
542
|
description:
|
|
@@ -1212,6 +1214,7 @@ export function apply(ctx, config) {
|
|
|
1212
1214
|
}
|
|
1213
1215
|
},
|
|
1214
1216
|
}),
|
|
1215
|
-
|
|
1217
|
+
)
|
|
1218
|
+
})
|
|
1216
1219
|
|
|
1217
1220
|
}
|
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.4",
|
|
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",
|
|
@@ -59,6 +59,10 @@
|
|
|
59
59
|
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
|
|
60
60
|
"@deepseek-ai/dsh-attachment": "^0.1.0-rc.6",
|
|
61
61
|
"@deepseek-ai/dsh-credentials": "^0.1.0-rc.6",
|
|
62
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6",
|
|
63
|
+
"@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
|
|
64
|
+
"@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
|
|
65
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6",
|
|
62
66
|
"@deepseek-ai/schemastery": "^3.18.1"
|
|
63
67
|
},
|
|
64
68
|
"scripts": {
|