@pedrofariasx/qwenproxy 1.6.0 → 1.6.2
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/accounts.ts +2 -3
- package/src/routes/chat.ts +2 -2
- package/src/services/playwright.ts +46 -46
- package/src/services/qwen.ts +6 -0
package/package.json
CHANGED
package/src/core/accounts.ts
CHANGED
|
@@ -74,9 +74,8 @@ export function listAccounts(): QwenAccount[] {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
export function getAccountCredentials(id: string): QwenAccount | undefined {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
return row as QwenAccount | undefined
|
|
77
|
+
const cached = getCachedAccounts()
|
|
78
|
+
return cached.find(a => a.id === id)
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
export function updateAccountCooldown(id: string, cooldownUntil: number, reason: string | null): void {
|
package/src/routes/chat.ts
CHANGED
|
@@ -566,12 +566,12 @@ export async function chatCompletions(c: Context) {
|
|
|
566
566
|
const createdTimestamp = Math.floor(Date.now() / 1000);
|
|
567
567
|
|
|
568
568
|
const fastWriteContent = (content: string) => {
|
|
569
|
-
const escaped =
|
|
569
|
+
const escaped = JSON.stringify(content).slice(1, -1);
|
|
570
570
|
streamWriter.write(`data: {"id":"${completionId}","object":"chat.completion.chunk","created":${createdTimestamp},"model":"${body.model}","choices":[{"index":0,"delta":{"content":"${escaped}"},"logprobs":null,"finish_reason":null}]}\n\n`);
|
|
571
571
|
};
|
|
572
572
|
|
|
573
573
|
const fastWriteReasoning = (content: string) => {
|
|
574
|
-
const escaped =
|
|
574
|
+
const escaped = JSON.stringify(content).slice(1, -1);
|
|
575
575
|
streamWriter.write(`data: {"id":"${completionId}","object":"chat.completion.chunk","created":${createdTimestamp},"model":"${body.model}","choices":[{"index":0,"delta":{"reasoning_content":"${escaped}"},"logprobs":null,"finish_reason":null}]}\n\n`);
|
|
576
576
|
};
|
|
577
577
|
|
|
@@ -562,21 +562,23 @@ export async function getGuestHeaders(): Promise<Record<string, string>> {
|
|
|
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(1500);
|
|
566
566
|
|
|
567
|
+
// Try pressing Enter first as it is highly reliable
|
|
568
|
+
await guestPage!.focus(inputSelector);
|
|
569
|
+
await guestPage!.keyboard.press('Enter');
|
|
570
|
+
|
|
567
571
|
const selectors = ['.message-input-right-button-send .send-button', '.chat-prompt-send-button', 'button.send-button'];
|
|
568
|
-
let clicked = false;
|
|
569
572
|
for (const selector of selectors) {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
573
|
+
try {
|
|
574
|
+
const btn = await guestPage!.$(selector);
|
|
575
|
+
if (btn && await btn.isVisible()) {
|
|
576
|
+
await btn.click({ force: true, delay: 50 }).catch(() => {});
|
|
577
|
+
}
|
|
578
|
+
} catch (e) {
|
|
579
|
+
// ignore click errors
|
|
575
580
|
}
|
|
576
581
|
}
|
|
577
|
-
if (!clicked) {
|
|
578
|
-
await guestPage!.keyboard.press('Enter');
|
|
579
|
-
}
|
|
580
582
|
} catch (e) {
|
|
581
583
|
clearTimeout(timeout);
|
|
582
584
|
reject(e);
|
|
@@ -825,47 +827,45 @@ async function _getQwenHeadersInternal(forceNew = false, accountId?: string): Pr
|
|
|
825
827
|
console.log(`[Playwright] Triggering request for ${cacheKey}...`);
|
|
826
828
|
const inputSelector = 'textarea:visible, [contenteditable="true"]:visible';
|
|
827
829
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
const selectors = [
|
|
835
|
-
'.message-input-right-button-send .send-button',
|
|
836
|
-
'.chat-prompt-send-button',
|
|
837
|
-
'button.send-button'
|
|
838
|
-
];
|
|
830
|
+
try {
|
|
831
|
+
await page.focus(inputSelector);
|
|
832
|
+
await page.fill(inputSelector, '');
|
|
833
|
+
await page.type(inputSelector, 'a', { delay: 50 });
|
|
834
|
+
console.log(`[Playwright] Typed char for ${cacheKey}, waiting for UI to update...`);
|
|
835
|
+
await sleep(1500);
|
|
839
836
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
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);
|
|
837
|
+
// Try pressing Enter first on the input field as it is highly reliable
|
|
838
|
+
console.log(`[Playwright] Pressing Enter for ${cacheKey}...`);
|
|
839
|
+
await page.focus(inputSelector);
|
|
840
|
+
await page.keyboard.press('Enter');
|
|
854
841
|
|
|
855
|
-
|
|
842
|
+
// Also attempt to click the send button in case Enter didn't submit
|
|
843
|
+
const selectors = [
|
|
844
|
+
'.message-input-right-button-send .send-button',
|
|
845
|
+
'.chat-prompt-send-button',
|
|
846
|
+
'button.send-button'
|
|
847
|
+
];
|
|
856
848
|
|
|
857
|
-
|
|
858
|
-
|
|
849
|
+
for (const selector of selectors) {
|
|
850
|
+
try {
|
|
851
|
+
const btn = await page.$(selector);
|
|
852
|
+
if (btn && await btn.isVisible()) {
|
|
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
|
|
859
865
|
}
|
|
860
|
-
} catch (e) {
|
|
861
|
-
console.error(`[Playwright] Error clicking ${selector} for ${cacheKey}:`, e);
|
|
862
866
|
}
|
|
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');
|
|
867
|
+
} catch (triggerErr: any) {
|
|
868
|
+
console.error(`[Playwright] Failed to trigger request for ${cacheKey}:`, triggerErr.message);
|
|
869
869
|
}
|
|
870
870
|
});
|
|
871
871
|
});
|
package/src/services/qwen.ts
CHANGED
|
@@ -86,6 +86,7 @@ const refillPromises: Map<string, Promise<void>> = new Map();
|
|
|
86
86
|
|
|
87
87
|
const WARM_POOL_SIZE = 10;
|
|
88
88
|
const WARM_POOL_TTL_MS = 10 * 60 * 1000;
|
|
89
|
+
const WARM_POOL_LOW_WATER = 3;
|
|
89
90
|
|
|
90
91
|
function cleanupStalePool(accountId: string) {
|
|
91
92
|
const pool = warmPool.get(accountId);
|
|
@@ -243,6 +244,11 @@ export async function getWarmedChat(accountId?: string) {
|
|
|
243
244
|
let pool = warmPool.get(key);
|
|
244
245
|
if (!pool) { pool = []; warmPool.set(key, pool); }
|
|
245
246
|
cleanupStalePool(key);
|
|
247
|
+
|
|
248
|
+
if (pool.length < WARM_POOL_LOW_WATER && !refillPromises.has(key)) {
|
|
249
|
+
refillPromises.set(key, refillPoolForAccount(key).finally(() => refillPromises.delete(key)));
|
|
250
|
+
}
|
|
251
|
+
|
|
246
252
|
if (pool.length === 0) {
|
|
247
253
|
if (!refillPromises.has(key)) {
|
|
248
254
|
refillPromises.set(key, refillPoolForAccount(key).finally(() => refillPromises.delete(key)));
|