yxmiler commited on
Commit
3ca17b9
·
verified ·
1 Parent(s): 9d46f45

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +111 -57
index.js CHANGED
@@ -23,11 +23,13 @@ const CONFIG = {
23
  "grok-3-reasoning": "grok-3"
24
  },
25
  API: {
 
26
  BASE_URL: "https://grok.com",
27
  API_KEY: process.env.API_KEY || "sk-123456",
28
  SIGNATURE_COOKIE: null,
29
  TEMP_COOKIE: null,
30
- PICGO_KEY: process.env.PICGO_KEY || null //想要流式生图的话需要填入这个PICGO图床的key
 
31
  },
32
  SERVER: {
33
  PORT: process.env.PORT || 3000,
@@ -36,7 +38,7 @@ const CONFIG = {
36
  RETRY: {
37
  MAX_ATTEMPTS: 2//重试次数
38
  },
39
- SHOW_THINKING:process.env.SHOW_THINKING === 'true',
40
  IS_THINKING: false,
41
  IS_IMG_GEN: false,
42
  IS_IMG_GEN2: false,
@@ -66,6 +68,10 @@ const DEFAULT_HEADERS = {
66
 
67
 
68
  async function initialization() {
 
 
 
 
69
  const ssoArray = process.env.SSO.split(',');
70
  const ssorwArray = process.env.SSO_RW.split(',');
71
  ssoArray.forEach((sso, index) => {
@@ -99,9 +105,17 @@ class AuthTokenManager {
99
  });
100
  }
101
  }
 
 
 
 
 
 
 
 
102
 
103
  getTokenByIndex(index, model) {
104
- if(this.activeTokens.length === 0){
105
  return null;
106
  }
107
  const token = this.activeTokens[index];
@@ -110,7 +124,7 @@ class AuthTokenManager {
110
  }
111
 
112
  recordModelRequest(token, model) {
113
- if(model === 'grok-3-search' || model === 'grok-3-imageGen'){
114
  model = 'grok-3';
115
  }
116
 
@@ -122,7 +136,7 @@ class AuthTokenManager {
122
  this.checkAndRemoveTokenIfLimitReached(token);
123
  }
124
  setModelLimit(index, model) {
125
- if(model === 'grok-3-search' || model === 'grok-3-imageGen'){
126
  model = 'grok-3';
127
  }
128
  if (!this.modelRateLimit[model]) return;
@@ -130,7 +144,7 @@ class AuthTokenManager {
130
  tokenFrequency[model] = 9999;
131
  }
132
  isTokenModelLimitReached(index, model) {
133
- if(model === 'grok-3-search' || model === 'grok-3-imageGen'){
134
  model = 'grok-3';
135
  }
136
  if (!this.modelRateLimit[model]) return;
@@ -170,6 +184,7 @@ class AuthTokenManager {
170
  }
171
 
172
  startTokenRecoveryProcess() {
 
173
  setInterval(() => {
174
  const now = Date.now();
175
  for (const [token, expiredTime] of this.expiredTokens.entries()) {
@@ -358,10 +373,10 @@ class GrokApiClient {
358
  }
359
 
360
  async prepareChatRequest(request) {
361
- if ((request.model === 'grok-2-imageGen' || request.model === 'grok-3-imageGen') && !CONFIG.API.PICGO_KEY && request.stream) {
362
- throw new Error(`该模型流式输出需要配置PICGO图床密钥!`);
363
  }
364
-
365
  // 处理画图模型的消息限制
366
  let todoMessages = request.messages;
367
  if (request.model === 'grok-2-imageGen' || request.model === 'grok-3-imageGen') {
@@ -369,22 +384,22 @@ class GrokApiClient {
369
  if (lastMessage.role !== 'user') {
370
  throw new Error('画图模型的最后一条消息必须是用户消息!');
371
  }
372
- todoMessages = [lastMessage];
373
  }
374
-
375
  const fileAttachments = [];
376
  let messages = '';
377
  let lastRole = null;
378
  let lastContent = '';
379
  const search = request.model === 'grok-2-search' || request.model === 'grok-3-search';
380
-
381
  // 移除<think>标签及其内容和base64图片
382
  const removeThinkTags = (text) => {
383
  text = text.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
384
  text = text.replace(/!\[image\]\(data:.*?base64,.*?\)/g, '[图片]');
385
  return text;
386
  };
387
-
388
  const processImageUrl = async (content) => {
389
  if (content.type === 'image_url' && content.image_url.url.includes('data:image')) {
390
  const imageResponse = await this.uploadBase64Image(
@@ -395,7 +410,7 @@ class GrokApiClient {
395
  }
396
  return null;
397
  };
398
-
399
  const processContent = async (content) => {
400
  if (Array.isArray(content)) {
401
  let textContent = '';
@@ -416,11 +431,11 @@ class GrokApiClient {
416
  }
417
  return removeThinkTags(this.processMessageContent(content));
418
  };
419
-
420
  for (const current of todoMessages) {
421
  const role = current.role === 'assistant' ? 'assistant' : 'user';
422
  const isLastMessage = current === todoMessages[todoMessages.length - 1];
423
-
424
  // 处理图片附件
425
  if (isLastMessage && current.content) {
426
  if (Array.isArray(current.content)) {
@@ -435,10 +450,10 @@ class GrokApiClient {
435
  if (processedImage) fileAttachments.push(processedImage);
436
  }
437
  }
438
-
439
  // 处理文本内容
440
  const textContent = await processContent(current.content);
441
-
442
  if (textContent || (isLastMessage && fileAttachments.length > 0)) {
443
  if (role === lastRole && textContent) {
444
  lastContent += '\n' + textContent;
@@ -451,7 +466,7 @@ class GrokApiClient {
451
  }
452
  }
453
  }
454
-
455
  return {
456
  modelName: this.modelId,
457
  message: messages.trim(),
@@ -519,7 +534,7 @@ class MessageProcessor {
519
  }
520
  }
521
  async function processModelResponse(linejosn, model) {
522
- let result = { token: '', imageUrl: null }
523
  if (CONFIG.IS_IMG_GEN) {
524
  if (linejosn?.cachedImageGenerationResponse && !CONFIG.IS_IMG_GEN2) {
525
  result.imageUrl = linejosn.cachedImageGenerationResponse.imageUrl;
@@ -549,7 +564,7 @@ async function processModelResponse(linejosn, model) {
549
  }
550
  return result;
551
  case 'grok-3-reasoning':
552
- if(linejosn?.isThinking && !CONFIG.SHOW_THINKING)return result;
553
 
554
  if (linejosn?.isThinking && !CONFIG.IS_THINKING) {
555
  result.token = "<think>" + linejosn?.token;
@@ -562,6 +577,7 @@ async function processModelResponse(linejosn, model) {
562
  }
563
  return result;
564
  }
 
565
  }
566
 
567
  async function handleResponse(response, model, res, isStream) {
@@ -570,12 +586,13 @@ async function handleResponse(response, model, res, isStream) {
570
  let buffer = '';
571
  let fullResponse = '';
572
  const dataPromises = [];
573
- if(isStream){
574
  res.setHeader('Content-Type', 'text/event-stream');
575
  res.setHeader('Cache-Control', 'no-cache');
576
  res.setHeader('Connection', 'keep-alive');
577
  }
578
- return new Promise((resolve, reject) => {
 
579
  stream.on('data', async (chunk) => {
580
  buffer += chunk.toString();
581
  const lines = buffer.split('\n');
@@ -588,12 +605,12 @@ async function handleResponse(response, model, res, isStream) {
588
  const data = trimmedLine.substring(6);
589
  try {
590
  if (!data.trim()) continue;
591
- if(data === "[DONE]") continue;
592
  const linejosn = JSON.parse(data);
593
  if (linejosn?.error) {
594
- Logger.error(JSON.stringify(linejosn,null,2), 'Server');
595
  stream.destroy();
596
- reject(new Error("RateLimitError"));
597
  return;
598
  }
599
  if (linejosn?.doImgGen || linejosn?.imageAttachmentInfo) {
@@ -601,6 +618,7 @@ async function handleResponse(response, model, res, isStream) {
601
  }
602
  const processPromise = (async () => {
603
  const result = await processModelResponse(linejosn, model);
 
604
  if (result.token) {
605
  if (isStream) {
606
  res.write(`data: ${JSON.stringify(MessageProcessor.createChatResponse(result.token, model, true))}\n\n`);
@@ -635,18 +653,18 @@ async function handleResponse(response, model, res, isStream) {
635
  } else {
636
  if (!CONFIG.IS_IMG_GEN2) {
637
  res.json(MessageProcessor.createChatResponse(fullResponse, model));
638
- }
639
  }
640
  CONFIG.IS_IMG_GEN = false;
641
  CONFIG.IS_IMG_GEN2 = false;
642
- resolve();
643
  } catch (error) {
644
- reject(error);
645
  }
646
  });
647
 
648
  stream.on('error', (error) => {
649
- reject(error);
650
  });
651
  });
652
  } catch (error) {
@@ -672,7 +690,7 @@ async function handleImageResponse(imageUrl) {
672
  }
673
  });
674
 
675
- if (imageBase64Response.ok) break;
676
  retryCount++;
677
  if (retryCount === MAX_RETRIES) {
678
  throw new Error(`上游服务请求失败! status: ${imageBase64Response.status}`);
@@ -692,34 +710,58 @@ async function handleImageResponse(imageUrl) {
692
  const arrayBuffer = await imageBase64Response.arrayBuffer();
693
  const imageBuffer = Buffer.from(arrayBuffer);
694
 
695
- if(!CONFIG.API.PICGO_KEY){
696
  const base64Image = imageBuffer.toString('base64');
697
  const imageContentType = imageBase64Response.headers.get('content-type');
698
  return `![image](data:${imageContentType};base64,${base64Image})`
699
  }
700
 
701
  const formData = new FormData();
702
-
703
- formData.append('source', imageBuffer, {
704
- filename: 'new.jpg',
705
- contentType: 'image/jpeg'
706
- });
707
- const formDataHeaders = formData.getHeaders();
708
- const responseURL = await fetch("https://www.picgo.net/api/1/upload", {
709
- method: "POST",
710
- headers: {
711
  ...formDataHeaders,
712
  "Content-Type": "multipart/form-data",
713
  "X-API-Key": CONFIG.API.PICGO_KEY
714
  },
715
  body: formData
716
- });
717
- if (!responseURL.ok) {
718
- return "生图失败,请查看图床密钥是否设置正确"
719
- } else {
720
- Logger.info("生图成功", 'Server');
721
- const result = await responseURL.json();
722
- return `![image](${result.image.url})`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723
  }
724
  }
725
 
@@ -753,14 +795,25 @@ app.get('/hf/v1/models', (req, res) => {
753
  app.post('/hf/v1/chat/completions', async (req, res) => {
754
  try {
755
  const authToken = req.headers.authorization?.replace('Bearer ', '');
756
- if (authToken !== CONFIG.API.API_KEY) {
 
 
 
 
 
 
 
 
 
 
 
757
  return res.status(401).json({ error: 'Unauthorized' });
758
  }
759
  let isTempCookie = req.body.model.includes("grok-2");
760
  let retryCount = 0;
761
  const grokClient = new GrokApiClient(req.body.model);
762
  const requestPayload = await grokClient.prepareChatRequest(req.body);
763
-
764
  while (retryCount < CONFIG.RETRY.MAX_ATTEMPTS) {
765
  retryCount++;
766
  if (!CONFIG.API.TEMP_COOKIE) {
@@ -773,6 +826,9 @@ app.post('/hf/v1/chat/completions', async (req, res) => {
773
  } else {
774
  CONFIG.API.SIGNATURE_COOKIE = await Utils.createAuthHeaders(req.body.model);
775
  }
 
 
 
776
  Logger.info(`当前令牌索引: ${CONFIG.SSO_INDEX}`, 'Server');
777
  const newMessageReq = await fetch(`${CONFIG.API.BASE_URL}/api/rpc`, {
778
  method: 'POST',
@@ -802,19 +858,18 @@ app.post('/hf/v1/chat/completions', async (req, res) => {
802
  },
803
  body: JSON.stringify(requestPayload)
804
  });
805
-
806
-
807
  if (response.ok) {
808
- CONFIG.SSO_INDEX = (CONFIG.SSO_INDEX + 1) % tokenManager.getTokenCount();
809
  Logger.info(`请求成功`, 'Server');
 
810
  Logger.info(`当前剩余可用令牌数: ${tokenManager.getTokenCount()}`, 'Server');
811
  try {
812
  await handleResponse(response, req.body.model, res, req.body.stream);
813
- return;
814
  } catch (error) {
815
- if(isTempCookie){
816
  await Utils.get_signature();
817
- }else{
818
  tokenManager.setModelLimit(CONFIG.SSO_INDEX, req.body.model);
819
  for (let i = 1; i <= tokenManager.getTokenCount(); i++) {
820
  CONFIG.SSO_INDEX = (CONFIG.SSO_INDEX + 1) % tokenManager.getTokenCount();
@@ -856,7 +911,6 @@ app.post('/hf/v1/chat/completions', async (req, res) => {
856
  }
857
  throw new Error('当前模型所有令牌都已耗尽');
858
  } catch (error) {
859
- CONFIG.SSO_INDEX = (CONFIG.SSO_INDEX + 1) % tokenManager.getTokenCount();
860
  Logger.error(error, 'ChatAPI');
861
  res.status(500).json({
862
  error: {
 
23
  "grok-3-reasoning": "grok-3"
24
  },
25
  API: {
26
+ IS_CUSTOM_SSO: process.env.IS_CUSTOM_SSO === 'true',
27
  BASE_URL: "https://grok.com",
28
  API_KEY: process.env.API_KEY || "sk-123456",
29
  SIGNATURE_COOKIE: null,
30
  TEMP_COOKIE: null,
31
+ PICGO_KEY: null, //想要流式生图的话需要填入这个PICGO图床的key
32
+ PICUI_KEY: process.env.PICUI_KEY || null //想要流式生图的话需要填入这个PICUI图床的key 两个图床二选一,默认使用PICGO
33
  },
34
  SERVER: {
35
  PORT: process.env.PORT || 3000,
 
38
  RETRY: {
39
  MAX_ATTEMPTS: 2//重试次数
40
  },
41
+ SHOW_THINKING: process.env.SHOW_THINKING === 'true',
42
  IS_THINKING: false,
43
  IS_IMG_GEN: false,
44
  IS_IMG_GEN2: false,
 
68
 
69
 
70
  async function initialization() {
71
+ if (CONFIG.API.IS_CUSTOM_SSO) {
72
+ await Utils.get_signature()
73
+ return;
74
+ }
75
  const ssoArray = process.env.SSO.split(',');
76
  const ssorwArray = process.env.SSO_RW.split(',');
77
  ssoArray.forEach((sso, index) => {
 
105
  });
106
  }
107
  }
108
+ setToken(token) {
109
+ this.activeTokens = [token];
110
+ this.tokenModelFrequency.set(token, {
111
+ "grok-3": 0,
112
+ "grok-3-deepsearch": 0,
113
+ "grok-3-reasoning": 0
114
+ });
115
+ }
116
 
117
  getTokenByIndex(index, model) {
118
+ if (this.activeTokens.length === 0) {
119
  return null;
120
  }
121
  const token = this.activeTokens[index];
 
124
  }
125
 
126
  recordModelRequest(token, model) {
127
+ if (model === 'grok-3-search' || model === 'grok-3-imageGen') {
128
  model = 'grok-3';
129
  }
130
 
 
136
  this.checkAndRemoveTokenIfLimitReached(token);
137
  }
138
  setModelLimit(index, model) {
139
+ if (model === 'grok-3-search' || model === 'grok-3-imageGen') {
140
  model = 'grok-3';
141
  }
142
  if (!this.modelRateLimit[model]) return;
 
144
  tokenFrequency[model] = 9999;
145
  }
146
  isTokenModelLimitReached(index, model) {
147
+ if (model === 'grok-3-search' || model === 'grok-3-imageGen') {
148
  model = 'grok-3';
149
  }
150
  if (!this.modelRateLimit[model]) return;
 
184
  }
185
 
186
  startTokenRecoveryProcess() {
187
+ if (CONFIG.API.IS_CUSTOM_SSO) return;
188
  setInterval(() => {
189
  const now = Date.now();
190
  for (const [token, expiredTime] of this.expiredTokens.entries()) {
 
373
  }
374
 
375
  async prepareChatRequest(request) {
376
+ if ((request.model === 'grok-2-imageGen' || request.model === 'grok-3-imageGen') && !CONFIG.API.PICGO_KEY && !CONFIG.API.PICUI_KEY && request.stream) {
377
+ throw new Error(`该模型流式输出需要配置PICGO或者PICUI图床密钥!`);
378
  }
379
+
380
  // 处理画图模型的消息限制
381
  let todoMessages = request.messages;
382
  if (request.model === 'grok-2-imageGen' || request.model === 'grok-3-imageGen') {
 
384
  if (lastMessage.role !== 'user') {
385
  throw new Error('画图模型的最后一条消息必须是用户消息!');
386
  }
387
+ todoMessages = [lastMessage];
388
  }
389
+
390
  const fileAttachments = [];
391
  let messages = '';
392
  let lastRole = null;
393
  let lastContent = '';
394
  const search = request.model === 'grok-2-search' || request.model === 'grok-3-search';
395
+
396
  // 移除<think>标签及其内容和base64图片
397
  const removeThinkTags = (text) => {
398
  text = text.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
399
  text = text.replace(/!\[image\]\(data:.*?base64,.*?\)/g, '[图片]');
400
  return text;
401
  };
402
+
403
  const processImageUrl = async (content) => {
404
  if (content.type === 'image_url' && content.image_url.url.includes('data:image')) {
405
  const imageResponse = await this.uploadBase64Image(
 
410
  }
411
  return null;
412
  };
413
+
414
  const processContent = async (content) => {
415
  if (Array.isArray(content)) {
416
  let textContent = '';
 
431
  }
432
  return removeThinkTags(this.processMessageContent(content));
433
  };
434
+
435
  for (const current of todoMessages) {
436
  const role = current.role === 'assistant' ? 'assistant' : 'user';
437
  const isLastMessage = current === todoMessages[todoMessages.length - 1];
438
+
439
  // 处理图片附件
440
  if (isLastMessage && current.content) {
441
  if (Array.isArray(current.content)) {
 
450
  if (processedImage) fileAttachments.push(processedImage);
451
  }
452
  }
453
+
454
  // 处理文本内容
455
  const textContent = await processContent(current.content);
456
+
457
  if (textContent || (isLastMessage && fileAttachments.length > 0)) {
458
  if (role === lastRole && textContent) {
459
  lastContent += '\n' + textContent;
 
466
  }
467
  }
468
  }
469
+
470
  return {
471
  modelName: this.modelId,
472
  message: messages.trim(),
 
534
  }
535
  }
536
  async function processModelResponse(linejosn, model) {
537
+ let result = { token: null, imageUrl: null }
538
  if (CONFIG.IS_IMG_GEN) {
539
  if (linejosn?.cachedImageGenerationResponse && !CONFIG.IS_IMG_GEN2) {
540
  result.imageUrl = linejosn.cachedImageGenerationResponse.imageUrl;
 
564
  }
565
  return result;
566
  case 'grok-3-reasoning':
567
+ if (linejosn?.isThinking && !CONFIG.SHOW_THINKING) return result;
568
 
569
  if (linejosn?.isThinking && !CONFIG.IS_THINKING) {
570
  result.token = "<think>" + linejosn?.token;
 
577
  }
578
  return result;
579
  }
580
+ return result;
581
  }
582
 
583
  async function handleResponse(response, model, res, isStream) {
 
586
  let buffer = '';
587
  let fullResponse = '';
588
  const dataPromises = [];
589
+ if (isStream) {
590
  res.setHeader('Content-Type', 'text/event-stream');
591
  res.setHeader('Cache-Control', 'no-cache');
592
  res.setHeader('Connection', 'keep-alive');
593
  }
594
+
595
+ return new Promise((resolve, reject) => {
596
  stream.on('data', async (chunk) => {
597
  buffer += chunk.toString();
598
  const lines = buffer.split('\n');
 
605
  const data = trimmedLine.substring(6);
606
  try {
607
  if (!data.trim()) continue;
608
+ if (data === "[DONE]") continue;
609
  const linejosn = JSON.parse(data);
610
  if (linejosn?.error) {
611
+ Logger.error(JSON.stringify(linejosn, null, 2), 'Server');
612
  stream.destroy();
613
+ reject(new Error("RateLimitError"));
614
  return;
615
  }
616
  if (linejosn?.doImgGen || linejosn?.imageAttachmentInfo) {
 
618
  }
619
  const processPromise = (async () => {
620
  const result = await processModelResponse(linejosn, model);
621
+
622
  if (result.token) {
623
  if (isStream) {
624
  res.write(`data: ${JSON.stringify(MessageProcessor.createChatResponse(result.token, model, true))}\n\n`);
 
653
  } else {
654
  if (!CONFIG.IS_IMG_GEN2) {
655
  res.json(MessageProcessor.createChatResponse(fullResponse, model));
656
+ }
657
  }
658
  CONFIG.IS_IMG_GEN = false;
659
  CONFIG.IS_IMG_GEN2 = false;
660
+ resolve();
661
  } catch (error) {
662
+ reject(error);
663
  }
664
  });
665
 
666
  stream.on('error', (error) => {
667
+ reject(error);
668
  });
669
  });
670
  } catch (error) {
 
690
  }
691
  });
692
 
693
+ if (imageBase64Response.ok) break;
694
  retryCount++;
695
  if (retryCount === MAX_RETRIES) {
696
  throw new Error(`上游服务请求失败! status: ${imageBase64Response.status}`);
 
710
  const arrayBuffer = await imageBase64Response.arrayBuffer();
711
  const imageBuffer = Buffer.from(arrayBuffer);
712
 
713
+ if (!CONFIG.API.PICGO_KEY && !CONFIG.API.PICUI_KEY) {
714
  const base64Image = imageBuffer.toString('base64');
715
  const imageContentType = imageBase64Response.headers.get('content-type');
716
  return `![image](data:${imageContentType};base64,${base64Image})`
717
  }
718
 
719
  const formData = new FormData();
720
+ if(CONFIG.API.PICGO_KEY){
721
+ formData.append('source', imageBuffer, {
722
+ filename: `image-${Date.now()}.jpg`,
723
+ contentType: 'image/jpeg'
724
+ });
725
+ const formDataHeaders = formData.getHeaders();
726
+ const responseURL = await fetch("https://www.picgo.net/api/1/upload", {
727
+ method: "POST",
728
+ headers: {
729
  ...formDataHeaders,
730
  "Content-Type": "multipart/form-data",
731
  "X-API-Key": CONFIG.API.PICGO_KEY
732
  },
733
  body: formData
734
+ });
735
+ if (!responseURL.ok) {
736
+ return "生图失败,请查看图床密钥是否设置正确"
737
+ } else {
738
+ Logger.info("生图成功", 'Server');
739
+ const result = await responseURL.json();
740
+ return `![image](${result.image.url})`
741
+ }
742
+ }else if(CONFIG.API.PICUI_KEY){
743
+ const formData = new FormData();
744
+ formData.append('file', imageBuffer, {
745
+ filename: `image-${Date.now()}.jpg`,
746
+ contentType: 'image/jpeg'
747
+ });
748
+ const formDataHeaders = formData.getHeaders();
749
+ const responseURL = await fetch("https://picui.cn/api/v1/upload", {
750
+ method: "POST",
751
+ headers: {
752
+ ...formDataHeaders,
753
+ "Accept": "application/json",
754
+ 'Authorization': `Bearer ${CONFIG.API.PICUI_KEY}`
755
+ },
756
+ body: formData
757
+ });
758
+ if (!responseURL.ok) {
759
+ return "生图失败,请查看图床密钥是否设置正确"
760
+ } else {
761
+ Logger.info("生图成功", 'Server');
762
+ const result = await responseURL.json();
763
+ return `![image](${result.data.links.url})`
764
+ }
765
  }
766
  }
767
 
 
795
  app.post('/hf/v1/chat/completions', async (req, res) => {
796
  try {
797
  const authToken = req.headers.authorization?.replace('Bearer ', '');
798
+ if (CONFIG.API.IS_CUSTOM_SSO) {
799
+ if (authToken && authToken.includes(';')) {
800
+ const parts = authToken.split(';');
801
+ const result = [
802
+ `sso=${parts[0]}`,
803
+ `ssp_rw=${parts[1]}`
804
+ ].join(';');
805
+ tokenManager.setToken(result);
806
+ } else {
807
+ return res.status(401).json({ error: '自定义的SSO令牌格式错误' });
808
+ }
809
+ } else if (authToken !== CONFIG.API.API_KEY) {
810
  return res.status(401).json({ error: 'Unauthorized' });
811
  }
812
  let isTempCookie = req.body.model.includes("grok-2");
813
  let retryCount = 0;
814
  const grokClient = new GrokApiClient(req.body.model);
815
  const requestPayload = await grokClient.prepareChatRequest(req.body);
816
+
817
  while (retryCount < CONFIG.RETRY.MAX_ATTEMPTS) {
818
  retryCount++;
819
  if (!CONFIG.API.TEMP_COOKIE) {
 
826
  } else {
827
  CONFIG.API.SIGNATURE_COOKIE = await Utils.createAuthHeaders(req.body.model);
828
  }
829
+ if (!CONFIG.API.SIGNATURE_COOKIE) {
830
+ throw new Error('无可用令牌');
831
+ }
832
  Logger.info(`当前令牌索引: ${CONFIG.SSO_INDEX}`, 'Server');
833
  const newMessageReq = await fetch(`${CONFIG.API.BASE_URL}/api/rpc`, {
834
  method: 'POST',
 
858
  },
859
  body: JSON.stringify(requestPayload)
860
  });
861
+
 
862
  if (response.ok) {
 
863
  Logger.info(`请求成功`, 'Server');
864
+ CONFIG.SSO_INDEX = (CONFIG.SSO_INDEX + 1) % tokenManager.getTokenCount();
865
  Logger.info(`当前剩余可用令牌数: ${tokenManager.getTokenCount()}`, 'Server');
866
  try {
867
  await handleResponse(response, req.body.model, res, req.body.stream);
868
+ return;
869
  } catch (error) {
870
+ if (isTempCookie) {
871
  await Utils.get_signature();
872
+ } else {
873
  tokenManager.setModelLimit(CONFIG.SSO_INDEX, req.body.model);
874
  for (let i = 1; i <= tokenManager.getTokenCount(); i++) {
875
  CONFIG.SSO_INDEX = (CONFIG.SSO_INDEX + 1) % tokenManager.getTokenCount();
 
911
  }
912
  throw new Error('当前模型所有令牌都已耗尽');
913
  } catch (error) {
 
914
  Logger.error(error, 'ChatAPI');
915
  res.status(500).json({
916
  error: {