caidaoli commited on
Commit
1918728
·
verified ·
1 Parent(s): 6a88dbb

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +173 -31
index.js CHANGED
@@ -6,13 +6,14 @@ import cors from 'cors';
6
  import Logger from './logger.js';
7
  import dotenv from 'dotenv';
8
 
 
9
  // 初始化环境变量
10
  dotenv.config();
11
 
12
  // 配置管理
13
  const CONFIG = {
14
  SERVER: {
15
- PORT: process.env.PORT || 25526,
16
  BODY_LIMIT: '5mb',
17
  CORS_OPTIONS: {
18
  origin: '*',
@@ -38,6 +39,7 @@ const CONFIG = {
38
  "grok-3-reasoning": "grok-3",
39
  "grok-3-imageGen": "grok-3",
40
  },
 
41
  IS_IMG_GEN: false,
42
  IS_THINKING: false
43
  };
@@ -58,6 +60,80 @@ const DEFAULT_HEADERS = {
58
  'priority': 'u=1, i'
59
  };
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  // 工具类
62
  class Utils {
63
  static generateRandomString(length, charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
@@ -65,12 +141,17 @@ class Utils {
65
  .map(() => charset[Math.floor(Math.random() * charset.length)])
66
  .join('');
67
  }
68
-
 
 
 
 
 
69
  static createAuthHeaders() {
70
  return {
71
  ...DEFAULT_HEADERS,
72
- 'x-csrf-token': CONFIG.API.CT0,
73
- 'cookie': `auth_token=${CONFIG.API.AUTH_TOKEN};ct0=${CONFIG.API.CT0}`
74
  };
75
  }
76
 
@@ -202,14 +283,45 @@ class TwitterGrokApiClient {
202
  }
203
 
204
  async transformMessages(messages) {
 
 
 
 
205
  const processedMessages = [];
206
- for (let i = 0; i < messages.length; i++) {
207
- const isLastTwoMessages = i >= messages.length - 2;
208
- const content = await this.processMessageContent(messages[i], isLastTwoMessages);
209
- if (content) {
210
- processedMessages.push(content);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  }
212
  }
 
 
 
 
 
 
 
 
 
 
 
 
213
  return processedMessages;
214
  }
215
 
@@ -228,7 +340,7 @@ class TwitterGrokApiClient {
228
 
229
  return {
230
  message,
231
- sender: role === 'user' ? 1 : 2,
232
  ...(role === 'user' && { fileAttachments })
233
  };
234
  }
@@ -386,7 +498,6 @@ class ResponseHandler {
386
  let buffer = '';
387
  let fullResponse = '';
388
  let imageUrl = null;
389
-
390
  try {
391
  for await (const chunk of reader) {
392
  const lines = (buffer + chunk.toString()).split('\n');
@@ -404,6 +515,9 @@ class ResponseHandler {
404
  if (imageUrl) {
405
  await this.sendImageResponse(imageUrl, model, res);
406
  } else {
 
 
 
407
  const responseData = MessageProcessor.createChatResponse(fullResponse, model);
408
  res.json(responseData);
409
  }
@@ -495,7 +609,6 @@ app.get('/hf/v1/models', (req, res) => {
495
  }))
496
  });
497
  });
498
-
499
  app.post('/hf/v1/chat/completions', async (req, res) => {
500
  try {
501
  const authToken = req.headers.authorization?.replace('Bearer ', '');
@@ -503,22 +616,54 @@ app.post('/hf/v1/chat/completions', async (req, res) => {
503
  return res.status(401).json({ error: 'Unauthorized' });
504
  }
505
 
506
- const grokClient = new TwitterGrokApiClient(req.body.model);
507
- const requestPayload = await grokClient.prepareChatRequest(req.body);
508
-
509
- const response = await fetch(CONFIG.API.ENDPOINTS.CHAT, {
510
- method: 'POST',
511
- headers: Utils.createAuthHeaders(),
512
- body: JSON.stringify(requestPayload)
513
- });
514
-
515
- if (!response.ok) {
516
- throw new Error(`上游服务请求失败! status: ${response.status}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
517
  }
518
 
519
- await (req.body.stream
520
- ? ResponseHandler.handleStreamResponse(response, req.body.model, res)
521
- : ResponseHandler.handleNormalResponse(response, req.body.model, res));
522
 
523
  } catch (error) {
524
  Logger.error('Chat Completions Request Error', error, 'ChatAPI');
@@ -530,10 +675,6 @@ app.post('/hf/v1/chat/completions', async (req, res) => {
530
  code: error.code || null
531
  }
532
  });
533
- } finally {
534
- if (req.body.conversationId) {
535
- await ConversationManager.deleteConversation(req.body.conversationId);
536
- }
537
  }
538
  });
539
 
@@ -545,4 +686,5 @@ app.use((req, res) => {
545
  // 启动服务器
546
  app.listen(CONFIG.SERVER.PORT, () => {
547
  Logger.info(`服务器运行在端口 ${CONFIG.SERVER.PORT}`, 'Server');
548
- });
 
 
6
  import Logger from './logger.js';
7
  import dotenv from 'dotenv';
8
 
9
+
10
  // 初始化环境变量
11
  dotenv.config();
12
 
13
  // 配置管理
14
  const CONFIG = {
15
  SERVER: {
16
+ PORT: process.env.PORT || 7860,
17
  BODY_LIMIT: '5mb',
18
  CORS_OPTIONS: {
19
  origin: '*',
 
39
  "grok-3-reasoning": "grok-3",
40
  "grok-3-imageGen": "grok-3",
41
  },
42
+ SIGNATURE_INDEX: 0,
43
  IS_IMG_GEN: false,
44
  IS_THINKING: false
45
  };
 
60
  'priority': 'u=1, i'
61
  };
62
 
63
+
64
+ async function initialization() {
65
+ const auth_tokenArray = CONFIG.API.AUTH_TOKEN.split(',');
66
+ const ct0Array = CONFIG.API.CT0.split(',');
67
+ auth_tokenArray.forEach((auth_token, index) => {
68
+ tokenManager.addToken(`auth_token=${auth_token};ct0=${ct0Array[index]}`);
69
+ });
70
+ Logger.info("初始化完成", 'Server');
71
+ }
72
+ class AuthTokenManager {
73
+ constructor() {
74
+ this.activeTokens = [];
75
+ this.expiredTokens = new Map();
76
+ this.isRecoveryProcess = false;
77
+ }
78
+
79
+ // 添加 token
80
+ addToken(token) {
81
+ if (!this.activeTokens.includes(token)) {
82
+ this.activeTokens.push(token);
83
+ }
84
+ }
85
+
86
+ // 通过下标获取 token
87
+ getTokenByIndex(index) {
88
+ if (index < 0 || index >= this.activeTokens.length) {
89
+ throw new Error(`无效的索引:${index}`);
90
+ }
91
+ return this.activeTokens[index];
92
+ }
93
+
94
+ // 通过下标移除 token
95
+ removeTokenByIndex(index) {
96
+ if (index < 0 || index >= this.activeTokens.length) {
97
+ throw new Error(`无效的索引:${index}`);
98
+ }
99
+
100
+ const token = this.activeTokens[index];
101
+ this.activeTokens.splice(index, 1);
102
+
103
+ // 记录失效时间
104
+ this.expiredTokens.set(token, Date.now());
105
+ return token;
106
+ }
107
+
108
+ // 启动定期恢复机制
109
+ startTokenRecoveryProcess() {
110
+ setInterval(() => {
111
+ const now = Date.now();
112
+ for (const [token, expiredTime] of this.expiredTokens.entries()) {
113
+ if (now - expiredTime >= 2 * 60 * 60 * 1000) {
114
+ this.activeTokens.push(token);
115
+ this.expiredTokens.delete(token);
116
+ console.log(`Token ${token} recovered`);
117
+ }
118
+ }
119
+ }, 2 * 60 * 60 * 1000);
120
+ }
121
+
122
+ // 获取 token 总数
123
+ getTokenCount() {
124
+ return this.activeTokens.length;
125
+ }
126
+
127
+ // 获取所有活跃 token
128
+ getActiveTokens() {
129
+ return [...this.activeTokens];
130
+ }
131
+ }
132
+
133
+ const tokenManager = new AuthTokenManager();
134
+ await initialization();
135
+
136
+
137
  // 工具类
138
  class Utils {
139
  static generateRandomString(length, charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
 
141
  .map(() => charset[Math.floor(Math.random() * charset.length)])
142
  .join('');
143
  }
144
+ static getRandomID(size) {
145
+ const customDict = '0123456789';
146
+ return Array(size).fill(null)
147
+ .map(() => customDict[(Math.random() * customDict.length) | 0])
148
+ .join('');
149
+ }
150
  static createAuthHeaders() {
151
  return {
152
  ...DEFAULT_HEADERS,
153
+ 'x-csrf-token': tokenManager.getTokenByIndex(CONFIG.SIGNATURE_INDEX).split(';')[1].split('=')[1],
154
+ 'cookie': `${tokenManager.getTokenByIndex(CONFIG.SIGNATURE_INDEX)}`
155
  };
156
  }
157
 
 
283
  }
284
 
285
  async transformMessages(messages) {
286
+ if (messages[0].role === 'assistant') {
287
+ throw new Error('ai不能是第一个消息');
288
+ }
289
+
290
  const processedMessages = [];
291
+ let currentMessage = null;
292
+
293
+ for (const msg of messages) {
294
+ const normalizedMsg = msg.role === 'system' ? { ...msg, role: 'user' } : msg;
295
+
296
+ if (!currentMessage || currentMessage.role !== normalizedMsg.role) {
297
+ if (currentMessage) {
298
+ const processedContent = await this.processMessageContent(
299
+ currentMessage,
300
+ processedMessages.length >= messages.length - 2
301
+ );
302
+ if (processedContent) {
303
+ processedMessages.push(processedContent);
304
+ }
305
+ }
306
+ currentMessage = normalizedMsg;
307
+ } else {
308
+ currentMessage.content = typeof currentMessage.content === 'string' && typeof normalizedMsg.content === 'string'
309
+ ? `${currentMessage.content}\n${normalizedMsg.content}`
310
+ : normalizedMsg.content;
311
  }
312
  }
313
+
314
+ // 处理最后一个消息
315
+ if (currentMessage) {
316
+ const processedContent = await this.processMessageContent(
317
+ currentMessage,
318
+ true
319
+ );
320
+ if (processedContent) {
321
+ processedMessages.push(processedContent);
322
+ }
323
+ }
324
+
325
  return processedMessages;
326
  }
327
 
 
340
 
341
  return {
342
  message,
343
+ sender: role === 'assistant' ? 2 : 1,
344
  ...(role === 'user' && { fileAttachments })
345
  };
346
  }
 
498
  let buffer = '';
499
  let fullResponse = '';
500
  let imageUrl = null;
 
501
  try {
502
  for await (const chunk of reader) {
503
  const lines = (buffer + chunk.toString()).split('\n');
 
515
  if (imageUrl) {
516
  await this.sendImageResponse(imageUrl, model, res);
517
  } else {
518
+ if (fullResponse.includes("You've reached your limit of 15 Grok")) {
519
+ throw new Error('You have reached your limit of 15 Grok');
520
+ }
521
  const responseData = MessageProcessor.createChatResponse(fullResponse, model);
522
  res.json(responseData);
523
  }
 
609
  }))
610
  });
611
  });
 
612
  app.post('/hf/v1/chat/completions', async (req, res) => {
613
  try {
614
  const authToken = req.headers.authorization?.replace('Bearer ', '');
 
616
  return res.status(401).json({ error: 'Unauthorized' });
617
  }
618
 
619
+ while (tokenManager.getTokenCount() > 0) {
620
+ const grokClient = new TwitterGrokApiClient(req.body.model);
621
+ const requestPayload = await grokClient.prepareChatRequest(req.body);
622
+ Logger.info(`当前令牌索引: ${CONFIG.SIGNATURE_INDEX}`, 'Server');
623
+ const response = await fetch(CONFIG.API.ENDPOINTS.CHAT, {
624
+ method: 'POST',
625
+ headers: Utils.createAuthHeaders(),
626
+ body: JSON.stringify(requestPayload)
627
+ });
628
+
629
+ if (response.ok) {
630
+ Logger.info(`请求成功`, 'Server');
631
+ CONFIG.SIGNATURE_INDEX = (CONFIG.SIGNATURE_INDEX + 1) % tokenManager.getTokenCount();
632
+ Logger.info(`当前剩余可用令牌数: ${tokenManager.getTokenCount()}`, 'Server');
633
+ try {
634
+ await (req.body.stream
635
+ ? ResponseHandler.handleStreamResponse(response, req.body.model, res)
636
+ : ResponseHandler.handleNormalResponse(response, req.body.model, res));
637
+ return; // 成功后直接返回
638
+ } catch (error) {
639
+ tokenManager.removeTokenByIndex(CONFIG.SIGNATURE_INDEX);
640
+ if (!tokenManager.isRecoveryProcess) {
641
+ tokenManager.startTokenRecoveryProcess();
642
+ }
643
+ Logger.warn(`当前令牌失效,已移除令牌,剩余令牌数: ${tokenManager.getTokenCount()}`, 'Server');
644
+ // 更新签名索引
645
+ CONFIG.SIGNATURE_INDEX = (CONFIG.SIGNATURE_INDEX + 1) % tokenManager.getTokenCount();
646
+ }
647
+ } else {
648
+ // 处理429错误
649
+ if (response.status === 429) {
650
+ tokenManager.removeTokenByIndex(CONFIG.SIGNATURE_INDEX);
651
+ if (!tokenManager.isRecoveryProcess) {
652
+ tokenManager.startTokenRecoveryProcess();
653
+ }
654
+ Logger.warn(`当前令牌失效,已移除令牌,剩余令牌数: ${tokenManager.getTokenCount()}`, 'Server');
655
+ // 更新签名索引
656
+ CONFIG.SIGNATURE_INDEX = (CONFIG.SIGNATURE_INDEX + 1) % tokenManager.getTokenCount();
657
+ Logger.warn(`请求被限流,剩余重试次数: ${tokenManager.getTokenCount()}`, 'ChatAPI');
658
+ } else {
659
+ // 非429错误直接抛出
660
+ throw new Error(`上游服务请求失败! status: ${response.status}`);
661
+ }
662
+ }
663
  }
664
 
665
+ // 如果重试次数用完仍然是429
666
+ throw new Error('所有令牌都已耗尽,请求被限流');
 
667
 
668
  } catch (error) {
669
  Logger.error('Chat Completions Request Error', error, 'ChatAPI');
 
675
  code: error.code || null
676
  }
677
  });
 
 
 
 
678
  }
679
  });
680
 
 
686
  // 启动服务器
687
  app.listen(CONFIG.SERVER.PORT, () => {
688
  Logger.info(`服务器运行在端口 ${CONFIG.SERVER.PORT}`, 'Server');
689
+ });
690
+