kingkont 0.7.19 → 0.7.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.
Files changed (2) hide show
  1. package/index.html +75 -5
  2. package/package.json +1 -1
package/index.html CHANGED
@@ -1343,6 +1343,17 @@
1343
1343
  <button class="seg" data-img-model="sdxl-lightning" type="button" title="Очень быстрая (3-5с)">⚡ SDXL Lightning</button>
1344
1344
  </div>
1345
1345
  </label>
1346
+ <label id="imageOptionsRow">Соотношение сторон
1347
+ <div class="seg-control" id="imageAspectCtl">
1348
+ <button class="seg active" data-img-asp="1:1" type="button">1:1</button>
1349
+ <button class="seg" data-img-asp="16:9" type="button">16:9</button>
1350
+ <button class="seg" data-img-asp="9:16" type="button">9:16</button>
1351
+ <button class="seg" data-img-asp="3:2" type="button">3:2</button>
1352
+ <button class="seg" data-img-asp="2:3" type="button">2:3</button>
1353
+ <button class="seg" data-img-asp="4:3" type="button" title="Не поддерживается Grok">4:3</button>
1354
+ <button class="seg" data-img-asp="3:4" type="button" title="Не поддерживается Grok">3:4</button>
1355
+ </div>
1356
+ </label>
1346
1357
  <label id="videoModelRow" style="display: none;">Модель для видео
1347
1358
  <div class="seg-control">
1348
1359
  <button class="seg active" data-vid-model="seedance-2" type="button" title="ByteDance Seedance 2 — основная">Seedance 2</button>
@@ -1778,6 +1789,7 @@ const state = {
1778
1789
  currentBoard: null, // { kind, name, key, handle, metadata, urls }
1779
1790
  genKind: 'image',
1780
1791
  imageModel: 'nano-banana-2', // 'nano-banana-2' | 'grok' | ...
1792
+ imageAspect: localStorage.getItem('imageAspect') || '1:1', // 1:1 / 16:9 / 9:16 / 3:2 / 2:3 / 4:3 / 3:4
1781
1793
  videoModel: localStorage.getItem('videoModel') || 'seedance-2', // 'seedance-2' | 'kling-o1' | 'kling-3.0' | ...
1782
1794
  ttsModel: localStorage.getItem('ttsModel') || 'qwen/qwen3-tts', // qwen/elevenlabs/v3/minimax/speech-02-hd/gemini
1783
1795
  videoDuration: +(localStorage.getItem('videoDuration') || 5),
@@ -3575,11 +3587,31 @@ async function renderNodeBody(node, body) {
3575
3587
  if (node.status === 'error') {
3576
3588
  const wrap = document.createElement('div');
3577
3589
  wrap.className = 'gen-error';
3578
- wrap.textContent = node.error || 'Ошибка генерации';
3579
- // Если ошибка указывает на отсутствующую авторизацию KingKont — показываем
3580
- // кнопку «Войти», открывающую окно настроек (там Chatium login flow).
3581
3590
  const errStr = String(node.error || '');
3582
- if (/[KК](?:ing|инг)?[Kк]ont|войдите/i.test(errStr) && /KingKont/i.test(errStr)) {
3591
+ const errBlock = document.createElement('div');
3592
+ // Делаем text selectable — для копирования при необходимости.
3593
+ errBlock.style.cssText = 'user-select: text; -webkit-user-select: text; cursor: text; word-break: break-word; margin-bottom: 8px;';
3594
+ errBlock.textContent = errStr || 'Ошибка генерации';
3595
+ wrap.appendChild(errBlock);
3596
+ // Кнопка «Скопировать» — для длинных server-ошибок.
3597
+ if (errStr) {
3598
+ const copyBtn = document.createElement('button');
3599
+ copyBtn.textContent = '📋 Скопировать';
3600
+ copyBtn.style.marginRight = '6px';
3601
+ copyBtn.addEventListener('click', async e => {
3602
+ e.stopPropagation();
3603
+ try {
3604
+ await navigator.clipboard.writeText(errStr);
3605
+ const orig = copyBtn.textContent;
3606
+ copyBtn.textContent = '✓ Скопировано';
3607
+ setTimeout(() => { copyBtn.textContent = orig; }, 1500);
3608
+ } catch {}
3609
+ });
3610
+ wrap.appendChild(copyBtn);
3611
+ }
3612
+ // Кнопка «Войти» — ТОЛЬКО когда сервер прислал 503 «Войдите в KingKont…»
3613
+ // (т.е. реально auth-проблема, а не любая ошибка которая упоминает KingKont).
3614
+ if (/Войдите в KingKont/i.test(errStr)) {
3583
3615
  const loginBtn = document.createElement('button');
3584
3616
  loginBtn.textContent = '🔑 Войти';
3585
3617
  loginBtn.style.marginRight = '6px';
@@ -3846,6 +3878,8 @@ async function openGenerateForRef(fromNode, clientX, clientY, forceKind) {
3846
3878
  document.querySelectorAll('#genModal [data-kind]').forEach(b =>
3847
3879
  b.classList.toggle('active', b.dataset.kind === forceKind));
3848
3880
  $('imageModelRow').style.display = forceKind === 'image' ? '' : 'none';
3881
+
3882
+ $('imageOptionsRow').style.display = forceKind === 'image' ? '' : 'none';
3849
3883
  $('videoOptionsRow').style.display = forceKind === 'video' ? '' : 'none';
3850
3884
 
3851
3885
  $('videoModelRow').style.display = forceKind === 'video' ? '' : 'none';
@@ -5100,6 +5134,8 @@ async function regenerateNode(node) {
5100
5134
  document.querySelectorAll('#genModal [data-kind]').forEach(b =>
5101
5135
  b.classList.toggle('active', b.dataset.kind === state.genKind));
5102
5136
  $('imageModelRow').style.display = state.genKind === 'image' ? '' : 'none';
5137
+
5138
+ $('imageOptionsRow').style.display = state.genKind === 'image' ? '' : 'none';
5103
5139
  $('videoOptionsRow').style.display = state.genKind === 'video' ? '' : 'none';
5104
5140
 
5105
5141
  $('videoModelRow').style.display = state.genKind === 'video' ? '' : 'none';
@@ -5112,6 +5148,10 @@ async function regenerateNode(node) {
5112
5148
  document.querySelectorAll('#genModal [data-img-model]').forEach(b =>
5113
5149
  b.classList.toggle('active', b.dataset.imgModel === g.modelKey));
5114
5150
  }
5151
+ if (state.genKind === 'image') {
5152
+ if (g.aspectRatio) state.imageAspect = g.aspectRatio;
5153
+ syncImageAspectActive();
5154
+ }
5115
5155
  // Видео: подставляем сохранённые duration/resolution/aspect для regenerate
5116
5156
  if (state.genKind === 'video') {
5117
5157
  if (g.duration) state.videoDuration = g.duration;
@@ -6054,6 +6094,8 @@ function openPhraseFor(charInfo) {
6054
6094
  document.querySelectorAll('#genModal [data-kind]').forEach(b =>
6055
6095
  b.classList.toggle('active', b.dataset.kind === 'audio'));
6056
6096
  $('imageModelRow').style.display = 'none';
6097
+
6098
+ $('imageOptionsRow').style.display = 'none';
6057
6099
  $('videoOptionsRow').style.display = 'none';
6058
6100
 
6059
6101
  $('videoModelRow').style.display = 'none';
@@ -6237,6 +6279,8 @@ async function openGenModal(kind) {
6237
6279
  b.classList.toggle('active', b.dataset.kind === kind));
6238
6280
  // Видимость рядов под текущий kind
6239
6281
  $('imageModelRow').style.display = kind === 'image' ? '' : 'none';
6282
+
6283
+ $('imageOptionsRow').style.display = kind === 'image' ? '' : 'none';
6240
6284
  $('videoOptionsRow').style.display = kind === 'video' ? '' : 'none';
6241
6285
 
6242
6286
  $('videoModelRow').style.display = kind === 'video' ? '' : 'none';
@@ -6659,6 +6703,8 @@ document.querySelectorAll('#genModal [data-kind]').forEach(b => {
6659
6703
  b.classList.add('active');
6660
6704
  state.genKind = b.dataset.kind;
6661
6705
  $('imageModelRow').style.display = state.genKind === 'image' ? '' : 'none';
6706
+
6707
+ $('imageOptionsRow').style.display = state.genKind === 'image' ? '' : 'none';
6662
6708
  $('videoOptionsRow').style.display = state.genKind === 'video' ? '' : 'none';
6663
6709
 
6664
6710
  $('videoModelRow').style.display = state.genKind === 'video' ? '' : 'none';
@@ -6933,6 +6979,21 @@ document.querySelectorAll('#genModal [data-vid-model]').forEach(b => {
6933
6979
  localStorage.setItem('videoModel', state.videoModel);
6934
6980
  });
6935
6981
  });
6982
+ // Переключатель aspect ratio для image
6983
+ document.querySelectorAll('#genModal [data-img-asp]').forEach(b => {
6984
+ b.addEventListener('click', () => {
6985
+ document.querySelectorAll('#genModal [data-img-asp]').forEach(x => x.classList.remove('active'));
6986
+ b.classList.add('active');
6987
+ state.imageAspect = b.dataset.imgAsp;
6988
+ localStorage.setItem('imageAspect', state.imageAspect);
6989
+ });
6990
+ });
6991
+ function syncImageAspectActive() {
6992
+ document.querySelectorAll('#genModal [data-img-asp]').forEach(b =>
6993
+ b.classList.toggle('active', b.dataset.imgAsp === state.imageAspect));
6994
+ }
6995
+ syncImageAspectActive();
6996
+
6936
6997
  // Переключатель модели TTS
6937
6998
  document.querySelectorAll('#genModal [data-tts-model]').forEach(b => {
6938
6999
  b.addEventListener('click', () => {
@@ -7209,12 +7270,15 @@ $('genSubmit').addEventListener('click', async () => {
7209
7270
  // Связь с родительской нодой (выведена через "вытягивание"). Хранится
7210
7271
  // даже если sourceRef.use=false в state — сохраняем структурную связь.
7211
7272
  ...(savedSourceRef ? { sourceRef: savedSourceRef } : {}),
7212
- // Параметры видео сохраняем — при regenerate используем те же (предсказуемость).
7273
+ // Параметры видео/картинки сохраняем — при regenerate используем те же.
7213
7274
  ...(kind === 'video' ? {
7214
7275
  duration: state.videoDuration,
7215
7276
  resolution: state.videoResolution,
7216
7277
  aspectRatio: state.videoAspect,
7217
7278
  } : {}),
7279
+ ...(kind === 'image' ? {
7280
+ aspectRatio: state.imageAspect,
7281
+ } : {}),
7218
7282
  },
7219
7283
  };
7220
7284
  if (saveOnly) node.status = 'draft';
@@ -7364,6 +7428,10 @@ async function startGenerationJob(node, kind, prompt, mediaRefs, boardHandle, bK
7364
7428
  submitBody.duration = node.generated?.duration ?? state.videoDuration;
7365
7429
  submitBody.resolution = node.generated?.resolution ?? state.videoResolution;
7366
7430
  submitBody.aspectRatio = node.generated?.aspectRatio ?? state.videoAspect;
7431
+ } else if (kind === 'image') {
7432
+ // Grok-imagine требует aspect_ratio из {2:3, 3:2, 1:1, 9:16, 16:9}.
7433
+ // Остальные модели (nano-banana-2, seedream и др.) тоже принимают.
7434
+ submitBody.aspectRatio = node.generated?.aspectRatio ?? state.imageAspect;
7367
7435
  }
7368
7436
  logJob(node.id, `POST /api/generate body: ${logSafe(submitBody)}`);
7369
7437
  logJob(node.id, `POST /api/generate (image_input=${imageInputs.length}, video_input=${videoInputs.length}, model=${modelKey})`);
@@ -7925,6 +7993,8 @@ async function openGenAudioForTimeline(charInfo, track, time) {
7925
7993
  document.querySelectorAll('#genModal [data-kind]').forEach(b =>
7926
7994
  b.classList.toggle('active', b.dataset.kind === 'audio'));
7927
7995
  $('imageModelRow').style.display = 'none';
7996
+
7997
+ $('imageOptionsRow').style.display = 'none';
7928
7998
  $('videoOptionsRow').style.display = 'none';
7929
7999
 
7930
8000
  $('videoModelRow').style.display = 'none';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.7.19",
3
+ "version": "0.7.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": {