kingkont 0.20.19 → 0.20.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.20.19",
3
+ "version": "0.20.21",
4
4
  "description": "KingKont \u00b7 Chatium \u2014 \u043d\u043e\u0434-\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0441\u0446\u0435\u043d \u0441 AI-\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 (\u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438/\u0432\u0438\u0434\u0435\u043e/\u0433\u043e\u043b\u043e\u0441/SFX/\u043c\u0443\u0437\u044b\u043a\u0430/\u0442\u0435\u043a\u0441\u0442)",
5
5
  "main": "main.js",
6
6
  "bin": {
@@ -1645,9 +1645,59 @@ $('genSubmit').addEventListener('click', async () => {
1645
1645
  $('locPickRow').style.display = 'none';
1646
1646
  $('genModal').classList.add('hidden');
1647
1647
  if (saveOnly) {
1648
- // Сохраняем правки промпта без запуска генерации.
1649
- target.generated = { ...(target.generated || {}), rawPrompt, kind };
1648
+ // Сохраняем правки ВСЕХ настроек модалки (промпт + модель + длина +
1649
+ // ratio + resolution + voiceId/tones для audio). Юзер: «иду в ноду А,
1650
+ // выставляю Kling O1, нажимаю Сохранить, иду в ноду Б, выставляю
1651
+ // Seedance Fast, возвращаюсь в А и вижу Seedance Fast». Раньше
1652
+ // сохранялись только rawPrompt+kind — модель/длина/aspect юзера
1653
+ // не закреплялись в ноде, и при следующем открытии regenerateNode
1654
+ // не находил их в g.modelKey → state.videoModel оставался "последний".
1655
+ const patch = { ...(target.generated || {}), rawPrompt, kind, prompt: rawPrompt };
1656
+ if (kind === 'video') {
1657
+ const modelMap = {
1658
+ 'seedance-2': 'bytedance/seedance-2',
1659
+ 'seedance-2-fast': 'bytedance/seedance-2-fast',
1660
+ 'kling-o1': 'kwaivgi/kling-o1',
1661
+ 'kling-3.0': 'kling-3.0/video',
1662
+ };
1663
+ const mk = state.videoModel || 'seedance-2';
1664
+ patch.modelKey = mk;
1665
+ patch.model = modelMap[mk] || 'bytedance/seedance-2';
1666
+ patch.duration = state.videoDuration;
1667
+ patch.resolution = state.videoResolution;
1668
+ patch.aspectRatio = state.videoAspect;
1669
+ } else if (kind === 'image') {
1670
+ const modelMap = {
1671
+ 'grok': 'grok-imagine/text-to-image',
1672
+ 'seedream': 'seedream/4.5-text-to-image',
1673
+ 'seedream-5-lite': 'seedream/5-lite-text-to-image',
1674
+ 'nano-banana-2': 'nano-banana-2',
1675
+ 'nano-banana-pro': 'nano-banana-pro',
1676
+ 'gpt-image-2': 'gpt-image-2-text-to-image',
1677
+ 'gpt-image-1.5': 'gpt-image/1.5-text-to-image',
1678
+ 'flux-schnell': 'flux/schnell',
1679
+ 'sdxl-lightning': 'sdxl/lightning',
1680
+ };
1681
+ const mk = state.imageModel || 'nano-banana-2';
1682
+ patch.modelKey = mk;
1683
+ patch.model = modelMap[mk] || 'nano-banana-2';
1684
+ patch.aspectRatio = state.imageAspect;
1685
+ if (state.imageQuality) patch.quality = state.imageQuality;
1686
+ } else if (kind === 'audio') {
1687
+ const voiceId = $('genVoice').value || target.generated?.voiceId;
1688
+ if (voiceId) patch.voiceId = voiceId;
1689
+ if (state.ttsModel) patch.ttsModel = state.ttsModel;
1690
+ patch.tones = [...(state.activeTones || [])];
1691
+ }
1692
+ target.generated = patch;
1693
+ // Если у ноды нет explicit status — считаем её draft (юзер
1694
+ // подготовил параметры, но ещё не запускал).
1695
+ if (!target.status) target.status = 'draft';
1650
1696
  scheduleSave();
1697
+ console.log('[regenerate saveOnly] persisted to node.generated:', {
1698
+ modelKey: patch.modelKey, duration: patch.duration,
1699
+ resolution: patch.resolution, aspectRatio: patch.aspectRatio,
1700
+ });
1651
1701
  return;
1652
1702
  }
1653
1703
  await regenerateInto(target, kind, rawPrompt, { sourceRef, pickedSheets });
@@ -2207,8 +2257,24 @@ async function runNodeJobDirectly(node) {
2207
2257
  const model = g.model || g.modelKey || 'anthropic/claude-sonnet-4';
2208
2258
  await runTextJob(node, g.prompt, model, boardHandle, bKey, imageRefs);
2209
2259
  } else {
2210
- // image / video
2211
- await startGenerationJob(node, kind, g.prompt, refs, boardHandle, bKey, g.modelKey);
2260
+ // image / video — modelKey должен быть short-key (state.videoModel-style),
2261
+ // а не full-slug. Если g.modelKey не сохранён (старые ноды) — конвертируем
2262
+ // из g.model через _shortVideoModelFromGen/_shortImageModelFromGen.
2263
+ let modelKey = g.modelKey;
2264
+ if (!modelKey) {
2265
+ if (kind === 'video' && typeof _shortVideoModelFromGen === 'function') {
2266
+ modelKey = _shortVideoModelFromGen(g);
2267
+ } else if (kind === 'image' && typeof _shortImageModelFromGen === 'function') {
2268
+ modelKey = _shortImageModelFromGen(g);
2269
+ }
2270
+ }
2271
+ console.log(`[runNodeJobDirectly ${kind}] using node-saved params:`, {
2272
+ modelKey,
2273
+ ...(kind === 'video' ? {
2274
+ duration: g.duration, resolution: g.resolution, aspectRatio: g.aspectRatio,
2275
+ } : { aspectRatio: g.aspectRatio }),
2276
+ });
2277
+ await startGenerationJob(node, kind, g.prompt, refs, boardHandle, bKey, modelKey);
2212
2278
  }
2213
2279
  } catch (e) {
2214
2280
  console.error('runNodeJobDirectly failed', e);
package/renderer/media.js CHANGED
@@ -648,6 +648,39 @@ async function restartJob(nodeId) {
648
648
  }
649
649
  }
650
650
 
651
+ // Конвертер full-slug → short-key для UI-кнопок [data-vid-model] / [data-img-model].
652
+ // Старые ноды могли сохранять только g.model (полный slug провайдера),
653
+ // а селектор кнопки сравнивает с short-key (state.videoModel = 'kling-3.0').
654
+ // Без этой конверсии restore модели из ноды ничего не делал, и юзер видел
655
+ // "последний выбранный мной", а не модель ноды.
656
+ const _VIDEO_SLUG_TO_KEY = {
657
+ 'bytedance/seedance-2': 'seedance-2',
658
+ 'bytedance/seedance-2-fast': 'seedance-2-fast',
659
+ 'kwaivgi/kling-o1': 'kling-o1',
660
+ 'kling-3.0/video': 'kling-3.0',
661
+ };
662
+ const _IMAGE_SLUG_TO_KEY = {
663
+ 'nano-banana-2': 'nano-banana-2',
664
+ 'nano-banana-pro': 'nano-banana-pro',
665
+ 'grok-imagine/text-to-image': 'grok',
666
+ 'seedream/4.5-text-to-image': 'seedream',
667
+ 'seedream/5-lite-text-to-image': 'seedream-5-lite',
668
+ 'gpt-image-2-text-to-image': 'gpt-image-2',
669
+ 'gpt-image/1.5-text-to-image': 'gpt-image-1.5',
670
+ 'flux/schnell': 'flux-schnell',
671
+ 'sdxl/lightning': 'sdxl-lightning',
672
+ };
673
+ function _shortVideoModelFromGen(g) {
674
+ if (g.modelKey) return g.modelKey;
675
+ if (g.model && _VIDEO_SLUG_TO_KEY[g.model]) return _VIDEO_SLUG_TO_KEY[g.model];
676
+ return null;
677
+ }
678
+ function _shortImageModelFromGen(g) {
679
+ if (g.modelKey) return g.modelKey;
680
+ if (g.model && _IMAGE_SLUG_TO_KEY[g.model]) return _IMAGE_SLUG_TO_KEY[g.model];
681
+ return null;
682
+ }
683
+
651
684
  async function regenerateNode(node) {
652
685
  if (node.status === 'generating') return;
653
686
  const g = node.generated || {};
@@ -742,23 +775,33 @@ async function regenerateNode(node) {
742
775
 
743
776
  $('ttsModelRow').style.display = state.genKind === 'audio' ? '' : 'none';
744
777
 
745
- if (g.modelKey && state.genKind === 'image') {
746
- state.imageModel = g.modelKey;
747
- document.querySelectorAll('#genModal [data-img-model]').forEach(b =>
748
- b.classList.toggle('active', b.dataset.imgModel === g.modelKey));
749
- }
750
778
  if (state.genKind === 'image') {
779
+ const imgKey = _shortImageModelFromGen(g);
780
+ if (imgKey) state.imageModel = imgKey;
781
+ document.querySelectorAll('#genModal [data-img-model]').forEach(b =>
782
+ b.classList.toggle('active', b.dataset.imgModel === state.imageModel));
751
783
  if (g.aspectRatio) state.imageAspect = g.aspectRatio;
752
784
  syncImageAspectActive();
753
785
  }
754
- // Видео: подставляем сохранённые duration/resolution/aspect для regenerate
786
+ // Видео: подставляем сохранённые duration/resolution/aspect/model для
787
+ // regenerate. Юзер: «если в ноде есть указанные параметры длины видео,
788
+ // модели, ratio — безусловно используй их в диалоге и в самой генерации».
789
+ // Раньше: `if (g.modelKey) state.videoModel = ...` — если у ноды только
790
+ // полный slug (g.model = 'bytedance/seedance-2', а modelKey пустой), мы
791
+ // оставляли state.videoModel = "последнее выбранное юзером". Теперь
792
+ // конвертируем full-slug → short-key через _shortVideoModelFromGen.
793
+ // duration приводим к number — старые ноды могли сохранять строкой.
755
794
  if (state.genKind === 'video') {
756
- if (g.duration) state.videoDuration = g.duration;
795
+ const vidKey = _shortVideoModelFromGen(g);
796
+ if (vidKey) state.videoModel = vidKey;
797
+ if (g.duration != null) state.videoDuration = +g.duration || state.videoDuration;
757
798
  if (g.resolution) state.videoResolution = g.resolution;
758
799
  if (g.aspectRatio) state.videoAspect = g.aspectRatio;
759
- if (g.modelKey) state.videoModel = g.modelKey;
760
800
  syncVideoOptionsActive();
761
801
  syncVideoModelActive();
802
+ console.log('[regenerateNode video] restored from node:',
803
+ { modelKey: state.videoModel, duration: state.videoDuration,
804
+ resolution: state.videoResolution, aspect: state.videoAspect });
762
805
  }
763
806
  if (state.genKind === 'audio') {
764
807
  if (g.ttsModel) state.ttsModel = g.ttsModel;