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/README.md +5 -5
- package/bin/qwen-api-proxy.js +53 -53
- package/index.js +33 -33
- 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 +692 -664
- package/src/utils/telegramNotifier.js +7 -7
package/README.md
CHANGED
|
@@ -311,7 +311,7 @@ docker run -d \
|
|
|
311
311
|
-v $(pwd)/logs:/app/logs \
|
|
312
312
|
-v $(pwd)/uploads:/app/uploads \
|
|
313
313
|
-v $(pwd)/temp:/app/temp \
|
|
314
|
-
endykaufman/qwen-api-proxy:1.0.
|
|
314
|
+
endykaufman/qwen-api-proxy:1.0.14
|
|
315
315
|
|
|
316
316
|
# 3. Смотрим логи
|
|
317
317
|
docker logs -f qwen-proxy
|
|
@@ -320,7 +320,7 @@ docker logs -f qwen-proxy
|
|
|
320
320
|
### Доступные теги
|
|
321
321
|
|
|
322
322
|
- `latest` - последняя стабильная версия
|
|
323
|
-
- `1.0.
|
|
323
|
+
- `1.0.14` - текущая версия
|
|
324
324
|
- `1.0.x` - предыдущие версии
|
|
325
325
|
|
|
326
326
|
> **💡 Важно:** Перед первым запуском добавьте аккаунт через `npm run auth` или загрузите сессию через Telegram бота.
|
|
@@ -341,7 +341,7 @@ docker logs -f qwen-proxy
|
|
|
341
341
|
```yaml
|
|
342
342
|
services:
|
|
343
343
|
qwen-proxy:
|
|
344
|
-
image: endykaufman/qwen-api-proxy:1.0.
|
|
344
|
+
image: endykaufman/qwen-api-proxy:1.0.14
|
|
345
345
|
container_name: qwen-proxy
|
|
346
346
|
env_file:
|
|
347
347
|
- .env
|
|
@@ -396,7 +396,7 @@ docker run -d \
|
|
|
396
396
|
-v $(pwd)/logs:/app/logs \
|
|
397
397
|
-v $(pwd)/uploads:/app/uploads \
|
|
398
398
|
-v $(pwd)/temp:/app/temp \
|
|
399
|
-
endykaufman/qwen-api-proxy:1.0.
|
|
399
|
+
endykaufman/qwen-api-proxy:1.0.14
|
|
400
400
|
```
|
|
401
401
|
|
|
402
402
|
Файл `docker-compose.yml`:
|
|
@@ -405,7 +405,7 @@ docker run -d \
|
|
|
405
405
|
services:
|
|
406
406
|
qwen-proxy:
|
|
407
407
|
build: .
|
|
408
|
-
image: endykaufman/qwen-api-proxy:1.0.
|
|
408
|
+
image: endykaufman/qwen-api-proxy:1.0.14
|
|
409
409
|
container_name: qwen-proxy
|
|
410
410
|
env_file:
|
|
411
411
|
- .env # Автоматическая загрузка переменных
|
package/bin/qwen-api-proxy.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* qwen-api-proxy - CLI entry point for global installation
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* This script:
|
|
7
7
|
* 1. Sets up the working directory structure in the current location
|
|
8
8
|
* 2. Creates necessary directories (session, logs, uploads, temp)
|
|
@@ -21,7 +21,7 @@ const WORKING_DIR = process.cwd();
|
|
|
21
21
|
|
|
22
22
|
// Parse command-line arguments early to get custom directory
|
|
23
23
|
const args = process.argv.slice(2);
|
|
24
|
-
const dirFlag = args.find(arg => arg.startsWith('--dir='));
|
|
24
|
+
const dirFlag = args.find((arg) => arg.startsWith('--dir='));
|
|
25
25
|
const customDir = dirFlag ? dirFlag.split('=')[1] : null;
|
|
26
26
|
|
|
27
27
|
// Use custom directory if specified
|
|
@@ -47,8 +47,8 @@ function setupWorkingDirectory(targetDir = EFFECTIVE_DIR) {
|
|
|
47
47
|
];
|
|
48
48
|
|
|
49
49
|
console.log('📁 Setting up working directory...');
|
|
50
|
-
|
|
51
|
-
dirs.forEach(dir => {
|
|
50
|
+
|
|
51
|
+
dirs.forEach((dir) => {
|
|
52
52
|
const dirPath = path.join(targetDir, dir);
|
|
53
53
|
if (!fs.existsSync(dirPath)) {
|
|
54
54
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
@@ -71,16 +71,16 @@ function setupWorkingDirectory(targetDir = EFFECTIVE_DIR) {
|
|
|
71
71
|
function setupEnvFile(targetDir = EFFECTIVE_DIR) {
|
|
72
72
|
const envPath = path.join(targetDir, '.env');
|
|
73
73
|
const envExamplePath = path.join(targetDir, '.env.example');
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
if (!fs.existsSync(envPath)) {
|
|
76
76
|
// Copy .env.example from package if it exists in working dir, otherwise create basic
|
|
77
77
|
const packageEnvExample = path.join(PACKAGE_ROOT, '.env.example');
|
|
78
|
-
|
|
78
|
+
|
|
79
79
|
if (fs.existsSync(packageEnvExample)) {
|
|
80
80
|
fs.copyFileSync(packageEnvExample, envExamplePath);
|
|
81
81
|
console.log(' ✓ Created .env.example');
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
// Create empty .env if not exists
|
|
85
85
|
if (!fs.existsSync(envPath)) {
|
|
86
86
|
fs.writeFileSync(envPath, '# Qwen API Proxy Configuration\n# See .env.example for available options\n\n');
|
|
@@ -105,12 +105,12 @@ function setupGitignore(targetDir = EFFECTIVE_DIR) {
|
|
|
105
105
|
'session_backup_*'
|
|
106
106
|
];
|
|
107
107
|
const missingEntries = [];
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
// Check which entries are missing from .gitignore
|
|
110
110
|
if (fs.existsSync(gitignorePath)) {
|
|
111
111
|
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
112
|
-
const lines = content.split('\n').map(line => line.trim());
|
|
113
|
-
requiredEntries.forEach(entry => {
|
|
112
|
+
const lines = content.split('\n').map((line) => line.trim());
|
|
113
|
+
requiredEntries.forEach((entry) => {
|
|
114
114
|
if (!lines.includes(entry)) {
|
|
115
115
|
missingEntries.push(entry);
|
|
116
116
|
}
|
|
@@ -146,7 +146,7 @@ npm-debug.log*
|
|
|
146
146
|
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
147
147
|
console.log(' ✓ Created .gitignore');
|
|
148
148
|
}
|
|
149
|
-
|
|
149
|
+
|
|
150
150
|
return missingEntries;
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -155,7 +155,7 @@ npm-debug.log*
|
|
|
155
155
|
*/
|
|
156
156
|
function checkDependencies() {
|
|
157
157
|
const isWindows = process.platform === 'win32';
|
|
158
|
-
|
|
158
|
+
|
|
159
159
|
try {
|
|
160
160
|
// On Windows, check for zip.exe or 7z.exe
|
|
161
161
|
if (isWindows) {
|
|
@@ -195,19 +195,19 @@ function setup() {
|
|
|
195
195
|
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
196
196
|
console.log('║ Qwen API Proxy - Working Directory Setup ║');
|
|
197
197
|
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
198
|
-
|
|
198
|
+
|
|
199
199
|
console.log(`📍 Working directory: ${EFFECTIVE_DIR}\n`);
|
|
200
|
-
|
|
200
|
+
|
|
201
201
|
setupWorkingDirectory();
|
|
202
202
|
console.log();
|
|
203
203
|
setupEnvFile();
|
|
204
204
|
console.log();
|
|
205
|
-
|
|
205
|
+
|
|
206
206
|
const missingGitignoreDirs = setupGitignore();
|
|
207
207
|
console.log();
|
|
208
|
-
|
|
208
|
+
|
|
209
209
|
checkDependencies();
|
|
210
|
-
|
|
210
|
+
|
|
211
211
|
console.log('\n✅ Working directory setup complete!\n');
|
|
212
212
|
console.log('📝 Next steps for first-time users:');
|
|
213
213
|
console.log(' 1. Add an account: qwen-api-proxy (or npx qwen-api-proxy)');
|
|
@@ -220,11 +220,11 @@ function setup() {
|
|
|
220
220
|
console.log(' - Configure TELEGRAM_BOT_TOKEN in .env file');
|
|
221
221
|
console.log(' - Send session archive to the bot');
|
|
222
222
|
console.log('\n');
|
|
223
|
-
|
|
223
|
+
|
|
224
224
|
// Show warnings for missing .gitignore entries
|
|
225
225
|
if (missingGitignoreDirs.length > 0) {
|
|
226
226
|
console.warn('⚠️ WARNING: The following entries are not in .gitignore:');
|
|
227
|
-
missingGitignoreDirs.forEach(entry => {
|
|
227
|
+
missingGitignoreDirs.forEach((entry) => {
|
|
228
228
|
console.warn(` - ${entry}`);
|
|
229
229
|
});
|
|
230
230
|
console.warn('\n Add them to .gitignore to prevent committing sensitive data!\n');
|
|
@@ -235,41 +235,41 @@ function setup() {
|
|
|
235
235
|
const needsSetup = args.includes('--setup') || !fs.existsSync(path.join(EFFECTIVE_DIR, 'session'));
|
|
236
236
|
|
|
237
237
|
// Parse command from arguments (already defined args above)
|
|
238
|
-
const command = args.find(arg => !arg.startsWith('-'));
|
|
238
|
+
const command = args.find((arg) => !arg.startsWith('-'));
|
|
239
239
|
|
|
240
240
|
// Handle 'init' command - manual setup only
|
|
241
241
|
if (command === 'init') {
|
|
242
242
|
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
243
243
|
console.log('║ Qwen API Proxy - Initialize Working Directory ║');
|
|
244
244
|
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
245
|
-
|
|
245
|
+
|
|
246
246
|
console.log(`📍 Working directory: ${EFFECTIVE_DIR}\n`);
|
|
247
|
-
|
|
247
|
+
|
|
248
248
|
setupWorkingDirectory(EFFECTIVE_DIR);
|
|
249
249
|
console.log();
|
|
250
250
|
setupEnvFile(EFFECTIVE_DIR);
|
|
251
251
|
console.log();
|
|
252
|
-
|
|
252
|
+
|
|
253
253
|
const missingGitignoreDirs = setupGitignore(EFFECTIVE_DIR);
|
|
254
254
|
console.log();
|
|
255
|
-
|
|
255
|
+
|
|
256
256
|
checkDependencies();
|
|
257
|
-
|
|
257
|
+
|
|
258
258
|
console.log('\n✅ Working directory initialized successfully!\n');
|
|
259
259
|
console.log('📝 Next steps:');
|
|
260
260
|
console.log(' 1. Edit .env file with your configuration');
|
|
261
261
|
console.log(' 2. Run: qwen-api-proxy');
|
|
262
262
|
console.log('\n');
|
|
263
|
-
|
|
263
|
+
|
|
264
264
|
// Show warnings for missing .gitignore entries
|
|
265
265
|
if (missingGitignoreDirs.length > 0) {
|
|
266
266
|
console.warn('⚠️ WARNING: The following entries are not in .gitignore:');
|
|
267
|
-
missingGitignoreDirs.forEach(entry => {
|
|
267
|
+
missingGitignoreDirs.forEach((entry) => {
|
|
268
268
|
console.warn(` - ${entry}`);
|
|
269
269
|
});
|
|
270
270
|
console.warn('\n Add them to .gitignore to prevent committing sensitive data!\n');
|
|
271
271
|
}
|
|
272
|
-
|
|
272
|
+
|
|
273
273
|
process.exit(0);
|
|
274
274
|
}
|
|
275
275
|
|
|
@@ -278,11 +278,11 @@ if (command === 'doctor') {
|
|
|
278
278
|
console.log('\n╔══════════════════════════════════════════════════════════╗');
|
|
279
279
|
console.log('║ Qwen API Proxy - System Health Check ║');
|
|
280
280
|
console.log('╚══════════════════════════════════════════════════════════╝\n');
|
|
281
|
-
|
|
281
|
+
|
|
282
282
|
const issues = [];
|
|
283
283
|
const warnings = [];
|
|
284
284
|
const ok = [];
|
|
285
|
-
|
|
285
|
+
|
|
286
286
|
// Check Node.js version
|
|
287
287
|
const nodeVersion = process.version;
|
|
288
288
|
const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]);
|
|
@@ -291,7 +291,7 @@ if (command === 'doctor') {
|
|
|
291
291
|
} else {
|
|
292
292
|
issues.push(`Node.js ${nodeVersion} (✗ requires >= 18)`);
|
|
293
293
|
}
|
|
294
|
-
|
|
294
|
+
|
|
295
295
|
// Check zip command (cross-platform)
|
|
296
296
|
const isWindows = process.platform === 'win32';
|
|
297
297
|
let zipAvailable = false;
|
|
@@ -315,16 +315,16 @@ if (command === 'doctor') {
|
|
|
315
315
|
} catch (error) {
|
|
316
316
|
// zip not available
|
|
317
317
|
}
|
|
318
|
-
|
|
318
|
+
|
|
319
319
|
if (zipAvailable) {
|
|
320
320
|
ok.push('zip/7z command available');
|
|
321
321
|
} else {
|
|
322
322
|
warnings.push('zip/7z command not found (required for archive command)');
|
|
323
323
|
}
|
|
324
|
-
|
|
324
|
+
|
|
325
325
|
// Check working directory structure
|
|
326
326
|
const requiredDirs = ['session', 'session/accounts', 'session/history', 'logs', 'uploads', 'temp'];
|
|
327
|
-
requiredDirs.forEach(dir => {
|
|
327
|
+
requiredDirs.forEach((dir) => {
|
|
328
328
|
const dirPath = path.join(EFFECTIVE_DIR, dir);
|
|
329
329
|
if (fs.existsSync(dirPath)) {
|
|
330
330
|
ok.push(`${dir}/ directory exists`);
|
|
@@ -332,12 +332,12 @@ if (command === 'doctor') {
|
|
|
332
332
|
warnings.push(`${dir}/ directory missing`);
|
|
333
333
|
}
|
|
334
334
|
});
|
|
335
|
-
|
|
335
|
+
|
|
336
336
|
// Check .env file
|
|
337
337
|
const envPath = path.join(EFFECTIVE_DIR, '.env');
|
|
338
338
|
if (fs.existsSync(envPath)) {
|
|
339
339
|
ok.push('.env file exists');
|
|
340
|
-
|
|
340
|
+
|
|
341
341
|
// Check for common configurations
|
|
342
342
|
const envContent = fs.readFileSync(envPath, 'utf8');
|
|
343
343
|
if (envContent.includes('TELEGRAM_BOT_TOKEN=') && !envContent.includes('TELEGRAM_BOT_TOKEN=your_bot_token_here')) {
|
|
@@ -348,7 +348,7 @@ if (command === 'doctor') {
|
|
|
348
348
|
} else {
|
|
349
349
|
warnings.push('.env file not found (run "qwen-api-proxy init" to create)');
|
|
350
350
|
}
|
|
351
|
-
|
|
351
|
+
|
|
352
352
|
// Check .gitignore file
|
|
353
353
|
const gitignorePath = path.join(EFFECTIVE_DIR, '.gitignore');
|
|
354
354
|
const requiredGitignoreEntries = [
|
|
@@ -360,16 +360,16 @@ if (command === 'doctor') {
|
|
|
360
360
|
'session_backup_*'
|
|
361
361
|
];
|
|
362
362
|
const missingGitignoreEntries = [];
|
|
363
|
-
|
|
363
|
+
|
|
364
364
|
if (fs.existsSync(gitignorePath)) {
|
|
365
365
|
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
366
|
-
const lines = content.split('\n').map(line => line.trim());
|
|
367
|
-
requiredGitignoreEntries.forEach(entry => {
|
|
366
|
+
const lines = content.split('\n').map((line) => line.trim());
|
|
367
|
+
requiredGitignoreEntries.forEach((entry) => {
|
|
368
368
|
if (!lines.includes(entry)) {
|
|
369
369
|
missingGitignoreEntries.push(entry);
|
|
370
370
|
}
|
|
371
371
|
});
|
|
372
|
-
|
|
372
|
+
|
|
373
373
|
if (missingGitignoreEntries.length === 0) {
|
|
374
374
|
ok.push('.gitignore properly configured');
|
|
375
375
|
} else {
|
|
@@ -378,11 +378,11 @@ if (command === 'doctor') {
|
|
|
378
378
|
} else {
|
|
379
379
|
warnings.push('.gitignore not found (run "qwen-api-proxy init" to create)');
|
|
380
380
|
}
|
|
381
|
-
|
|
381
|
+
|
|
382
382
|
// Check permissions
|
|
383
383
|
const testDirs = ['session', 'logs', 'uploads'];
|
|
384
384
|
let permissionsOk = true;
|
|
385
|
-
testDirs.forEach(dir => {
|
|
385
|
+
testDirs.forEach((dir) => {
|
|
386
386
|
const dirPath = path.join(EFFECTIVE_DIR, dir);
|
|
387
387
|
if (fs.existsSync(dirPath)) {
|
|
388
388
|
try {
|
|
@@ -398,7 +398,7 @@ if (command === 'doctor') {
|
|
|
398
398
|
if (permissionsOk) {
|
|
399
399
|
ok.push('Directory permissions OK');
|
|
400
400
|
}
|
|
401
|
-
|
|
401
|
+
|
|
402
402
|
// Check session data
|
|
403
403
|
const tokensPath = path.join(EFFECTIVE_DIR, 'session', 'tokens.json');
|
|
404
404
|
if (fs.existsSync(tokensPath)) {
|
|
@@ -415,7 +415,7 @@ if (command === 'doctor') {
|
|
|
415
415
|
} else {
|
|
416
416
|
warnings.push('No accounts configured yet');
|
|
417
417
|
}
|
|
418
|
-
|
|
418
|
+
|
|
419
419
|
// Check disk space (cross-platform)
|
|
420
420
|
try {
|
|
421
421
|
if (isWindows) {
|
|
@@ -467,21 +467,21 @@ if (command === 'doctor') {
|
|
|
467
467
|
} catch (error) {
|
|
468
468
|
// df/wmic not available, skip
|
|
469
469
|
}
|
|
470
|
-
|
|
470
|
+
|
|
471
471
|
// Print results
|
|
472
472
|
console.log('✅ OK:');
|
|
473
|
-
ok.forEach(msg => console.log(` ✓ ${msg}`));
|
|
474
|
-
|
|
473
|
+
ok.forEach((msg) => console.log(` ✓ ${msg}`));
|
|
474
|
+
|
|
475
475
|
if (warnings.length > 0) {
|
|
476
476
|
console.log('\n⚠️ Warnings:');
|
|
477
|
-
warnings.forEach(msg => console.log(` ⚠ ${msg}`));
|
|
477
|
+
warnings.forEach((msg) => console.log(` ⚠ ${msg}`));
|
|
478
478
|
}
|
|
479
|
-
|
|
479
|
+
|
|
480
480
|
if (issues.length > 0) {
|
|
481
481
|
console.log('\n❌ Issues:');
|
|
482
|
-
issues.forEach(msg => console.log(` ✗ ${msg}`));
|
|
482
|
+
issues.forEach((msg) => console.log(` ✗ ${msg}`));
|
|
483
483
|
}
|
|
484
|
-
|
|
484
|
+
|
|
485
485
|
console.log('\n' + '='.repeat(60));
|
|
486
486
|
if (issues.length === 0 && warnings.length === 0) {
|
|
487
487
|
console.log('🎉 All checks passed! System is healthy.');
|
|
@@ -491,7 +491,7 @@ if (command === 'doctor') {
|
|
|
491
491
|
console.log(`✗ ${issues.length} issue(s) found - please fix before running`);
|
|
492
492
|
}
|
|
493
493
|
console.log('='.repeat(60) + '\n');
|
|
494
|
-
|
|
494
|
+
|
|
495
495
|
process.exit(issues.length > 0 ? 1 : 0);
|
|
496
496
|
}
|
|
497
497
|
|
package/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { checkPermissions } from './src/utils/permissionChecker.js';
|
|
|
15
15
|
import fs from 'fs';
|
|
16
16
|
import path from 'path';
|
|
17
17
|
import { execSync } from 'child_process';
|
|
18
|
-
import { SESSION_DIR } from './src/config.js';
|
|
18
|
+
import { SESSION_DIR, ACCOUNTS_DIR } from './src/config.js';
|
|
19
19
|
|
|
20
20
|
const app = express();
|
|
21
21
|
|
|
@@ -27,7 +27,7 @@ if (Number.isNaN(port) || port <= 0 || port > 65535) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function toBoolean(value) {
|
|
30
|
-
if (typeof value !== 'string') return false;
|
|
30
|
+
if (typeof value !== 'string') {return false;}
|
|
31
31
|
return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -42,7 +42,7 @@ function ensureNonInteractiveTokens() {
|
|
|
42
42
|
return false;
|
|
43
43
|
}
|
|
44
44
|
const now = Date.now();
|
|
45
|
-
const validTokens = tokens.filter(t => (!t.resetAt || new Date(t.resetAt).getTime() <= now) && !t.invalid);
|
|
45
|
+
const validTokens = tokens.filter((t) => (!t.resetAt || new Date(t.resetAt).getTime() <= now) && !t.invalid);
|
|
46
46
|
if (!validTokens.length) {
|
|
47
47
|
logWarn('⚠️ Все аккаунты недоступны. Сервер работает в режиме Telegram бота.');
|
|
48
48
|
logWarn('📦 Отправьте архив с сессиями через Telegram бот для обновления аккаунтов.');
|
|
@@ -75,7 +75,7 @@ app.use((req, res, next) => {
|
|
|
75
75
|
res.header('Access-Control-Allow-Origin', '*');
|
|
76
76
|
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
77
77
|
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
|
78
|
-
if (req.method === 'OPTIONS') return res.sendStatus(200);
|
|
78
|
+
if (req.method === 'OPTIONS') {return res.sendStatus(200);}
|
|
79
79
|
next();
|
|
80
80
|
});
|
|
81
81
|
|
|
@@ -134,10 +134,10 @@ function createSessionArchive() {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
// Проверяем, есть ли реальные данные (accounts, tokens.json, и т.д.)
|
|
137
|
-
const hasAccounts = fs.existsSync(path.join(sessionPath, 'accounts')) &&
|
|
137
|
+
const hasAccounts = fs.existsSync(path.join(sessionPath, 'accounts')) &&
|
|
138
138
|
fs.readdirSync(path.join(sessionPath, 'accounts')).length > 0;
|
|
139
139
|
const hasTokens = fs.existsSync(path.join(sessionPath, 'tokens.json'));
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
if (!hasAccounts && !hasTokens) {
|
|
142
142
|
throw new Error('Папка сессии не содержит данных аккаунтов.');
|
|
143
143
|
}
|
|
@@ -212,29 +212,29 @@ function validateGitignore() {
|
|
|
212
212
|
'session_backup',
|
|
213
213
|
'session_backup_*'
|
|
214
214
|
];
|
|
215
|
-
|
|
215
|
+
|
|
216
216
|
if (!fs.existsSync(gitignorePath)) {
|
|
217
217
|
logWarn('⚠️ Файл .gitignore не найден в корневой директории');
|
|
218
218
|
logWarn(' Рекомендуется создать .gitignore для защиты чувствительных данных');
|
|
219
219
|
return false;
|
|
220
220
|
}
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
223
|
-
const lines = content.split('\n').map(line => line.trim());
|
|
223
|
+
const lines = content.split('\n').map((line) => line.trim());
|
|
224
224
|
const missingEntries = [];
|
|
225
|
-
|
|
226
|
-
requiredEntries.forEach(entry => {
|
|
225
|
+
|
|
226
|
+
requiredEntries.forEach((entry) => {
|
|
227
227
|
if (!lines.includes(entry)) {
|
|
228
228
|
missingEntries.push(entry);
|
|
229
229
|
}
|
|
230
230
|
});
|
|
231
|
-
|
|
231
|
+
|
|
232
232
|
if (missingEntries.length > 0) {
|
|
233
233
|
logWarn(`⚠️ .gitignore отсутствует: ${missingEntries.join(', ')}`);
|
|
234
234
|
logWarn(' Добавьте эти записи в .gitignore для защиты данных');
|
|
235
235
|
return false;
|
|
236
236
|
}
|
|
237
|
-
|
|
237
|
+
|
|
238
238
|
logInfo('✅ .gitignore проверен - все записи на месте');
|
|
239
239
|
return true;
|
|
240
240
|
}
|
|
@@ -261,9 +261,9 @@ async function handleCLICommand() {
|
|
|
261
261
|
// Проверяем, есть ли уже аккаунты
|
|
262
262
|
const tokensPath = path.join(process.cwd(), SESSION_DIR, 'tokens.json');
|
|
263
263
|
const accountsPath = path.join(process.cwd(), SESSION_DIR, ACCOUNTS_DIR);
|
|
264
|
-
|
|
264
|
+
|
|
265
265
|
let hasAccounts = false;
|
|
266
|
-
|
|
266
|
+
|
|
267
267
|
if (fs.existsSync(tokensPath)) {
|
|
268
268
|
try {
|
|
269
269
|
const tokens = JSON.parse(fs.readFileSync(tokensPath, 'utf8'));
|
|
@@ -274,24 +274,24 @@ async function handleCLICommand() {
|
|
|
274
274
|
// tokens.json corrupted
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
|
-
|
|
277
|
+
|
|
278
278
|
if (!hasAccounts && fs.existsSync(accountsPath)) {
|
|
279
279
|
const accounts = fs.readdirSync(accountsPath);
|
|
280
280
|
if (accounts.length > 0) {
|
|
281
281
|
hasAccounts = true;
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
|
-
|
|
284
|
+
|
|
285
285
|
// Если аккаунтов нет, предлагаем добавить
|
|
286
286
|
if (!hasAccounts) {
|
|
287
287
|
console.log('📝 Аккаунты не найдены. Необходимо добавить аккаунт перед созданием архива.\n');
|
|
288
288
|
console.log('🔹 Вариант 1: Добавить аккаунт сейчас (откроется браузер)');
|
|
289
289
|
console.log('🔹 Вариант 2: Отправить файл сессии через Telegram бота');
|
|
290
290
|
console.log('🔹 Вариант 3: Выйти и запустить вручную: npx qwen-api-proxy\n');
|
|
291
|
-
|
|
291
|
+
|
|
292
292
|
const { prompt } = await import('./src/utils/prompt.js');
|
|
293
293
|
const choice = await prompt('Ваш выбор (1/2/3, Enter = 1): ');
|
|
294
|
-
|
|
294
|
+
|
|
295
295
|
if (choice === '2') {
|
|
296
296
|
console.log('\n💡 Для использования Telegram бота:');
|
|
297
297
|
console.log(' 1. Добавьте TELEGRAM_BOT_TOKEN в .env файл');
|
|
@@ -302,23 +302,23 @@ async function handleCLICommand() {
|
|
|
302
302
|
console.log('\n👋 Выход. Запустите "npx qwen-api-proxy" для добавления аккаунта.\n');
|
|
303
303
|
process.exit(0);
|
|
304
304
|
}
|
|
305
|
-
|
|
305
|
+
|
|
306
306
|
// choice === '1' или Enter - добавляем аккаунт
|
|
307
307
|
console.log('\n🔐 Запуск браузера для добавления аккаунта...\n');
|
|
308
|
-
|
|
308
|
+
|
|
309
309
|
const { addAccountInteractive } = await import('./src/utils/accountSetup.js');
|
|
310
310
|
const accountId = await addAccountInteractive();
|
|
311
|
-
|
|
311
|
+
|
|
312
312
|
if (!accountId) {
|
|
313
313
|
console.log('\n❌ Аккаунт не был добавлен. Архив не создан.\n');
|
|
314
314
|
process.exit(1);
|
|
315
315
|
}
|
|
316
|
-
|
|
316
|
+
|
|
317
317
|
console.log(`\n✅ Аккаунт ${accountId} успешно добавлен!\n`);
|
|
318
318
|
} else {
|
|
319
319
|
console.log('✅ Найден существующий аккаунт\n');
|
|
320
320
|
}
|
|
321
|
-
|
|
321
|
+
|
|
322
322
|
// Теперь создаем архив
|
|
323
323
|
const archivePath = createSessionArchive();
|
|
324
324
|
console.log('\n🎉 ГОТОВО!');
|
|
@@ -406,7 +406,7 @@ async function startServer() {
|
|
|
406
406
|
console.log('4 - Удалить аккаунт');
|
|
407
407
|
|
|
408
408
|
let choice = await prompt('Ваш выбор (Enter = 3): ');
|
|
409
|
-
if (!choice) choice = '3';
|
|
409
|
+
if (!choice) {choice = '3';}
|
|
410
410
|
|
|
411
411
|
if (choice === '1') {
|
|
412
412
|
await addAccountInteractive();
|
|
@@ -414,9 +414,9 @@ async function startServer() {
|
|
|
414
414
|
const { reloginAccountInteractive } = await import('./src/utils/accountSetup.js');
|
|
415
415
|
await reloginAccountInteractive();
|
|
416
416
|
} else if (choice === '3') {
|
|
417
|
-
const hasValidToken = tokens.some(t => {
|
|
418
|
-
if (t.invalid) return false;
|
|
419
|
-
if (!t.resetAt) return true;
|
|
417
|
+
const hasValidToken = tokens.some((t) => {
|
|
418
|
+
if (t.invalid) {return false;}
|
|
419
|
+
if (!t.resetAt) {return true;}
|
|
420
420
|
return new Date(t.resetAt).getTime() <= Date.now();
|
|
421
421
|
});
|
|
422
422
|
if (!tokens.length || !hasValidToken) {
|
|
@@ -508,7 +508,7 @@ async function startServer() {
|
|
|
508
508
|
logInfo('🔍 Начинаем загрузку списка моделей...');
|
|
509
509
|
const apiModels = await fetchModelsFromAPI();
|
|
510
510
|
logDebug(`fetchModelsFromAPI вернул: ${apiModels ? apiModels.length + ' моделей' : 'null'}`);
|
|
511
|
-
|
|
511
|
+
|
|
512
512
|
if (apiModels && apiModels.length > 0) {
|
|
513
513
|
logInfo(`✅ Загружено ${apiModels.length} моделей с Qwen API`);
|
|
514
514
|
logDebug(`Первые 5 моделей: ${apiModels.slice(0, 5).join(', ')}`);
|
|
@@ -519,11 +519,11 @@ async function startServer() {
|
|
|
519
519
|
const fileModels = getAvailableModelsFromFile();
|
|
520
520
|
logDebug(`getAvailableModelsFromFile вернул: ${fileModels ? fileModels.length + ' моделей' : 'null'}`);
|
|
521
521
|
}
|
|
522
|
-
|
|
522
|
+
|
|
523
523
|
const defaultModel = getDefaultModel();
|
|
524
524
|
logInfo(`🎯 Модель по умолчанию: ${defaultModel}`);
|
|
525
525
|
logDebug(`getDefaultModel() вернул: ${defaultModel}`);
|
|
526
|
-
|
|
526
|
+
|
|
527
527
|
getApiKeys();
|
|
528
528
|
});
|
|
529
529
|
} catch (err) {
|
|
@@ -537,10 +537,10 @@ async function startServer() {
|
|
|
537
537
|
}
|
|
538
538
|
|
|
539
539
|
// Проверяем CLI команды перед запуском сервера
|
|
540
|
-
handleCLICommand().then(hasCommand => {
|
|
540
|
+
handleCLICommand().then((hasCommand) => {
|
|
541
541
|
if (!hasCommand) {
|
|
542
542
|
// Нет команды CLI, запускаем сервер как обычно
|
|
543
|
-
startServer().catch(async error => {
|
|
543
|
+
startServer().catch(async (error) => {
|
|
544
544
|
logError('Ошибка при запуске сервера', error);
|
|
545
545
|
await shutdownBrowser();
|
|
546
546
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwen-api-proxy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
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": {
|
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
"scripts": {
|
|
45
45
|
"start": "node index.js",
|
|
46
46
|
"archive": "node index.js archive",
|
|
47
|
+
"lint": "eslint .",
|
|
48
|
+
"lint:fix": "eslint . --fix",
|
|
47
49
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
48
50
|
"test:cross-platform": "node test-cross-platform.js",
|
|
49
51
|
"check-permissions": "node scripts/checkPermissions.js",
|
|
@@ -82,5 +84,9 @@
|
|
|
82
84
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
83
85
|
"undici": "^6.21.1",
|
|
84
86
|
"winston": "^3.17.0"
|
|
87
|
+
},
|
|
88
|
+
"devDependencies": {
|
|
89
|
+
"eslint": "^9.39.4",
|
|
90
|
+
"eslint-plugin-import": "^2.32.0"
|
|
85
91
|
}
|
|
86
|
-
}
|
|
92
|
+
}
|