Add files via upload

This commit is contained in:
被遗忘的记忆
2025-03-14 09:47:17 +08:00
committed by GitHub
parent ee9a10800d
commit 2b6902a54d
+468 -467
View File
@@ -1,467 +1,468 @@
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import { connect } from "puppeteer-real-browser"; import { connect } from "puppeteer-real-browser";
import { v4 as uuidV4 } from "uuid"; import { v4 as uuidV4 } from "uuid";
import path from "path"; import path from "path";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
import { createDirectoryIfNotExists, sleep, extractPerplexityCookie, getPerplexitySessionCookie } from "../utils.mjs"; import { createDirectoryIfNotExists, sleep, extractPerplexityCookie, getPerplexitySessionCookie } from "../utils/cookieUtils.mjs";
import '../proxyAgent.mjs'; import '../proxyAgent.mjs';
import { detectBrowser } from '../utils/browserDetector.mjs'; import { detectBrowser } from '../utils/browserDetector.mjs';
import NetworkMonitor from '../networkMonitor.mjs'; import NetworkMonitor from '../networkMonitor.mjs';
import io from 'socket.io-client'; import io from 'socket.io-client';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
class PerplexityProvider { class PerplexityProvider {
constructor(config) { constructor(config) {
this.config = config; this.config = config;
this.sessions = {}; this.sessions = {};
this.preferredBrowser = 'auto'; // 可以是 'chrome', 'edge', 或 'auto'
this.networkMonitor = new NetworkMonitor(); this.preferredBrowser = 'auto';
} this.networkMonitor = new NetworkMonitor();
}
async init(config) {
console.log(`本项目依赖Chrome或Edge浏览器,请勿关闭弹出的浏览器窗口。如果出现错误请检查是否已安装Chrome或Edge浏览器。`); async init(config) {
console.log(`本项目依赖Chrome或Edge浏览器,请勿关闭弹出的浏览器窗口。如果出现错误请检查是否已安装Chrome或Edge浏览器。`);
const browserPath = detectBrowser(this.preferredBrowser); // 检测Chrome和Edge浏览器
const browserPath = detectBrowser(this.preferredBrowser); // 检测Chrome和Edge浏览器
this.sessions = {};
const timeout = 120000; this.sessions = {};
const timeout = 120000;
if (process.env.USE_MANUAL_LOGIN === "true") {
this.sessions['manual_login'] = { if (process.env.USE_MANUAL_LOGIN === "true") {
configIndex: 0, this.sessions['manual_login'] = {
valid: false, configIndex: 0,
}; valid: false,
console.log("当前使用手动登录模式,跳过config.mjs文件中的 cookie 验证"); };
} else { console.log("当前使用手动登录模式,跳过config.mjs文件中的 cookie 验证");
// 使用配置文件中的 cookie } else {
for (let index = 0; index < config.sessions.length; index++) { // 使用配置文件中的 cookie
const session = config.sessions[index]; for (let index = 0; index < config.sessions.length; index++) {
const extractedCookie = extractPerplexityCookie(session.cookie); const session = config.sessions[index];
const extractedCookie = extractPerplexityCookie(session.cookie);
if (extractedCookie.sessionToken) {
const uniqueId = `user_${index}`; if (extractedCookie.sessionToken) {
this.sessions[uniqueId] = { const uniqueId = `user_${index}`;
configIndex: index, this.sessions[uniqueId] = {
...extractedCookie, configIndex: index,
valid: false, ...extractedCookie,
}; valid: false,
console.log(`已添加 #${index} ${uniqueId} (Perplexity cookie)`); };
} else { console.log(`已添加 #${index} ${uniqueId} (Perplexity cookie)`);
console.error(`${index}个cookie无效,请重新获取。`); } else {
console.error(`未检测到有效的__Secure-next-auth.session-token字段`); console.error(`${index}个cookie无效,请重新获取`);
} console.error(`未检测到有效的__Secure-next-auth.session-token字段。`);
} }
console.log(`已添加 ${Object.keys(this.sessions).length} 个 cookie,开始验证有效性`); }
} console.log(`已添加 ${Object.keys(this.sessions).length} 个 cookie,开始验证有效性`);
}
for (const originalUsername of Object.keys(this.sessions)) {
let currentUsername = originalUsername; for (const originalUsername of Object.keys(this.sessions)) {
let session = this.sessions[currentUsername]; let currentUsername = originalUsername;
createDirectoryIfNotExists(path.join(__dirname, "browser_profiles", currentUsername)); let session = this.sessions[currentUsername];
createDirectoryIfNotExists(path.join(__dirname, "browser_profiles", currentUsername));
try {
const response = await connect({ try {
headless: "auto", const response = await connect({
turnstile: true, headless: "auto",
customConfig: { turnstile: true,
userDataDir: path.join(__dirname, "browser_profiles", currentUsername), customConfig: {
executablePath: browserPath, userDataDir: path.join(__dirname, "browser_profiles", currentUsername),
}, executablePath: browserPath,
}); },
});
const {page, browser} = response;
if (process.env.USE_MANUAL_LOGIN === "true") { const {page, browser} = response;
console.log(`正在为 session #${session.configIndex} 进行手动登录...`); if (process.env.USE_MANUAL_LOGIN === "true") {
await page.goto("https://www.perplexity.ai", {timeout: timeout}); console.log(`正在为 session #${session.configIndex} 进行手动登录...`);
await sleep(3000); await page.goto("https://www.perplexity.ai", {timeout: timeout});
console.log(`请在打开的浏览器窗口中手动登录 Perplexity.ai (session #${session.configIndex})`); await sleep(3000);
const { sessionCookie, accountStatus } = await this.waitForManualLogin(page); console.log(`请在打开的浏览器窗口中手动登录 Perplexity.ai (session #${session.configIndex})`);
if (sessionCookie) { const { sessionCookie, accountStatus } = await this.waitForManualLogin(page);
const email = accountStatus.username || 'unknown_user'; if (sessionCookie) {
this.sessions[email] = { const email = accountStatus.username || 'unknown_user';
...session, this.sessions[email] = {
cookies: sessionCookie, ...session,
isPro: accountStatus.isPro, cookies: sessionCookie,
}; isPro: accountStatus.isPro,
delete this.sessions[currentUsername]; };
currentUsername = email; delete this.sessions[currentUsername];
session = this.sessions[currentUsername]; currentUsername = email;
session = this.sessions[currentUsername];
console.log(`成功获取 ${email} 登录的 cookie${accountStatus.isPro ? 'Pro 账号)' : ''}`);
} else { console.log(`成功获取 ${email} 登录的 cookie${accountStatus.isPro ? 'Pro 账号)' : ''}`);
console.error(`未能获取到 session #${session.configIndex} 有效登录的 cookie`); } else {
await browser.close(); console.error(`未能获取到 session #${session.configIndex} 有效登录的 cookie`);
continue; await browser.close();
} continue;
} else { }
// 使用已有的 cookie } else {
const perplexityCookies = getPerplexitySessionCookie(session); // 使用已有的 cookie
await page.setCookie(...perplexityCookies); const perplexityCookies = getPerplexitySessionCookie(session);
await page.goto("https://www.perplexity.ai", {timeout: timeout}); await page.setCookie(...perplexityCookies);
await sleep(5000); await page.goto("https://www.perplexity.ai", {timeout: timeout});
} await sleep(5000);
}
// 如果遇到 Cloudflare 挑战就多等一段时间
const pageContent = await page.content(); // 如果遇到 Cloudflare 挑战就多等一段时间
if (pageContent.indexOf("challenges.cloudflare.com") > -1) { const pageContent = await page.content();
console.log(`请在30秒内完成人机验证 (${currentUsername})`); if (pageContent.indexOf("challenges.cloudflare.com") > -1) {
await page.evaluate(() => { console.log(`请在30秒内完成人机验证 (${currentUsername})`);
alert("请在30秒内完成人机验证"); await page.evaluate(() => {
}); alert("请在30秒内完成人机验证");
await sleep(30000); });
} await sleep(30000);
try { }
const isValid = await this.validateSession(page); try {
if (isValid) { const isValid = await this.validateSession(page);
session.valid = true; if (isValid) {
session.browser = browser; session.valid = true;
session.page = page; session.browser = browser;
} else { session.page = page;
console.warn(`警告: ${currentUsername} 验证失败。请检查cookie是否有效。`); } else {
await this.clearPerplexityCookies(page); console.warn(`警告: ${currentUsername} 验证失败。请检查cookie是否有效。`);
await browser.close(); await this.clearPerplexityCookies(page);
} await browser.close();
} catch (e) { }
console.warn(`警告: ${currentUsername} 验证失败。请检查cookie是否有效。`); } catch (e) {
console.error(e); console.warn(`警告: ${currentUsername} 验证失败。请检查cookie是否有效。`);
await this.clearPerplexityCookies(page); console.error(e);
await browser.close(); await this.clearPerplexityCookies(page);
} await browser.close();
}
} catch (e) {
console.error(`初始化浏览器失败 (${currentUsername})`); } catch (e) {
console.error(e); console.error(`初始化浏览器失败 (${currentUsername})`);
} console.error(e);
} }
}
console.log(`验证完毕,有效cookie数量 ${Object.keys(this.sessions).filter((username) => this.sessions[username].valid).length}`);
// 开始网络监控 console.log(`验证完毕,有效cookie数量 ${Object.keys(this.sessions).filter((username) => this.sessions[username].valid).length}`);
await this.networkMonitor.startMonitoring(); // 开始网络监控
} await this.networkMonitor.startMonitoring();
}
async clearPerplexityCookies(page) {
const client = await page.target().createCDPSession(); async clearPerplexityCookies(page) {
await client.send('Network.clearBrowserCookies'); const client = await page.target().createCDPSession();
await client.send('Network.clearBrowserCache'); await client.send('Network.clearBrowserCookies');
const cookies = await page.cookies('https://www.perplexity.ai'); await client.send('Network.clearBrowserCache');
for (const cookie of cookies) { const cookies = await page.cookies('https://www.perplexity.ai');
await page.deleteCookie(cookie); for (const cookie of cookies) {
} await page.deleteCookie(cookie);
console.log('已自动清理 cookie'); }
} console.log('已自动清理 cookie');
}
async checkAccountStatus(page) {
if (process.env.USE_MANUAL_LOGIN !== "true" && process.env.INCOGNITO_MODE === "true") { async checkAccountStatus(page) {
try { if (process.env.USE_MANUAL_LOGIN !== "true" && process.env.INCOGNITO_MODE === "true") {
await page.waitForSelector('div[class*="inline-flex w-full cursor-pointer select-none items-center justify-start gap-sm rounded-full"]', { timeout: 2000 }); try {
await page.waitForSelector('div[class*="inline-flex w-full cursor-pointer select-none items-center justify-start gap-sm rounded-full"]', { timeout: 2000 });
// 检查无痕模式图标
const isIncognito = await page.evaluate(() => { // 检查无痕模式图标
const incognitoElement = document.querySelector('div[class*="inline-flex w-full cursor-pointer select-none items-center justify-start gap-sm rounded-full"]'); const isIncognito = await page.evaluate(() => {
return incognitoElement && incognitoElement.innerHTML.includes('viewBox="0 0 24 24"'); const incognitoElement = document.querySelector('div[class*="inline-flex w-full cursor-pointer select-none items-center justify-start gap-sm rounded-full"]');
}); return incognitoElement && incognitoElement.innerHTML.includes('viewBox="0 0 24 24"');
});
if (isIncognito) {
return { isPro: false, username: 'Incognito User', isIncognito: true }; if (isIncognito) {
} else { return { isPro: false, username: 'Incognito User', isIncognito: true };
return { isPro: false, username: null, isIncognito: false }; } else {
} return { isPro: false, username: null, isIncognito: false };
} catch (error) { }
return { isPro: false, username: null, isIncognito: false }; } catch (error) {
} return { isPro: false, username: null, isIncognito: false };
} else { }
try { } else {
await page.waitForSelector('div[class*="relative flex items-center gap-x-xs"]', { timeout: 2000 }); try {
await page.waitForSelector('div[class*="relative flex items-center gap-x-xs"]', { timeout: 2000 });
const isPro = await page.evaluate(() => {
const svgElement = document.querySelector('div[class*="relative flex aspect-square"] svg'); const isPro = await page.evaluate(() => {
return svgElement && svgElement.innerHTML.includes('fill-super dark:fill-superDark'); const svgElement = document.querySelector('div[class*="relative flex aspect-square"] svg');
}); return svgElement && svgElement.innerHTML.includes('fill-super dark:fill-superDark');
});
const username = await page.evaluate(() => {
const usernameElement = document.querySelector('div[class*="relative flex items-center gap-x-xs"] div'); const username = await page.evaluate(() => {
return usernameElement ? usernameElement.textContent.trim() : null; const usernameElement = document.querySelector('div[class*="relative flex items-center gap-x-xs"] div');
}); return usernameElement ? usernameElement.textContent.trim() : null;
});
return { isPro, username, isIncognito: false };
} catch (error) { return { isPro, username, isIncognito: false };
return { isPro: false, username: null, isIncognito: false }; } catch (error) {
} return { isPro: false, username: null, isIncognito: false };
} }
} }
}
async waitForManualLogin(page) {
return new Promise(async (resolve) => { async waitForManualLogin(page) {
let isResolved = false; return new Promise(async (resolve) => {
let isResolved = false;
const checkLoginCompletion = async () => {
if (isResolved) return; const checkLoginCompletion = async () => {
if (isResolved) return;
try {
const accountStatus = await this.checkAccountStatus(page); try {
if (accountStatus.username) { const accountStatus = await this.checkAccountStatus(page);
console.log(`登录成功: ${accountStatus.username}`); if (accountStatus.username) {
const cookies = await page.cookies(); console.log(`登录成功: ${accountStatus.username}`);
const sessionCookie = this.extractPerplexitySessionCookie(cookies); const cookies = await page.cookies();
isResolved = true; const sessionCookie = this.extractPerplexitySessionCookie(cookies);
resolve({ sessionCookie, accountStatus }); isResolved = true;
} resolve({ sessionCookie, accountStatus });
} catch (error) { }
// 如果检查失败,继续等待 } catch (error) {
} // 如果检查失败,继续等待
}; }
};
// 监听 DOM 变化
await page.evaluate(() => { // 监听 DOM 变化
const observer = new MutationObserver((mutations) => { await page.evaluate(() => {
for (let mutation of mutations) { const observer = new MutationObserver((mutations) => {
if (mutation.type === 'childList' || mutation.type === 'subtree') { for (let mutation of mutations) {
window.dispatchEvent(new CustomEvent('domChanged')); if (mutation.type === 'childList' || mutation.type === 'subtree') {
break; window.dispatchEvent(new CustomEvent('domChanged'));
} break;
} }
}); }
});
observer.observe(document.body, {
childList: true, observer.observe(document.body, {
subtree: true, childList: true,
}); subtree: true,
}); });
});
// 监听 DOM 变化
await page.exposeFunction('notifyDomChanged', checkLoginCompletion); // 监听 DOM 变化
await page.evaluate(() => { await page.exposeFunction('notifyDomChanged', checkLoginCompletion);
window.addEventListener('domChanged', window.notifyDomChanged); await page.evaluate(() => {
}); window.addEventListener('domChanged', window.notifyDomChanged);
});
// 监听导航完成
page.on('load', checkLoginCompletion); // 监听导航完成
page.on('load', checkLoginCompletion);
setTimeout(() => {
if (!isResolved) { setTimeout(() => {
console.log('登录等待超时'); if (!isResolved) {
resolve({ sessionCookie: null, accountStatus: null }); console.log('登录等待超时');
} resolve({ sessionCookie: null, accountStatus: null });
}, 300000); }
}, 300000);
// 初始检查
await checkLoginCompletion(); // 初始检查
}); await checkLoginCompletion();
} });
}
async validateSession(page) {
const accountStatus = await this.checkAccountStatus(page); async validateSession(page) {
if (accountStatus.username || accountStatus.isIncognito) { const accountStatus = await this.checkAccountStatus(page);
if (accountStatus.isIncognito) { if (accountStatus.username || accountStatus.isIncognito) {
console.log('无痕模式验证成功'); if (accountStatus.isIncognito) {
} else { console.log('无痕模式验证成功');
console.log(`账号 ${accountStatus.username} 登录有效${accountStatus.isPro ? 'Pro 账号)' : ''}`); } else {
} console.log(`账号 ${accountStatus.username} 登录有效${accountStatus.isPro ? 'Pro 账号)' : ''}`);
return true; }
} else { return true;
console.log('账号验证失败'); } else {
return false; console.log('账号验证失败');
} return false;
} }
}
extractPerplexitySessionCookie(cookies) {
let sessionCookie = []; extractPerplexitySessionCookie(cookies) {
let sessionCookie = [];
const sessionToken = cookies.find(c => c.name === '__Secure-next-auth.session-token');
if (sessionToken) { const sessionToken = cookies.find(c => c.name === '__Secure-next-auth.session-token');
sessionCookie.push(sessionToken); if (sessionToken) {
} sessionCookie.push(sessionToken);
}
if (sessionCookie.length === 0) {
console.error('无法提取有效的会话 cookie'); if (sessionCookie.length === 0) {
return null; console.error('无法提取有效的会话 cookie');
} return null;
}
return sessionCookie;
} return sessionCookie;
}
async getCompletion({ username, messages, stream = false, proxyModel }) {
if (this.networkMonitor.isNetworkBlocked()) { async getCompletion({ username, messages, stream = false, proxyModel }) {
throw new Error("网络异常,请稍后再试"); if (this.networkMonitor.isNetworkBlocked()) {
} throw new Error("网络异常,请稍后再试");
const session = this.sessions[username]; }
if (!session || !session.valid) { const session = this.sessions[username];
throw new Error(`用户 ${username} 的会话无效`); if (!session || !session.valid) {
} throw new Error(`用户 ${username} 的会话无效`);
}
const { page } = session;
const emitter = new EventEmitter(); const { page } = session;
const emitter = new EventEmitter();
// 转换纯文本
let previousMessages = messages.map(msg => msg.content).join("\n\n"); // 转换纯文本
let previousMessages = messages.map(msg => msg.content).join("\n\n");
// 生成必要的参数
const messagePayload = { // 生成必要的参数
version: "2.13", const messagePayload = {
source: "default", version: "2.13",
language: "en-GB", source: "default",
timezone: "Europe/London", language: "en-GB",
search_focus: "writing", timezone: "Europe/London",
frontend_uuid: uuidV4(), search_focus: "writing",
mode: "concise", frontend_uuid: uuidV4(),
is_related_query: false, mode: "concise",
is_default_related_query: false, is_related_query: false,
visitor_id: uuidV4(), is_default_related_query: false,
user_nextauth_id: uuidV4(), visitor_id: uuidV4(),
frontend_context_uuid: uuidV4(), user_nextauth_id: uuidV4(),
prompt_source: "user", frontend_context_uuid: uuidV4(),
query_source: "home", prompt_source: "user",
}; query_source: "home",
};
await page.addScriptTag({ url: 'https://cdn.socket.io/4.4.1/socket.io.min.js' });
await page.addScriptTag({ url: 'https://cdn.socket.io/4.4.1/socket.io.min.js' });
const ioExists = await page.evaluate(() => typeof io !== 'undefined');
if (!ioExists) { const ioExists = await page.evaluate(() => typeof io !== 'undefined');
throw new Error("socket.io 客户端脚本加载失败"); if (!ioExists) {
} throw new Error("socket.io 客户端脚本加载失败");
}
// 移除之前 console
page.removeAllListeners('console'); // 移除之前 console
page.removeAllListeners('console');
page.on('console', msg => {
const text = msg.text(); page.on('console', msg => {
console.log(text); const text = msg.text();
}); console.log(text);
});
// 唯一的回调函数名
const callbackName = `nodeCallback_${uuidV4()}`; // 唯一的回调函数名
const callbackName = `nodeCallback_${uuidV4()}`;
// 在浏览器上下文中建立 WebSocket 连接并发送消息
await page.exposeFunction(callbackName, (event, data) => { // 在浏览器上下文中建立 WebSocket 连接并发送消息
if (event === "completion") { await page.exposeFunction(callbackName, (event, data) => {
const { id, text } = data; if (event === "completion") {
emitter.emit("completion", id, text); const { id, text } = data;
} else if (event === "end") { emitter.emit("completion", id, text);
emitter.emit("end"); } else if (event === "end") {
} else if (event === "error") { emitter.emit("end");
console.error("Error from page.evaluate:", data); } else if (event === "error") {
emitter.emit("error", data); console.error("Error from page.evaluate:", data);
} emitter.emit("error", data);
}); }
});
await page.evaluate(
(previousMessages, messagePayload, callbackName, stream) => { await page.evaluate(
try { (previousMessages, messagePayload, callbackName, stream) => {
if (typeof io === 'undefined') { try {
window[callbackName]("error", "Socket.io 客户端未定义,请检查脚本是否正确加载。"); if (typeof io === 'undefined') {
return; window[callbackName]("error", "Socket.io 客户端未定义,请检查脚本是否正确加载。");
} return;
}
if (window.socket) {
// 如果已有 socket 连接 if (window.socket) {
window.socket.disconnect(); // 如果已有 socket 连接
window.socket = null; window.socket.disconnect();
} window.socket = null;
}
// 累积接收到的 chunk(用于非流)
let accumulatedChunks = ''; // 累积接收到的 chunk(用于非流)
let accumulatedChunks = '';
const socket = io("wss://www.perplexity.ai/", {
path: "/socket.io", const socket = io("wss://www.perplexity.ai/", {
transports: ["websocket"], path: "/socket.io",
}); transports: ["websocket"],
});
window.socket = socket;
window.socket = socket;
// 定义监听器函数
function onQueryProgress(data) { // 定义监听器函数
try { function onQueryProgress(data) {
if (data.text) { try {
const textData = JSON.parse(data.text); if (data.text) {
const chunk = textData.chunks[textData.chunks.length - 1]; const textData = JSON.parse(data.text);
if (chunk) { const chunk = textData.chunks[textData.chunks.length - 1];
if (stream) { if (chunk) {
// 实时发送 chunk if (stream) {
console.log(chunk); // 直接输出 chunk 内容 // 实时发送 chunk
window[callbackName]("completion", { id: messagePayload.frontend_uuid, text: chunk }); console.log(chunk); // 直接输出 chunk 内容
} else { window[callbackName]("completion", { id: messagePayload.frontend_uuid, text: chunk });
// 累积 chunk } else {
accumulatedChunks += chunk; // 累积 chunk
} accumulatedChunks += chunk;
} }
} }
// 检查是否为最后一条消息 }
if (data.final) { // 检查是否为最后一条消息
if (!stream) { if (data.final) {
// 非流发送完整的响应 if (!stream) {
console.log(accumulatedChunks); // 非流发送完整的响应
window[callbackName]("completion", { id: messagePayload.frontend_uuid, text: accumulatedChunks }); console.log(accumulatedChunks);
} window[callbackName]("completion", { id: messagePayload.frontend_uuid, text: accumulatedChunks });
console.log("请求结束"); }
window[callbackName]("end"); console.log("请求结束");
window[callbackName]("end");
// 清理资源
socket.off("query_progress", onQueryProgress); // 清理资源
socket.disconnect(); socket.off("query_progress", onQueryProgress);
window.socket = null; socket.disconnect();
delete window[callbackName]; window.socket = null;
} delete window[callbackName];
} catch (err) { }
console.error("Error processing query_progress data:", err); } catch (err) {
window[callbackName]("error", err.toString()); console.error("Error processing query_progress data:", err);
} window[callbackName]("error", err.toString());
} }
}
// 添加监听器
socket.on("query_progress", onQueryProgress); // 添加监听器
socket.on("query_progress", onQueryProgress);
socket.on("connect", () => {
// 使用回调处理确认响应 socket.on("connect", () => {
socket.emit("perplexity_ask", previousMessages, messagePayload, (response) => { // 使用回调处理确认响应
}); socket.emit("perplexity_ask", previousMessages, messagePayload, (response) => {
}); });
socket.on("error", (error) => { });
console.error("Socket error:", error); socket.on("error", (error) => {
window[callbackName]("error", error.toString()); console.error("Socket error:", error);
}); window[callbackName]("error", error.toString());
});
socket.on("connect_error", (error) => {
console.error("Socket connect_error:", error); socket.on("connect_error", (error) => {
window[callbackName]("error", error.toString()); console.error("Socket connect_error:", error);
}); window[callbackName]("error", error.toString());
});
socket.on("connect_timeout", (timeout) => {
console.error("Socket connect_timeout:", timeout); socket.on("connect_timeout", (timeout) => {
window[callbackName]("error", "Connection timed out"); console.error("Socket connect_timeout:", timeout);
}); window[callbackName]("error", "Connection timed out");
} catch (err) { });
console.error("Error in page.evaluate:", err); } catch (err) {
window[callbackName]("error", err.toString()); console.error("Error in page.evaluate:", err);
} window[callbackName]("error", err.toString());
}, }
previousMessages, },
messagePayload, previousMessages,
callbackName, messagePayload,
stream callbackName,
); stream
);
const cancel = () => {
page.evaluate((callbackName) => { const cancel = () => {
if (window.socket) { page.evaluate((callbackName) => {
window.socket.disconnect(); if (window.socket) {
window.socket = null; window.socket.disconnect();
} window.socket = null;
if (window[callbackName]) { }
delete window[callbackName]; if (window[callbackName]) {
} delete window[callbackName];
}, callbackName).catch(console.error); }
}; }, callbackName).catch(console.error);
};
// 触发 'start'
emitter.emit("start", messagePayload.frontend_uuid); // 触发 'start'
emitter.emit("start", messagePayload.frontend_uuid);
return { completion: emitter, cancel };
} return { completion: emitter, cancel };
} }
}
export default PerplexityProvider;
export default PerplexityProvider;