Niansuh commited on
Commit
aff3448
·
verified ·
1 Parent(s): 5e480df

Upload 11 files

Browse files
Files changed (11) hide show
  1. .env +4 -0
  2. .gitignore +5 -0
  3. Dockerfile +7 -0
  4. docker-build.sh +1 -0
  5. docker-compose.yml +13 -0
  6. docker_use.md +82 -0
  7. index.js +246 -0
  8. package.json +17 -0
  9. start.bat +6 -0
  10. start.sh +6 -0
  11. usage.md +57 -0
.env ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
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 ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ node_modules
2
+ package-lock.json
3
+ .vscode
4
+ config
5
+ test.js
Dockerfile ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
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" ]
docker-build.sh ADDED
@@ -0,0 +1 @@
 
 
1
+ docker build . -t 'archeb/pplx-proxy'
docker-compose.yml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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寻求帮助。
index.js ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }
start.bat ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.