├── .env ├── .gitignore ├── Dockerfile ├── README.md ├── docker-build.sh ├── docker-compose.yml ├── docker_use.md ├── index.js ├── package.json ├── start.bat ├── start.sh └── usage.md /.env: -------------------------------------------------------------------------------- 1 | PPLX_COOKIE=Your_Cookie_Here 2 | USER_AGENT=Your_User_Agent_Here 3 | all_proxy= 4 | API_TOKEN=Your_Secure_API_Token_Here -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | .vscode 4 | config 5 | test.js -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:21 2 | WORKDIR /usr/src/app 3 | COPY package*.json ./ 4 | 5 | RUN npm install 6 | COPY . . 7 | CMD [ "node", "index.js" ] 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 本仓库来源于 [Archeb/pplx-proxy (github.com)](https://github.com/Archeb/pplx-proxy) ,我只是在其基础上进行的简单修改。 2 | 3 | ## PPLX-Proxy: Perplexity AI 代理服务 4 | 5 | 这个仓库提供了一个代理服务,允许用户通过标准的 OpenAI API 格式访问 Perplexity AI 的 Claude 模型。和原版相比多添加了docker-compose文件,安全密钥,想用docker安装参考 [[docker_use.md]](https://github.com/h-mygit-f/pplx2api/blob/main/docker_use.md) 6 | 7 | ## 主要功能 8 | 9 | 1. **API 转换**: 将 OpenAI API 格式的请求转换为 Perplexity AI 可以理解的格式,并将响应转换回 OpenAI API 格式。 10 | 2. **流式响应**: 支持流式 API 响应,实时返回 AI 生成的内容。 11 | 3. **认证机制**: 实现了基本的 API 令牌验证,确保只有授权用户可以访问代理服务。 12 | 4. **错误处理**: 包含基本的错误处理和日志记录功能。 13 | 5. **Docker 支持**: 提供 Dockerfile 和 docker-compose.yml,方便在 Docker 环境中部署。 14 | 15 | ## 技术实现 16 | 17 | - 使用 Express.js 构建 Web 服务器 18 | - 使用 Socket.IO 与 Perplexity AI 的 WebSocket 服务通信 19 | - 使用环境变量进行配置,包括 Perplexity 的 Cookie、User-Agent 和代理设置 20 | 21 | ## 使用方法 22 | 23 | 详细的使用说明请参考 [docker_use.md](docker_use.md) 和 [usage.md](usage.md) 文件。 24 | 25 | 基本步骤如下: 26 | 27 | 1. 克隆仓库 28 | 2. 设置必要的环境变量(PPLX_COOKIE, USER_AGENT, API_TOKEN) 29 | 3. 使用 Docker Compose 构建和运行服务 30 | 4. 通过 `http://localhost:8081/v1/chat/completions` 访问 API(具体的请自行实验) 31 | 32 | ## 注意事项 33 | 34 | - 本服务仅支持流式响应。请在请求中将 `stream` 参数设置为 `true`。 35 | - 确保您有有效的 Perplexity AI 账户和必要的认证信息。 36 | - 使用时请遵守 Perplexity AI 的服务条款和使用政策。 37 | 38 | ## 免责声明 39 | 40 | 本项目仅供个人学习和研究使用。严禁用于商业用途或转售。使用本服务访问 Perplexity AI 时,请确保您遵守了相关的服务条款和使用政策。不提供任何技术支持,也不为任何违规使用导致的后果负责。 41 | -------------------------------------------------------------------------------- /docker-build.sh: -------------------------------------------------------------------------------- 1 | docker build . -t 'archeb/pplx-proxy' 2 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | pplx-proxy: 4 | build: . 5 | ports: 6 | - "8081:8081" 7 | environment: 8 | - PORT=8081 9 | - PPLX_COOKIE=${PPLX_COOKIE} 10 | - USER_AGENT=${USER_AGENT} 11 | - all_proxy=${all_proxy} 12 | - API_TOKEN=${API_TOKEN} 13 | restart: unless-stopped -------------------------------------------------------------------------------- /docker_use.md: -------------------------------------------------------------------------------- 1 | # 使用Docker部署Perplexity AI代理服务 2 | 3 | 本教程将指导您如何使用Docker来部署Perplexity AI代理服务。 4 | 5 | ## 前提条件 6 | 7 | 1. 安装Docker和Docker Compose 8 | - 对于Windows和Mac用户,安装 [Docker Desktop](https://www.docker.com/products/docker-desktop) 9 | - 对于Linux用户,按照[官方文档](https://docs.docker.com/engine/install/)安装Docker和Docker Compose 10 | 11 | 2. 获取Perplexity AI的Cookie和User-Agent 12 | - 按照 `usage.md` 中的说明获取这些信息 13 | 14 | ## 部署步骤 15 | 16 | 1. 克隆或下载项目代码到本地 17 | 18 | 2. 在项目根目录创建一个 `.env` 文件,内容如下: 19 | 20 | ``` 21 | PPLX_COOKIE=your_perplexity_cookie_here 22 | USER_AGENT=your_user_agent_here 23 | API_TOKEN=your_api_token_here 24 | all_proxy=your_proxy_here # 如果需要使用代理,否则可以省略 25 | ``` 26 | 27 | 将 `your_perplexity_cookie_here`, `your_user_agent_here`, 和 `your_api_token_here` 替换为您的实际值。 28 | 29 | 对于 `all_proxy`,您可以使用以下格式之一: 30 | - HTTP 代理:`http://host:port` 31 | - HTTPS 代理:`https://host:port` 32 | - SOCKS4 代理:`socks4://host:port` 33 | - SOCKS5 代理:`socks5://host:port` 34 | 35 | 例如:`all_proxy=http://192.168.3.13:39999` 36 | 37 | 3. 打开终端,进入项目根目录 38 | 39 | 4. 构建Docker镜像: 40 | 41 | ``` 42 | docker-compose build 43 | ``` 44 | 45 | 5. 启动服务: 46 | 47 | ``` 48 | docker-compose up -d 49 | ``` 50 | 51 | 6. 服务现在应该在后台运行。您可以通过以下命令查看日志: 52 | 53 | ``` 54 | docker-compose logs -f 55 | ``` 56 | 57 | 7. 要停止服务,运行: 58 | 59 | ``` 60 | docker-compose down 61 | ``` 62 | 63 | ## 使用服务 64 | 65 | 服务启动后,它将在 `http://localhost:8081` 上运行。您可以按照 `usage.md` 中的说明配置您的客户端使用这个地址。 66 | 67 | ## 故障排除 68 | 69 | 1. 如果遇到权限问题,尝试在命令前加上 `sudo` 70 | 71 | 2. 确保端口8081没有被其他服务占用 72 | 73 | 3. 如果服务无法连接到Perplexity AI,检查您的Cookie是否有效,以及是否需要配置代理 74 | 75 | 4. 如果使用代理,确保代理地址格式正确且代理服务器可用 76 | 77 | 5. 查看Docker日志以获取更多错误信息: 78 | ``` 79 | docker-compose logs 80 | ``` 81 | 82 | 如果仍然遇到问题,请查看项目的issue页面或创建新的issue寻求帮助。 83 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { io } = require("socket.io-client"); 3 | const { v4: uuidv4 } = require("uuid"); 4 | const { ProxyAgent } = require("proxy-agent"); 5 | const agent = new ProxyAgent(); 6 | const crypto = require('crypto'); 7 | 8 | const app = express(); 9 | const port = process.env.PORT || 8081; 10 | 11 | var opts = { 12 | agent: agent, 13 | auth: { 14 | jwt: "anonymous-ask-user", 15 | }, 16 | reconnection: false, 17 | transports: ["websocket"], 18 | path: "/socket.io", 19 | hostname: "www.perplexity.ai", 20 | secure: true, 21 | port: "443", 22 | extraHeaders: { 23 | Cookie: process.env.PPLX_COOKIE, 24 | "User-Agent": process.env.USER_AGENT, 25 | Accept: "*/*", 26 | priority: "u=1, i", 27 | Referer: "https://www.perplexity.ai/", 28 | }, 29 | }; 30 | 31 | // Add API token validation middleware 32 | function validateApiToken(req, res, next) { 33 | const apiToken = req.headers['authorization']; 34 | if (!apiToken || !apiToken.startsWith('Bearer ') || apiToken.split(' ')[1] !== process.env.API_TOKEN) { 35 | return res.status(401).json({ error: 'Unauthorized' }); 36 | } 37 | next(); 38 | } 39 | 40 | // Use the validation middleware 41 | app.use(validateApiToken); 42 | 43 | // 添加更详细的日志记录 44 | app.use((req, res, next) => { 45 | console.log(`Received ${req.method} request to ${req.url}`); 46 | next(); 47 | }); 48 | 49 | app.post("/v1/chat/completions", (req, res) => { 50 | console.log("Received request to /v1/chat/completions"); 51 | req.rawBody = ""; 52 | req.setEncoding("utf8"); 53 | 54 | req.on("data", function (chunk) { 55 | req.rawBody += chunk; 56 | }); 57 | 58 | req.on("end", async () => { 59 | try { 60 | let jsonBody = JSON.parse(req.rawBody); 61 | console.log("Parsed request body:", jsonBody); 62 | 63 | if (jsonBody.stream !== true) { 64 | // 处理非流式请求 65 | res.json({ 66 | id: "chatcmpl-" + crypto.randomBytes(16).toString('hex'), 67 | object: "chat.completion", 68 | created: Math.floor(Date.now() / 1000), 69 | model: "claude-3-opus-20240229", 70 | choices: [ 71 | { 72 | index: 0, 73 | message: { 74 | role: "assistant", 75 | content: "This API only supports streaming responses. Please set 'stream' to true in your request.", 76 | }, 77 | finish_reason: "stop" 78 | } 79 | ], 80 | usage: { 81 | prompt_tokens: 0, 82 | completion_tokens: 0, 83 | total_tokens: 0 84 | } 85 | }); 86 | } else { 87 | // 处理流式请求 88 | res.setHeader("Content-Type", "text/event-stream"); 89 | res.setHeader("Cache-Control", "no-cache"); 90 | res.setHeader("Connection", "keep-alive"); 91 | 92 | // 将OpenAI API格式的消息历史转换为Perplexity AI可以理解的格式 93 | let previousMessages = jsonBody.messages 94 | .map((msg) => msg.content) 95 | .join("\n\n"); 96 | 97 | var socket = io("wss://www.perplexity.ai/", opts); 98 | 99 | socket.on("connect", function () { 100 | console.log(" > [Connected]"); 101 | socket 102 | .emitWithAck("perplexity_ask", previousMessages, { 103 | "version": "2.9", 104 | "source": "default", 105 | "attachments": [], 106 | "language": "en-GB", 107 | "timezone": "Europe/London", 108 | "search_focus": "writing", 109 | "frontend_uuid": uuidv4(), 110 | "mode": "concise", 111 | "is_related_query": false, 112 | "is_default_related_query": false, 113 | "visitor_id": uuidv4(), 114 | "frontend_context_uuid": uuidv4(), 115 | "prompt_source": "user", 116 | "query_source": "home" 117 | }) 118 | .then((response) => { 119 | console.log(response); 120 | sendFinalChunk(res); 121 | }).catch((error) => { 122 | if(error.message != "socket has been disconnected"){ 123 | console.log(error); 124 | } 125 | sendFinalChunk(res); 126 | }); 127 | }); 128 | 129 | socket.on("query_progress", (data) => { 130 | if(data.text){ 131 | var text = JSON.parse(data.text) 132 | var chunk = text.chunks[text.chunks.length - 1]; 133 | if(chunk){ 134 | sendChunk(res, chunk); 135 | } 136 | } 137 | }); 138 | 139 | socket.on("disconnect", function () { 140 | console.log(" > [Disconnected]"); 141 | sendFinalChunk(res); 142 | }); 143 | 144 | socket.on("error", (error) => { 145 | console.log(error); 146 | sendErrorChunk(res, "Error occurred while fetching output. Please refer to the log for more information."); 147 | sendFinalChunk(res); 148 | }); 149 | 150 | socket.on("connect_error", function (error) { 151 | console.log(error); 152 | sendErrorChunk(res, "Failed to connect to Perplexity.ai. Please refer to the log for more information."); 153 | sendFinalChunk(res); 154 | }); 155 | 156 | res.on("close", function () { 157 | console.log(" > [Client closed]"); 158 | socket.disconnect(); 159 | }); 160 | } 161 | } catch (e) { 162 | console.error("Error processing request:", e); 163 | res.status(400).json({ error: e.message }); 164 | } 165 | }); 166 | }); 167 | 168 | function sendChunk(res, content) { 169 | const chunk = { 170 | id: "chatcmpl-" + crypto.randomBytes(16).toString('hex'), 171 | object: "chat.completion.chunk", 172 | created: Math.floor(Date.now() / 1000), 173 | model: "claude-3-opus-20240229", 174 | choices: [{ 175 | index: 0, 176 | delta: { 177 | content: content 178 | }, 179 | finish_reason: null 180 | }] 181 | }; 182 | res.write(`data: ${JSON.stringify(chunk)}\n\n`); 183 | } 184 | 185 | function sendErrorChunk(res, errorMessage) { 186 | const chunk = { 187 | id: "chatcmpl-" + crypto.randomBytes(16).toString('hex'), 188 | object: "chat.completion.chunk", 189 | created: Math.floor(Date.now() / 1000), 190 | model: "claude-3-opus-20240229", 191 | choices: [{ 192 | index: 0, 193 | delta: { 194 | content: errorMessage 195 | }, 196 | finish_reason: "stop" 197 | }] 198 | }; 199 | res.write(`data: ${JSON.stringify(chunk)}\n\n`); 200 | } 201 | 202 | function sendFinalChunk(res) { 203 | const finalChunk = { 204 | id: "chatcmpl-" + crypto.randomBytes(16).toString('hex'), 205 | object: "chat.completion.chunk", 206 | created: Math.floor(Date.now() / 1000), 207 | model: "claude-3-opus-20240229", 208 | choices: [{ 209 | index: 0, 210 | delta: {}, 211 | finish_reason: "stop" 212 | }] 213 | }; 214 | res.write(`data: ${JSON.stringify(finalChunk)}\n\n`); 215 | res.write("data: [DONE]\n\n"); 216 | res.end(); 217 | } 218 | 219 | // 修改404处理 220 | app.use((req, res, next) => { 221 | console.log(`404 Not Found: ${req.method} ${req.url}`); 222 | res.status(404).json({ error: "Not Found" }); 223 | }); 224 | 225 | // 添加全局错误处理 226 | app.use((err, req, res, next) => { 227 | console.error("Unhandled error:", err); 228 | res.status(500).json({ error: "Internal Server Error" }); 229 | }); 230 | 231 | // handle other 232 | app.use((req, res, next) => { 233 | res.status(404).send("Not Found"); 234 | }); 235 | 236 | app.listen(port, () => { 237 | console.log(`Perplexity proxy listening on port ${port}`); 238 | }); 239 | // eventStream util 240 | function createEvent(event, data) { 241 | // if data is object, stringify it 242 | if (typeof data === "object") { 243 | data = JSON.stringify(data); 244 | } 245 | return `event: ${event}\ndata: ${data}\n\n`; 246 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pplx-proxy", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "description": "", 11 | "dependencies": { 12 | "express": "^4.19.2", 13 | "proxy-agent": "^6.4.0", 14 | "socket.io-client": "^4.7.5", 15 | "uuid": "^9.0.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /start.bat: -------------------------------------------------------------------------------- 1 | call npm install 2 | set PPLX_COOKIE=Your Cookie 3 | set USER_AGENT=Your User-Agent 4 | set all_proxy= 5 | node index 6 | pause -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | npm install 3 | export PPLX_COOKIE="Your Cookie" 4 | export USER_AGENT="Your User-Agent" 5 | export all_proxy="" 6 | node index -------------------------------------------------------------------------------- /usage.md: -------------------------------------------------------------------------------- 1 | # 使用方法 2 | 3 | 1. 获得一个 Perplexity 账户并且订阅,登录。 4 | 5 | 2. 打开 F12(DevTools),找到 “Network(网络)”、刷新一下页面,找到“www.perplexity.ai”这个项目 6 | 7 | 3. 点进去,往下滑找到 "Cookie",完整的复制后面的内容。 8 | 9 | 4. 用同样的方法找到 "User-Agent",完整的复制后面的内容。 10 | 11 | 5. 下载或Clone本项目代码,解压 12 | 13 | 6. 编辑 `start.bat` 文件,把上面的 Cookie 和 User Agent 粘贴进去 14 | 15 | 7. 启动 start.bat (Linux/macOS用户使用 start.sh) 16 | 17 | 8. 酒馆中选择 Claude,反向代理地址填 http://127.0.0.1:8081/v1。反代密码必须填,随便什么都可以。 18 | 19 | 9. 开始使用。如果失败了/没有结果/403/Warning 就多重试几次。 20 | 21 | # 使用代理 22 | 23 | 可以使用本地的socks5或http(s)代理。只需在 start.bat 中设置 `all_proxy` 环境变量。 24 | 25 | 比如,如要使用 Clash 的默认本地SOCKS5代理,则应设置为 `set all_proxy=socks5://127.0.0.1:7890` 26 | 27 | ## 注意事项 28 | 29 | 出现 403 错误请重新抓 COOKIE 或者更换代理出口 IP。 30 | 31 | # Usage 32 | 33 | 1. Get a Perplexity account and subscribe, log in. 34 | 35 | 2. Open F12 (DevTools), find “Network”, refresh the page, and find “www.perplexity.ai”. 36 | 37 | 3. Click on it, scroll down and find “Cookie:”, and copy the entire contents. 38 | 39 | 4. Find the "user-agnet" in the same way. 40 | 41 | 5. Download or Clone the code of this project and unzip it. 42 | 43 | 6. Edit the `start.bat` file and paste the cookie and User Agent into it. 44 | 45 | 7. Start start.bat 46 | 47 | 8. Select Claude in the Tavern and put http://127.0.0.1:8081/v1 as the address of the reverse proxy. Use any random string for password. 48 | 49 | 9. Enjoy it. If it fails/no result/403/Warning, try again. 50 | 51 | # Use custom proxy 52 | 53 | Use the `all_proxy` env to set custom proxy. Refer to https://www.npmjs.com/package/proxy-from-env for detail. 54 | 55 | ## Caution 56 | 57 | If you get 403 errors, consider getting the cookie again or changing your IP. --------------------------------------------------------------------------------