qwen-api-proxy 1.0.11 → 1.0.13
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/README.md +7 -5
- package/bin/qwen-api-proxy.js +64 -53
- package/index.js +106 -20
- package/package.json +8 -2
- package/src/api/chat.js +71 -71
- package/src/api/chatHistory.js +19 -19
- package/src/api/fileUpload.js +23 -23
- package/src/api/imageGeneration.js +23 -23
- package/src/api/modelMapping.js +145 -153
- package/src/api/routes.js +148 -148
- package/src/api/tokenManager.js +93 -93
- package/src/browser/auth.js +13 -13
- package/src/browser/browser.js +9 -9
- package/src/browser/session.js +3 -3
- package/src/config.js +4 -4
- package/src/utils/accountSetup.js +14 -14
- package/src/utils/botSettings.js +14 -14
- package/src/utils/permissionChecker.js +157 -157
- package/src/utils/prompt.js +1 -1
- package/src/utils/proxy.js +11 -11
- package/src/utils/telegramBot.js +656 -654
- package/src/utils/telegramNotifier.js +7 -7
package/src/api/fileUpload.js
CHANGED
|
@@ -14,7 +14,7 @@ const DOCUMENT_FILE_TYPE = 'document';
|
|
|
14
14
|
|
|
15
15
|
function validateBrowserContext() {
|
|
16
16
|
const browserContext = getBrowserContext();
|
|
17
|
-
if (!browserContext) throw new Error('Браузер не инициализирован');
|
|
17
|
+
if (!browserContext) {throw new Error('Браузер не инициализирован');}
|
|
18
18
|
return browserContext;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -29,7 +29,7 @@ async function validateAuthToken(browserContext) {
|
|
|
29
29
|
if (!token) {
|
|
30
30
|
logInfo('Токен авторизации не найден в памяти, пытаемся извлечь из браузера');
|
|
31
31
|
token = await extractAuthToken(browserContext);
|
|
32
|
-
if (!token) throw new Error('Не удалось получить токен авторизации');
|
|
32
|
+
if (!token) {throw new Error('Не удалось получить токен авторизации');}
|
|
33
33
|
}
|
|
34
34
|
return token;
|
|
35
35
|
}
|
|
@@ -49,7 +49,7 @@ export async function getStsToken(fileInfo) {
|
|
|
49
49
|
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${data.token}`, 'Accept': 'application/json' },
|
|
50
50
|
body: JSON.stringify(data.fileInfo)
|
|
51
51
|
});
|
|
52
|
-
if (response.ok) return { success: true, data: await response.json() };
|
|
52
|
+
if (response.ok) {return { success: true, data: await response.json() };}
|
|
53
53
|
return { success: false, status: response.status, statusText: response.statusText, errorBody: await response.text() };
|
|
54
54
|
} catch (error) { return { success: false, error: error.toString() }; }
|
|
55
55
|
}, { apiUrl: STS_TOKEN_API_URL, token, fileInfo });
|
|
@@ -78,9 +78,9 @@ export async function uploadFile(filePath, stsData) {
|
|
|
78
78
|
throw new Error('Некорректные или неполные данные STS токена');
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
logInfo(
|
|
81
|
+
logInfo('[OSS] Загрузка через браузер');
|
|
82
82
|
logInfo(`[OSS] Регион: ${stsData.region}, Бакет: ${stsData.bucketname}`);
|
|
83
|
-
if (stsData.endpoint) logInfo(`[OSS] Endpoint: ${stsData.endpoint}`);
|
|
83
|
+
if (stsData.endpoint) {logInfo(`[OSS] Endpoint: ${stsData.endpoint}`);}
|
|
84
84
|
logInfo(`[OSS] File path: ${stsData.file_path}`);
|
|
85
85
|
logInfo(`[OSS] File URL: ${stsData.file_url}`);
|
|
86
86
|
|
|
@@ -104,11 +104,11 @@ export async function uploadFile(filePath, stsData) {
|
|
|
104
104
|
});
|
|
105
105
|
console.log('[OSS] SDK загружен успешно');
|
|
106
106
|
}
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
console.log('[OSS] Создание Blob из файла...');
|
|
109
|
-
const blob = new Blob([Uint8Array.from(atob(data.fileBase64), c => c.charCodeAt(0))]);
|
|
109
|
+
const blob = new Blob([Uint8Array.from(atob(data.fileBase64), (c) => c.charCodeAt(0))]);
|
|
110
110
|
console.log(`[OSS] Blob создан, размер: ${blob.size} байт`);
|
|
111
|
-
|
|
111
|
+
|
|
112
112
|
console.log('[OSS] Создание OSS клиента...');
|
|
113
113
|
const client = new window.OSS({
|
|
114
114
|
region: data.stsData.region,
|
|
@@ -118,16 +118,16 @@ export async function uploadFile(filePath, stsData) {
|
|
|
118
118
|
bucket: data.stsData.bucketname,
|
|
119
119
|
secure: true
|
|
120
120
|
});
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
console.log(`[OSS] Загрузка файла в OSS: ${data.stsData.file_path}`);
|
|
123
123
|
await client.put(data.stsData.file_path, blob);
|
|
124
124
|
console.log('[OSS] Файл успешно загружен');
|
|
125
|
-
|
|
125
|
+
|
|
126
126
|
return { success: true };
|
|
127
|
-
} catch (error) {
|
|
127
|
+
} catch (error) {
|
|
128
128
|
console.error(`[OSS Browser] Ошибка: ${error.toString()}`);
|
|
129
129
|
console.error(`[OSS Browser] Stack: ${error.stack || 'N/A'}`);
|
|
130
|
-
return { success: false, error: error.toString() };
|
|
130
|
+
return { success: false, error: error.toString() };
|
|
131
131
|
}
|
|
132
132
|
}, {
|
|
133
133
|
fileBase64,
|
|
@@ -136,7 +136,7 @@ export async function uploadFile(filePath, stsData) {
|
|
|
136
136
|
});
|
|
137
137
|
|
|
138
138
|
if (result.success) {
|
|
139
|
-
logInfo(
|
|
139
|
+
logInfo('[OSS] Загрузка завершена успешно');
|
|
140
140
|
return { success: true, fileName: path.basename(filePath), url: stsData.file_url, fileId: stsData.file_id, filePath: stsData.file_path };
|
|
141
141
|
}
|
|
142
142
|
logError(`[OSS] Ошибка загрузки: ${result.error}`);
|
|
@@ -151,27 +151,27 @@ export async function uploadFile(filePath, stsData) {
|
|
|
151
151
|
|
|
152
152
|
export async function uploadFileToQwen(filePath) {
|
|
153
153
|
try {
|
|
154
|
-
if (!fs.existsSync(filePath)) throw new Error(`Файл не найден: ${filePath}`);
|
|
154
|
+
if (!fs.existsSync(filePath)) {throw new Error(`Файл не найден: ${filePath}`);}
|
|
155
155
|
|
|
156
156
|
const fileName = path.basename(filePath);
|
|
157
157
|
const fileSize = fs.statSync(filePath).size;
|
|
158
158
|
const fileExt = path.extname(fileName).toLowerCase();
|
|
159
159
|
|
|
160
160
|
let fileType = DEFAULT_FILE_TYPE;
|
|
161
|
-
if (IMAGE_EXTENSIONS.includes(fileExt)) fileType = IMAGE_FILE_TYPE;
|
|
162
|
-
else if (DOCUMENT_EXTENSIONS.includes(fileExt)) fileType = DOCUMENT_FILE_TYPE;
|
|
161
|
+
if (IMAGE_EXTENSIONS.includes(fileExt)) {fileType = IMAGE_FILE_TYPE;}
|
|
162
|
+
else if (DOCUMENT_EXTENSIONS.includes(fileExt)) {fileType = DOCUMENT_FILE_TYPE;}
|
|
163
163
|
|
|
164
164
|
logInfo(`📤 Загрузка файла в Qwen: ${fileName} (${fileSize} байт, тип: ${fileType})`);
|
|
165
|
-
|
|
165
|
+
|
|
166
166
|
const fileInfo = { filename: fileName, filesize: fileSize, filetype: fileType };
|
|
167
167
|
const stsData = await getStsToken(fileInfo);
|
|
168
|
-
|
|
169
|
-
logInfo(
|
|
170
|
-
|
|
168
|
+
|
|
169
|
+
logInfo('✅ STS токен получен, начинаем загрузку в OSS');
|
|
170
|
+
|
|
171
171
|
const uploadResult = await uploadFile(filePath, stsData);
|
|
172
|
-
|
|
173
|
-
logInfo(
|
|
174
|
-
|
|
172
|
+
|
|
173
|
+
logInfo('✅ Файл успешно загружен в Qwen');
|
|
174
|
+
|
|
175
175
|
return { ...uploadResult, fileInfo, stsData };
|
|
176
176
|
} catch (error) {
|
|
177
177
|
logError(`❌ Ошибка в процессе загрузки файла: ${error.message}`, error);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// imageGeneration.js - Модуль для генерации изображений через Qwen Image API
|
|
2
2
|
import axios from 'axios';
|
|
3
|
-
import { logInfo, logError, logDebug } from '../logger/index.js';
|
|
3
|
+
import { logInfo, logError, logDebug, logWarn } from '../logger/index.js';
|
|
4
4
|
import { sendMessage } from './chat.js';
|
|
5
5
|
import { uploadFileToQwen } from './fileUpload.js';
|
|
6
6
|
import { IMAGE_GENERATION_MODE, DASHSCOPE_API_KEY } from '../config.js';
|
|
@@ -27,7 +27,7 @@ const IMAGE_GENERATION_MODELS = [
|
|
|
27
27
|
export async function generateImage(prompt, model = 'qwen-image-plus', options = {}) {
|
|
28
28
|
// Определяем режим генерации
|
|
29
29
|
const mode = IMAGE_GENERATION_MODE;
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
if (mode === 'browser') {
|
|
32
32
|
logInfo('🎨 Генерация изображения через browser mode...');
|
|
33
33
|
return generateImageViaBrowser(prompt, model, options);
|
|
@@ -42,7 +42,7 @@ export async function generateImage(prompt, model = 'qwen-image-plus', options =
|
|
|
42
42
|
*/
|
|
43
43
|
async function generateImageViaDashScope(prompt, model = 'qwen-image-plus', options = {}) {
|
|
44
44
|
const apiKey = process.env.DASHSCOPE_API_KEY;
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
if (!apiKey) {
|
|
47
47
|
logError('API ключ DASHSCOPE_API_KEY не установлен');
|
|
48
48
|
return {
|
|
@@ -71,17 +71,17 @@ async function generateImageViaDashScope(prompt, model = 'qwen-image-plus', opti
|
|
|
71
71
|
// Если есть изображение для image-to-image
|
|
72
72
|
if (options.imagePath) {
|
|
73
73
|
logInfo(`📸 Image-to-image mode: загружаем файл ${options.imagePath}`);
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
// Загружаем файл в Qwen и получаем URL
|
|
76
76
|
const uploadResult = await uploadFileToQwen(options.imagePath);
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
// Проверяем успешность загрузки
|
|
79
79
|
if (!uploadResult || uploadResult.success === false) {
|
|
80
80
|
const errorMsg = uploadResult?.error || 'Unknown error';
|
|
81
81
|
logError(`❌ Ошибка загрузки файла: ${errorMsg}`);
|
|
82
82
|
throw new Error(`Не удалось загрузить изображение: ${errorMsg}`);
|
|
83
83
|
}
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
if (uploadResult.file_url || uploadResult.url) {
|
|
86
86
|
const fileUrl = uploadResult.file_url || uploadResult.url;
|
|
87
87
|
logInfo(`✅ Файл загружен: ${fileUrl}`);
|
|
@@ -94,7 +94,7 @@ async function generateImageViaDashScope(prompt, model = 'qwen-image-plus', opti
|
|
|
94
94
|
|
|
95
95
|
// Асинхронный запрос для Wan моделей
|
|
96
96
|
const isWanModel = model.startsWith('wan');
|
|
97
|
-
const endpoint = isWanModel
|
|
97
|
+
const endpoint = isWanModel
|
|
98
98
|
? `${DASHSCOPE_API_BASE}/services/aigc/text2image/image-synthesis`
|
|
99
99
|
: `${DASHSCOPE_API_BASE}/services/aigc/text2image/image-synthesis`;
|
|
100
100
|
|
|
@@ -154,17 +154,17 @@ async function generateImageViaBrowser(prompt, model = 'qwen-image-plus', option
|
|
|
154
154
|
let files = null;
|
|
155
155
|
if (options.imagePath) {
|
|
156
156
|
logInfo(`📸 Image-to-image mode: загружаем файл ${options.imagePath}`);
|
|
157
|
-
|
|
157
|
+
|
|
158
158
|
// Загружаем файл в Qwen и получаем URL
|
|
159
159
|
const uploadResult = await uploadFileToQwen(options.imagePath);
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
// Проверяем успешность загрузки
|
|
162
162
|
if (!uploadResult || uploadResult.success === false) {
|
|
163
163
|
const errorMsg = uploadResult?.error || 'Unknown error';
|
|
164
164
|
logError(`❌ Ошибка загрузки файла: ${errorMsg}`);
|
|
165
165
|
throw new Error(`Не удалось загрузить изображение: ${errorMsg}`);
|
|
166
166
|
}
|
|
167
|
-
|
|
167
|
+
|
|
168
168
|
if (uploadResult.file_url || uploadResult.url) {
|
|
169
169
|
const fileUrl = uploadResult.file_url || uploadResult.url;
|
|
170
170
|
logInfo(`✅ Файл загружен: ${fileUrl}`);
|
|
@@ -202,7 +202,7 @@ async function generateImageViaBrowser(prompt, model = 'qwen-image-plus', option
|
|
|
202
202
|
|
|
203
203
|
// Извлекаем URL изображения из ответа
|
|
204
204
|
let imageUrl = null;
|
|
205
|
-
|
|
205
|
+
|
|
206
206
|
// Проверяем разные форматы ответа
|
|
207
207
|
if (result.imageUrl) {
|
|
208
208
|
imageUrl = result.imageUrl;
|
|
@@ -232,15 +232,15 @@ async function generateImageViaBrowser(prompt, model = 'qwen-image-plus', option
|
|
|
232
232
|
if (!imageUrl) {
|
|
233
233
|
logError('❌ URL изображения не найден в ответе');
|
|
234
234
|
logDebug('Response:', JSON.stringify(result, null, 2));
|
|
235
|
-
|
|
235
|
+
|
|
236
236
|
// Логируем структуру ошибки для отладки
|
|
237
|
-
if (result.error) logDebug('result.error exists:', JSON.stringify(result.error));
|
|
238
|
-
if (result.errorBody) logDebug('result.errorBody exists:', result.errorBody.substring(0, 200));
|
|
239
|
-
if (result.details) logDebug('result.details exists:', result.details.substring(0, 200));
|
|
240
|
-
|
|
237
|
+
if (result.error) {logDebug('result.error exists:', JSON.stringify(result.error));}
|
|
238
|
+
if (result.errorBody) {logDebug('result.errorBody exists:', result.errorBody.substring(0, 200));}
|
|
239
|
+
if (result.details) {logDebug('result.details exists:', result.details.substring(0, 200));}
|
|
240
|
+
|
|
241
241
|
// Проверяем, есть ли в ответе реальная ошибка
|
|
242
242
|
let errorMessage = 'Image URL not found in response';
|
|
243
|
-
|
|
243
|
+
|
|
244
244
|
// Проверяем формат ошибки API (прямое поле error)
|
|
245
245
|
if (result.error) {
|
|
246
246
|
// API вернул ошибку
|
|
@@ -325,7 +325,7 @@ async function generateImageViaBrowser(prompt, model = 'qwen-image-plus', option
|
|
|
325
325
|
// Не JSON, оставляем стандартное сообщение
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
|
-
|
|
328
|
+
|
|
329
329
|
return {
|
|
330
330
|
error: errorMessage,
|
|
331
331
|
rawResponse: result
|
|
@@ -398,14 +398,14 @@ async function pollTaskStatus(taskId, apiKey) {
|
|
|
398
398
|
}
|
|
399
399
|
|
|
400
400
|
// PENDING или RUNNING - продолжаем опрос
|
|
401
|
-
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
401
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
402
402
|
|
|
403
403
|
} catch (error) {
|
|
404
404
|
logError(`Ошибка при опросе задачи ${taskId}`, error);
|
|
405
405
|
if (attempt === maxAttempts - 1) {
|
|
406
406
|
return { error: `Ошибка опроса: ${error.message}` };
|
|
407
407
|
}
|
|
408
|
-
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
408
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
409
409
|
}
|
|
410
410
|
}
|
|
411
411
|
|
|
@@ -426,7 +426,7 @@ export function getAvailableImageModels() {
|
|
|
426
426
|
*/
|
|
427
427
|
export async function checkImageApiAvailability() {
|
|
428
428
|
const mode = IMAGE_GENERATION_MODE;
|
|
429
|
-
|
|
429
|
+
|
|
430
430
|
// Browser mode всегда доступен (если браузер работает)
|
|
431
431
|
if (mode === 'browser') {
|
|
432
432
|
logDebug('🖼️ Browser mode: проверка через статус браузера');
|
|
@@ -435,10 +435,10 @@ export async function checkImageApiAvailability() {
|
|
|
435
435
|
const isAuthenticated = getAuthenticationStatus();
|
|
436
436
|
return !!(browserContext && isAuthenticated);
|
|
437
437
|
}
|
|
438
|
-
|
|
438
|
+
|
|
439
439
|
// DashScope mode: проверяем API ключ
|
|
440
440
|
const apiKey = DASHSCOPE_API_KEY;
|
|
441
|
-
|
|
441
|
+
|
|
442
442
|
if (!apiKey) {
|
|
443
443
|
return false;
|
|
444
444
|
}
|
package/src/api/modelMapping.js
CHANGED
|
@@ -9,182 +9,174 @@ const __dirname = path.dirname(__filename);
|
|
|
9
9
|
const MODELS_FILE = path.join(__dirname, '..', 'AvailableModels.txt');
|
|
10
10
|
|
|
11
11
|
const CANONICAL_MODELS = Object.freeze([
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
12
|
+
'qwen3.5-plus',
|
|
13
|
+
'qwen3.5-397b-a17b',
|
|
14
|
+
'qwen3-max',
|
|
15
|
+
'qwen3-vl-plus',
|
|
16
|
+
'qwen3-coder-plus',
|
|
17
|
+
'qwen3-omni-flash',
|
|
18
|
+
'qwen3-omni-flash-2025-12-01',
|
|
19
|
+
'qwen-max-latest',
|
|
20
|
+
'qwen-plus-2025-09-11',
|
|
21
|
+
'qwen-plus-2025-01-25',
|
|
22
|
+
'qwq-32b',
|
|
23
|
+
'qwen3-235b-a22b',
|
|
24
|
+
'qwen3-30b-a3b',
|
|
25
|
+
'qwen3-coder-30b-a3b-instruct',
|
|
26
|
+
'qwen-turbo-2025-02-11',
|
|
27
|
+
'qwen2.5-omni-7b',
|
|
28
|
+
'qvq-72b-preview-0310',
|
|
29
|
+
'qwen2.5-vl-32b-instruct',
|
|
30
|
+
'qwen2.5-14b-instruct-1m',
|
|
31
|
+
'qwen2.5-coder-32b-instruct',
|
|
32
|
+
'qwen2.5-72b-instruct',
|
|
33
|
+
'qwen3.5-plus',
|
|
34
|
+
'qwen3.5-flash',
|
|
35
|
+
'qwen3.5-397b-a17b',
|
|
36
|
+
'qwen3.5-122b-a10b',
|
|
37
|
+
'qwen3.5-27b',
|
|
38
|
+
'qwen3.5-35b-a3b'
|
|
39
39
|
]);
|
|
40
40
|
|
|
41
41
|
const CANONICAL_MODEL_SET = new Set(CANONICAL_MODELS);
|
|
42
42
|
|
|
43
43
|
const ALIAS_GROUPS = Object.freeze({
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
'qwen3.5-plus': [
|
|
45
|
+
'qwen3.5',
|
|
46
|
+
'Qwen3.5-Plus',
|
|
47
|
+
'qwen3.5-plus-latest'
|
|
48
48
|
],
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
'qwen3-max': [
|
|
50
|
+
'qwen-max',
|
|
51
|
+
'Qwen3-Max',
|
|
52
|
+
'Qwen3-Maximum',
|
|
53
|
+
'qwen3-max-preview',
|
|
54
|
+
'Qwen3-Max-Preview'
|
|
52
55
|
],
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
'qwen3-vl-plus': [
|
|
57
|
+
'qwen-vl',
|
|
58
|
+
'qwen-vl-plus',
|
|
59
|
+
'qwen-vl-plus-latest',
|
|
60
|
+
'qwen-vl-max',
|
|
61
|
+
'qwen-vl-max-latest',
|
|
62
|
+
'Qwen3-VL-235B-A22B',
|
|
63
|
+
'qwen3-vl-235b-a22b'
|
|
59
64
|
],
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
'qwen3-coder-plus': [
|
|
66
|
+
'qwen3-coder',
|
|
67
|
+
'qwen-coder-plus',
|
|
68
|
+
'qwen-coder-plus-latest',
|
|
69
|
+
'Qwen3-Coder-Plus',
|
|
70
|
+
'qwen2.5-coder-3b-instruct',
|
|
71
|
+
'qwen2.5-coder-1.5b-instruct',
|
|
72
|
+
'qwen2.5-coder-0.5b-instruct',
|
|
73
|
+
'Qwen3-Coder'
|
|
68
74
|
],
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"qwen2.5-coder-1.5b-instruct",
|
|
76
|
-
"qwen2.5-coder-0.5b-instruct",
|
|
77
|
-
"Qwen3-Coder"
|
|
75
|
+
'qwen3-omni-flash': [
|
|
76
|
+
'qwen3-omni',
|
|
77
|
+
'qwen3-omni-latest',
|
|
78
|
+
'Qwen3-omni-flash',
|
|
79
|
+
'Qwen3-Omni-Flash',
|
|
80
|
+
'Qwen3-Omni'
|
|
78
81
|
],
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"qwen3-omni-latest",
|
|
82
|
-
"Qwen3-omni-flash",
|
|
83
|
-
"Qwen3-Omni-Flash",
|
|
84
|
-
"Qwen3-Omni"
|
|
82
|
+
'qwen3-omni-flash-2025-12-01': [
|
|
83
|
+
'Qwen3-Omni-Flash-2025-12-01'
|
|
85
84
|
],
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
'qwen-plus-2025-09-11': [
|
|
86
|
+
'qwen-plus',
|
|
87
|
+
'qwen-plus-latest',
|
|
88
|
+
'Qwen3-Next',
|
|
89
|
+
'Qwen3-Next-80B-A3B',
|
|
90
|
+
'qwen3-next',
|
|
91
|
+
'qwen3-next-80b-a3b'
|
|
88
92
|
],
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
'qwen3-235b-a22b': [
|
|
94
|
+
'qwen3',
|
|
95
|
+
'qwen-3',
|
|
96
|
+
'qwen3-235b',
|
|
97
|
+
'Qwen3-235B-A22B',
|
|
98
|
+
'Qwen3-235B-A22B-2507',
|
|
99
|
+
'qwen3-235b-a22b-2507'
|
|
96
100
|
],
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
"qwen3-235b-a22b-2507"
|
|
101
|
+
'qwen3-30b-a3b': [
|
|
102
|
+
'qwen3-plus',
|
|
103
|
+
'qwen3-30b',
|
|
104
|
+
'Qwen3-30B-A3B',
|
|
105
|
+
'Qwen3-30B-A3B-2507',
|
|
106
|
+
'qwen3-30b-a3b-2507'
|
|
104
107
|
],
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"qwen3-30b-a3b-2507"
|
|
108
|
+
'qwen3-coder-30b-a3b-instruct': [
|
|
109
|
+
'qwen3-coder-flash',
|
|
110
|
+
'Qwen3-Coder-Flash',
|
|
111
|
+
'qwen3-coder-30b',
|
|
112
|
+
'Qwen3-Coder-30B-A3B-Instruct'
|
|
111
113
|
],
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
"qwen3-coder-30b",
|
|
116
|
-
"Qwen3-Coder-30B-A3B-Instruct"
|
|
114
|
+
'qwen-max-latest': [
|
|
115
|
+
'Qwen2.5-Max',
|
|
116
|
+
'qwen2.5-max'
|
|
117
117
|
],
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
'qwen-plus-2025-01-25': [
|
|
119
|
+
'Qwen2.5-Plus',
|
|
120
|
+
'qwen2.5-plus'
|
|
121
121
|
],
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
'qwq-32b': [
|
|
123
|
+
'qwq',
|
|
124
|
+
'QwQ-32B',
|
|
125
|
+
'qwq-32b-preview'
|
|
125
126
|
],
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
'qwen-turbo-2025-02-11': [
|
|
128
|
+
'qwen-turbo',
|
|
129
|
+
'qwen-turbo-latest',
|
|
130
|
+
'Qwen2.5-Turbo'
|
|
130
131
|
],
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
'qwen2.5-omni-7b': [
|
|
133
|
+
'qwen2.5-omni',
|
|
134
|
+
'Qwen2.5-Omni-7B',
|
|
135
|
+
'qwen-omni-7b'
|
|
135
136
|
],
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
'qvq-72b-preview-0310': [
|
|
138
|
+
'qvq',
|
|
139
|
+
'QVQ-Max',
|
|
140
|
+
'qvq-72b'
|
|
140
141
|
],
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
"qvq-72b"
|
|
142
|
+
'qwen2.5-vl-32b-instruct': [
|
|
143
|
+
'qwen2.5-vl',
|
|
144
|
+
'Qwen2.5-VL-32B-Instruct'
|
|
145
145
|
],
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
'qwen2.5-14b-instruct-1m': [
|
|
147
|
+
'qwen2.5-14b',
|
|
148
|
+
'qwen2.5-coder-14b-instruct',
|
|
149
|
+
'Qwen2.5-14B-Instruct-1M'
|
|
149
150
|
],
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
'qwen2.5-coder-32b-instruct': [
|
|
152
|
+
'qwen2.5-coder',
|
|
153
|
+
'qwen2.5-coder-plus',
|
|
154
|
+
'Qwen2.5-Coder-32B-Instruct'
|
|
154
155
|
],
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"Qwen2.5-Coder-32B-Instruct"
|
|
156
|
+
'qwen2.5-72b-instruct': [
|
|
157
|
+
'qwen2.5-72b',
|
|
158
|
+
'Qwen2.5-72B-Instruct'
|
|
159
159
|
],
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
'qwen3.5-flash': [
|
|
161
|
+
'qwen3.5-flash-latest',
|
|
162
|
+
'Qwen3.5-Flash'
|
|
163
163
|
],
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
'qwen3.5-397b-a17b': [
|
|
165
|
+
'qwen3.5-397b',
|
|
166
|
+
'Qwen3.5-397B-A17B',
|
|
167
|
+
'qwen3.5-huge'
|
|
167
168
|
],
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
'qwen3.5-122b-a10b': [
|
|
170
|
+
'qwen3.5-122b',
|
|
171
|
+
'Qwen3.5-122B-A10B'
|
|
171
172
|
],
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
"qwen3.5-huge"
|
|
173
|
+
'qwen3.5-27b': [
|
|
174
|
+
'qwen3.5-27b-instruct',
|
|
175
|
+
'Qwen3.5-27B'
|
|
176
176
|
],
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
],
|
|
181
|
-
"qwen3.5-27b": [
|
|
182
|
-
"qwen3.5-27b-instruct",
|
|
183
|
-
"Qwen3.5-27B"
|
|
184
|
-
],
|
|
185
|
-
"qwen3.5-35b-a3b": [
|
|
186
|
-
"qwen3.5-35b",
|
|
187
|
-
"Qwen3.5-35B-A3B"
|
|
177
|
+
'qwen3.5-35b-a3b': [
|
|
178
|
+
'qwen3.5-35b',
|
|
179
|
+
'Qwen3.5-35B-A3B'
|
|
188
180
|
]
|
|
189
181
|
});
|
|
190
182
|
|
|
@@ -201,7 +193,7 @@ const buildModelMapping = () => {
|
|
|
201
193
|
}
|
|
202
194
|
|
|
203
195
|
for (const alias of aliases) {
|
|
204
|
-
if (!alias) continue;
|
|
196
|
+
if (!alias) {continue;}
|
|
205
197
|
mapping[alias] = target;
|
|
206
198
|
}
|
|
207
199
|
}
|
|
@@ -222,8 +214,8 @@ function getAvailableModelsList() {
|
|
|
222
214
|
}
|
|
223
215
|
return fs.readFileSync(MODELS_FILE, 'utf8')
|
|
224
216
|
.split('\n')
|
|
225
|
-
.map(l => l.trim())
|
|
226
|
-
.filter(l => l && !l.startsWith('#'));
|
|
217
|
+
.map((l) => l.trim())
|
|
218
|
+
.filter((l) => l && !l.startsWith('#'));
|
|
227
219
|
} catch (error) {
|
|
228
220
|
return [];
|
|
229
221
|
}
|
|
@@ -248,7 +240,7 @@ export function isValidModel(modelName) {
|
|
|
248
240
|
export function getMappedModel(requestedModel, defaultModel = null) {
|
|
249
241
|
// Если defaultModel не передан, используем динамический default
|
|
250
242
|
const effectiveDefault = defaultModel || getActiveModel();
|
|
251
|
-
if (!requestedModel) return effectiveDefault;
|
|
243
|
+
if (!requestedModel) {return effectiveDefault;}
|
|
252
244
|
|
|
253
245
|
// Проверяем точное соответствие в словаре
|
|
254
246
|
if (MODEL_MAPPING[requestedModel]) {
|
|
@@ -268,7 +260,7 @@ export function getMappedModel(requestedModel, defaultModel = null) {
|
|
|
268
260
|
// Если запрошенная модель не найдена, логируем предупреждение
|
|
269
261
|
logWarn(`Модель "${requestedModel}" не найдена в списке доступных.`);
|
|
270
262
|
logWarn(`Используем модель по умолчанию: ${effectiveDefault}`);
|
|
271
|
-
|
|
263
|
+
|
|
272
264
|
// Возвращаем модель по умолчанию
|
|
273
265
|
return effectiveDefault;
|
|
274
|
-
}
|
|
266
|
+
}
|