kingkont 0.20.0 → 0.20.2

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 CHANGED
@@ -86,6 +86,11 @@ const CHATIUM_IMAGE_MODELS = {
86
86
  'grok': 'grok-imagine/text-to-image',
87
87
  'grok-i2i': 'grok-imagine/image-to-image',
88
88
  'seedream-5-lite': 'bytedance/seedream-5-lite',
89
+ // OpenAI gpt-image-2 — Chatium proxy поддерживает (проверено через
90
+ // probe). image-to-image вариант под отдельным slug, переключаем
91
+ // в startGeneration при наличии imageInputs.
92
+ // (gpt-image/1.5 НЕ доступен через Chatium — только KIE.)
93
+ 'gpt-image-2': 'gpt-image-2-text-to-image',
89
94
  };
90
95
  const CHATIUM_VIDEO_MODELS = {
91
96
  'seedance-2': 'bytedance/seedance-2',
@@ -304,7 +309,15 @@ async function startGeneration(args) {
304
309
  const kieAvailable = s.useKie && process.env.KIE_API_KEY;
305
310
  const kieSupportsModel = !!kieMap[kieKey];
306
311
 
307
- if (kieAvailable && kieSupportsModel) {
312
+ // gpt-image-2 — приоритет Chatium (биллинг через kingkont credits,
313
+ // юзеру одна точка оплаты). KIE — fallback если Chatium недоступен
314
+ // или не поддерживает модель (например gpt-image-1.5).
315
+ const chatiumAvailable = s.useChatium && s.chatium?.token && s.chatium?.base;
316
+ const chatiumMap = kind === 'video' ? CHATIUM_VIDEO_MODELS : CHATIUM_IMAGE_MODELS;
317
+ const isGptImage = kind === 'image' && (kieKey === 'gpt-image-2' || kieKey === 'gpt-image-1.5');
318
+ if (isGptImage && chatiumAvailable && chatiumMap[kieKey]) {
319
+ // → Chatium-путь ниже (skip KIE).
320
+ } else if (kieAvailable && kieSupportsModel) {
308
321
  return await _startGenerationViaKie({ kind, prompt, key: kieKey, imageInputs, videoInputs, aspectRatio, resolution, duration, quality });
309
322
  }
310
323
 
@@ -324,8 +337,14 @@ async function startGeneration(args) {
324
337
  body = { prompt, model: fullModel, imageInputs, videoInputs, firstFrame, lastFrame, aspectRatio, resolution, duration };
325
338
  } else {
326
339
  const isSeedream = fullModel.includes('seedream');
340
+ const isGptImage = fullModel.startsWith('gpt-image');
341
+ // gpt-image-2 — auto-switch на image-to-image вариант если есть refs.
342
+ let actualModel = fullModel;
343
+ if (isGptImage && imageInputs?.length) {
344
+ actualModel = 'gpt-image-2-image-to-image';
345
+ }
327
346
  body = {
328
- prompt, model: fullModel, aspectRatio, resolution,
347
+ prompt, model: actualModel, aspectRatio, resolution,
329
348
  outputFormat: isSeedream ? 'jpeg' : 'jpg',
330
349
  };
331
350
  if (quality) body.quality = quality; // 'low' | 'medium' | 'high' — модель сама решит как мапить
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kingkont",
3
- "version": "0.20.0",
3
+ "version": "0.20.2",
4
4
  "description": "KingKont · Chatium — нод-редактор сцен с AI-генерацией (картинки/видео/голос/SFX/музыка/текст)",
5
5
  "main": "main.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -623,7 +623,13 @@ async function serveStatic(res, url) {
623
623
  // Router
624
624
  // =============================================================================
625
625
 
626
- const server = createServer(async (req, res) => {
626
+ // Главный request-handler. Выделен из createServer чтобы start() мог
627
+ // создавать СВЕЖИЙ server на каждый retry — раньше глобальный server
628
+ // шарился между attempt'ами, и при EADDRINUSE на Windows несколько
629
+ // pending listen() callbacks в итоге фаерились (когда порт освобождался)
630
+ // → wsHub.attach вызывался N раз → multiple WebSocketServer на одном
631
+ // upgrade event → "handleUpgrade called more than once" uncaughtException.
632
+ async function _requestHandler(req, res) {
627
633
  const url = new URL(req.url, `http://${req.headers.host}`);
628
634
  try {
629
635
  if (req.method === 'POST' && url.pathname === '/api/generate') return handleGenerate(req, res);
@@ -686,7 +692,7 @@ const server = createServer(async (req, res) => {
686
692
  console.error('[error]', e);
687
693
  send(res, 500, { error: e.message || 'server error' });
688
694
  }
689
- });
695
+ }
690
696
 
691
697
  process.on('unhandledRejection', (err) => console.error('[unhandledRejection]', err));
692
698
  process.on('uncaughtException', (err) => console.error('[uncaughtException]', err));
@@ -702,9 +708,16 @@ function start(port = PORT, opts = {}) {
702
708
  // jobsHub нужен settingsGetter чтобы поллить провайдеров (Chatium token,
703
709
  // KIE_API_KEY и т.п.).
704
710
  jobsHub.setSettingsGetter(getSettings);
711
+ // ВАЖНО: createServer на каждый retry. Раньше сервер был module-global
712
+ // и шарился, что приводило к multiple wsHub.attach при port-fallback'е
713
+ // (несколько pending listen() callbacks → multiple WebSocketServer на
714
+ // одном upgrade-event → uncaughtException на первом upgrade).
715
+ const server = createServer(_requestHandler);
705
716
  return new Promise((resolveOk, reject) => {
706
- server.once('error', reject);
717
+ const onError = (err) => { server.removeAllListeners('listening'); reject(err); };
718
+ server.once('error', onError);
707
719
  server.listen(port, () => {
720
+ server.removeListener('error', onError);
708
721
  const addr = server.address();
709
722
  // Attach WebSocket hub поверх того же HTTP-сервера (path /ws).
710
723
  try { wsHub.attach(server); } catch (e) { console.warn('WS attach failed:', e.message); }