kingkont 0.7.49 → 0.7.51
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/lib/providers.js +43 -9
- package/package.json +1 -1
- package/renderer/board.js +5 -22
- package/skill/SKILL.md +3 -3
package/lib/providers.js
CHANGED
|
@@ -216,8 +216,27 @@ async function startGeneration(args) {
|
|
|
216
216
|
if (kind !== 'image' && kind !== 'video') throw new Error(`unknown kind: ${kind}`);
|
|
217
217
|
if (!prompt && kind !== 'video') throw new Error('prompt обязателен');
|
|
218
218
|
|
|
219
|
+
// Приоритет провайдеров:
|
|
220
|
+
// 1) KIE — если useKie=true И KIE_API_KEY И модель поддерживается KIE
|
|
221
|
+
// (юзер явно включил прямой коннектор → используем его, экономим
|
|
222
|
+
// Chatium-кредиты).
|
|
223
|
+
// 2) Chatium — fallback, либо если модель не входит в KIE (kling-3.0,
|
|
224
|
+
// veo-3.1, runway и т.д.).
|
|
225
|
+
// 3) Если ни один не доступен — ошибка.
|
|
226
|
+
const kieMap = kind === 'video' ? KIE_VIDEO_MODELS : KIE_IMAGE_MODELS;
|
|
227
|
+
const kieKey = modelKey || (kind === 'video' ? 'seedance-2' : 'nano-banana-2');
|
|
228
|
+
const kieAvailable = s.useKie && process.env.KIE_API_KEY;
|
|
229
|
+
const kieSupportsModel = !!kieMap[kieKey];
|
|
230
|
+
|
|
231
|
+
if (kieAvailable && kieSupportsModel) {
|
|
232
|
+
return await _startGenerationViaKie({ kind, prompt, key: kieKey, imageInputs, videoInputs, aspectRatio, resolution, duration });
|
|
233
|
+
}
|
|
234
|
+
|
|
219
235
|
// Chatium-путь.
|
|
220
236
|
if (s.useChatium && s.chatium?.token && s.chatium?.base) {
|
|
237
|
+
if (kieAvailable && !kieSupportsModel) {
|
|
238
|
+
console.warn(`[providers] KIE включен, но не поддерживает "${kieKey}" → fallback на KingKont`);
|
|
239
|
+
}
|
|
221
240
|
const map = kind === 'video' ? CHATIUM_VIDEO_MODELS : CHATIUM_IMAGE_MODELS;
|
|
222
241
|
const fullModel = resolveModel(map, modelKey, kind === 'video' ? 'bytedance/seedance-2-fast' : 'nano-banana-2');
|
|
223
242
|
if (!fullModel) {
|
|
@@ -241,14 +260,19 @@ async function startGeneration(args) {
|
|
|
241
260
|
return { taskId: 'chatium:' + taskId, provider: 'kingkont' };
|
|
242
261
|
}
|
|
243
262
|
|
|
244
|
-
//
|
|
245
|
-
if (
|
|
246
|
-
throw new Error(
|
|
247
|
-
? 'Войдите в KingKont или KIE для видео.'
|
|
248
|
-
: 'Войдите в KingKont или KIE для картинок.');
|
|
263
|
+
// Ни один провайдер не доступен.
|
|
264
|
+
if (s.useKie && !process.env.KIE_API_KEY) {
|
|
265
|
+
throw new Error('KIE включён, но KIE_API_KEY не задан в настройках.');
|
|
249
266
|
}
|
|
267
|
+
throw new Error(kind === 'video'
|
|
268
|
+
? 'Войдите в KingKont или KIE для видео.'
|
|
269
|
+
: 'Войдите в KingKont или KIE для картинок.');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Внутренний helper: KIE-путь startGeneration. Вынесен чтобы не дублировать
|
|
273
|
+
// логику между «KIE первичный» и старым «KIE fallback».
|
|
274
|
+
async function _startGenerationViaKie({ kind, prompt, key, imageInputs, videoInputs, aspectRatio, resolution, duration }) {
|
|
250
275
|
const map = kind === 'video' ? KIE_VIDEO_MODELS : KIE_IMAGE_MODELS;
|
|
251
|
-
const key = modelKey || (kind === 'video' ? 'seedance-2' : 'nano-banana-2');
|
|
252
276
|
const fullModel = map[key];
|
|
253
277
|
if (!fullModel) throw new Error(`unknown ${kind} model: ${key}`);
|
|
254
278
|
|
|
@@ -364,7 +388,13 @@ async function waitForGeneration(taskId, settings, opts = {}) {
|
|
|
364
388
|
async function generateText({ prompt, model = 'anthropic/claude-sonnet-4', system, images, settings: s }) {
|
|
365
389
|
if (!prompt) throw new Error('нужен prompt');
|
|
366
390
|
|
|
367
|
-
|
|
391
|
+
// Приоритет: OpenRouter direct (если useOpenrouter+key) → Chatium → ошибка.
|
|
392
|
+
// Юзер явно включил прямой коннектор → используем его (Chatium-кредиты
|
|
393
|
+
// не тратим). OpenRouter принимает все те же model-slugs что Chatium-text
|
|
394
|
+
// (anthropic/claude-sonnet-4, openai/gpt-4o, google/gemini-..., etc.).
|
|
395
|
+
const directOpenrouter = s.useOpenrouter && process.env.OPENROUTER_API_KEY;
|
|
396
|
+
|
|
397
|
+
if (s.useChatium && s.chatium?.token && s.chatium?.base && !directOpenrouter) {
|
|
368
398
|
const body = {
|
|
369
399
|
prompt, model, system,
|
|
370
400
|
images: Array.isArray(images) ? images.filter(i => i?.url) : undefined,
|
|
@@ -379,9 +409,13 @@ async function generateText({ prompt, model = 'anthropic/claude-sonnet-4', syste
|
|
|
379
409
|
};
|
|
380
410
|
}
|
|
381
411
|
|
|
382
|
-
if (!
|
|
412
|
+
if (!directOpenrouter) {
|
|
413
|
+
if (s.useOpenrouter && !process.env.OPENROUTER_API_KEY) {
|
|
414
|
+
throw new Error('OpenRouter включён, но OPENROUTER_API_KEY не задан в настройках.');
|
|
415
|
+
}
|
|
416
|
+
throw new Error('Войдите в KingKont или OpenRouter для генерации текста.');
|
|
417
|
+
}
|
|
383
418
|
const key = process.env.OPENROUTER_API_KEY;
|
|
384
|
-
if (!key) throw new Error('OPENROUTER_API_KEY не задан');
|
|
385
419
|
|
|
386
420
|
const messages = [];
|
|
387
421
|
if (system) messages.push({ role: 'system', content: system });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kingkont",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.51",
|
|
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": {
|
package/renderer/board.js
CHANGED
|
@@ -1136,19 +1136,14 @@ async function selectBoard(board) {
|
|
|
1136
1136
|
|
|
1137
1137
|
// =============================================================================
|
|
1138
1138
|
// External file watcher (FSAH polling).
|
|
1139
|
-
// FSAH не имеет нативного file-watch API — поллим scene.json's lastModified
|
|
1140
|
-
// Если mtime новее чем lastDiskMtime (который мы
|
|
1141
|
-
// write) — кто-то правил scene.json извне.
|
|
1139
|
+
// FSAH не имеет нативного file-watch API — поллим scene.json's lastModified
|
|
1140
|
+
// раз в EXTERNAL_POLL_MS. Если mtime новее чем lastDiskMtime (который мы
|
|
1141
|
+
// обновляем при каждом своём write) — кто-то правил scene.json извне.
|
|
1142
1142
|
// • dirty=false → тихо перечитать и перерендерить
|
|
1143
1143
|
// • dirty=true → confirm() «перечитать с диска? текущие правки утеряются»
|
|
1144
|
-
//
|
|
1145
|
-
// Интервал адаптивный: когда окно в фокусе — 300мс (юзер видит изменения
|
|
1146
|
-
// от skill/CLI почти моментально, прогрессивно: добавил ноду — увидел).
|
|
1147
|
-
// Когда вкладка скрыта — 3 сек (экономим CPU, юзер всё равно не смотрит).
|
|
1148
1144
|
// =============================================================================
|
|
1149
1145
|
|
|
1150
|
-
const
|
|
1151
|
-
const EXTERNAL_POLL_MS_HIDDEN = 3000;
|
|
1146
|
+
const EXTERNAL_POLL_MS = 3000;
|
|
1152
1147
|
let _externalWatchTimer = null;
|
|
1153
1148
|
let _externalReloadInFlight = false;
|
|
1154
1149
|
|
|
@@ -1163,23 +1158,11 @@ function stopExternalWatcher() {
|
|
|
1163
1158
|
if (_externalWatchTimer) { clearInterval(_externalWatchTimer); _externalWatchTimer = null; }
|
|
1164
1159
|
}
|
|
1165
1160
|
|
|
1166
|
-
function _currentPollInterval() {
|
|
1167
|
-
return document.hidden ? EXTERNAL_POLL_MS_HIDDEN : EXTERNAL_POLL_MS_ACTIVE;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
1161
|
function startExternalWatcher() {
|
|
1171
1162
|
stopExternalWatcher();
|
|
1172
|
-
_externalWatchTimer = setInterval(checkExternalChanges,
|
|
1163
|
+
_externalWatchTimer = setInterval(checkExternalChanges, EXTERNAL_POLL_MS);
|
|
1173
1164
|
}
|
|
1174
1165
|
|
|
1175
|
-
// При смене visibility пересоздаём timer с новым интервалом.
|
|
1176
|
-
document.addEventListener('visibilitychange', () => {
|
|
1177
|
-
if (_externalWatchTimer) {
|
|
1178
|
-
stopExternalWatcher();
|
|
1179
|
-
_externalWatchTimer = setInterval(checkExternalChanges, _currentPollInterval());
|
|
1180
|
-
}
|
|
1181
|
-
});
|
|
1182
|
-
|
|
1183
1166
|
async function checkExternalChanges() {
|
|
1184
1167
|
if (_externalReloadInFlight) return;
|
|
1185
1168
|
if (!state.currentBoard?.handle) { stopExternalWatcher(); return; }
|
package/skill/SKILL.md
CHANGED
|
@@ -152,9 +152,9 @@ kingkont gen <project> <board> --kind=text --name=name \
|
|
|
152
152
|
|
|
153
153
|
## ⚠️ Изменения визуально — добавляй ноды по одной
|
|
154
154
|
|
|
155
|
-
Если открыто приложение KingKont, оно поллит `scene.json` каждые
|
|
155
|
+
Если открыто приложение KingKont, оно поллит `scene.json` каждые 3 сек
|
|
156
156
|
и автоматически перерисовывает холст когда обнаруживает внешнюю правку.
|
|
157
|
-
Это значит **юзер видит каждую новую ноду
|
|
157
|
+
Это значит **юзер видит каждую новую ноду в течение нескольких секунд**.
|
|
158
158
|
|
|
159
159
|
Поэтому когда нужно добавить несколько нод — **не батчи их в один скрипт**,
|
|
160
160
|
запускай `kingkont add-node` (или `gen`) по одной команде за раз. Между
|
|
@@ -163,7 +163,7 @@ kingkont gen <project> <board> --kind=text --name=name \
|
|
|
163
163
|
✅ Хорошо (юзер видит появление каждой ноды):
|
|
164
164
|
```bash
|
|
165
165
|
kingkont add-node <project> <board> --kind=text --name=intro --text="..."
|
|
166
|
-
# (юзер видит ноду на холсте
|
|
166
|
+
# (юзер видит ноду на холсте в течение нескольких секунд)
|
|
167
167
|
kingkont add-node <project> <board> --kind=text --name=dialog --text="..."
|
|
168
168
|
# (видит вторую)
|
|
169
169
|
kingkont add-node <project> <board> --kind=text --name=outro --text="..."
|