qwen-api-proxy 1.0.10

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.
@@ -0,0 +1,274 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { getActiveModel } from '../utils/botSettings.js';
5
+ import { logWarn } from '../logger/index.js';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ const MODELS_FILE = path.join(__dirname, '..', 'AvailableModels.txt');
10
+
11
+ const CANONICAL_MODELS = Object.freeze([
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
+ ]);
40
+
41
+ const CANONICAL_MODEL_SET = new Set(CANONICAL_MODELS);
42
+
43
+ const ALIAS_GROUPS = Object.freeze({
44
+ "qwen3.5-plus": [
45
+ "qwen3.5",
46
+ "Qwen3.5-Plus",
47
+ "qwen3.5-plus-latest"
48
+ ],
49
+ "qwen3.5-397b-a17b": [
50
+ "qwen3.5-397b",
51
+ "Qwen3.5-397B-A17B"
52
+ ],
53
+ "qwen3-max": [
54
+ "qwen-max",
55
+ "Qwen3-Max",
56
+ "Qwen3-Maximum",
57
+ "qwen3-max-preview",
58
+ "Qwen3-Max-Preview"
59
+ ],
60
+ "qwen3-vl-plus": [
61
+ "qwen-vl",
62
+ "qwen-vl-plus",
63
+ "qwen-vl-plus-latest",
64
+ "qwen-vl-max",
65
+ "qwen-vl-max-latest",
66
+ "Qwen3-VL-235B-A22B",
67
+ "qwen3-vl-235b-a22b"
68
+ ],
69
+ "qwen3-coder-plus": [
70
+ "qwen3-coder",
71
+ "qwen-coder-plus",
72
+ "qwen-coder-plus-latest",
73
+ "Qwen3-Coder-Plus",
74
+ "qwen2.5-coder-3b-instruct",
75
+ "qwen2.5-coder-1.5b-instruct",
76
+ "qwen2.5-coder-0.5b-instruct",
77
+ "Qwen3-Coder"
78
+ ],
79
+ "qwen3-omni-flash": [
80
+ "qwen3-omni",
81
+ "qwen3-omni-latest",
82
+ "Qwen3-omni-flash",
83
+ "Qwen3-Omni-Flash",
84
+ "Qwen3-Omni"
85
+ ],
86
+ "qwen3-omni-flash-2025-12-01": [
87
+ "Qwen3-Omni-Flash-2025-12-01"
88
+ ],
89
+ "qwen-plus-2025-09-11": [
90
+ "qwen-plus",
91
+ "qwen-plus-latest",
92
+ "Qwen3-Next",
93
+ "Qwen3-Next-80B-A3B",
94
+ "qwen3-next",
95
+ "qwen3-next-80b-a3b"
96
+ ],
97
+ "qwen3-235b-a22b": [
98
+ "qwen3",
99
+ "qwen-3",
100
+ "qwen3-235b",
101
+ "Qwen3-235B-A22B",
102
+ "Qwen3-235B-A22B-2507",
103
+ "qwen3-235b-a22b-2507"
104
+ ],
105
+ "qwen3-30b-a3b": [
106
+ "qwen3-plus",
107
+ "qwen3-30b",
108
+ "Qwen3-30B-A3B",
109
+ "Qwen3-30B-A3B-2507",
110
+ "qwen3-30b-a3b-2507"
111
+ ],
112
+ "qwen3-coder-30b-a3b-instruct": [
113
+ "qwen3-coder-flash",
114
+ "Qwen3-Coder-Flash",
115
+ "qwen3-coder-30b",
116
+ "Qwen3-Coder-30B-A3B-Instruct"
117
+ ],
118
+ "qwen-max-latest": [
119
+ "Qwen2.5-Max",
120
+ "qwen2.5-max"
121
+ ],
122
+ "qwen-plus-2025-01-25": [
123
+ "Qwen2.5-Plus",
124
+ "qwen2.5-plus"
125
+ ],
126
+ "qwq-32b": [
127
+ "qwq",
128
+ "QwQ-32B",
129
+ "qwq-32b-preview"
130
+ ],
131
+ "qwen-turbo-2025-02-11": [
132
+ "qwen-turbo",
133
+ "qwen-turbo-latest",
134
+ "Qwen2.5-Turbo"
135
+ ],
136
+ "qwen2.5-omni-7b": [
137
+ "qwen2.5-omni",
138
+ "Qwen2.5-Omni-7B",
139
+ "qwen-omni-7b"
140
+ ],
141
+ "qvq-72b-preview-0310": [
142
+ "qvq",
143
+ "QVQ-Max",
144
+ "qvq-72b"
145
+ ],
146
+ "qwen2.5-vl-32b-instruct": [
147
+ "qwen2.5-vl",
148
+ "Qwen2.5-VL-32B-Instruct"
149
+ ],
150
+ "qwen2.5-14b-instruct-1m": [
151
+ "qwen2.5-14b",
152
+ "qwen2.5-coder-14b-instruct",
153
+ "Qwen2.5-14B-Instruct-1M"
154
+ ],
155
+ "qwen2.5-coder-32b-instruct": [
156
+ "qwen2.5-coder",
157
+ "qwen2.5-coder-plus",
158
+ "Qwen2.5-Coder-32B-Instruct"
159
+ ],
160
+ "qwen2.5-72b-instruct": [
161
+ "qwen2.5-72b",
162
+ "Qwen2.5-72B-Instruct"
163
+ ],
164
+ "qwen3.5-plus": [
165
+ "qwen3.5-plus-latest",
166
+ "Qwen3.5-Plus"
167
+ ],
168
+ "qwen3.5-flash": [
169
+ "qwen3.5-flash-latest",
170
+ "Qwen3.5-Flash"
171
+ ],
172
+ "qwen3.5-397b-a17b": [
173
+ "qwen3.5-397b",
174
+ "Qwen3.5-397B-A17B",
175
+ "qwen3.5-huge"
176
+ ],
177
+ "qwen3.5-122b-a10b": [
178
+ "qwen3.5-122b",
179
+ "Qwen3.5-122B-A10B"
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"
188
+ ]
189
+ });
190
+
191
+ const buildModelMapping = () => {
192
+ const mapping = Object.create(null);
193
+
194
+ for (const model of CANONICAL_MODELS) {
195
+ mapping[model] = model;
196
+ }
197
+
198
+ for (const [target, aliases] of Object.entries(ALIAS_GROUPS)) {
199
+ if (!CANONICAL_MODEL_SET.has(target)) {
200
+ continue;
201
+ }
202
+
203
+ for (const alias of aliases) {
204
+ if (!alias) continue;
205
+ mapping[alias] = target;
206
+ }
207
+ }
208
+
209
+ return Object.freeze(mapping);
210
+ };
211
+
212
+ export const MODEL_MAPPING = buildModelMapping();
213
+
214
+ /**
215
+ * Получить список доступных моделей из кэша или файла
216
+ * @returns {string[]} - Список доступных моделей
217
+ */
218
+ function getAvailableModelsList() {
219
+ try {
220
+ if (!fs.existsSync(MODELS_FILE)) {
221
+ return [];
222
+ }
223
+ return fs.readFileSync(MODELS_FILE, 'utf8')
224
+ .split('\n')
225
+ .map(l => l.trim())
226
+ .filter(l => l && !l.startsWith('#'));
227
+ } catch (error) {
228
+ return [];
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Проверить, существует ли модель в списке доступных
234
+ * @param {string} modelName - Название модели для проверки
235
+ * @returns {boolean} - true если модель доступна
236
+ */
237
+ export function isValidModel(modelName) {
238
+ const availableModels = getAvailableModelsList();
239
+ return availableModels.includes(modelName);
240
+ }
241
+
242
+ /**
243
+ * Получить соответствующую доступную модель с валидацией
244
+ * @param {string} requestedModel - Запрошенная модель
245
+ * @param {string} defaultModel - Модель по умолчанию
246
+ * @returns {string} - Доступная модель
247
+ */
248
+ export function getMappedModel(requestedModel, defaultModel = null) {
249
+ // Если defaultModel не передан, используем динамический default
250
+ const effectiveDefault = defaultModel || getActiveModel();
251
+ if (!requestedModel) return effectiveDefault;
252
+
253
+ // Проверяем точное соответствие в словаре
254
+ if (MODEL_MAPPING[requestedModel]) {
255
+ const mappedModel = MODEL_MAPPING[requestedModel];
256
+ // Валидируем, что mapped модель существует в списке доступных
257
+ if (isValidModel(mappedModel)) {
258
+ return mappedModel;
259
+ }
260
+ logWarn(`Маппированная модель "${mappedModel}" не найдена в AvailableModels.txt`);
261
+ }
262
+
263
+ // Проверяем, является ли запрошенная модель уже доступной
264
+ if (isValidModel(requestedModel)) {
265
+ return requestedModel;
266
+ }
267
+
268
+ // Если запрошенная модель не найдена, логируем предупреждение
269
+ logWarn(`Модель "${requestedModel}" не найдена в списке доступных.`);
270
+ logWarn(`Используем модель по умолчанию: ${effectiveDefault}`);
271
+
272
+ // Возвращаем модель по умолчанию
273
+ return effectiveDefault;
274
+ }