alcex commited on
Commit
93be000
·
verified ·
1 Parent(s): 1b59411

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +152 -553
index.js CHANGED
@@ -1,595 +1,194 @@
1
- import fetch from 'node-fetch';
2
- import express from 'express';
3
- import cors from 'cors';
4
- import dotenv from 'dotenv';
5
- import puppeteer from 'puppeteer-extra'
6
- import StealthPlugin from 'puppeteer-extra-plugin-stealth'
7
- import UserAgent from 'user-agents';
 
 
 
 
 
 
 
8
 
9
- dotenv.config();
10
 
11
- const Tokens = [];
12
- let tokenManager;
13
- let redisClient;
14
- let currentIndex = 0;
15
- let sessionId = null;
16
- const CONFIG = {
17
- API: {
18
- BASE_URL: process.env.DENO_URL || "https://partyrock.aws/stream/getCompletion",//如果需要多号循环,需要设置你自己的denourl
19
- API_KEY: process.env.API_KEY || "sk-123456",//自定义你自己的认证密钥,记得修改
20
- RedisUrl: process.env.RedisUrl,
21
- RedisToken: process.env.RedisToken
22
- },
23
- SERVER: {
24
- PORT: process.env.PORT || 3000,
25
- BODY_LIMIT: '5mb'
26
- },
27
- MODELS: {
28
- 'claude-3-5-haiku-20241022': 'bedrock-anthropic.claude-3-5-haiku',
29
- 'claude-3-5-sonnet-20241022': 'bedrock-anthropic.claude-3-5-sonnet-v2-0',
30
- 'nova-lite-v1-0': 'bedrock-amazon.nova-lite-v1-0',
31
- 'nova-pro-v1-0': 'bedrock-amazon.nova-pro-v1-0',
32
- 'llama3-1-7b': 'bedrock-meta.llama3-1-8b-instruct-v1',
33
- 'llama3-1-70b': 'bedrock-meta.llama3-1-70b-instruct-v1',
34
- 'mistral-small': 'bedrock-mistral.mistral-small-2402-v1-0',
35
- 'mistral-large': 'bedrock-mistral.mistral-large-2407-v1-0'
36
- },
37
- DEFAULT_HEADERS: {
38
- "request-id": "",
39
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
40
- "Cache-Control": "no-cache, no-store",
41
- "pragma": "no-cache",
42
- "Accept": "text/event-stream",
43
- "Accept-Encoding": "gzip, deflate, br, zstd",
44
- "Content-Type": "application/json",
45
- "anti-csrftoken-a2z": "",
46
- "origin": "https://partyrock.aws",
47
- "sec-fetch-site": "same-origin",
48
- "sec-fetch-mode": "cors",
49
- "sec-fetch-dest": "empty",
50
- "referer": "",
51
- "Cookie": "",
52
- "accept-language": "zh-CN,zh;q=0.9",
53
- "priority": "u=1, i"
54
- },
55
- CHROME_PATH: process.env.CHROME_PATH || "/usr/bin/chromium"
56
- };
57
- var RedisClient = class {
58
- constructor() {
59
- this.url = CONFIG.API.RedisUrl;
60
- this.token = CONFIG.API.RedisToken;
61
  }
62
- async get(key) {
63
- const response = await fetch(`${this.url}/get/${key}`, {
64
- headers: {
65
- Authorization: `Bearer ${this.token}`
66
- }
67
- });
68
- if (!response.ok) {
69
- console.log("redis获取内容失败", response.status);
70
- }
71
  const data = await response.json();
72
- return data.result;
 
 
73
  }
74
- async set(key, value) {
75
- const url = `${this.url}/set/${key}`;
76
- const response = await fetch(url, {
77
- method: "POST",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  headers: {
79
- Authorization: `Bearer ${this.token}`
 
 
 
 
80
  },
81
- body: `${value}`
82
  });
83
- if (!response.ok) {
84
- console.log("redis设置内容失败", response.status);
85
- }
86
- }
87
- };
88
- class TokenManager {
89
- async updateRedisTokens() {
90
- await redisClient.set(`tokens_${currentIndex}`, JSON.stringify(Tokens[currentIndex]));
91
- }
92
- async getRedisTokens() {
93
- var checkRedis = JSON.parse(await redisClient.get(`tokens_${currentIndex}`));
94
- return checkRedis;
95
- }
96
 
97
- async updateCacheTokens() {
98
- sessionId = Utils.uuidv4();
99
- CONFIG.DEFAULT_HEADERS["anti-csrftoken-a2z"] = Tokens[currentIndex].anti_csrftoken_a2z;
100
- CONFIG.DEFAULT_HEADERS.Cookie = `idToken=${Tokens[currentIndex].idToken}; pr_refresh_token=${Tokens[currentIndex].pr_refresh_token};aws-waf-token=${Tokens[currentIndex].aws_waf_token};cwr_s=${Tokens[currentIndex].cwr_s};cwr_u=${sessionId}`;
101
- CONFIG.DEFAULT_HEADERS.referer = Tokens[currentIndex].refreshUrl;
102
- CONFIG.DEFAULT_HEADERS["request-id"] = `request-id-${Utils.uuidv4()}`;
103
- }
104
 
105
- async updateTokens(response, isWaf = false) {
106
- if (isWaf) {
107
- var wafToken = await Utils.extractWaf();
108
- if (wafToken) {
109
- Tokens[currentIndex].aws_waf_token = wafToken;
110
- await this.updateCacheTokens();
111
- this.updateRedisTokens();
112
- currentIndex = (currentIndex + 1) % Tokens.length;
113
- console.log("成功提取 aws-waf-token");
114
- } else {
115
- currentIndex = (currentIndex + 1) % Tokens.length;
116
- await this.updateCacheTokens();
117
- console.log("提取aws-waf-token失败");
118
- }
119
- } else {
120
- const newCsrfToken = response.headers.get('anti-csrftoken-a2z');
121
- const cookies = response.headers.get('set-cookie');
122
- if (newCsrfToken && cookies) {
123
- console.log("更新缓存");
124
- Tokens[currentIndex].anti_csrftoken_a2z = newCsrfToken;
125
- const idTokenMatch = cookies.match(/idToken=([^;]+)/);
126
- if (idTokenMatch && idTokenMatch[1]) {
127
- Tokens[currentIndex].idToken = idTokenMatch[1];
128
  }
129
- this.updateRedisTokens();//最后更新redis数据库缓存,异步
130
- console.log("更新缓存完毕");
131
  }
132
- currentIndex = (currentIndex + 1) % Tokens.length;
133
  }
134
- }
135
- }
136
-
137
 
138
- class Utils {
139
- static async getRandomUserAgent() {
140
- try {
141
- let type = ["Win32", "MacIntel", "Linux x86_64"]
142
- const userAgent = new UserAgent({ platform: type[Math.floor(Math.random() * type.length)] });
143
- return userAgent.random().toString();
144
- } catch (error) {
145
- let type = [
146
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
147
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15"
148
- ]
149
- return type[Math.floor(Math.random() * type.length)]
150
- }
151
  }
152
- static async extractWaf() {
153
- puppeteer.use(StealthPlugin())
154
- const browser = await puppeteer.launch({
155
- headless: true,
156
- args: [
157
- '--no-sandbox',
158
- '--disable-setuid-sandbox',
159
- '--disable-dev-shm-usage',
160
- '--disable-gpu'
161
- ],
162
- executablePath: CONFIG.CHROME_PATH
163
- });
164
- try {
165
- const page = await browser.newPage();
166
- await page.setExtraHTTPHeaders({
167
- cookie: `pr_refresh_token=${Tokens[currentIndex].pr_refresh_token};idToken=${Tokens[currentIndex].idToken};aws-waf-token=${Tokens[currentIndex].aws_waf_token};cwr_s=${Tokens[currentIndex].cwr_s};cwr_u=${Utils.uuidv4()}`
168
- });
169
- await page.setUserAgent(
170
- CONFIG.DEFAULT_HEADERS["User-Agent"]
171
- )
172
- await page.goto(Tokens[currentIndex].refreshUrl, {
173
- waitUntil: 'networkidle2',
174
- timeout: 30000
175
- });
176
- await page.evaluate(() => {
177
- // 随机滚动
178
- window.scrollBy(0, Math.random() * 500)
179
- })
180
- await page.evaluate(() => {
181
- return new Promise(resolve => setTimeout(resolve, 2000))
182
- })
183
- // 直接从页面 cookies 中提取 aws-waf-token
184
- const awsWafToken = (await page.cookies()).find(
185
- cookie => cookie.name.toLowerCase() === 'aws-waf-token'
186
- )?.value;
187
-
188
- if (awsWafToken) {
189
- await browser.close();
190
- return awsWafToken;
191
- } else {
192
- await browser.close();
193
- return null;
194
- }
195
 
196
- } catch (error) {
197
- console.error('获取 aws-waf-token 出错:', error);
198
- await browser.close();
199
- return null;
 
 
 
200
  }
201
  }
202
 
203
- static async extractTokens(cookieString) {
204
- const tokens = {};
205
- const cookiePairs = cookieString.split(';').map(pair => pair.trim());
206
-
207
- cookiePairs.forEach(pair => {
208
- const splitIndex = pair.indexOf('=');
209
- const key = pair.slice(0, splitIndex).trim();
210
- const value = pair.slice(splitIndex + 1).trim();
211
-
212
- tokens[key] = value;
213
- });
214
-
215
- return tokens;
216
- }
217
- // 获取数组中的随机元素
218
- static getRandomElement(arr) {
219
- return arr[Math.floor(Math.random() * arr.length)];
220
- }
221
-
222
- // 生成UUID
223
- static uuidv4() {
224
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
225
- const r = (Math.random() * 16) | 0;
226
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
227
- return v.toString(16);
228
  });
229
  }
230
 
231
- // 生成随机十六进制字符串
232
- static generateRandomHexString(length) {
233
- let result = '';
234
- const characters = '0123456789ABCDEF';
235
- for (let i = 0; i < length; i++) {
236
- result += characters.charAt(Math.floor(Math.random() * characters.length));
237
- }
238
- return result;
239
- }
240
- }
241
- async function initializeService() {
242
- console.log('服务初始化中...');
243
- tokenManager = new TokenManager();
244
- redisClient = new RedisClient();
245
- let index = 0;
246
- while (true) {
247
- console.log(index, '开始检测是否有缓存');
248
- // 使用 JSON.parse 确保正确解析
249
- var checkRedis = await redisClient.get(`tokens_${index}`);
250
- if (checkRedis) {
251
- // 尝试解析 JSON 字符串
252
- try {
253
- const parsedRedis = typeof checkRedis === 'string'
254
- ? JSON.parse(checkRedis)
255
- : checkRedis;
256
- Tokens.push({
257
- refreshUrl: parsedRedis.refreshUrl,
258
- anti_csrftoken_a2z: parsedRedis.anti_csrftoken_a2z,
259
- pr_refresh_token: parsedRedis.pr_refresh_token,
260
- aws_waf_token: parsedRedis.aws_waf_token,
261
- idToken: parsedRedis.idToken,
262
- cwr_s: parsedRedis.cwr_s
263
- });
264
- console.log(`成功添加第 ${index} 组 Token`);
265
- } catch (error) {
266
- console.error(`解析第 ${index} 组 Token 时出错:`, error);
267
- }
268
- } else {
269
- console.log(index, '没有缓存,开始提取环境变量');
270
- const refreshUrl = process.env[`AUTH_TOKENS_${index}_REFRESH_URL`];
271
- const anti_csrftoken_a2z = process.env[`AUTH_TOKENS_${index}_ANTI_CSRF_TOKEN`];
272
- const cookie = process.env[`AUTH_TOKENS_${index}_COOKIE`];
273
-
274
- if (!refreshUrl && !anti_csrftoken_a2z && !cookie) {
275
- break;
276
- }
277
- const cookies = await Utils.extractTokens(cookie);
278
-
279
- if (refreshUrl && anti_csrftoken_a2z && cookie) {
280
- Tokens.push({
281
- refreshUrl,
282
- anti_csrftoken_a2z,
283
- pr_refresh_token: cookies["pr_refresh_token"],
284
- aws_waf_token: cookies["aws-waf-token"],
285
- idToken: cookies["idToken"],
286
- cwr_s: cookies["cwr_s"]
287
- });
288
- }
289
- }
290
- index++;
291
- }
292
- console.log('服务初始化完毕');
293
- }
294
-
295
- await initializeService();
296
-
297
- class ApiClient {
298
- constructor(modelId) {
299
- if (!CONFIG.MODELS[modelId]) {
300
- throw new Error(`不支持的模型: ${modelId}`);
301
- }
302
- this.modelId = CONFIG.MODELS[modelId];
303
- }
304
-
305
- processMessageContent(content) {
306
- if (typeof content === 'string') return content;
307
-
308
- if (Array.isArray(content)) {
309
- return content
310
- .map(item => item.text)
311
- .join('\n');
312
- }
313
-
314
- if (typeof content === 'object') return content.text || null;
315
- return null;
316
  }
317
 
318
- //合并相同role的消息
319
- async transformMessages(request) {
320
- const mergedMessages = await request.messages.reduce(async (accPromise, current) => {
321
- const acc = await accPromise;
322
- const lastMessage = acc[acc.length - 1];
323
- if (lastMessage && lastMessage.role == "system") {
324
- lastMessage.role = "user"
325
- }
326
- if (current && current.role == "system") {
327
- current.role = "user"
328
- }
329
- const currentContent = this.processMessageContent(current.content);
330
 
331
- if (currentContent === null) return acc;
 
 
332
 
333
- if (lastMessage && current && (lastMessage.role == current.role)) {
334
- const lastContent = this.processMessageContent(lastMessage.content);
335
- if (lastContent !== null) {
336
- lastMessage.content = [
337
- {
338
- "text": `${lastContent}\r\n${currentContent}`
339
- }
340
- ];
341
- return acc;
342
- }
343
- }
344
- current.content = [
345
- {
346
- "text": currentContent
347
- }
348
- ]
349
- acc.push(current);
350
- return acc;
351
- }, Promise.resolve([]));
352
- // 处理请求参数
353
- let topP = request.top_p || 0.5;
354
- let temperature = request.temperature || 0.95;
355
- if (topP >= 1) {
356
- topP = 1;
357
- }
358
- if (temperature >= 1) {
359
- temperature = 1;
360
- }
361
- const extractPartyRockId = url => url.match(/https:\/\/partyrock\.aws\/u\/[^/]+\/([^/]+)/)?.[1];
362
- console.log("当前请求的是", CONFIG.DEFAULT_HEADERS.referer);
363
 
364
- const requestPayload = {
365
- "messages": mergedMessages,
366
- "modelName": this.modelId,
367
- "context": {
368
- "type": "chat-widget",
369
- "appId": extractPartyRockId(CONFIG.DEFAULT_HEADERS.referer)
370
- },
371
- "options": {
372
- "temperature": temperature,
373
- "topP": topP
374
- },
375
- "apiVersion": 3
376
- }
377
- return requestPayload;
378
- }
379
- }
380
- class MessageProcessor {
381
- static createChatResponse(message, model, isStream = false) {
382
- const baseResponse = {
383
- id: `chatcmpl-${Utils.uuidv4()}`,
384
- created: Math.floor(Date.now() / 1000),
385
- model: model
386
- };
387
 
388
  if (isStream) {
389
- return {
390
- ...baseResponse,
391
- object: 'chat.completion.chunk',
 
 
 
 
 
 
 
 
 
392
  choices: [{
393
- index: 0,
394
- delta: { content: message }
395
  }]
396
  };
397
- }
398
-
399
- return {
400
- ...baseResponse,
401
- object: 'chat.completion',
402
- choices: [{
403
- index: 0,
404
- message: {
405
- role: 'assistant',
406
- content: message
407
- },
408
- finish_reason: 'stop'
409
- }],
410
- usage: null
411
- };
412
- }
413
- }
414
- class ResponseHandler {
415
- static async handleStreamResponse(response, model, res) {
416
- res.setHeader('Content-Type', 'text/event-stream');
417
- res.setHeader('Cache-Control', 'no-cache');
418
- res.setHeader('Connection', 'keep-alive');
419
-
420
- try {
421
- const stream = response.body;
422
- let buffer = '';
423
- let decoder = new TextDecoder('utf-8');
424
- stream.on('data', (chunk) => {
425
- buffer += decoder.decode(chunk, { stream: true });
426
- const lines = buffer.split('\n');
427
- buffer = lines.pop() || '';
428
-
429
- for (const line of lines) {
430
- if (!line.trim()) continue;
431
- if (line.startsWith('data: ')) {
432
- const data = line.substring(6);
433
- if (!data) continue;
434
- if (data == "[DONE]") {
435
- res.write('data: [DONE]\n\n');
436
- return res.end();
437
- }
438
- try {
439
- const json = JSON.parse(data);
440
- if (json?.text) {
441
- var content = json.text;
442
- const responseData = MessageProcessor.createChatResponse(content, model, true);
443
- res.write(`data: ${JSON.stringify(responseData)}\n\n`);
444
- }
445
- } catch (error) {
446
- console.error('JSON解析错误:', error);
447
- }
448
- }
449
- }
450
- });
451
- stream.on('end', () => {
452
- res.write('data: [DONE]\n\n');
453
- res.end();
454
- });
455
- stream.on('error', (error) => {
456
- console.error('流处理错误:', error);
457
- res.write('data: [DONE]\n\n');
458
- res.end();
459
  });
460
 
461
- } catch (error) {
462
- console.error('处理响应错误:', error);
463
  res.write('data: [DONE]\n\n');
464
  res.end();
465
- }
466
- }
467
-
468
- static async handleNormalResponse(response, model, res) {
469
- const text = await response.text();
470
- const lines = text.split("\n");
471
- let fullResponse = '';
472
-
473
- for (let line of lines) {
474
- line = line.trim();
475
- if (line) {
476
- if (line.startsWith('data: ')) {
477
- let data = line.substring(6);
478
- if (data === '[DONE]') break;
479
- try {
480
- let json = JSON.parse(data)
481
- if (json?.text) {
482
- fullResponse += json.text;
483
- }
484
- } catch (error) {
485
- console.log("json解析错误");
486
- continue
487
- }
488
- }
489
- }
490
- }
491
- const responseData = MessageProcessor.createChatResponse(fullResponse, model);
492
- res.json(responseData);
493
- }
494
- }
495
- // Express 应用设置
496
- const app = express();
497
- app.use(express.json({ limit: CONFIG.SERVER.BODY_LIMIT }));
498
- app.use(express.urlencoded({ extended: true, limit: CONFIG.SERVER.BODY_LIMIT }));
499
-
500
- app.use(cors({
501
- origin: '*',
502
- methods: ['GET', 'POST', 'OPTIONS'],
503
- allowedHeaders: ['*']
504
- }));
505
- // 路由处理
506
- app.get('/hf/v1/models', (req, res) => {
507
- res.json({
508
- object: "list",
509
- data: Object.keys(CONFIG.MODELS).map((model, index) => ({
510
- id: model,
511
- object: "model",
512
- created: Math.floor(Date.now() / 1000),
513
- owned_by: "partyrock",
514
- }))
515
- });
516
- });
517
-
518
- app.post('/hf/v1/chat/completions', async (req, res) => {
519
- var reqStatus = 500;
520
- try {
521
- const authToken = req.headers.authorization?.replace('Bearer ', '');
522
- if (authToken !== CONFIG.API.API_KEY) {
523
- return res.status(401).json({ error: "Unauthorized" });
524
- }
525
- await tokenManager.updateCacheTokens();
526
- const apiClient = new ApiClient(req.body.model);
527
- const requestPayload = await apiClient.transformMessages(req.body);
528
-
529
- try {
530
- console.log("开始请求");
531
- //发送请求
532
- var response = await fetch(`${CONFIG.API.BASE_URL}`, {
533
- method: "POST",
534
- headers: {
535
- ...CONFIG.DEFAULT_HEADERS
536
- },
537
- body: JSON.stringify(requestPayload)
538
- });
539
- reqStatus = response.status;
540
- switch (reqStatus) {
541
- case 200:
542
- console.log("请求成功");
543
- // 异步更新token
544
- tokenManager.updateTokens(response)
545
- // 处理响应
546
- if (req.body.stream) {
547
- await ResponseHandler.handleStreamResponse(response, req.body.model, res);
548
- } else {
549
- await ResponseHandler.handleNormalResponse(response, req.body.model, res);
550
- }
551
- return;
552
- case 202:
553
- console.log("请求受限,更新WAF");
554
- await tokenManager.updateTokens(response, true);
555
- throw new Error(`请求失败! status: ${response.statusText},已刷新验证信息,请重新请求`);
556
- case 405:
557
- console.log("人机验证");
558
- await tokenManager.updateTokens(response, true);//尝试获取waf,然后返回错误提示。
559
- throw new Error(`请求失败! status: ${response.statusText},人机验证,请重新请求,如果多次失败,请重新更换token`);
560
- case 400:
561
- console.log("信息过期,请求失败");
562
- await tokenManager.updateTokens(response);
563
- throw new Error(`请求失败! status: ${response.statusText},已刷新验证信息,请重新请求`);
564
- case 403:
565
- console.log("请求被阻止");
566
- await tokenManager.updateTokens(response, true);//尝试获取waf,然后返回错误提示。
567
- CONFIG.DEFAULT_HEADERS["User-Agent"] = await Utils.getRandomUserAgent();
568
- throw new Error(`请求失败! status: ${response.statusText},请重新请求,如果多次失败,请重新更换token`);
569
- default:
570
- throw new Error(`请求失败! status: ${response.status}`);
571
- }
572
- } catch (error) {
573
- throw new Error(`请求失败! status: ${response.status}`);
574
  }
575
  } catch (error) {
576
- res.status(parseInt(reqStatus)).json({
577
- error: {
578
- message: error.message,
579
- type: 'server_error',
580
- param: null,
581
- code: error.code || null
582
- }
583
- });
584
  }
585
  });
586
 
587
-
588
- app.use((req, res) => {
589
- res.status(404).send("API服务运行正常,,请使用正确请求路径");
590
- });
591
-
592
- // 启动服务器
593
- app.listen(CONFIG.SERVER.PORT, () => {
594
- console.log(`服务器运行在端口 ${CONFIG.SERVER.PORT} `);
595
  });
 
1
+ const express = require('express');
2
+ const fetch = require('node-fetch');
3
+ const { v4: uuidv4 } = require('uuid');
4
+ const app = express();
5
+ require('dotenv').config();
6
+
7
+ const modelMapping = {
8
+ "gpt-4o-mini": "GPT-4o mini",
9
+ "claude-haiku": "Claude Haiku",
10
+ "llama-3": "Llama 3",
11
+ "gemini-1.5": "Gemini 1.5",
12
+ "gemini-flash": "Gemini Flash",
13
+ "command-r": "Command R"
14
+ };
15
 
16
+ app.use(express.json());
17
 
18
+ const getCurrentTimestamp = () => Math.floor(Date.now() / 1000);
19
+
20
+ const splitIntoChunks = (text, chunkSize) => {
21
+ const chunks = [];
22
+ for (let i = 0; i < text.length; i += chunkSize) {
23
+ chunks.push(text.slice(i, i + chunkSize));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
+ return chunks;
26
+ };
27
+
28
+ const getTempUserID = async () => {
29
+ try {
30
+ const response = await fetch('https://playground.julius.ai/api/temp_user_id');
 
 
 
31
  const data = await response.json();
32
+ return data.temp_user_id;
33
+ } catch (error) {
34
+ throw new Error('Failed to get temp user ID');
35
  }
36
+ };
37
+
38
+ const sendToJulius = async (tempUserID, message, model) => {
39
+ const conversationID = uuidv4();
40
+ const juliusReq = {
41
+ message: {
42
+ content: message,
43
+ role: "user"
44
+ },
45
+ provider: "default",
46
+ chat_mode: "auto",
47
+ client_version: "20240130",
48
+ theme: "dark",
49
+ selectedModels: [model]
50
+ };
51
+
52
+ try {
53
+ const response = await fetch('https://playground.julius.ai/api/chat/message', {
54
+ method: 'POST',
55
  headers: {
56
+ 'is-demo': tempUserID,
57
+ 'Content-Type': 'application/json',
58
+ 'Platform': 'web',
59
+ 'conversation-id': conversationID,
60
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36'
61
  },
62
+ body: JSON.stringify(juliusReq)
63
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
66
+ let fullResponse = '';
 
 
 
 
 
67
 
68
+ while (true) {
69
+ const { done, value } = await reader.read();
70
+ if (done) break;
71
+
72
+ const lines = value.split('\n');
73
+ for (const line of lines) {
74
+ try {
75
+ const jsonResp = JSON.parse(line);
76
+ if (jsonResp.content) {
77
+ fullResponse += jsonResp.content;
78
+ }
79
+ } catch (e) {
80
+ // 忽略解析错误
 
 
 
 
 
 
 
 
 
 
81
  }
 
 
82
  }
 
83
  }
 
 
 
84
 
85
+ return fullResponse;
86
+ } catch (error) {
87
+ throw new Error('Failed to send to Julius');
 
 
 
 
 
 
 
 
 
 
88
  }
89
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ app.all('*', async (req, res) => {
92
+ // 身份验证
93
+ const authToken = process.env.AUTH_TOKEN;
94
+ if (authToken) {
95
+ const requestToken = req.headers.authorization?.replace('Bearer ', '');
96
+ if (!requestToken || requestToken !== authToken) {
97
+ return res.status(401).send('Access Denied');
98
  }
99
  }
100
 
101
+ // 健康检查
102
+ if (req.path !== '/v1/chat/completions') {
103
+ return res.json({
104
+ status: "Julius2Api Service Running...",
105
+ message: "MoLoveSze..."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  });
107
  }
108
 
109
+ if (req.method !== 'POST') {
110
+ return res.status(405).send('Method not allowed');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  }
112
 
113
+ try {
114
+ const openAIReq = req.body;
115
+ const isStream = openAIReq.stream || false;
 
 
 
 
 
 
 
 
 
116
 
117
+ // 模型映射
118
+ const mappedModel = modelMapping[openAIReq.model] || 'GPT-4o mini';
119
+ openAIReq.model = mappedModel;
120
 
121
+ const tempUserID = await getTempUserID();
122
+ const juliusResp = await sendToJulius(tempUserID,
123
+ openAIReq.messages[openAIReq.messages.length - 1].content,
124
+ mappedModel
125
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
+ const respId = `chatcmpl-${tempUserID}`;
128
+ const created = getCurrentTimestamp();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
  if (isStream) {
131
+ res.writeHead(200, {
132
+ 'Content-Type': 'text/event-stream',
133
+ 'Cache-Control': 'no-cache',
134
+ 'Connection': 'keep-alive'
135
+ });
136
+
137
+ // 发送初始响应
138
+ const firstResponse = {
139
+ id: respId,
140
+ object: "chat.completion.chunk",
141
+ created: created,
142
+ model: mappedModel,
143
  choices: [{
144
+ delta: { role: "assistant" },
145
+ index: 0
146
  }]
147
  };
148
+ res.write(`data: ${JSON.stringify(firstResponse)}\n\n`);
149
+
150
+ // 分块发送内容
151
+ const chunks = splitIntoChunks(juliusResp, 50);
152
+ chunks.forEach((chunk, index) => {
153
+ const response = {
154
+ id: respId,
155
+ object: "chat.completion.chunk",
156
+ created: created,
157
+ model: mappedModel,
158
+ choices: [{
159
+ delta: { content: chunk },
160
+ index: 0,
161
+ finish_reason: index === chunks.length - 1 ? 'stop' : null
162
+ }]
163
+ };
164
+ res.write(`data: ${JSON.stringify(response)}\n\n`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  });
166
 
 
 
167
  res.write('data: [DONE]\n\n');
168
  res.end();
169
+ } else {
170
+ const response = {
171
+ id: respId,
172
+ object: "chat.completion",
173
+ created: created,
174
+ model: mappedModel,
175
+ choices: [{
176
+ message: {
177
+ role: "assistant",
178
+ content: juliusResp
179
+ },
180
+ finish_reason: "stop"
181
+ }]
182
+ };
183
+ res.json(response);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  }
185
  } catch (error) {
186
+ console.error(error);
187
+ res.status(500).send(error.message);
 
 
 
 
 
 
188
  }
189
  });
190
 
191
+ const PORT = process.env.PORT || 3000;
192
+ app.listen(PORT, () => {
193
+ console.log(`Server running on port ${PORT}`);
 
 
 
 
 
194
  });