pplx-proxy / index.js
tianlong12's picture
Update index.js
a1b41df verified
const express = require("express");
const { io } = require("socket.io-client");
const { v4: uuidv4 } = require("uuid");
const { ProxyAgent } = require("proxy-agent");
// 创建代理实例
const 代理 = new ProxyAgent();
// 获取环境变量值并赋给中文变量名
const 曲奇池 = process.env.COOKIE_POOL || '';
const 用户代理 = process.env.USER_AGENT || '';
const 全局代理 = process.env.ALL_PROXY || '';
const 应用 = express();
const 端口 = process.env.PORT || 7860;
// 解析曲奇池,支持单个或多个曲奇(用逗号分隔)
const cookiePool = 曲奇池
? 曲奇池.split(',').map(cookie => cookie.trim()).filter(cookie => cookie.length > 0)
: [];
if (cookiePool.length === 0) {
console.error("错误:环境变量 曲奇池 未设置或为空。");
process.exit(1);
}
// 创建事件流的工具函数
function 创建事件(事件, 数据) {
if (typeof 数据 === "object") {
数据 = JSON.stringify(数据);
}
return `event: ${事件}\ndata: ${数据}\n\n`;
}
// 处理 POST 请求的路由 /v1/messages
应用.post("/hf/v1/messages", (请求, 响应) => {
请求.rawBody = "";
请求.setEncoding("utf8");
// 收集请求的原始数据
请求.on("data", function (片段) {
请求.rawBody += 片段;
});
请求.on("end", async () => {
响应.setHeader("Content-Type", "text/event-stream;charset=utf-8");
try {
let 请求数据 = JSON.parse(请求.rawBody);
if (请求数据.stream == false) {
// 当 stream 为 false 时,返回固定的响应
响应.send(
JSON.stringify({
id: uuidv4(),
content: [
{
text: "请开启流式传输。",
},
{
id: "string",
name: "string",
input: {},
},
],
model: "string",
stop_reason: "end_turn",
stop_sequence: "string",
usage: {
input_tokens: 0,
output_tokens: 0,
},
})
);
} else if (请求数据.stream == true) {
// 处理 stream 为 true 的情况
let 用户消息 = [{ 问题: "", 回答: "" }];
let 最后更新 = true;
if (请求数据.system) {
// 将系统消息添加到消息列表的首位
请求数据.messages.unshift({ role: "system", content: 请求数据.system });
}
console.log(请求数据.messages);
// 遍历消息列表,构建用户和助手的问答对
请求数据.messages.forEach((消息) => {
if (消息.role == "system" || 消息.role == "user") {
if (最后更新) {
用户消息[用户消息.length - 1].问题 += 消息.content + "\n";
} else if (用户消息[用户消息.length - 1].问题 == "") {
用户消息[用户消息.length - 1].问题 += 消息.content + "\n";
} else {
用户消息.push({ 问题: 消息.content + "\n", 回答: "" });
}
最后更新 = true;
} else if (消息.role == "assistant") {
if (!最后更新) {
用户消息[用户消息.length - 1].回答 += 消息.content + "\n";
} else if (用户消息[用户消息.length - 1].回答 == "") {
用户消息[用户消息.length - 1].回答 += 消息.content + "\n";
} else {
用户消息.push({ 问题: "", 回答: 消息.content + "\n" });
}
最后更新 = false;
}
});
// 查找最新的用户消息
const 最新用户消息 = 请求数据.messages
.slice().reverse()
.find(消息 => 消息.role === "user");
if (!最新用户消息) {
throw new Error("请求中未找到用户消息。");
}
// 获取最新用户消息的索引
const 最新用户索引 = 请求数据.messages.lastIndexOf(最新用户消息);
// 构建除最新用户消息外的所有消息
const 先前消息列表 = 请求数据.messages.slice(0, 最新用户索引);
// 改进上下文拼接格式,增加提示并避免重复
let 先前消息 = 先前消息列表
.map((消息) => {
if (消息.role === "user") {
return `用户: ${消息.content}`;
} else if (消息.role === "assistant") {
return `助手: ${消息.content}`;
} else if (消息.role === "system") {
return `系统: ${消息.content}`;
}
return 消息.content;
})
.join("\n\n");
// 在上下文末尾添加提示,不再重复添加最新的用户消息
先前消息 += `\n\n# ↓请关注用户最新的消息↓\n\n`;
// 追加最新的用户消息
先前消息 += `用户: ${最新用户消息.content}`;
let 消息ID = uuidv4();
// 发送消息开始的事件
响应.write(
创建事件("message_start", {
type: "message_start",
message: {
id: 消息ID,
type: "message",
role: "assistant",
content: [],
model: "claude-3-opus-20240229",
stop_reason: null,
stop_sequence: null,
usage: { input_tokens: 8, output_tokens: 1 },
},
})
);
响应.write(创建事件("content_block_start", { type: "content_block_start", index: 0, content_block: { type: "text", text: "" } }));
响应.write(创建事件("ping", { type: "ping" }));
// 随机选择一个曲奇
const 随机曲奇 = cookiePool[Math.floor(Math.random() * cookiePool.length)];
// 配置 Socket.IO 客户端选项
var 选项 = {
agent: 代理,
auth: {
jwt: "anonymous-ask-user",
},
reconnection: false,
transports: ["websocket"],
path: "/socket.io",
hostname: "www.perplexity.ai",
secure: true,
port: "443",
extraHeaders: {
Cookie: 随机曲奇, // 使用随机选择的曲奇
"User-Agent": 用户代理,
Accept: "*/*",
priority: "u=1, i",
Referer: "https://www.perplexity.ai/",
},
};
// 通过 Socket.IO 连接 Perplexity.ai 的 WebSocket
var socket = io("wss://www.perplexity.ai/", 选项);
socket.on("connect", function () {
console.log(" > [已连接]");
socket
.emitWithAck("perplexity_ask", 先前消息, {
"version": "2.9",
"source": "default",
"attachments": [],
"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(),
"frontend_context_uuid": uuidv4(),
"prompt_source": "user",
"query_source": "home"
})
.then((响应数据) => {
console.log(响应数据);
响应.write(创建事件("content_block_stop", { type: "content_block_stop", index: 0 }));
响应.write(
创建事件("message_delta", {
type: "message_delta",
delta: { stop_reason: "end_turn", stop_sequence: null },
usage: { output_tokens: 12 },
})
);
响应.write(创建事件("message_stop", { type: "message_stop" }));
响应.end();
}).catch((错误) => {
if(错误.message != "socket has been disconnected"){
console.log(错误);
}
});
});
// 监听所有事件,记录日志
socket.onAny((事件, ...参数) => {
console.log(`> [收到事件: ${事件}]`);
});
// 监听查询进度事件,处理返回的文本块
socket.on("query_progress", (数据) => {
if(数据.text){
try {
var 文本 = JSON.parse(数据.text)
var 块 = 文本.chunks[文本.chunks.length - 1];
if (块) {
letJSON = JSON.stringify({
type: "content_block_delta",
index: 0,
delta: { type: "text_delta", text: 块 },
});
响应.write(创建事件("content_block_delta", 块JSON));
}
} catch (错误) {
console.log("解析 query_progress 数据时出错:", 错误);
}
}
});
// 监听断开连接事件
socket.on("disconnect", function () {
console.log(" > [已断开连接]");
});
// 监听错误事件,返回错误信息给客户端
socket.on("error", (错误) => {
letJSON = JSON.stringify({
type: "content_block_delta",
index: 0,
delta: { type: "text_delta", text: "获取输出时出现错误\n请查看日志以获取更多信息" },
});
响应.write(创建事件("content_block_delta", 块JSON));
响应.write(创建事件("content_block_stop", { type: "content_block_stop", index: 0 }));
响应.write(
创建事件("message_delta", {
type: "message_delta",
delta: { stop_reason: "end_turn", stop_sequence: null },
usage: { output_tokens: 12 },
})
);
响应.write(创建事件("message_stop", { type: "message_stop" }));
响应.end();
console.log(错误);
});
// 监听连接错误事件,返回错误信息给客户端
socket.on("connect_error", function (错误) {
letJSON = JSON.stringify({
type: "content_block_delta",
index: 0,
delta: { type: "text_delta", text: "连接到 Perplexity.ai 失败\n请查看日志以获取更多信息" },
});
响应.write(创建事件("content_block_delta", 块JSON));
响应.write(创建事件("content_block_stop", { type: "content_block_stop", index: 0 }));
响应.write(
创建事件("message_delta", {
type: "message_delta",
delta: { stop_reason: "end_turn", stop_sequence: null },
usage: { output_tokens: 12 },
})
);
响应.write(创建事件("message_stop", { type: "message_stop" }));
响应.end();
console.log(错误);
});
// 监听客户端关闭事件,断开 Socket 连接
响应.on("close", function () {
console.log(" > [客户端已关闭连接]");
socket.disconnect();
});
} else {
throw new Error("无效的请求");
}
} catch (错误) {
console.log(错误);
响应.write(JSON.stringify({ error: 错误.message }));
响应.end();
return;
}
});
});
// 处理所有未定义的路由,返回 418
应用.use((请求, 响应, 下一个) => {
响应.status(418).send("418 I'm a teapot");
});
// 启动服务器,监听指定端口
应用.listen(端口, () => {
console.log(`Perplexity 代理服务器正在监听端口 ${端口}`);
});