qwen-api-proxy 1.0.12 → 1.0.14

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/src/api/chat.js CHANGED
@@ -33,7 +33,7 @@ let authKeys = null;
33
33
  let browserTokenRateLimited = false;
34
34
  let resolvedDefaultModel = null; // Будет установлен при загрузке моделей
35
35
 
36
- const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
36
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
37
37
 
38
38
  // ─── Page helpers ────────────────────────────────────────────────────────────
39
39
 
@@ -114,7 +114,7 @@ export const pagePool = {
114
114
 
115
115
  releasePage(page) {
116
116
  try {
117
- if (page.isClosed()) return;
117
+ if (page.isClosed()) {return;}
118
118
  } catch { return; }
119
119
 
120
120
  const baseContext = getBrowserContext();
@@ -126,14 +126,14 @@ export const pagePool = {
126
126
  if (this.pages.length < this.maxSize) {
127
127
  this.pages.push(page);
128
128
  } else {
129
- page.close().catch(e => logError('Ошибка при закрытии страницы', e));
129
+ page.close().catch((e) => logError('Ошибка при закрытии страницы', e));
130
130
  }
131
131
  },
132
132
 
133
133
  async clear() {
134
134
  const baseContext = getBrowserContext();
135
135
  for (const page of this.pages) {
136
- if (page === baseContext) continue;
136
+ if (page === baseContext) {continue;}
137
137
  try { await page.close(); } catch (e) {
138
138
  logError('Ошибка при закрытии страницы в пуле', e);
139
139
  }
@@ -171,7 +171,7 @@ export async function pollTaskStatus(taskId, page, token, maxAttempts = TASK_POL
171
171
 
172
172
  if (!result.success) {
173
173
  logWarn(`Ошибка при проверке статуса (попытка ${attempt}/${maxAttempts}): ${result.error}`);
174
- if (attempt < maxAttempts) await delay(interval);
174
+ if (attempt < maxAttempts) {await delay(interval);}
175
175
  continue;
176
176
  }
177
177
 
@@ -189,10 +189,10 @@ export async function pollTaskStatus(taskId, page, token, maxAttempts = TASK_POL
189
189
  return { success: false, status: 'failed', error: taskData.error || taskData.message || 'Task failed', data: taskData };
190
190
  }
191
191
 
192
- if (attempt < maxAttempts) await delay(interval);
192
+ if (attempt < maxAttempts) {await delay(interval);}
193
193
  } catch (error) {
194
194
  logError(`Ошибка при опросе задачи (попытка ${attempt}/${maxAttempts})`, error);
195
- if (attempt < maxAttempts) await delay(interval);
195
+ if (attempt < maxAttempts) {await delay(interval);}
196
196
  }
197
197
  }
198
198
 
@@ -203,7 +203,7 @@ export async function pollTaskStatus(taskId, page, token, maxAttempts = TASK_POL
203
203
  // ─── Token extraction ────────────────────────────────────────────────────────
204
204
 
205
205
  export async function extractAuthToken(context, forceRefresh = false) {
206
- if (authToken && !forceRefresh) return authToken;
206
+ if (authToken && !forceRefresh) {return authToken;}
207
207
 
208
208
  try {
209
209
  const page = await getPage(context);
@@ -213,7 +213,7 @@ export async function extractAuthToken(context, forceRefresh = false) {
213
213
  await delay(RETRY_DELAY);
214
214
 
215
215
  const newToken = await page.evaluate(() => localStorage.getItem('token'));
216
- if (shouldClosePage) await page.close();
216
+ if (shouldClosePage) {await page.close();}
217
217
 
218
218
  if (newToken) {
219
219
  authToken = newToken;
@@ -224,7 +224,7 @@ export async function extractAuthToken(context, forceRefresh = false) {
224
224
  logError('Токен авторизации не найден в браузере');
225
225
  return null;
226
226
  } catch (error) {
227
- if (shouldClosePage) await page.close().catch(() => { });
227
+ if (shouldClosePage) {await page.close().catch(() => { });}
228
228
  throw error;
229
229
  }
230
230
  } catch (error) {
@@ -248,7 +248,7 @@ export async function fetchModelsFromAPI() {
248
248
  if (!MODELS_API_URL.includes('?')) {
249
249
  // Qwen API использует limit для пагинации
250
250
  const params = new URLSearchParams({
251
- limit: '1000' // Максимальное количество моделей
251
+ limit: '1000' // Максимальное количество моделей
252
252
  });
253
253
  modelsUrl = `${MODELS_API_URL}?${params.toString()}`;
254
254
  logDebug(`URL с параметрами пагинации: ${modelsUrl}`);
@@ -311,13 +311,13 @@ export async function fetchModelsFromAPI() {
311
311
  logDebug(`Извлечены модели: data.models (${data.models.length} элементов)`);
312
312
  } else {
313
313
  logWarn(`⚠️ Не удалось распознать формат ответа API. Keys: ${Object.keys(data).join(', ')}`);
314
- logWarn(`Полный JSON ответ от API:`);
314
+ logWarn('Полный JSON ответ от API:');
315
315
  logWarn(JSON.stringify(data, null, 2));
316
316
  }
317
317
 
318
318
  // Извлекаем ID моделей
319
- const modelIds = models.map(m => {
320
- if (typeof m === 'string') return m;
319
+ const modelIds = models.map((m) => {
320
+ if (typeof m === 'string') {return m;}
321
321
  return m.id || m.model_id || m.name;
322
322
  }).filter(Boolean);
323
323
 
@@ -396,7 +396,7 @@ export async function ensureModelsLoaded() {
396
396
  modelsLoadedFromAPI = true;
397
397
  logInfo(`✅ Загружено ${apiModels.length} моделей с Qwen API`);
398
398
  logInfo('===== ДОСТУПНЫЕ МОДЕЛИ (API) =====');
399
- apiModels.forEach(m => logInfo(`- ${m}`));
399
+ apiModels.forEach((m) => logInfo(`- ${m}`));
400
400
  logInfo('===================================');
401
401
 
402
402
  // Устанавливаем default model как первую из API, если не задана в .env
@@ -414,7 +414,7 @@ export async function ensureModelsLoaded() {
414
414
  logDebug(`loadModelsFromFile вернул: ${fileModels ? fileModels.length + ' моделей' : 'null'}`);
415
415
  return fileModels;
416
416
  } catch (error) {
417
- logError(`❌ Ошибка загрузки моделей из API`, error);
417
+ logError('❌ Ошибка загрузки моделей из API', error);
418
418
  logWarn('⚠️ Используем резервный список из AvailableModels.txt');
419
419
  const fileModels = loadModelsFromFile();
420
420
  logDebug(`loadModelsFromFile (catch) вернул: ${fileModels ? fileModels.length + ' моделей' : 'null'}`);
@@ -447,8 +447,8 @@ function loadModelsFromFile() {
447
447
 
448
448
  const models = fileContent
449
449
  .split('\n')
450
- .map(l => l.trim())
451
- .filter(l => l && !l.startsWith('#'));
450
+ .map((l) => l.trim())
451
+ .filter((l) => l && !l.startsWith('#'));
452
452
 
453
453
  logDebug(`Распознано моделей: ${models.length}`);
454
454
 
@@ -457,7 +457,7 @@ function loadModelsFromFile() {
457
457
  modelsLoadedFromAPI = false;
458
458
 
459
459
  logInfo('===== ДОСТУПНЫЕ МОДЕЛИ (ФАЙЛ) =====');
460
- models.forEach(m => logInfo(`- ${m}`));
460
+ models.forEach((m) => logInfo(`- ${m}`));
461
461
  logInfo('====================================');
462
462
 
463
463
  // Устанавливаем default model как первую из файла, если не задана в .env
@@ -471,7 +471,7 @@ function loadModelsFromFile() {
471
471
 
472
472
  return models;
473
473
  } catch (error) {
474
- logError(`❌ Ошибка при чтении файла с моделями`, error);
474
+ logError('❌ Ошибка при чтении файла с моделями', error);
475
475
  const fallback = resolvedDefaultModel ? [resolvedDefaultModel] : [getActiveModel()];
476
476
  logDebug(`Fallback модели после ошибки: ${fallback.join(', ')}`);
477
477
  return fallback;
@@ -493,7 +493,7 @@ export function getAvailableModelsFromFile() {
493
493
  function getAuthKeysFromFile() {
494
494
  try {
495
495
  if (!fs.existsSync(AUTH_KEYS_FILE)) {
496
- const template = `# Файл API-ключей для прокси\n# --------------------------------------------\n# В этом файле перечислены токены, которые\n# прокси будет считать «действительными».\n# Один ключ — одна строка без пробелов.\n#\n# 1) Хотите ОТКЛЮЧИТЬ авторизацию целиком?\n# Оставьте файл пустым — сервер перестанет\n# проверять заголовок Authorization.\n#\n# 2) Хотите разрешить доступ нескольким людям?\n# Впишите каждый ключ в отдельной строке:\n# d35ab3e1-a6f9-4d...\n# f2b1cd9c-1b2e-4a...\n#\n# Пустые строки и строки, начинающиеся с «#»,\n# игнорируются.`;
496
+ const template = '# Файл API-ключей для прокси\n# --------------------------------------------\n# В этом файле перечислены токены, которые\n# прокси будет считать «действительными».\n# Один ключ — одна строка без пробелов.\n#\n# 1) Хотите ОТКЛЮЧИТЬ авторизацию целиком?\n# Оставьте файл пустым — сервер перестанет\n# проверять заголовок Authorization.\n#\n# 2) Хотите разрешить доступ нескольким людям?\n# Впишите каждый ключ в отдельной строке:\n# d35ab3e1-a6f9-4d...\n# f2b1cd9c-1b2e-4a...\n#\n# Пустые строки и строки, начинающиеся с «#»,\n# игнорируются.';
497
497
  try {
498
498
  fs.writeFileSync(AUTH_KEYS_FILE, template, { encoding: 'utf8', flag: 'wx' });
499
499
  logInfo(`Создан шаблон файла ключей: ${AUTH_KEYS_FILE}`);
@@ -504,8 +504,8 @@ function getAuthKeysFromFile() {
504
504
  }
505
505
  return fs.readFileSync(AUTH_KEYS_FILE, 'utf8')
506
506
  .split('\n')
507
- .map(l => l.trim())
508
- .filter(l => l && !l.startsWith('#'));
507
+ .map((l) => l.trim())
508
+ .filter((l) => l && !l.startsWith('#'));
509
509
  } catch (error) {
510
510
  logError('Ошибка при чтении файла с ключами авторизации', error);
511
511
  return [];
@@ -513,7 +513,7 @@ function getAuthKeysFromFile() {
513
513
  }
514
514
 
515
515
  export function isValidModel(modelName) {
516
- if (!availableModels) availableModels = getAvailableModelsFromFile();
516
+ if (!availableModels) {availableModels = getAvailableModelsFromFile();}
517
517
  return availableModels.includes(modelName);
518
518
  }
519
519
 
@@ -523,9 +523,9 @@ export function getDefaultModel() {
523
523
  }
524
524
 
525
525
  export function getAllModels() {
526
- if (!availableModels) availableModels = getAvailableModelsFromFile();
526
+ if (!availableModels) {availableModels = getAvailableModelsFromFile();}
527
527
  return {
528
- models: availableModels.map(model => ({
528
+ models: availableModels.map((model) => ({
529
529
  id: model,
530
530
  name: model,
531
531
  description: `Модель ${model}`
@@ -534,7 +534,7 @@ export function getAllModels() {
534
534
  }
535
535
 
536
536
  export function getApiKeys() {
537
- if (!authKeys) authKeys = getAuthKeysFromFile();
537
+ if (!authKeys) {authKeys = getAuthKeysFromFile();}
538
538
  return authKeys;
539
539
  }
540
540
 
@@ -544,14 +544,14 @@ function validateAndPrepareMessage(message) {
544
544
  if (message === null || message === undefined) {
545
545
  return { error: 'Сообщение не может быть пустым' };
546
546
  }
547
- if (typeof message === 'string') return { content: message };
547
+ if (typeof message === 'string') {return { content: message };}
548
548
  if (Array.isArray(message)) {
549
- const isValid = message.every(item =>
549
+ const isValid = message.every((item) =>
550
550
  (item.type === 'text' && typeof item.text === 'string') ||
551
551
  (item.type === 'image' && typeof item.image === 'string') ||
552
552
  (item.type === 'file' && typeof item.file === 'string')
553
553
  );
554
- if (!isValid) return { error: 'Некорректная структура составного сообщения' };
554
+ if (!isValid) {return { error: 'Некорректная структура составного сообщения' };}
555
555
  return { content: message };
556
556
  }
557
557
  return { error: 'Неподдерживаемый формат сообщения' };
@@ -620,7 +620,7 @@ async function resolveAuthToken(browserContext) {
620
620
  if (!getAuthenticationStatus()) {
621
621
  logInfo('Проверка авторизации...');
622
622
  const authCheck = await checkAuthentication(browserContext);
623
- if (!authCheck) return null;
623
+ if (!authCheck) {return null;}
624
624
  }
625
625
 
626
626
  if (!authToken) {
@@ -674,7 +674,7 @@ function buildPayloadV2(messageContent, model, chatId, parentId, files, systemMe
674
674
  timestamp: Math.floor(Date.now() / 1000)
675
675
  };
676
676
 
677
- if (size) payload.size = size;
677
+ if (size) {payload.size = size;}
678
678
 
679
679
  if (systemMessage) {
680
680
  payload.system_message = systemMessage;
@@ -721,8 +721,8 @@ function parseNonSseCompletionBody(body) {
721
721
 
722
722
  async function executeApiRequestWithNodeStreaming(apiUrl, payload, token, onChunk) {
723
723
  try {
724
- if (!token) return { success: false, error: 'Токен авторизации не найден' };
725
- if (typeof fetch !== 'function') return { success: false, error: 'Fetch API is unavailable' };
724
+ if (!token) {return { success: false, error: 'Токен авторизации не найден' };}
725
+ if (typeof fetch !== 'function') {return { success: false, error: 'Fetch API is unavailable' };}
726
726
 
727
727
  const response = await fetchWithQwenProxy(apiUrl, {
728
728
  method: 'POST',
@@ -770,7 +770,7 @@ async function executeApiRequestWithNodeStreaming(apiUrl, payload, token, onChun
770
770
 
771
771
  while (!finished) {
772
772
  const { done, value } = await reader.read();
773
- if (done) break;
773
+ if (done) {break;}
774
774
 
775
775
  buffer += decoder.decode(value, { stream: true });
776
776
  const lines = buffer.split('\n');
@@ -778,10 +778,10 @@ async function executeApiRequestWithNodeStreaming(apiUrl, payload, token, onChun
778
778
 
779
779
  for (const rawLine of lines) {
780
780
  const line = rawLine.trim();
781
- if (!line || !line.startsWith('data:')) continue;
781
+ if (!line || !line.startsWith('data:')) {continue;}
782
782
 
783
783
  const jsonStr = line.substring(5).trim();
784
- if (!jsonStr) continue;
784
+ if (!jsonStr) {continue;}
785
785
  if (jsonStr === '[DONE]') {
786
786
  finished = true;
787
787
  break;
@@ -801,8 +801,8 @@ async function executeApiRequestWithNodeStreaming(apiUrl, payload, token, onChun
801
801
  break;
802
802
  }
803
803
 
804
- if (chunk['response.created']) responseId = chunk['response.created'].response_id;
805
- if (chunk.response_id) responseId = chunk.response_id;
804
+ if (chunk['response.created']) {responseId = chunk['response.created'].response_id;}
805
+ if (chunk.response_id) {responseId = chunk.response_id;}
806
806
 
807
807
  if (chunk.choices && chunk.choices[0]) {
808
808
  const delta = chunk.choices[0].delta;
@@ -813,11 +813,11 @@ async function executeApiRequestWithNodeStreaming(apiUrl, payload, token, onChun
813
813
  hasStreamedChunks = true;
814
814
  }
815
815
  }
816
- if (delta && delta.status === 'finished') finished = true;
817
- if (chunk.choices[0].finish_reason) finished = true;
816
+ if (delta && delta.status === 'finished') {finished = true;}
817
+ if (chunk.choices[0].finish_reason) {finished = true;}
818
818
  }
819
819
 
820
- if (chunk.usage) usage = chunk.usage;
820
+ if (chunk.usage) {usage = chunk.usage;}
821
821
  } catch {
822
822
  // Ignore broken chunks, keep reading stream.
823
823
  }
@@ -872,7 +872,7 @@ async function executeApiRequest(page, apiUrl, payload, token, onChunk = null) {
872
872
  return page.evaluate(async (data) => {
873
873
  try {
874
874
  const t = data.token;
875
- if (!t) return { success: false, error: 'Токен авторизации не найден' };
875
+ if (!t) {return { success: false, error: 'Токен авторизации не найден' };}
876
876
 
877
877
  const response = await fetch(data.apiUrl, {
878
878
  method: 'POST',
@@ -936,15 +936,15 @@ async function executeApiRequest(page, apiUrl, payload, token, onChunk = null) {
936
936
 
937
937
  while (!finished) {
938
938
  const { done, value } = await reader.read();
939
- if (done) break;
939
+ if (done) {break;}
940
940
  buffer += decoder.decode(value, { stream: true });
941
941
  const lines = buffer.split('\n');
942
942
  buffer = lines.pop() || '';
943
943
 
944
944
  for (const line of lines) {
945
- if (!line.trim() || !line.startsWith('data: ')) continue;
945
+ if (!line.trim() || !line.startsWith('data: ')) {continue;}
946
946
  const jsonStr = line.substring(6).trim();
947
- if (!jsonStr) continue;
947
+ if (!jsonStr) {continue;}
948
948
  try {
949
949
  const chunk = JSON.parse(jsonStr);
950
950
 
@@ -959,13 +959,13 @@ async function executeApiRequest(page, apiUrl, payload, token, onChunk = null) {
959
959
  break;
960
960
  }
961
961
 
962
- if (chunk['response.created']) responseId = chunk['response.created'].response_id;
962
+ if (chunk['response.created']) {responseId = chunk['response.created'].response_id;}
963
963
  if (chunk.choices && chunk.choices[0]) {
964
964
  const delta = chunk.choices[0].delta;
965
- if (delta && delta.content) fullContent += delta.content;
966
- if (delta && delta.status === 'finished') finished = true;
965
+ if (delta && delta.content) {fullContent += delta.content;}
966
+ if (delta && delta.status === 'finished') {finished = true;}
967
967
  }
968
- if (chunk.usage) usage = chunk.usage;
968
+ if (chunk.usage) {usage = chunk.usage;}
969
969
  } catch { /* ignore parse errors for individual chunks */ }
970
970
  }
971
971
  }
@@ -1005,10 +1005,10 @@ async function handleApiError(response, tokenObj, message, model, chatId, parent
1005
1005
  logError(`Ошибка при получении ответа: ${errorMessage}`);
1006
1006
 
1007
1007
  // Логируем дополнительную информацию для отладки
1008
- if (response.status) logDebug(`HTTP статус: ${response.status}`);
1009
- if (response.errorBody) logDebug(`Тело ответа с ошибкой: ${response.errorBody.substring(0, 500)}${response.errorBody.length > 500 ? '...' : ''}`);
1010
- if (response.error) logDebug(`Ошибка из response: ${response.error}`);
1011
- if (response.statusText) logDebug(`StatusText: ${response.statusText}`);
1008
+ if (response.status) {logDebug(`HTTP статус: ${response.status}`);}
1009
+ if (response.errorBody) {logDebug(`Тело ответа с ошибкой: ${response.errorBody.substring(0, 500)}${response.errorBody.length > 500 ? '...' : ''}`);}
1010
+ if (response.error) {logDebug(`Ошибка из response: ${response.error}`);}
1011
+ if (response.statusText) {logDebug(`StatusText: ${response.statusText}`);}
1012
1012
  logDebug(`Полный объект ответа: ${JSON.stringify(response, null, 2).substring(0, 1000)}`);
1013
1013
 
1014
1014
  if (response.html && response.html.includes('Verification')) {
@@ -1085,7 +1085,7 @@ async function handleApiError(response, tokenObj, message, model, chatId, parent
1085
1085
  // ─── Main public API ─────────────────────────────────────────────────────────
1086
1086
 
1087
1087
  export async function sendMessage(message, model = null, chatId = null, parentId = null, files = null, tools = null, toolChoice = null, systemMessage = null, chatType = 't2t', size = null, waitForCompletion = true, retryCount = 0, onChunk = null) {
1088
- if (!availableModels) availableModels = getAvailableModelsFromFile();
1088
+ if (!availableModels) {availableModels = getAvailableModelsFromFile();}
1089
1089
 
1090
1090
  if (!chatId) {
1091
1091
  const newChatResult = await createChatV2(model);
@@ -1119,10 +1119,10 @@ export async function sendMessage(message, model = null, chatId = null, parentId
1119
1119
  }
1120
1120
 
1121
1121
  const browserContext = getBrowserContext();
1122
- if (!browserContext) return { error: 'Браузер не инициализирован', chatId };
1122
+ if (!browserContext) {return { error: 'Браузер не инициализирован', chatId };}
1123
1123
 
1124
1124
  const tokenObj = await resolveAuthToken(browserContext);
1125
- if (!tokenObj) return { error: 'Ошибка авторизации: не удалось получить токен', chatId };
1125
+ if (!tokenObj) {return { error: 'Ошибка авторизации: не удалось получить токен', chatId };}
1126
1126
 
1127
1127
  let page = null;
1128
1128
  try {
@@ -1136,7 +1136,7 @@ export async function sendMessage(message, model = null, chatId = null, parentId
1136
1136
  if (!authToken) {
1137
1137
  logWarn('Токен отсутствует перед отправкой запроса');
1138
1138
  authToken = await page.evaluate(() => localStorage.getItem('token'));
1139
- if (!authToken) return { error: 'Токен авторизации не найден. Требуется перезапуск в ручном режиме.', chatId };
1139
+ if (!authToken) {return { error: 'Токен авторизации не найден. Требуется перезапуск в ручном режиме.', chatId };}
1140
1140
  saveAuthToken(authToken);
1141
1141
  }
1142
1142
 
@@ -1245,15 +1245,15 @@ export async function sendMessage(message, model = null, chatId = null, parentId
1245
1245
 
1246
1246
  function extractTaskId(data) {
1247
1247
  const firstMsg = data.data?.messages?.[0];
1248
- if (firstMsg?.extra?.wanx?.task_id) return firstMsg.extra.wanx.task_id;
1248
+ if (firstMsg?.extra?.wanx?.task_id) {return firstMsg.extra.wanx.task_id;}
1249
1249
  return data.id || data.task_id || data.response_id || data.data?.message_id || null;
1250
1250
  }
1251
1251
 
1252
1252
  function extractVideoUrl(taskData) {
1253
- if (taskData.content) return taskData.content;
1254
- if (typeof taskData.result === 'string') return taskData.result;
1255
- if (taskData.result?.url) return taskData.result.url;
1256
- if (taskData.result?.video_url) return taskData.result.video_url;
1253
+ if (taskData.content) {return taskData.content;}
1254
+ if (typeof taskData.result === 'string') {return taskData.result;}
1255
+ if (taskData.result?.url) {return taskData.result.url;}
1256
+ if (taskData.result?.video_url) {return taskData.result.video_url;}
1257
1257
  return null;
1258
1258
  }
1259
1259
 
@@ -1269,7 +1269,7 @@ export function getAuthToken() {
1269
1269
 
1270
1270
  export async function createChatV2(model = getDefaultModel(), title = 'Новый чат', retryCount = 0) {
1271
1271
  const browserContext = getBrowserContext();
1272
- if (!browserContext) return { error: 'Браузер не инициализирован' };
1272
+ if (!browserContext) {return { error: 'Браузер не инициализирован' };}
1273
1273
 
1274
1274
  // Используем безопасный токен
1275
1275
  const tokenObj = await getSafeToken(TOKEN_EXPIRY_WARNING_MS);
@@ -1291,7 +1291,7 @@ export async function createChatV2(model = getDefaultModel(), title = 'Новы
1291
1291
  if (!authToken) {
1292
1292
  logInfo('Получение токена авторизации для создания чата...');
1293
1293
  authToken = await extractAuthToken(browserContext);
1294
- if (!authToken) return { error: 'Не удалось получить токен авторизации' };
1294
+ if (!authToken) {return { error: 'Не удалось получить токен авторизации' };}
1295
1295
  }
1296
1296
 
1297
1297
  let page = null;
@@ -1308,7 +1308,7 @@ export async function createChatV2(model = getDefaultModel(), title = 'Новы
1308
1308
  headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${data.token}` },
1309
1309
  body: JSON.stringify(data.payload)
1310
1310
  });
1311
- if (response.ok) return { success: true, data: await response.json() };
1311
+ if (response.ok) {return { success: true, data: await response.json() };}
1312
1312
  return { success: false, status: response.status, errorBody: await response.text() };
1313
1313
  } catch (error) {
1314
1314
  return { success: false, error: error.toString() };
@@ -1349,7 +1349,7 @@ export async function createChatV2(model = getDefaultModel(), title = 'Новы
1349
1349
 
1350
1350
  export async function testToken(token) {
1351
1351
  const browserContext = getBrowserContext();
1352
- if (!browserContext) return 'ERROR';
1352
+ if (!browserContext) {return 'ERROR';}
1353
1353
 
1354
1354
  let page;
1355
1355
  let shouldClosePage = false;
@@ -1377,16 +1377,16 @@ export async function testToken(token) {
1377
1377
  }
1378
1378
  }, requestBody);
1379
1379
 
1380
- if (result.ok || result.status === 400) return 'OK';
1381
- if (result.status === 401 || result.status === 403) return 'UNAUTHORIZED';
1382
- if (result.status === 429) return 'RATELIMIT';
1380
+ if (result.ok || result.status === 400) {return 'OK';}
1381
+ if (result.status === 401 || result.status === 403) {return 'UNAUTHORIZED';}
1382
+ if (result.status === 429) {return 'RATELIMIT';}
1383
1383
  return 'ERROR';
1384
1384
  } catch (e) {
1385
1385
  logError('testToken error', e);
1386
1386
  return 'ERROR';
1387
1387
  } finally {
1388
1388
  if (page) {
1389
- try { if (shouldClosePage) await page.close(); } catch { }
1389
+ try { if (shouldClosePage) {await page.close();} } catch { }
1390
1390
  }
1391
1391
  }
1392
1392
  }
@@ -157,9 +157,9 @@ export function addUserMessage(chatId, content) {
157
157
  let contentDesc;
158
158
  if (Array.isArray(content)) {
159
159
  // Составное сообщение (текст + изображения)
160
- const textParts = content.filter(item => item.type === 'text');
161
- const imageParts = content.filter(item => item.type === 'image');
162
- const fileParts = content.filter(item => item.type === 'file');
160
+ const textParts = content.filter((item) => item.type === 'text');
161
+ const imageParts = content.filter((item) => item.type === 'image');
162
+ const fileParts = content.filter((item) => item.type === 'file');
163
163
 
164
164
  contentDesc = `составное сообщение (${textParts.length} текст., ${imageParts.length} изобр., ${fileParts.length} файл.)`;
165
165
  } else if (typeof content === 'object' && content !== null) {
@@ -170,10 +170,10 @@ export function addUserMessage(chatId, content) {
170
170
 
171
171
  const message = {
172
172
  id: messageId,
173
- role: "user",
173
+ role: 'user',
174
174
  content: content,
175
175
  timestamp: timestamp,
176
- chat_type: "t2t"
176
+ chat_type: 't2t'
177
177
  };
178
178
 
179
179
  logInfo(`Добавление сообщения пользователя в чат ${chatId}: ${contentDesc}`);
@@ -186,11 +186,11 @@ export function addAssistantMessage(chatId, content, info = {}) {
186
186
 
187
187
  const message = {
188
188
  id: messageId,
189
- role: "assistant",
189
+ role: 'assistant',
190
190
  content: content,
191
191
  timestamp: timestamp,
192
192
  info: info,
193
- chat_type: "t2t"
193
+ chat_type: 't2t'
194
194
  };
195
195
 
196
196
  logInfo(`Добавление ответа ассистента в чат ${chatId}, длина: ${content.length}`);
@@ -225,8 +225,8 @@ export function getAllChats() {
225
225
 
226
226
  let convertedCount = 0;
227
227
  const chats = files
228
- .filter(file => file.endsWith('.json'))
229
- .map(file => {
228
+ .filter((file) => file.endsWith('.json'))
229
+ .map((file) => {
230
230
  const chatId = file.replace('.json', '');
231
231
  const chatData = loadHistory(chatId);
232
232
 
@@ -240,7 +240,7 @@ export function getAllChats() {
240
240
  created: chatData.created || 0,
241
241
  messageCount: chatData.messages ? chatData.messages.length : 0,
242
242
  userMessageCount: chatData.messages ?
243
- chatData.messages.filter(m => m.role === 'user').length : 0
243
+ chatData.messages.filter((m) => m.role === 'user').length : 0
244
244
  };
245
245
  });
246
246
 
@@ -285,24 +285,24 @@ export function deleteChatsAutomatically(criteria = {}) {
285
285
  // Фильтрация по возрасту (в миллисекундах)
286
286
  if (olderThan) {
287
287
  const cutoffTime = Date.now() - olderThan;
288
- const oldChatsCount = chatsToDelete.filter(chat => chat.created < cutoffTime).length;
288
+ const oldChatsCount = chatsToDelete.filter((chat) => chat.created < cutoffTime).length;
289
289
  logInfo(`Чатов старше ${olderThan}мс (${new Date(cutoffTime).toLocaleString()}): ${oldChatsCount}`);
290
- chatsToDelete = chatsToDelete.filter(chat => chat.created < cutoffTime);
290
+ chatsToDelete = chatsToDelete.filter((chat) => chat.created < cutoffTime);
291
291
  }
292
292
 
293
293
  if (userMessageCountLessThan !== undefined) {
294
- const lowUserMsgChatsCount = chatsToDelete.filter(chat =>
294
+ const lowUserMsgChatsCount = chatsToDelete.filter((chat) =>
295
295
  chat.userMessageCount < userMessageCountLessThan).length;
296
296
  logInfo(`Чатов с менее чем ${userMessageCountLessThan} сообщений пользователя: ${lowUserMsgChatsCount}`);
297
- chatsToDelete = chatsToDelete.filter(chat =>
297
+ chatsToDelete = chatsToDelete.filter((chat) =>
298
298
  chat.userMessageCount < userMessageCountLessThan);
299
299
  }
300
300
 
301
301
  if (messageCountLessThan !== undefined) {
302
- const lowMsgChatsCount = chatsToDelete.filter(chat =>
302
+ const lowMsgChatsCount = chatsToDelete.filter((chat) =>
303
303
  chat.messageCount < messageCountLessThan).length;
304
304
  logInfo(`Чатов с менее чем ${messageCountLessThan} сообщений всего: ${lowMsgChatsCount}`);
305
- chatsToDelete = chatsToDelete.filter(chat =>
305
+ chatsToDelete = chatsToDelete.filter((chat) =>
306
306
  chat.messageCount < messageCountLessThan);
307
307
  }
308
308
 
@@ -311,8 +311,8 @@ export function deleteChatsAutomatically(criteria = {}) {
311
311
  const sortedChats = [...chats].sort((a, b) => a.created - b.created);
312
312
  const oldestChats = sortedChats.slice(0, chats.length - maxChats);
313
313
 
314
- oldestChats.forEach(chat => {
315
- if (!chatsToDelete.some(c => c.id === chat.id)) {
314
+ oldestChats.forEach((chat) => {
315
+ if (!chatsToDelete.some((c) => c.id === chat.id)) {
316
316
  chatsToDelete.push(chat);
317
317
  }
318
318
  });
@@ -341,4 +341,4 @@ export function deleteChatsAutomatically(criteria = {}) {
341
341
  error: error.message
342
342
  };
343
343
  }
344
- }
344
+ }