qwen-api-proxy 1.0.10 → 1.0.12
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 +121 -18
- package/bin/qwen-api-proxy.js +118 -23
- package/index.js +110 -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,60 @@ 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
|
+
> 🆕 **Новые пользователи?** Начните с [QUICK_START.md](QUICK_START.md) - пошаговое руководство с устранением常见ных ошибок
|
|
145
|
+
|
|
146
|
+
### 🌍 Кросс-платформенная поддержка
|
|
147
|
+
|
|
148
|
+
Этот проект полностью поддерживает работу на:
|
|
149
|
+
- ✅ **Windows** (10/11, Server 2019+)
|
|
150
|
+
- ✅ **Linux** (Ubuntu 18.04+, Debian 10+, CentOS 8+)
|
|
151
|
+
- ✅ **macOS** (10.15+, включая Apple Silicon)
|
|
152
|
+
|
|
153
|
+
**Требования:**
|
|
154
|
+
- Node.js >= 18.0.0 (рекомендуется 20.x или 22.x LTS)
|
|
155
|
+
- Для команды `archive`: `zip` (Linux/macOS) или `zip`/`7-Zip`/PowerShell (Windows)
|
|
156
|
+
|
|
157
|
+
> 📖 **Полное руководство:** [CROSS_PLATFORM.md](CROSS_PLATFORM.md)
|
|
158
|
+
|
|
159
|
+
### 📦 Через npm (Рекомендуется)
|
|
160
|
+
|
|
161
|
+
**Без установки (npx):**
|
|
162
|
+
```bash
|
|
163
|
+
# Инициализация директории
|
|
164
|
+
npx qwen-api-proxy init
|
|
165
|
+
|
|
166
|
+
# Запуск сервера
|
|
167
|
+
npx qwen-api-proxy
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Глобальная установка:**
|
|
171
|
+
```bash
|
|
172
|
+
npm install -g qwen-api-proxy
|
|
173
|
+
|
|
174
|
+
# Инициализация
|
|
175
|
+
qwen-api-proxy init
|
|
176
|
+
|
|
177
|
+
# Запуск сервера
|
|
178
|
+
qwen-api-proxy
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
> 💡 **Подробнее:** [README_NPM.md](README_NPM.md) - полное руководство по npm пакету
|
|
182
|
+
|
|
183
|
+
### 💻 Ручная установка
|
|
184
|
+
|
|
138
185
|
```bash
|
|
139
186
|
# Node.js (Основной)
|
|
140
187
|
git clone https://github.com/y13sint/FreeQwenApi
|
|
@@ -186,6 +233,62 @@ python main.py
|
|
|
186
233
|
|
|
187
234
|
---
|
|
188
235
|
|
|
236
|
+
## 🛠️ CLI команды
|
|
237
|
+
|
|
238
|
+
Все команды можно запускать через `npx` (без установки) или после глобальной установки:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# Без установки (рекомендуется для редкого использования)
|
|
242
|
+
npx qwen-api-proxy <command>
|
|
243
|
+
|
|
244
|
+
# После глобальной установки (для частого использования)
|
|
245
|
+
qwen-api-proxy <command>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Основные команды
|
|
249
|
+
|
|
250
|
+
| Команда | Описание |
|
|
251
|
+
|---------|----------|
|
|
252
|
+
| `npx qwen-api-proxy` | Запуск сервера |
|
|
253
|
+
| `npx qwen-api-proxy init` | Инициализация директории (без запуска) |
|
|
254
|
+
| `npx qwen-api-proxy archive` | Создание архива сессии |
|
|
255
|
+
| `npx qwen-api-proxy extend` | Продление сессий |
|
|
256
|
+
| `npx qwen-api-proxy doctor` | Проверка здоровья системы |
|
|
257
|
+
|
|
258
|
+
### Примеры использования
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Инициализация проекта
|
|
262
|
+
npx qwen-api-proxy init
|
|
263
|
+
|
|
264
|
+
# Создание архива сессии для backup
|
|
265
|
+
npx qwen-api-proxy archive
|
|
266
|
+
|
|
267
|
+
# Продление всех сессий
|
|
268
|
+
npx qwen-api-proxy extend
|
|
269
|
+
|
|
270
|
+
# Продление конкретного аккаунта
|
|
271
|
+
npx qwen-api-proxy extend --account-id acc_1234567890
|
|
272
|
+
|
|
273
|
+
# Проверка здоровья системы
|
|
274
|
+
npx qwen-api-proxy doctor
|
|
275
|
+
|
|
276
|
+
# С пользовательской директорией
|
|
277
|
+
npx qwen-api-proxy archive --dir=/path/to/project
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 🔧 NPM Scripts (для разработчиков)
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
npm start # Запуск сервера
|
|
284
|
+
npm run archive # Создание архива
|
|
285
|
+
npm run auth # Добавить аккаунт
|
|
286
|
+
npm run rebuild-tokens # Перестроить tokens.json
|
|
287
|
+
npm run check-sessions # Проверить сессии
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
189
292
|
## Docker Hub
|
|
190
293
|
|
|
191
294
|
Готовый Docker образ доступен на Docker Hub:
|
|
@@ -208,7 +311,7 @@ docker run -d \
|
|
|
208
311
|
-v $(pwd)/logs:/app/logs \
|
|
209
312
|
-v $(pwd)/uploads:/app/uploads \
|
|
210
313
|
-v $(pwd)/temp:/app/temp \
|
|
211
|
-
endykaufman/qwen-api-proxy:1.0.
|
|
314
|
+
endykaufman/qwen-api-proxy:1.0.12
|
|
212
315
|
|
|
213
316
|
# 3. Смотрим логи
|
|
214
317
|
docker logs -f qwen-proxy
|
|
@@ -217,7 +320,7 @@ docker logs -f qwen-proxy
|
|
|
217
320
|
### Доступные теги
|
|
218
321
|
|
|
219
322
|
- `latest` - последняя стабильная версия
|
|
220
|
-
- `1.0.
|
|
323
|
+
- `1.0.12` - текущая версия
|
|
221
324
|
- `1.0.x` - предыдущие версии
|
|
222
325
|
|
|
223
326
|
> **💡 Важно:** Перед первым запуском добавьте аккаунт через `npm run auth` или загрузите сессию через Telegram бота.
|
|
@@ -238,7 +341,7 @@ docker logs -f qwen-proxy
|
|
|
238
341
|
```yaml
|
|
239
342
|
services:
|
|
240
343
|
qwen-proxy:
|
|
241
|
-
image: endykaufman/qwen-api-proxy:1.0.
|
|
344
|
+
image: endykaufman/qwen-api-proxy:1.0.12
|
|
242
345
|
container_name: qwen-proxy
|
|
243
346
|
env_file:
|
|
244
347
|
- .env
|
|
@@ -293,7 +396,7 @@ docker run -d \
|
|
|
293
396
|
-v $(pwd)/logs:/app/logs \
|
|
294
397
|
-v $(pwd)/uploads:/app/uploads \
|
|
295
398
|
-v $(pwd)/temp:/app/temp \
|
|
296
|
-
endykaufman/qwen-api-proxy:1.0.
|
|
399
|
+
endykaufman/qwen-api-proxy:1.0.12
|
|
297
400
|
```
|
|
298
401
|
|
|
299
402
|
Файл `docker-compose.yml`:
|
|
@@ -302,7 +405,7 @@ docker run -d \
|
|
|
302
405
|
services:
|
|
303
406
|
qwen-proxy:
|
|
304
407
|
build: .
|
|
305
|
-
image: endykaufman/qwen-api-proxy:1.0.
|
|
408
|
+
image: endykaufman/qwen-api-proxy:1.0.12
|
|
306
409
|
container_name: qwen-proxy
|
|
307
410
|
env_file:
|
|
308
411
|
- .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
|
|
|
@@ -184,6 +209,17 @@ function setup() {
|
|
|
184
209
|
checkDependencies();
|
|
185
210
|
|
|
186
211
|
console.log('\n✅ Working directory setup complete!\n');
|
|
212
|
+
console.log('📝 Next steps for first-time users:');
|
|
213
|
+
console.log(' 1. Add an account: qwen-api-proxy (or npx qwen-api-proxy)');
|
|
214
|
+
console.log(' - Select "1 - Add new account"');
|
|
215
|
+
console.log(' - Browser will open for authentication');
|
|
216
|
+
console.log(' - Login to Qwen and press ENTER in console');
|
|
217
|
+
console.log(' 2. Create archive: qwen-api-proxy archive');
|
|
218
|
+
console.log(' 3. Start server: qwen-api-proxy');
|
|
219
|
+
console.log('\n💡 Alternative: Use Telegram bot to upload session files');
|
|
220
|
+
console.log(' - Configure TELEGRAM_BOT_TOKEN in .env file');
|
|
221
|
+
console.log(' - Send session archive to the bot');
|
|
222
|
+
console.log('\n');
|
|
187
223
|
|
|
188
224
|
// Show warnings for missing .gitignore entries
|
|
189
225
|
if (missingGitignoreDirs.length > 0) {
|
|
@@ -256,12 +292,34 @@ if (command === 'doctor') {
|
|
|
256
292
|
issues.push(`Node.js ${nodeVersion} (✗ requires >= 18)`);
|
|
257
293
|
}
|
|
258
294
|
|
|
259
|
-
// Check zip command
|
|
295
|
+
// Check zip command (cross-platform)
|
|
296
|
+
const isWindows = process.platform === 'win32';
|
|
297
|
+
let zipAvailable = false;
|
|
260
298
|
try {
|
|
261
|
-
|
|
262
|
-
|
|
299
|
+
if (isWindows) {
|
|
300
|
+
try {
|
|
301
|
+
execSync('zip --version', { stdio: 'ignore' });
|
|
302
|
+
zipAvailable = true;
|
|
303
|
+
} catch (e) {
|
|
304
|
+
try {
|
|
305
|
+
execSync('7z --help', { stdio: 'ignore' });
|
|
306
|
+
zipAvailable = true; // 7z can work as alternative
|
|
307
|
+
} catch (e2) {
|
|
308
|
+
// Neither available
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
} else {
|
|
312
|
+
execSync('zip --version', { stdio: 'ignore' });
|
|
313
|
+
zipAvailable = true;
|
|
314
|
+
}
|
|
263
315
|
} catch (error) {
|
|
264
|
-
|
|
316
|
+
// zip not available
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (zipAvailable) {
|
|
320
|
+
ok.push('zip/7z command available');
|
|
321
|
+
} else {
|
|
322
|
+
warnings.push('zip/7z command not found (required for archive command)');
|
|
265
323
|
}
|
|
266
324
|
|
|
267
325
|
// Check working directory structure
|
|
@@ -358,22 +416,56 @@ if (command === 'doctor') {
|
|
|
358
416
|
warnings.push('No accounts configured yet');
|
|
359
417
|
}
|
|
360
418
|
|
|
361
|
-
// Check disk space
|
|
419
|
+
// Check disk space (cross-platform)
|
|
362
420
|
try {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
421
|
+
if (isWindows) {
|
|
422
|
+
// Use PowerShell or wmic on Windows
|
|
423
|
+
try {
|
|
424
|
+
const wmicOutput = execSync('wmic logicaldisk where "DeviceID=\'C:\'" get FreeSpace /value', { encoding: 'utf8' });
|
|
425
|
+
const match = wmicOutput.match(/FreeSpace=(\d+)/);
|
|
426
|
+
if (match) {
|
|
427
|
+
const availableBytes = parseInt(match[1]);
|
|
428
|
+
const availableGB = (availableBytes / 1024 / 1024 / 1024).toFixed(2);
|
|
429
|
+
if (availableGB > 1) {
|
|
430
|
+
ok.push(`Disk space: ${availableGB} GB available`);
|
|
431
|
+
} else {
|
|
432
|
+
warnings.push(`Low disk space: ${availableGB} GB available`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
} catch (e) {
|
|
436
|
+
// wmic might not be available, try PowerShell
|
|
437
|
+
try {
|
|
438
|
+
const psOutput = execSync('powershell -Command "(Get-PSDrive C).Free"', { encoding: 'utf8' });
|
|
439
|
+
const freeBytes = parseInt(psOutput.trim());
|
|
440
|
+
if (!isNaN(freeBytes)) {
|
|
441
|
+
const availableGB = (freeBytes / 1024 / 1024 / 1024).toFixed(2);
|
|
442
|
+
if (availableGB > 1) {
|
|
443
|
+
ok.push(`Disk space: ${availableGB} GB available`);
|
|
444
|
+
} else {
|
|
445
|
+
warnings.push(`Low disk space: ${availableGB} GB available`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
} catch (e2) {
|
|
449
|
+
// Skip disk check on Windows if commands fail
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
} else {
|
|
453
|
+
// Unix-like systems
|
|
454
|
+
const dfOutput = execSync('df -k .', { encoding: 'utf8' });
|
|
455
|
+
const lines = dfOutput.split('\n');
|
|
456
|
+
if (lines.length >= 2) {
|
|
457
|
+
const parts = lines[1].split(/\s+/);
|
|
458
|
+
const availableKB = parseInt(parts[3]);
|
|
459
|
+
const availableGB = (availableKB / 1024 / 1024).toFixed(2);
|
|
460
|
+
if (availableGB > 1) {
|
|
461
|
+
ok.push(`Disk space: ${availableGB} GB available`);
|
|
462
|
+
} else {
|
|
463
|
+
warnings.push(`Low disk space: ${availableGB} GB available`);
|
|
464
|
+
}
|
|
373
465
|
}
|
|
374
466
|
}
|
|
375
467
|
} catch (error) {
|
|
376
|
-
// df not available, skip
|
|
468
|
+
// df/wmic not available, skip
|
|
377
469
|
}
|
|
378
470
|
|
|
379
471
|
// Print results
|
|
@@ -411,4 +503,7 @@ if (needsSetup) {
|
|
|
411
503
|
process.env.QWEN_API_PROXY_GLOBAL = 'true';
|
|
412
504
|
|
|
413
505
|
// Import and run the main application
|
|
414
|
-
|
|
506
|
+
// Convert path to file:// URL for cross-platform ESM compatibility
|
|
507
|
+
const indexPath = path.join(PACKAGE_ROOT, 'index.js');
|
|
508
|
+
const indexUrl = pathToFileURL(indexPath).href;
|
|
509
|
+
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,52 @@ function createSessionArchive() {
|
|
|
132
133
|
throw new Error('Папка сессии пуста. Сначала выполните авторизацию.');
|
|
133
134
|
}
|
|
134
135
|
|
|
135
|
-
//
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
// Проверяем, есть ли реальные данные (accounts, tokens.json, и т.д.)
|
|
137
|
+
const hasAccounts = fs.existsSync(path.join(sessionPath, 'accounts')) &&
|
|
138
|
+
fs.readdirSync(path.join(sessionPath, 'accounts')).length > 0;
|
|
139
|
+
const hasTokens = fs.existsSync(path.join(sessionPath, 'tokens.json'));
|
|
140
|
+
|
|
141
|
+
if (!hasAccounts && !hasTokens) {
|
|
142
|
+
throw new Error('Папка сессии не содержит данных аккаунтов.');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Показываем статистику
|
|
146
|
+
console.log('\n📊 Найденные данные:');
|
|
147
|
+
if (hasAccounts) {
|
|
148
|
+
const accounts = fs.readdirSync(path.join(sessionPath, 'accounts'));
|
|
149
|
+
console.log(` ✓ Аккаунты: ${accounts.length} (${accounts.join(', ')})`);
|
|
150
|
+
}
|
|
151
|
+
if (hasTokens) {
|
|
152
|
+
try {
|
|
153
|
+
const tokens = JSON.parse(fs.readFileSync(path.join(sessionPath, 'tokens.json'), 'utf8'));
|
|
154
|
+
console.log(` ✓ Токены: ${Array.isArray(tokens) ? tokens.length : 0} записей`);
|
|
155
|
+
} catch (e) {
|
|
156
|
+
console.log(' ⚠ tokens.json не удалось прочитать');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Создаем ZIP архив (cross-platform)
|
|
161
|
+
let command;
|
|
162
|
+
if (isWindows) {
|
|
163
|
+
// Try zip first, fallback to PowerShell Compress-Archive
|
|
164
|
+
try {
|
|
165
|
+
command = `cd /d "${process.cwd()}" && zip -r "${archiveName}" "${SESSION_DIR}"`;
|
|
166
|
+
logInfo(`Выполнение команды: ${command}`);
|
|
167
|
+
execSync(command, { stdio: 'inherit' });
|
|
168
|
+
} catch (zipError) {
|
|
169
|
+
// Fallback to PowerShell Compress-Archive
|
|
170
|
+
logInfo('zip не найден, используем PowerShell Compress-Archive');
|
|
171
|
+
const psCommand = `Compress-Archive -Path "${sessionPath}" -DestinationPath "${archivePath}" -Force`;
|
|
172
|
+
command = `powershell -Command "${psCommand}"`;
|
|
173
|
+
logInfo(`Выполнение команды: ${command}`);
|
|
174
|
+
execSync(command, { stdio: 'inherit' });
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
// Unix-like systems (Linux, macOS)
|
|
178
|
+
command = `cd "${process.cwd()}" && zip -r "${archiveName}" "${SESSION_DIR}/"`;
|
|
179
|
+
logInfo(`Выполнение команды: ${command}`);
|
|
180
|
+
execSync(command, { stdio: 'inherit' });
|
|
181
|
+
}
|
|
139
182
|
|
|
140
183
|
// Проверяем создание архива
|
|
141
184
|
if (!fs.existsSync(archivePath)) {
|
|
@@ -215,6 +258,68 @@ async function handleCLICommand() {
|
|
|
215
258
|
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
216
259
|
|
|
217
260
|
try {
|
|
261
|
+
// Проверяем, есть ли уже аккаунты
|
|
262
|
+
const tokensPath = path.join(process.cwd(), SESSION_DIR, 'tokens.json');
|
|
263
|
+
const accountsPath = path.join(process.cwd(), SESSION_DIR, ACCOUNTS_DIR);
|
|
264
|
+
|
|
265
|
+
let hasAccounts = false;
|
|
266
|
+
|
|
267
|
+
if (fs.existsSync(tokensPath)) {
|
|
268
|
+
try {
|
|
269
|
+
const tokens = JSON.parse(fs.readFileSync(tokensPath, 'utf8'));
|
|
270
|
+
if (Array.isArray(tokens) && tokens.length > 0) {
|
|
271
|
+
hasAccounts = true;
|
|
272
|
+
}
|
|
273
|
+
} catch (e) {
|
|
274
|
+
// tokens.json corrupted
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (!hasAccounts && fs.existsSync(accountsPath)) {
|
|
279
|
+
const accounts = fs.readdirSync(accountsPath);
|
|
280
|
+
if (accounts.length > 0) {
|
|
281
|
+
hasAccounts = true;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Если аккаунтов нет, предлагаем добавить
|
|
286
|
+
if (!hasAccounts) {
|
|
287
|
+
console.log('📝 Аккаунты не найдены. Необходимо добавить аккаунт перед созданием архива.\n');
|
|
288
|
+
console.log('🔹 Вариант 1: Добавить аккаунт сейчас (откроется браузер)');
|
|
289
|
+
console.log('🔹 Вариант 2: Отправить файл сессии через Telegram бота');
|
|
290
|
+
console.log('🔹 Вариант 3: Выйти и запустить вручную: npx qwen-api-proxy\n');
|
|
291
|
+
|
|
292
|
+
const { prompt } = await import('./src/utils/prompt.js');
|
|
293
|
+
const choice = await prompt('Ваш выбор (1/2/3, Enter = 1): ');
|
|
294
|
+
|
|
295
|
+
if (choice === '2') {
|
|
296
|
+
console.log('\n💡 Для использования Telegram бота:');
|
|
297
|
+
console.log(' 1. Добавьте TELEGRAM_BOT_TOKEN в .env файл');
|
|
298
|
+
console.log(' 2. Запустите: npx qwen-api-proxy');
|
|
299
|
+
console.log(' 3. Отправьте файл сессии боту\n');
|
|
300
|
+
process.exit(0);
|
|
301
|
+
} else if (choice === '3') {
|
|
302
|
+
console.log('\n👋 Выход. Запустите "npx qwen-api-proxy" для добавления аккаунта.\n');
|
|
303
|
+
process.exit(0);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// choice === '1' или Enter - добавляем аккаунт
|
|
307
|
+
console.log('\n🔐 Запуск браузера для добавления аккаунта...\n');
|
|
308
|
+
|
|
309
|
+
const { addAccountInteractive } = await import('./src/utils/accountSetup.js');
|
|
310
|
+
const accountId = await addAccountInteractive();
|
|
311
|
+
|
|
312
|
+
if (!accountId) {
|
|
313
|
+
console.log('\n❌ Аккаунт не был добавлен. Архив не создан.\n');
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
console.log(`\n✅ Аккаунт ${accountId} успешно добавлен!\n`);
|
|
318
|
+
} else {
|
|
319
|
+
console.log('✅ Найден существующий аккаунт\n');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Теперь создаем архив
|
|
218
323
|
const archivePath = createSessionArchive();
|
|
219
324
|
console.log('\n🎉 ГОТОВО!');
|
|
220
325
|
console.log(`📄 Архив: ${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.12",
|
|
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",
|