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