qwen-api-proxy 1.0.10 → 1.0.11
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 +119 -18
- package/bin/qwen-api-proxy.js +107 -23
- package/index.js +24 -5
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# FreeQwenApi
|
|
2
2
|
|
|
3
|
+
[](https://badge.fury.io/js/qwen-api-proxy)
|
|
4
|
+
[](https://www.npmjs.com/package/qwen-api-proxy)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
|
|
7
|
+
> **📦 npm:** `npx qwen-api-proxy` или `npm install -g qwen-api-proxy`
|
|
3
8
|
> **🐳 Docker Hub:** https://hub.docker.com/r/endykaufman/qwen-api-proxy
|
|
4
9
|
> **🔧 Форк:** https://github.com/EndyKaufman/FreeQwenApi
|
|
5
10
|
> **🌐 Оригинал:** https://github.com/y13sint/FreeQwenApi
|
|
@@ -109,11 +114,12 @@ curl http://localhost:3264/api/chat/completions \
|
|
|
109
114
|
## Содержание
|
|
110
115
|
|
|
111
116
|
1. [Быстрый старт](#быстрый-старт)
|
|
112
|
-
2. [
|
|
113
|
-
3. [Docker](#docker)
|
|
114
|
-
4. [
|
|
115
|
-
5. [
|
|
116
|
-
6. [API
|
|
117
|
+
2. [CLI команды](#-cli-команды) 🆕
|
|
118
|
+
3. [Docker Hub](#docker-hub) 🆕
|
|
119
|
+
4. [Docker](#docker)
|
|
120
|
+
5. [Управление аккаунтами](#управление-аккаунтами)
|
|
121
|
+
6. [Авторизация API-ключами](#авторизация-api-ключами)
|
|
122
|
+
7. [API Reference](#api-reference)
|
|
117
123
|
- [POST /api/chat](#post-apichat)
|
|
118
124
|
- [POST /api/chat/completions](#post-apichatcompletions)
|
|
119
125
|
- [GET /api/models](#get-apimodels)
|
|
@@ -122,19 +128,58 @@ curl http://localhost:3264/api/chat/completions \
|
|
|
122
128
|
- [POST /api/files/upload](#post-apifilesupload)
|
|
123
129
|
- [POST /api/files/getstsToken](#post-apifilesgetststoken)
|
|
124
130
|
- [POST /api/images/generations](#post-apiimagesgenerations)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
8. [Работа с контекстом (API v2)](#работа-с-контекстом-api-v2)
|
|
132
|
+
9. [Работа с изображениями](#работа-с-изображениями)
|
|
133
|
+
10. [Генерация изображений](#генерация-изображений) 🆕
|
|
134
|
+
11. [OpenAI SDK](#openai-sdk)
|
|
135
|
+
12. [Python](#python-альтернативная-реализация)
|
|
136
|
+
13. [Доступные модели](#доступные-модели)
|
|
137
|
+
14. [Переменные окружения](#переменные-окружения)
|
|
138
|
+
15. [Структура проекта](#структура-проекта)
|
|
133
139
|
|
|
134
140
|
---
|
|
135
141
|
|
|
136
142
|
## Быстрый старт
|
|
137
143
|
|
|
144
|
+
### 🌍 Кросс-платформенная поддержка
|
|
145
|
+
|
|
146
|
+
Этот проект полностью поддерживает работу на:
|
|
147
|
+
- ✅ **Windows** (10/11, Server 2019+)
|
|
148
|
+
- ✅ **Linux** (Ubuntu 18.04+, Debian 10+, CentOS 8+)
|
|
149
|
+
- ✅ **macOS** (10.15+, включая Apple Silicon)
|
|
150
|
+
|
|
151
|
+
**Требования:**
|
|
152
|
+
- Node.js >= 18.0.0 (рекомендуется 20.x или 22.x LTS)
|
|
153
|
+
- Для команды `archive`: `zip` (Linux/macOS) или `zip`/`7-Zip`/PowerShell (Windows)
|
|
154
|
+
|
|
155
|
+
> 📖 **Полное руководство:** [CROSS_PLATFORM.md](CROSS_PLATFORM.md)
|
|
156
|
+
|
|
157
|
+
### 📦 Через npm (Рекомендуется)
|
|
158
|
+
|
|
159
|
+
**Без установки (npx):**
|
|
160
|
+
```bash
|
|
161
|
+
# Инициализация директории
|
|
162
|
+
npx qwen-api-proxy init
|
|
163
|
+
|
|
164
|
+
# Запуск сервера
|
|
165
|
+
npx qwen-api-proxy
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Глобальная установка:**
|
|
169
|
+
```bash
|
|
170
|
+
npm install -g qwen-api-proxy
|
|
171
|
+
|
|
172
|
+
# Инициализация
|
|
173
|
+
qwen-api-proxy init
|
|
174
|
+
|
|
175
|
+
# Запуск сервера
|
|
176
|
+
qwen-api-proxy
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
> 💡 **Подробнее:** [README_NPM.md](README_NPM.md) - полное руководство по npm пакету
|
|
180
|
+
|
|
181
|
+
### 💻 Ручная установка
|
|
182
|
+
|
|
138
183
|
```bash
|
|
139
184
|
# Node.js (Основной)
|
|
140
185
|
git clone https://github.com/y13sint/FreeQwenApi
|
|
@@ -186,6 +231,62 @@ python main.py
|
|
|
186
231
|
|
|
187
232
|
---
|
|
188
233
|
|
|
234
|
+
## 🛠️ CLI команды
|
|
235
|
+
|
|
236
|
+
Все команды можно запускать через `npx` (без установки) или после глобальной установки:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# Без установки (рекомендуется для редкого использования)
|
|
240
|
+
npx qwen-api-proxy <command>
|
|
241
|
+
|
|
242
|
+
# После глобальной установки (для частого использования)
|
|
243
|
+
qwen-api-proxy <command>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Основные команды
|
|
247
|
+
|
|
248
|
+
| Команда | Описание |
|
|
249
|
+
|---------|----------|
|
|
250
|
+
| `npx qwen-api-proxy` | Запуск сервера |
|
|
251
|
+
| `npx qwen-api-proxy init` | Инициализация директории (без запуска) |
|
|
252
|
+
| `npx qwen-api-proxy archive` | Создание архива сессии |
|
|
253
|
+
| `npx qwen-api-proxy extend` | Продление сессий |
|
|
254
|
+
| `npx qwen-api-proxy doctor` | Проверка здоровья системы |
|
|
255
|
+
|
|
256
|
+
### Примеры использования
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Инициализация проекта
|
|
260
|
+
npx qwen-api-proxy init
|
|
261
|
+
|
|
262
|
+
# Создание архива сессии для backup
|
|
263
|
+
npx qwen-api-proxy archive
|
|
264
|
+
|
|
265
|
+
# Продление всех сессий
|
|
266
|
+
npx qwen-api-proxy extend
|
|
267
|
+
|
|
268
|
+
# Продление конкретного аккаунта
|
|
269
|
+
npx qwen-api-proxy extend --account-id acc_1234567890
|
|
270
|
+
|
|
271
|
+
# Проверка здоровья системы
|
|
272
|
+
npx qwen-api-proxy doctor
|
|
273
|
+
|
|
274
|
+
# С пользовательской директорией
|
|
275
|
+
npx qwen-api-proxy archive --dir=/path/to/project
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### 🔧 NPM Scripts (для разработчиков)
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
npm start # Запуск сервера
|
|
282
|
+
npm run archive # Создание архива
|
|
283
|
+
npm run auth # Добавить аккаунт
|
|
284
|
+
npm run rebuild-tokens # Перестроить tokens.json
|
|
285
|
+
npm run check-sessions # Проверить сессии
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
189
290
|
## Docker Hub
|
|
190
291
|
|
|
191
292
|
Готовый Docker образ доступен на Docker Hub:
|
|
@@ -208,7 +309,7 @@ docker run -d \
|
|
|
208
309
|
-v $(pwd)/logs:/app/logs \
|
|
209
310
|
-v $(pwd)/uploads:/app/uploads \
|
|
210
311
|
-v $(pwd)/temp:/app/temp \
|
|
211
|
-
endykaufman/qwen-api-proxy:1.0.
|
|
312
|
+
endykaufman/qwen-api-proxy:1.0.11
|
|
212
313
|
|
|
213
314
|
# 3. Смотрим логи
|
|
214
315
|
docker logs -f qwen-proxy
|
|
@@ -217,7 +318,7 @@ docker logs -f qwen-proxy
|
|
|
217
318
|
### Доступные теги
|
|
218
319
|
|
|
219
320
|
- `latest` - последняя стабильная версия
|
|
220
|
-
- `1.0.
|
|
321
|
+
- `1.0.11` - текущая версия
|
|
221
322
|
- `1.0.x` - предыдущие версии
|
|
222
323
|
|
|
223
324
|
> **💡 Важно:** Перед первым запуском добавьте аккаунт через `npm run auth` или загрузите сессию через Telegram бота.
|
|
@@ -238,7 +339,7 @@ docker logs -f qwen-proxy
|
|
|
238
339
|
```yaml
|
|
239
340
|
services:
|
|
240
341
|
qwen-proxy:
|
|
241
|
-
image: endykaufman/qwen-api-proxy:1.0.
|
|
342
|
+
image: endykaufman/qwen-api-proxy:1.0.11
|
|
242
343
|
container_name: qwen-proxy
|
|
243
344
|
env_file:
|
|
244
345
|
- .env
|
|
@@ -293,7 +394,7 @@ docker run -d \
|
|
|
293
394
|
-v $(pwd)/logs:/app/logs \
|
|
294
395
|
-v $(pwd)/uploads:/app/uploads \
|
|
295
396
|
-v $(pwd)/temp:/app/temp \
|
|
296
|
-
endykaufman/qwen-api-proxy:1.0.
|
|
397
|
+
endykaufman/qwen-api-proxy:1.0.11
|
|
297
398
|
```
|
|
298
399
|
|
|
299
400
|
Файл `docker-compose.yml`:
|
|
@@ -302,7 +403,7 @@ docker run -d \
|
|
|
302
403
|
services:
|
|
303
404
|
qwen-proxy:
|
|
304
405
|
build: .
|
|
305
|
-
image: endykaufman/qwen-api-proxy:1.0.
|
|
406
|
+
image: endykaufman/qwen-api-proxy:1.0.11
|
|
306
407
|
container_name: qwen-proxy
|
|
307
408
|
env_file:
|
|
308
409
|
- .env # Автоматическая загрузка переменных
|
package/bin/qwen-api-proxy.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 4. Passes control to the main index.js
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
13
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
14
14
|
import path from 'path';
|
|
15
15
|
import fs from 'fs';
|
|
16
16
|
import { execSync } from 'child_process';
|
|
@@ -151,15 +151,40 @@ npm-debug.log*
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/**
|
|
154
|
-
* Check if zip is available
|
|
154
|
+
* Check if zip is available (cross-platform)
|
|
155
155
|
*/
|
|
156
156
|
function checkDependencies() {
|
|
157
|
+
const isWindows = process.platform === 'win32';
|
|
158
|
+
|
|
157
159
|
try {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
// On Windows, check for zip.exe or 7z.exe
|
|
161
|
+
if (isWindows) {
|
|
162
|
+
try {
|
|
163
|
+
execSync('zip --version', { stdio: 'ignore' });
|
|
164
|
+
console.log(' ✓ zip command available');
|
|
165
|
+
return;
|
|
166
|
+
} catch (e) {
|
|
167
|
+
// Try 7z as alternative
|
|
168
|
+
try {
|
|
169
|
+
execSync('7z --help', { stdio: 'ignore' });
|
|
170
|
+
console.log(' ✓ 7z command available (alternative to zip)');
|
|
171
|
+
return;
|
|
172
|
+
} catch (e2) {
|
|
173
|
+
// Neither available
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
console.warn(' ⚠️ zip/7z command not found (required for archive command)');
|
|
177
|
+
console.warn(' Install with: choco install zip or download 7-Zip from 7-zip.org');
|
|
178
|
+
} else {
|
|
179
|
+
// Unix-like systems (Linux, macOS)
|
|
180
|
+
execSync('zip --version', { stdio: 'ignore' });
|
|
181
|
+
console.log(' ✓ zip command available');
|
|
182
|
+
}
|
|
160
183
|
} catch (error) {
|
|
161
|
-
|
|
162
|
-
|
|
184
|
+
if (!isWindows) {
|
|
185
|
+
console.warn(' ⚠️ zip command not found (required for archive command)');
|
|
186
|
+
console.warn(' Install with: sudo apt install zip (Ubuntu) or brew install zip (macOS)');
|
|
187
|
+
}
|
|
163
188
|
}
|
|
164
189
|
}
|
|
165
190
|
|
|
@@ -256,12 +281,34 @@ if (command === 'doctor') {
|
|
|
256
281
|
issues.push(`Node.js ${nodeVersion} (✗ requires >= 18)`);
|
|
257
282
|
}
|
|
258
283
|
|
|
259
|
-
// Check zip command
|
|
284
|
+
// Check zip command (cross-platform)
|
|
285
|
+
const isWindows = process.platform === 'win32';
|
|
286
|
+
let zipAvailable = false;
|
|
260
287
|
try {
|
|
261
|
-
|
|
262
|
-
|
|
288
|
+
if (isWindows) {
|
|
289
|
+
try {
|
|
290
|
+
execSync('zip --version', { stdio: 'ignore' });
|
|
291
|
+
zipAvailable = true;
|
|
292
|
+
} catch (e) {
|
|
293
|
+
try {
|
|
294
|
+
execSync('7z --help', { stdio: 'ignore' });
|
|
295
|
+
zipAvailable = true; // 7z can work as alternative
|
|
296
|
+
} catch (e2) {
|
|
297
|
+
// Neither available
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
execSync('zip --version', { stdio: 'ignore' });
|
|
302
|
+
zipAvailable = true;
|
|
303
|
+
}
|
|
263
304
|
} catch (error) {
|
|
264
|
-
|
|
305
|
+
// zip not available
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (zipAvailable) {
|
|
309
|
+
ok.push('zip/7z command available');
|
|
310
|
+
} else {
|
|
311
|
+
warnings.push('zip/7z command not found (required for archive command)');
|
|
265
312
|
}
|
|
266
313
|
|
|
267
314
|
// Check working directory structure
|
|
@@ -358,22 +405,56 @@ if (command === 'doctor') {
|
|
|
358
405
|
warnings.push('No accounts configured yet');
|
|
359
406
|
}
|
|
360
407
|
|
|
361
|
-
// Check disk space
|
|
408
|
+
// Check disk space (cross-platform)
|
|
362
409
|
try {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
410
|
+
if (isWindows) {
|
|
411
|
+
// Use PowerShell or wmic on Windows
|
|
412
|
+
try {
|
|
413
|
+
const wmicOutput = execSync('wmic logicaldisk where "DeviceID=\'C:\'" get FreeSpace /value', { encoding: 'utf8' });
|
|
414
|
+
const match = wmicOutput.match(/FreeSpace=(\d+)/);
|
|
415
|
+
if (match) {
|
|
416
|
+
const availableBytes = parseInt(match[1]);
|
|
417
|
+
const availableGB = (availableBytes / 1024 / 1024 / 1024).toFixed(2);
|
|
418
|
+
if (availableGB > 1) {
|
|
419
|
+
ok.push(`Disk space: ${availableGB} GB available`);
|
|
420
|
+
} else {
|
|
421
|
+
warnings.push(`Low disk space: ${availableGB} GB available`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
} catch (e) {
|
|
425
|
+
// wmic might not be available, try PowerShell
|
|
426
|
+
try {
|
|
427
|
+
const psOutput = execSync('powershell -Command "(Get-PSDrive C).Free"', { encoding: 'utf8' });
|
|
428
|
+
const freeBytes = parseInt(psOutput.trim());
|
|
429
|
+
if (!isNaN(freeBytes)) {
|
|
430
|
+
const availableGB = (freeBytes / 1024 / 1024 / 1024).toFixed(2);
|
|
431
|
+
if (availableGB > 1) {
|
|
432
|
+
ok.push(`Disk space: ${availableGB} GB available`);
|
|
433
|
+
} else {
|
|
434
|
+
warnings.push(`Low disk space: ${availableGB} GB available`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
} catch (e2) {
|
|
438
|
+
// Skip disk check on Windows if commands fail
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
// Unix-like systems
|
|
443
|
+
const dfOutput = execSync('df -k .', { encoding: 'utf8' });
|
|
444
|
+
const lines = dfOutput.split('\n');
|
|
445
|
+
if (lines.length >= 2) {
|
|
446
|
+
const parts = lines[1].split(/\s+/);
|
|
447
|
+
const availableKB = parseInt(parts[3]);
|
|
448
|
+
const availableGB = (availableKB / 1024 / 1024).toFixed(2);
|
|
449
|
+
if (availableGB > 1) {
|
|
450
|
+
ok.push(`Disk space: ${availableGB} GB available`);
|
|
451
|
+
} else {
|
|
452
|
+
warnings.push(`Low disk space: ${availableGB} GB available`);
|
|
453
|
+
}
|
|
373
454
|
}
|
|
374
455
|
}
|
|
375
456
|
} catch (error) {
|
|
376
|
-
// df not available, skip
|
|
457
|
+
// df/wmic not available, skip
|
|
377
458
|
}
|
|
378
459
|
|
|
379
460
|
// Print results
|
|
@@ -411,4 +492,7 @@ if (needsSetup) {
|
|
|
411
492
|
process.env.QWEN_API_PROXY_GLOBAL = 'true';
|
|
412
493
|
|
|
413
494
|
// Import and run the main application
|
|
414
|
-
|
|
495
|
+
// Convert path to file:// URL for cross-platform ESM compatibility
|
|
496
|
+
const indexPath = path.join(PACKAGE_ROOT, 'index.js');
|
|
497
|
+
const indexUrl = pathToFileURL(indexPath).href;
|
|
498
|
+
await import(indexUrl);
|
package/index.js
CHANGED
|
@@ -108,13 +108,14 @@ async function handleShutdown() {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
|
-
* Создает ZIP архив папки session/
|
|
111
|
+
* Создает ZIP архив папки session/ (cross-platform)
|
|
112
112
|
*/
|
|
113
113
|
function createSessionArchive() {
|
|
114
114
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
115
115
|
const archiveName = `session_backup_${timestamp}.zip`;
|
|
116
116
|
const archivePath = path.resolve(process.cwd(), archiveName);
|
|
117
117
|
const sessionPath = path.resolve(process.cwd(), SESSION_DIR);
|
|
118
|
+
const isWindows = process.platform === 'win32';
|
|
118
119
|
|
|
119
120
|
console.log('\n📦 Создание архива сессии...');
|
|
120
121
|
console.log(`📂 Путь к сессии: ${sessionPath}`);
|
|
@@ -132,10 +133,28 @@ function createSessionArchive() {
|
|
|
132
133
|
throw new Error('Папка сессии пуста. Сначала выполните авторизацию.');
|
|
133
134
|
}
|
|
134
135
|
|
|
135
|
-
// Создаем ZIP архив
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
// Создаем ZIP архив (cross-platform)
|
|
137
|
+
let command;
|
|
138
|
+
if (isWindows) {
|
|
139
|
+
// Try zip first, fallback to PowerShell Compress-Archive
|
|
140
|
+
try {
|
|
141
|
+
command = `cd /d "${process.cwd()}" && zip -r "${archiveName}" "${SESSION_DIR}"`;
|
|
142
|
+
logInfo(`Выполнение команды: ${command}`);
|
|
143
|
+
execSync(command, { stdio: 'inherit' });
|
|
144
|
+
} catch (zipError) {
|
|
145
|
+
// Fallback to PowerShell Compress-Archive
|
|
146
|
+
logInfo('zip не найден, используем PowerShell Compress-Archive');
|
|
147
|
+
const psCommand = `Compress-Archive -Path "${sessionPath}" -DestinationPath "${archivePath}" -Force`;
|
|
148
|
+
command = `powershell -Command "${psCommand}"`;
|
|
149
|
+
logInfo(`Выполнение команды: ${command}`);
|
|
150
|
+
execSync(command, { stdio: 'inherit' });
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
// Unix-like systems (Linux, macOS)
|
|
154
|
+
command = `cd "${process.cwd()}" && zip -r "${archiveName}" "${SESSION_DIR}/"`;
|
|
155
|
+
logInfo(`Выполнение команды: ${command}`);
|
|
156
|
+
execSync(command, { stdio: 'inherit' });
|
|
157
|
+
}
|
|
139
158
|
|
|
140
159
|
// Проверяем создание архива
|
|
141
160
|
if (!fs.existsSync(archivePath)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwen-api-proxy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "Proxy server for accessing Qwen API through browser emulation with OpenAI-compatible API and Telegram bot",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"start": "node index.js",
|
|
46
46
|
"archive": "node index.js archive",
|
|
47
47
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
48
|
+
"test:cross-platform": "node test-cross-platform.js",
|
|
48
49
|
"check-permissions": "node scripts/checkPermissions.js",
|
|
49
50
|
"fix-permissions": "bash fix-permissions.sh",
|
|
50
51
|
"rebuild-tokens": "node scripts/rebuildTokens.js",
|