kingkont 0.7.97 → 0.7.99
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 +1 -1
- package/renderer/board.js +6 -3
- package/renderer/generate.js +47 -13
- package/renderer/settings.js +11 -0
package/package.json
CHANGED
package/renderer/board.js
CHANGED
|
@@ -59,6 +59,12 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
|
+
// Стартуем обновление баланса СРАЗУ (до autoload-блока), потому что
|
|
63
|
+
// openFilm() ниже делает early-return. Если он отрабатывает — следующие
|
|
64
|
+
// строки не выполняются и баланс не обновляется.
|
|
65
|
+
refreshBalance().catch(() => {});
|
|
66
|
+
setInterval(() => { refreshBalance().catch(() => {}); }, 60_000);
|
|
67
|
+
|
|
62
68
|
// Тихий autoload: первый recent с granted-permission (если есть).
|
|
63
69
|
try {
|
|
64
70
|
const recents = await getRecents();
|
|
@@ -76,9 +82,6 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|
|
76
82
|
vlog('err', 'restore failed: ' + (e?.message || e));
|
|
77
83
|
}
|
|
78
84
|
await renderWelcomeRecents();
|
|
79
|
-
// Стартуем обновление баланса. Сразу + каждые 60 сек.
|
|
80
|
-
refreshBalance().catch(() => {});
|
|
81
|
-
setInterval(() => { refreshBalance().catch(() => {}); }, 60_000);
|
|
82
85
|
|
|
83
86
|
// Дабл-клик на логотипе (sidebar или welcome) → открытие окна настроек.
|
|
84
87
|
const openSettingsFromLogo = () => {
|
package/renderer/generate.js
CHANGED
|
@@ -398,6 +398,20 @@ async function openGenModal(kind) {
|
|
|
398
398
|
state.imageAspect = 'source';
|
|
399
399
|
syncImageAspectActive();
|
|
400
400
|
}
|
|
401
|
+
// Для video-из-картинки нет 'source' опции (ratios у video свои), но
|
|
402
|
+
// юзер всё равно ожидает сохранения пропорций. Считаем aspect картинки
|
|
403
|
+
// и выбираем ближайший из видео-списка. localStorage НЕ обновляем —
|
|
404
|
+
// это per-open default, не sticky (следующий open без source вернёт
|
|
405
|
+
// последний явный выбор юзера).
|
|
406
|
+
if (kind === 'video'
|
|
407
|
+
&& state.sourceRef && state.sourceRef.type === 'image' && state.sourceRef.use) {
|
|
408
|
+
computeSourceMediaAspect(VIDEO_ASPECTS).then(asp => {
|
|
409
|
+
if (asp && state.genKind === 'video') {
|
|
410
|
+
state.videoAspect = asp;
|
|
411
|
+
if (typeof syncVideoOptionsActive === 'function') syncVideoOptionsActive();
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
}
|
|
401
415
|
$('genModal').classList.remove('hidden');
|
|
402
416
|
setTimeout(() => $('genPrompt').focus(), 50);
|
|
403
417
|
}
|
|
@@ -825,9 +839,32 @@ document.querySelectorAll('#genModal [data-kind]').forEach(b => {
|
|
|
825
839
|
});
|
|
826
840
|
});
|
|
827
841
|
|
|
842
|
+
// Списки поддерживаемых aspect-ratio для image vs video — не идентичны,
|
|
843
|
+
// потому что у моделей разные ограничения (image поддерживает 3:2/2:3,
|
|
844
|
+
// video — 21:9 ultra-wide). При выводе video-из-image выбираем ближайший
|
|
845
|
+
// видео-aspect к natural-aspect'у картинки (см. computeSourceMediaAspect).
|
|
846
|
+
const IMAGE_ASPECTS = [
|
|
847
|
+
{ name: '1:1', v: 1.0 },
|
|
848
|
+
{ name: '16:9', v: 16/9 },
|
|
849
|
+
{ name: '9:16', v: 9/16 },
|
|
850
|
+
{ name: '3:2', v: 3/2 },
|
|
851
|
+
{ name: '2:3', v: 2/3 },
|
|
852
|
+
{ name: '4:3', v: 4/3 },
|
|
853
|
+
{ name: '3:4', v: 3/4 },
|
|
854
|
+
];
|
|
855
|
+
const VIDEO_ASPECTS = [
|
|
856
|
+
{ name: '1:1', v: 1.0 },
|
|
857
|
+
{ name: '16:9', v: 16/9 },
|
|
858
|
+
{ name: '9:16', v: 9/16 },
|
|
859
|
+
{ name: '4:3', v: 4/3 },
|
|
860
|
+
{ name: '3:4', v: 3/4 },
|
|
861
|
+
{ name: '21:9', v: 21/9 },
|
|
862
|
+
];
|
|
863
|
+
|
|
828
864
|
// Вычислить ближайший поддерживаемый aspect ratio из state.sourceRef.
|
|
865
|
+
// opts — список поддерживаемых семейством (image/video).
|
|
829
866
|
// Возвращает строку '16:9' / '1:1' / etc, или null если не удалось.
|
|
830
|
-
async function
|
|
867
|
+
async function computeSourceMediaAspect(opts = IMAGE_ASPECTS) {
|
|
831
868
|
if (!state.sourceRef || state.sourceRef.type !== 'image' || !state.sourceRef.file) return null;
|
|
832
869
|
const handle = state.sourceRef.boardHandle || state.currentBoard?.handle;
|
|
833
870
|
if (!handle) return null;
|
|
@@ -843,24 +880,21 @@ async function computeSourceImageAspect() {
|
|
|
843
880
|
img.src = url;
|
|
844
881
|
});
|
|
845
882
|
if (!dim.w || !dim.h) return null;
|
|
846
|
-
return nearestSupportedAspect(dim.w / dim.h);
|
|
883
|
+
return nearestSupportedAspect(dim.w / dim.h, opts);
|
|
847
884
|
} catch { return null; }
|
|
848
885
|
finally { if (url) URL.revokeObjectURL(url); }
|
|
849
886
|
}
|
|
850
887
|
|
|
851
|
-
//
|
|
888
|
+
// Backward-compat: старое имя computeSourceImageAspect используется в
|
|
889
|
+
// submit-flow image'а. Для image-aspect списка по умолчанию.
|
|
890
|
+
async function computeSourceImageAspect() {
|
|
891
|
+
return computeSourceMediaAspect(IMAGE_ASPECTS);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// Из произвольного ratio выбирает ближайший из переданного списка.
|
|
852
895
|
// Сравнение в логарифмической метрике — справедливо для пропорций
|
|
853
896
|
// (1.5 ↔ 0.667 равноудалены от 1.0).
|
|
854
|
-
function nearestSupportedAspect(ratio) {
|
|
855
|
-
const opts = [
|
|
856
|
-
{ name: '1:1', v: 1.0 },
|
|
857
|
-
{ name: '16:9', v: 16/9 },
|
|
858
|
-
{ name: '9:16', v: 9/16 },
|
|
859
|
-
{ name: '3:2', v: 3/2 },
|
|
860
|
-
{ name: '2:3', v: 2/3 },
|
|
861
|
-
{ name: '4:3', v: 4/3 },
|
|
862
|
-
{ name: '3:4', v: 3/4 },
|
|
863
|
-
];
|
|
897
|
+
function nearestSupportedAspect(ratio, opts = IMAGE_ASPECTS) {
|
|
864
898
|
let best = opts[0];
|
|
865
899
|
let bestDiff = Math.abs(Math.log(ratio / best.v));
|
|
866
900
|
for (const o of opts) {
|
package/renderer/settings.js
CHANGED
|
@@ -678,6 +678,17 @@ async function openGenerateForRef(fromNode, clientX, clientY, forceKind) {
|
|
|
678
678
|
state.imageAspect = 'source';
|
|
679
679
|
syncImageAspectActive();
|
|
680
680
|
}
|
|
681
|
+
// Video-из-картинки: подбираем ближайший видео-aspect к natural-aspect
|
|
682
|
+
// картинки (см. openGenModal для аналогичной логики).
|
|
683
|
+
if (forceKind === 'video'
|
|
684
|
+
&& state.sourceRef && state.sourceRef.type === 'image' && state.sourceRef.use) {
|
|
685
|
+
computeSourceMediaAspect(VIDEO_ASPECTS).then(asp => {
|
|
686
|
+
if (asp && state.genKind === 'video') {
|
|
687
|
+
state.videoAspect = asp;
|
|
688
|
+
if (typeof syncVideoOptionsActive === 'function') syncVideoOptionsActive();
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
}
|
|
681
692
|
|
|
682
693
|
closeMentionPopup();
|
|
683
694
|
$('genModal').classList.remove('hidden');
|