@pedrofariasx/qwenproxy 1.6.2 → 1.6.4
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/package.json +1 -1
- package/src/core/config.ts +5 -3
- package/src/services/playwright.ts +57 -57
- package/src/services/qwen.ts +93 -9
package/package.json
CHANGED
package/src/core/config.ts
CHANGED
|
@@ -8,9 +8,10 @@ const envSchema = z.object({
|
|
|
8
8
|
USER_DATA_DIR: z.string().default('./qwen_profiles'),
|
|
9
9
|
USER_AGENT: z.string().default('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'),
|
|
10
10
|
LOG_CONSOLE: z.string().default('false'),
|
|
11
|
-
NAVIGATION_TIMEOUT: z.string().default('
|
|
12
|
-
PAGE_TIMEOUT: z.string().default('
|
|
13
|
-
HTTP_TIMEOUT: z.string().default('
|
|
11
|
+
NAVIGATION_TIMEOUT: z.string().default('45000'),
|
|
12
|
+
PAGE_TIMEOUT: z.string().default('30000'),
|
|
13
|
+
HTTP_TIMEOUT: z.string().default('30000'),
|
|
14
|
+
HEADERS_TIMEOUT: z.string().default('60000'),
|
|
14
15
|
CHAT_TIMEOUT: z.string().default('120000'),
|
|
15
16
|
CACHE_TTL: z.string().default('3600'),
|
|
16
17
|
RESPONSE_TTL: z.string().default('1800'),
|
|
@@ -59,6 +60,7 @@ export const config = {
|
|
|
59
60
|
navigation: parseInt(env.NAVIGATION_TIMEOUT),
|
|
60
61
|
page: parseInt(env.PAGE_TIMEOUT),
|
|
61
62
|
http: parseInt(env.HTTP_TIMEOUT),
|
|
63
|
+
headers: parseInt(env.HEADERS_TIMEOUT),
|
|
62
64
|
chat: parseInt(env.CHAT_TIMEOUT),
|
|
63
65
|
},
|
|
64
66
|
cache: {
|
|
@@ -385,7 +385,7 @@ async function checkValidSession(): Promise<boolean> {
|
|
|
385
385
|
const cookies = await activePage.context().cookies();
|
|
386
386
|
const hasAuthCookie = cookies.some(c => c.name.toLowerCase().includes('token') || c.name.toLowerCase().includes('session'));
|
|
387
387
|
if (!hasAuthCookie) return false;
|
|
388
|
-
await activePage.goto('https://chat.qwen.ai/', { waitUntil: 'domcontentloaded', timeout:
|
|
388
|
+
await activePage.goto('https://chat.qwen.ai/', { waitUntil: 'domcontentloaded', timeout: config.timeouts.navigation });
|
|
389
389
|
const isLogged = !activePage.url().includes('auth') && !activePage.url().includes('login');
|
|
390
390
|
return isLogged;
|
|
391
391
|
} catch {
|
|
@@ -450,7 +450,7 @@ async function loginToQwenUI(email: string, password: string): Promise<boolean>
|
|
|
450
450
|
}
|
|
451
451
|
|
|
452
452
|
try {
|
|
453
|
-
await activePage.waitForSelector('input[type="email"], input[placeholder*="Email"]', { timeout:
|
|
453
|
+
await activePage.waitForSelector('input[type="email"], input[placeholder*="Email"]', { timeout: config.timeouts.page });
|
|
454
454
|
} catch {
|
|
455
455
|
if (activePage.url().includes('/auth')) throw new Error('Email input not found');
|
|
456
456
|
console.log('[Playwright] Already logged in');
|
|
@@ -462,7 +462,7 @@ async function loginToQwenUI(email: string, password: string): Promise<boolean>
|
|
|
462
462
|
await activePage.keyboard.press('Enter');
|
|
463
463
|
await sleep(1000);
|
|
464
464
|
|
|
465
|
-
await activePage.waitForSelector('input[type="password"]', { timeout:
|
|
465
|
+
await activePage.waitForSelector('input[type="password"]', { timeout: config.timeouts.page });
|
|
466
466
|
console.log('[Playwright] UI: Filling password...');
|
|
467
467
|
await activePage.fill('input[type="password"]', password);
|
|
468
468
|
await activePage.keyboard.press('Enter');
|
|
@@ -502,7 +502,7 @@ export async function getGuestHeaders(): Promise<Record<string, string>> {
|
|
|
502
502
|
await guestContext.addInitScript(getStealthScript());
|
|
503
503
|
guestPage = await guestContext.newPage();
|
|
504
504
|
|
|
505
|
-
await guestPage.goto('https://chat.qwen.ai/c/guest', { waitUntil: 'domcontentloaded' });
|
|
505
|
+
await guestPage.goto('https://chat.qwen.ai/c/guest', { waitUntil: 'domcontentloaded', timeout: config.timeouts.navigation });
|
|
506
506
|
|
|
507
507
|
try {
|
|
508
508
|
const keepSessionBtn = await guestPage.$('button:has-text("Manter sessão terminada"), button:has-text("Keep session ended"), button:has-text("Manter sessão encerrada")');
|
|
@@ -517,7 +517,7 @@ export async function getGuestHeaders(): Promise<Record<string, string>> {
|
|
|
517
517
|
}
|
|
518
518
|
|
|
519
519
|
return new Promise((resolve, reject) => {
|
|
520
|
-
const timeout = setTimeout(() => reject(new Error('Timeout getting guest headers')),
|
|
520
|
+
const timeout = setTimeout(() => reject(new Error('Timeout getting guest headers')), config.timeouts.headers);
|
|
521
521
|
|
|
522
522
|
const routeHandler = async (route: any, request: any) => {
|
|
523
523
|
clearTimeout(timeout);
|
|
@@ -558,27 +558,25 @@ export async function getGuestHeaders(): Promise<Record<string, string>> {
|
|
|
558
558
|
guestPage!.route('**/api/v2/chat/completions*', routeHandler).then(async () => {
|
|
559
559
|
const inputSelector = 'textarea:visible, [contenteditable="true"]:visible';
|
|
560
560
|
try {
|
|
561
|
-
await guestPage!.waitForSelector(inputSelector, { timeout:
|
|
561
|
+
await guestPage!.waitForSelector(inputSelector, { timeout: config.timeouts.page });
|
|
562
562
|
await guestPage!.focus(inputSelector);
|
|
563
563
|
await guestPage!.fill(inputSelector, '');
|
|
564
564
|
await guestPage!.type(inputSelector, 'a', { delay: 50 });
|
|
565
|
-
await sleep(
|
|
565
|
+
await sleep(1000);
|
|
566
566
|
|
|
567
|
-
// Try pressing Enter first as it is highly reliable
|
|
568
|
-
await guestPage!.focus(inputSelector);
|
|
569
|
-
await guestPage!.keyboard.press('Enter');
|
|
570
|
-
|
|
571
567
|
const selectors = ['.message-input-right-button-send .send-button', '.chat-prompt-send-button', 'button.send-button'];
|
|
568
|
+
let clicked = false;
|
|
572
569
|
for (const selector of selectors) {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
} catch (e) {
|
|
579
|
-
// ignore click errors
|
|
570
|
+
const btn = await guestPage!.$(selector);
|
|
571
|
+
if (btn && await btn.isVisible()) {
|
|
572
|
+
await btn.click({ force: true, delay: 50 }).catch(() => {});
|
|
573
|
+
clicked = true;
|
|
574
|
+
break;
|
|
580
575
|
}
|
|
581
576
|
}
|
|
577
|
+
if (!clicked) {
|
|
578
|
+
await guestPage!.keyboard.press('Enter');
|
|
579
|
+
}
|
|
582
580
|
} catch (e) {
|
|
583
581
|
clearTimeout(timeout);
|
|
584
582
|
reject(e);
|
|
@@ -753,7 +751,7 @@ async function _getQwenHeadersInternal(forceNew = false, accountId?: string): Pr
|
|
|
753
751
|
|
|
754
752
|
console.log(`[Playwright] Waiting for chat input for ${cacheKey}...`);
|
|
755
753
|
const inputSelector = 'textarea:visible, [contenteditable="true"]:visible';
|
|
756
|
-
await page.waitForSelector(inputSelector, { timeout:
|
|
754
|
+
await page.waitForSelector(inputSelector, { timeout: config.timeouts.page }).catch(() => {
|
|
757
755
|
console.error(`[Playwright] Chat input not found for ${cacheKey}. Current URL:`, page.url());
|
|
758
756
|
throw new Error(`Timeout waiting for chat input for ${cacheKey}. Are you logged in?`);
|
|
759
757
|
});
|
|
@@ -769,7 +767,7 @@ async function _getQwenHeadersInternal(forceNew = false, accountId?: string): Pr
|
|
|
769
767
|
console.error('[Playwright] Failed to save error screenshot:', err.message);
|
|
770
768
|
}
|
|
771
769
|
reject(new Error(`Timeout waiting for Qwen headers for ${cacheKey}`));
|
|
772
|
-
},
|
|
770
|
+
}, config.timeouts.headers);
|
|
773
771
|
|
|
774
772
|
console.log(`[Playwright] Setting up route interception for ${cacheKey}...`);
|
|
775
773
|
const routeHandler = async (route: any, request: any) => {
|
|
@@ -827,45 +825,47 @@ async function _getQwenHeadersInternal(forceNew = false, accountId?: string): Pr
|
|
|
827
825
|
console.log(`[Playwright] Triggering request for ${cacheKey}...`);
|
|
828
826
|
const inputSelector = 'textarea:visible, [contenteditable="true"]:visible';
|
|
829
827
|
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
await sleep(1500);
|
|
828
|
+
await page.focus(inputSelector);
|
|
829
|
+
await page.fill(inputSelector, '');
|
|
830
|
+
await page.type(inputSelector, 'a', { delay: 100 });
|
|
831
|
+
console.log(`[Playwright] Typed char for ${cacheKey}, waiting for UI to update...`);
|
|
832
|
+
await sleep(2000);
|
|
836
833
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
834
|
+
const selectors = [
|
|
835
|
+
'.message-input-right-button-send .send-button',
|
|
836
|
+
'.chat-prompt-send-button',
|
|
837
|
+
'button.send-button'
|
|
838
|
+
];
|
|
841
839
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
840
|
+
let clicked = false;
|
|
841
|
+
for (const selector of selectors) {
|
|
842
|
+
try {
|
|
843
|
+
const btn = await page.$(selector);
|
|
844
|
+
if (btn && await btn.isVisible()) {
|
|
845
|
+
console.log(`[Playwright] Attempting click on: ${selector}`);
|
|
846
|
+
|
|
847
|
+
await page.evaluate((sel) => {
|
|
848
|
+
const element = document.querySelector(sel) as HTMLElement;
|
|
849
|
+
if (element) {
|
|
850
|
+
element.focus();
|
|
851
|
+
element.click();
|
|
852
|
+
}
|
|
853
|
+
}, selector);
|
|
848
854
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
console.log(`[Playwright] Also attempting click on: ${selector}`);
|
|
854
|
-
await page.evaluate((sel) => {
|
|
855
|
-
const element = document.querySelector(sel) as HTMLElement;
|
|
856
|
-
if (element) {
|
|
857
|
-
element.focus();
|
|
858
|
-
element.click();
|
|
859
|
-
}
|
|
860
|
-
}, selector);
|
|
861
|
-
await btn.click({ force: true, delay: 50 }).catch(() => {});
|
|
862
|
-
}
|
|
863
|
-
} catch (e) {
|
|
864
|
-
// ignore click errors
|
|
855
|
+
await btn.click({ force: true, delay: 50 }).catch(() => {});
|
|
856
|
+
|
|
857
|
+
clicked = true;
|
|
858
|
+
break;
|
|
865
859
|
}
|
|
860
|
+
} catch (e) {
|
|
861
|
+
console.error(`[Playwright] Error clicking ${selector} for ${cacheKey}:`, e);
|
|
866
862
|
}
|
|
867
|
-
}
|
|
868
|
-
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
if (!clicked) {
|
|
866
|
+
console.log(`[Playwright] No send button found/clicked for ${cacheKey}, fallback to Enter...`);
|
|
867
|
+
await page.focus(inputSelector);
|
|
868
|
+
await page.keyboard.press('Enter');
|
|
869
869
|
}
|
|
870
870
|
});
|
|
871
871
|
});
|
|
@@ -906,13 +906,13 @@ export async function initPlaywrightForAccount(account: QwenAccount, headless =
|
|
|
906
906
|
|
|
907
907
|
// Navigate to Qwen home to validate session and populate cookies
|
|
908
908
|
try {
|
|
909
|
-
await acctPage.goto('https://chat.qwen.ai/', { waitUntil: 'domcontentloaded', timeout:
|
|
909
|
+
await acctPage.goto('https://chat.qwen.ai/', { waitUntil: 'domcontentloaded', timeout: config.timeouts.navigation });
|
|
910
910
|
const url = acctPage.url();
|
|
911
911
|
if (url.includes('auth') || url.includes('login')) {
|
|
912
912
|
if (account.email && account.password) {
|
|
913
913
|
console.log(`[Playwright] Session expired for ${account.email}, re-logging in...`);
|
|
914
914
|
await loginToQwenWithContext(acctContext, acctPage, account.email, account.password);
|
|
915
|
-
await acctPage.goto('https://chat.qwen.ai/', { waitUntil: 'domcontentloaded', timeout:
|
|
915
|
+
await acctPage.goto('https://chat.qwen.ai/', { waitUntil: 'domcontentloaded', timeout: config.timeouts.navigation });
|
|
916
916
|
} else {
|
|
917
917
|
console.warn(`[Playwright] Session expired for account ${account.id} but no credentials available for re-login.`);
|
|
918
918
|
}
|
|
@@ -1122,7 +1122,7 @@ export async function browserStreamFetch(
|
|
|
1122
1122
|
streamCallbacks.delete(reqId);
|
|
1123
1123
|
abortControllers.delete(reqId);
|
|
1124
1124
|
metaResolve({ status: 0, statusText: 'Timeout', contentType: '', headers: {} });
|
|
1125
|
-
}, options.timeoutMs ||
|
|
1125
|
+
}, options.timeoutMs || config.timeouts.chat);
|
|
1126
1126
|
|
|
1127
1127
|
streamCallbacks.set(reqId, {
|
|
1128
1128
|
onMeta: (meta) => {
|
package/src/services/qwen.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getQwenHeaders, getBasicHeaders, getGuestHeaders, getPageForAccount, browserFetch, browserStreamFetch, CHROME_CLIENT_HINTS, CHROME_UA } from './playwright.js';
|
|
2
2
|
import { MAX_PAYLOAD_SIZE } from '../core/model-registry.js';
|
|
3
3
|
import { markAccountRateLimited } from '../core/account-manager.js';
|
|
4
|
+
import { config } from '../core/config.js';
|
|
4
5
|
import crypto from 'crypto';
|
|
5
6
|
|
|
6
7
|
const CACHED_TIMEZONE = new Date().toString().split(' (')[0];
|
|
@@ -132,7 +133,7 @@ async function createRealQwenChat(header: Record<string, string>, accountId?: st
|
|
|
132
133
|
'timezone': CACHED_TIMEZONE,
|
|
133
134
|
},
|
|
134
135
|
body,
|
|
135
|
-
timeoutMs:
|
|
136
|
+
timeoutMs: config.timeouts.http,
|
|
136
137
|
});
|
|
137
138
|
|
|
138
139
|
if (result.status === 429) {
|
|
@@ -176,7 +177,7 @@ async function createRealQwenChat(header: Record<string, string>, accountId?: st
|
|
|
176
177
|
...getClientHintsHeaders(),
|
|
177
178
|
},
|
|
178
179
|
body,
|
|
179
|
-
signal: AbortSignal.timeout(
|
|
180
|
+
signal: AbortSignal.timeout(config.timeouts.http),
|
|
180
181
|
});
|
|
181
182
|
|
|
182
183
|
if (!response.ok) {
|
|
@@ -200,6 +201,69 @@ async function createRealQwenChat(header: Record<string, string>, accountId?: st
|
|
|
200
201
|
return chatId;
|
|
201
202
|
}
|
|
202
203
|
|
|
204
|
+
async function fetchUnusedChats(headers: Record<string, string>, accountId?: string): Promise<string[]> {
|
|
205
|
+
const page = getPageForAccount(accountId);
|
|
206
|
+
const url = 'https://chat.qwen.ai/api/v2/chats/?page=1&exclude_project=true';
|
|
207
|
+
const reqHeaders: Record<string, string> = {
|
|
208
|
+
'accept': 'application/json, text/plain, */*',
|
|
209
|
+
'x-request-id': crypto.randomUUID(),
|
|
210
|
+
'timezone': CACHED_TIMEZONE,
|
|
211
|
+
'source': 'web',
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
let body = '';
|
|
215
|
+
if (page && !page.isClosed() && page.url().includes('chat.qwen.ai')) {
|
|
216
|
+
try {
|
|
217
|
+
const result = await browserFetch(page, url, {
|
|
218
|
+
method: 'GET',
|
|
219
|
+
headers: reqHeaders,
|
|
220
|
+
timeoutMs: config.timeouts.http,
|
|
221
|
+
});
|
|
222
|
+
if (result.status && result.status < 400) {
|
|
223
|
+
body = result.body;
|
|
224
|
+
}
|
|
225
|
+
} catch (err: any) {
|
|
226
|
+
console.warn('[WarmPool] browserFetch failed for chat list, falling back:', err.message);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (!body) {
|
|
231
|
+
const response = await fetch(url, {
|
|
232
|
+
headers: {
|
|
233
|
+
'accept': 'application/json, text/plain, */*',
|
|
234
|
+
'accept-language': 'pt-BR,pt;q=0.9',
|
|
235
|
+
'cookie': headers['cookie'],
|
|
236
|
+
'referer': 'https://chat.qwen.ai/',
|
|
237
|
+
'user-agent': headers['user-agent'],
|
|
238
|
+
'x-request-id': crypto.randomUUID(),
|
|
239
|
+
'bx-v': headers['bx-v'],
|
|
240
|
+
'bx-ua': headers['bx-ua'] || '',
|
|
241
|
+
'bx-umidtoken': headers['bx-umidtoken'] || '',
|
|
242
|
+
'timezone': CACHED_TIMEZONE,
|
|
243
|
+
'source': 'web',
|
|
244
|
+
...getClientHintsHeaders(),
|
|
245
|
+
},
|
|
246
|
+
signal: AbortSignal.timeout(config.timeouts.http),
|
|
247
|
+
});
|
|
248
|
+
if (!response.ok) return [];
|
|
249
|
+
body = await response.text();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
const json = JSON.parse(body);
|
|
254
|
+
if (!json.success || !Array.isArray(json.data)) return [];
|
|
255
|
+
const unused: string[] = [];
|
|
256
|
+
for (const chat of json.data) {
|
|
257
|
+
if (chat.title === 'Nova Conversa' && chat.created_at === chat.updated_at) {
|
|
258
|
+
unused.push(chat.id);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return unused;
|
|
262
|
+
} catch {
|
|
263
|
+
return [];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
203
267
|
async function refillPoolForAccount(accountId: string) {
|
|
204
268
|
let pool = warmPool.get(accountId);
|
|
205
269
|
if (!pool) { pool = []; warmPool.set(accountId, pool); }
|
|
@@ -217,7 +281,27 @@ async function refillPoolForAccount(accountId: string) {
|
|
|
217
281
|
}
|
|
218
282
|
|
|
219
283
|
const acctId = accountId === 'global' ? undefined : accountId;
|
|
220
|
-
|
|
284
|
+
const existingIds = new Set(pool.map(e => e.chatId));
|
|
285
|
+
|
|
286
|
+
let reused = 0;
|
|
287
|
+
try {
|
|
288
|
+
const unusedChats = await fetchUnusedChats(headers, acctId);
|
|
289
|
+
for (const chatId of unusedChats) {
|
|
290
|
+
if (reused >= need) break;
|
|
291
|
+
if (existingIds.has(chatId)) continue;
|
|
292
|
+
pool.push({ chatId, headers, accountId, timestamp: Date.now() });
|
|
293
|
+
existingIds.add(chatId);
|
|
294
|
+
reused++;
|
|
295
|
+
}
|
|
296
|
+
if (reused > 0) {
|
|
297
|
+
console.log(`[WarmPool] Reused ${reused} existing unused chats for ${accountId}`);
|
|
298
|
+
}
|
|
299
|
+
} catch (err: any) {
|
|
300
|
+
console.warn(`[WarmPool] Failed to fetch unused chats for ${accountId}:`, err.message);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const stillNeed = Math.max(0, need - reused);
|
|
304
|
+
for (let i = 0; i < stillNeed; i++) {
|
|
221
305
|
if (i > 0) {
|
|
222
306
|
await sleep(800 + Math.floor(Math.random() * 2200));
|
|
223
307
|
}
|
|
@@ -355,7 +439,7 @@ export async function disableNativeTools(accountId?: string): Promise<void> {
|
|
|
355
439
|
'timezone': CACHED_TIMEZONE,
|
|
356
440
|
},
|
|
357
441
|
body: JSON.stringify(payload),
|
|
358
|
-
timeoutMs:
|
|
442
|
+
timeoutMs: config.timeouts.http,
|
|
359
443
|
});
|
|
360
444
|
if (result.status && result.status < 400) {
|
|
361
445
|
console.log(`[Qwen] Native tools disabled successfully for ${cacheKey}.`);
|
|
@@ -370,7 +454,7 @@ export async function disableNativeTools(accountId?: string): Promise<void> {
|
|
|
370
454
|
}
|
|
371
455
|
|
|
372
456
|
const controller = new AbortController();
|
|
373
|
-
const timeoutId = setTimeout(() => controller.abort(),
|
|
457
|
+
const timeoutId = setTimeout(() => controller.abort(), config.timeouts.http);
|
|
374
458
|
const response = await fetch('https://chat.qwen.ai/api/v2/users/user/settings/update', {
|
|
375
459
|
method: 'POST',
|
|
376
460
|
headers: {
|
|
@@ -422,7 +506,7 @@ export async function fetchQwenModels(accountId?: string): Promise<any[]> {
|
|
|
422
506
|
'timezone': CACHED_TIMEZONE,
|
|
423
507
|
'source': 'web',
|
|
424
508
|
},
|
|
425
|
-
timeoutMs:
|
|
509
|
+
timeoutMs: config.timeouts.http,
|
|
426
510
|
});
|
|
427
511
|
if (result.status && result.status < 400) {
|
|
428
512
|
return processModelsJson(JSON.parse(result.body));
|
|
@@ -526,7 +610,7 @@ export async function createQwenStream(
|
|
|
526
610
|
method: 'POST',
|
|
527
611
|
headers: { 'accept': 'application/json, text/plain, */*', 'content-type': 'application/json', 'x-request-id': crypto.randomUUID(), 'timezone': CACHED_TIMEZONE },
|
|
528
612
|
body: guestBody,
|
|
529
|
-
timeoutMs:
|
|
613
|
+
timeoutMs: config.timeouts.http,
|
|
530
614
|
});
|
|
531
615
|
if (!result.status || result.status >= 400) throw new Error(`Failed to create guest chat: ${result.status}`);
|
|
532
616
|
const json = JSON.parse(result.body);
|
|
@@ -538,7 +622,7 @@ export async function createQwenStream(
|
|
|
538
622
|
method: 'POST',
|
|
539
623
|
headers: { 'accept': 'application/json, text/plain, */*', 'content-type': 'application/json', cookie: chatHeaders['cookie'], origin: 'https://chat.qwen.ai', referer: 'https://chat.qwen.ai/c/guest', 'user-agent': chatHeaders['user-agent'], 'x-request-id': crypto.randomUUID(), 'bx-v': chatHeaders['bx-v'], 'bx-ua': chatHeaders['bx-ua'], 'bx-umidtoken': chatHeaders['bx-umidtoken'], ...getClientHintsHeaders() },
|
|
540
624
|
body: guestBody,
|
|
541
|
-
signal: AbortSignal.timeout(
|
|
625
|
+
signal: AbortSignal.timeout(config.timeouts.http),
|
|
542
626
|
});
|
|
543
627
|
if (!response.ok) throw new Error(`Failed to create guest chat: ${response.status}`);
|
|
544
628
|
const json = await response.json();
|
|
@@ -550,7 +634,7 @@ export async function createQwenStream(
|
|
|
550
634
|
method: 'POST',
|
|
551
635
|
headers: { 'accept': 'application/json, text/plain, */*', 'content-type': 'application/json', cookie: chatHeaders['cookie'], origin: 'https://chat.qwen.ai', referer: 'https://chat.qwen.ai/c/guest', 'user-agent': chatHeaders['user-agent'], 'x-request-id': crypto.randomUUID(), 'bx-v': chatHeaders['bx-v'], 'bx-ua': chatHeaders['bx-ua'], 'bx-umidtoken': chatHeaders['bx-umidtoken'], ...getClientHintsHeaders() },
|
|
552
636
|
body: guestBody,
|
|
553
|
-
signal: AbortSignal.timeout(
|
|
637
|
+
signal: AbortSignal.timeout(config.timeouts.http),
|
|
554
638
|
});
|
|
555
639
|
if (!response.ok) throw new Error(`Failed to create guest chat: ${response.status}`);
|
|
556
640
|
const json = await response.json();
|