yxmiler commited on
Commit
71f79a5
·
verified ·
1 Parent(s): c2d361e

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +88 -58
index.js CHANGED
@@ -26,7 +26,7 @@ const CONFIG = {
26
  API_KEY: process.env.API_KEY || "sk-123456",
27
  SIGNATURE_COOKIE: null,
28
  TEMP_COOKIE: null,
29
- PICGO_KEY: process.env.PICGO_KEY || null //想要生图的话需要填入这个PICGO图床的key
30
  },
31
  SERVER: {
32
  PORT: process.env.PORT || 3000,
@@ -35,6 +35,7 @@ const CONFIG = {
35
  RETRY: {
36
  MAX_ATTEMPTS: 2//重试次数
37
  },
 
38
  IS_THINKING: false,
39
  IS_IMG_GEN: false,
40
  IS_IMG_GEN2: false,
@@ -69,6 +70,7 @@ async function initialization() {
69
  ssoArray.forEach((sso, index) => {
70
  tokenManager.addToken(`sso-rw=${ssorwArray[index]};sso=${sso}`);
71
  });
 
72
  await Utils.get_signature()
73
  Logger.info("初始化完成", 'Server');
74
  }
@@ -347,17 +349,33 @@ class GrokApiClient {
347
  }
348
 
349
  async prepareChatRequest(request) {
350
- if ((request.model === 'grok-2-imageGen' || request.model === 'grok-3-imageGen') && !CONFIG.API.PICGO_KEY) {
351
- throw new Error(`该模型需要配置PICGO图床密钥!`);
352
  }
353
- var todoMessages = request.messages;
354
-
355
- let fileAttachments = [];
 
 
 
 
 
 
 
 
 
356
  let messages = '';
357
  let lastRole = null;
358
  let lastContent = '';
359
- let search = false;
360
-
 
 
 
 
 
 
 
361
  const processImageUrl = async (content) => {
362
  if (content.type === 'image_url' && content.image_url.url.includes('data:image')) {
363
  const imageResponse = await this.uploadBase64Image(
@@ -368,64 +386,67 @@ class GrokApiClient {
368
  }
369
  return null;
370
  };
371
-
372
- for (const current of todoMessages) {
373
- const role = current.role === 'assistant' ? 'assistant' : 'user';
374
- let textContent = '';
375
-
376
- if (Array.isArray(current.content)) {
377
- for (const item of current.content) {
378
  if (item.type === 'image_url') {
379
- if (current === todoMessages[todoMessages.length - 1]) {
380
- const processedImage = await processImageUrl(item);
381
- if (processedImage) fileAttachments.push(processedImage);
382
- }
383
  textContent += (textContent ? '\n' : '') + "[图片]";
384
  } else if (item.type === 'text') {
385
- textContent += (textContent ? '\n' : '') + item.text;
386
  }
387
  }
388
- } else if (typeof current.content === 'object' && current.content !== null) {
389
- if (current.content.type === 'image_url') {
390
- if (current === todoMessages[todoMessages.length - 1]) {
391
- const processedImage = await processImageUrl(current.content);
392
- if (processedImage) fileAttachments.push(processedImage);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  }
394
- textContent += (textContent ? '\n' : '') + "[图片]";
395
- } else if (current.content.type === 'text') {
396
- textContent = current.content.text;
397
  }
398
- } else {
399
- textContent = this.processMessageContent(current.content);
400
  }
401
- if (textContent) {
402
- if (role === lastRole) {
 
 
 
 
403
  lastContent += '\n' + textContent;
404
  messages = messages.substring(0, messages.lastIndexOf(`${role.toUpperCase()}: `)) +
405
  `${role.toUpperCase()}: ${lastContent}\n`;
406
  } else {
407
- messages += `${role.toUpperCase()}: ${textContent}\n`;
408
  lastContent = textContent;
409
  lastRole = role;
410
  }
411
- } else if (current === todoMessages[todoMessages.length - 1] && fileAttachments.length > 0) {
412
- messages += `${role.toUpperCase()}: [图片]\n`;
413
  }
414
  }
415
-
416
- if (fileAttachments.length > 4) {
417
- fileAttachments = fileAttachments.slice(0, 4); // 最多上传4张
418
- }
419
-
420
- messages = messages.trim();
421
-
422
- if (request.model === 'grok-2-search') {
423
- search = true;
424
- }
425
  return {
426
  modelName: this.modelId,
427
- message: messages,
428
- fileAttachments: fileAttachments,
429
  imageAttachments: [],
430
  disableSearch: false,
431
  enableImageGeneration: true,
@@ -519,6 +540,8 @@ async function processModelResponse(linejosn, model) {
519
  }
520
  return result;
521
  case 'grok-3-reasoning':
 
 
522
  if (linejosn?.isThinking && !CONFIG.IS_THINKING) {
523
  result.token = "<think>" + token;
524
  CONFIG.IS_THINKING = true;
@@ -538,8 +561,8 @@ async function handleResponse(response, model, res, isStream) {
538
  let buffer = '';
539
  let fullResponse = '';
540
  const dataPromises = [];
541
-
542
- return new Promise((resolve, reject) => {
543
  stream.on('data', async (chunk) => {
544
  buffer += chunk.toString();
545
  const lines = buffer.split('\n');
@@ -552,10 +575,11 @@ async function handleResponse(response, model, res, isStream) {
552
  const data = trimmedLine.substring(6);
553
  try {
554
  if (!data.trim()) continue;
555
- if(data === "[DONE]")continue;
556
  const linejosn = JSON.parse(data);
557
  if (linejosn?.error) {
558
- reject(new Error(linejosn));
 
559
  return;
560
  }
561
  if (linejosn?.doImgGen || linejosn?.imageAttachmentInfo) {
@@ -582,7 +606,6 @@ async function handleResponse(response, model, res, isStream) {
582
  })();
583
  dataPromises.push(processPromise);
584
  } catch (error) {
585
- console.log(error);
586
  continue;
587
  }
588
  }
@@ -602,14 +625,14 @@ async function handleResponse(response, model, res, isStream) {
602
  }
603
  CONFIG.IS_IMG_GEN = false;
604
  CONFIG.IS_IMG_GEN2 = false;
605
- resolve();
606
  } catch (error) {
607
- reject(error);
608
  }
609
  });
 
610
  stream.on('error', (error) => {
611
- Logger.error(error, 'Server');
612
- reject(error);
613
  });
614
  });
615
  } catch (error) {
@@ -618,7 +641,6 @@ async function handleResponse(response, model, res, isStream) {
618
  CONFIG.IS_IMG_GEN2 = false;
619
  throw error;
620
  }
621
-
622
  }
623
 
624
  async function handleImageResponse(imageUrl) {
@@ -652,8 +674,16 @@ async function handleImageResponse(imageUrl) {
652
  }
653
  }
654
 
 
655
  const arrayBuffer = await imageBase64Response.arrayBuffer();
656
  const imageBuffer = Buffer.from(arrayBuffer);
 
 
 
 
 
 
 
657
  const formData = new FormData();
658
 
659
  formData.append('source', imageBuffer, {
@@ -718,7 +748,7 @@ app.post('/hf/v1/chat/completions', async (req, res) => {
718
  while (retryCount < CONFIG.RETRY.MAX_ATTEMPTS) {
719
  retryCount++;
720
  const grokClient = new GrokApiClient(req.body.model);
721
- const requestPayload = await grokClient.prepareChatRequest(req.body);
722
 
723
  if (!CONFIG.API.TEMP_COOKIE) {
724
  await Utils.get_signature();
 
26
  API_KEY: process.env.API_KEY || "sk-123456",
27
  SIGNATURE_COOKIE: null,
28
  TEMP_COOKIE: null,
29
+ PICGO_KEY: null //想要流式生图的话需要填入这个PICGO图床的key
30
  },
31
  SERVER: {
32
  PORT: process.env.PORT || 3000,
 
35
  RETRY: {
36
  MAX_ATTEMPTS: 2//重试次数
37
  },
38
+ SHOW_THINKING:process.env.SHOW_THINKING === 'true',//显示思考过程
39
  IS_THINKING: false,
40
  IS_IMG_GEN: false,
41
  IS_IMG_GEN2: false,
 
70
  ssoArray.forEach((sso, index) => {
71
  tokenManager.addToken(`sso-rw=${ssorwArray[index]};sso=${sso}`);
72
  });
73
+ console.log(JSON.stringify(tokenManager.getActiveTokens(), null, 2));
74
  await Utils.get_signature()
75
  Logger.info("初始化完成", 'Server');
76
  }
 
349
  }
350
 
351
  async prepareChatRequest(request) {
352
+ if ((request.model === 'grok-2-imageGen' || request.model === 'grok-3-imageGen') && !CONFIG.API.PICGO_KEY && request.stream) {
353
+ throw new Error(`该模型流式输出需要配置PICGO图床密钥!`);
354
  }
355
+
356
+ // 处理画图模型的消息限制
357
+ let todoMessages = request.messages;
358
+ if (request.model === 'grok-2-imageGen' || request.model === 'grok-3-imageGen') {
359
+ const lastMessage = todoMessages[todoMessages.length - 1];
360
+ if (lastMessage.role !== 'user') {
361
+ throw new Error('画图模型的最后一条消息必须是用户消息!');
362
+ }
363
+ todoMessages = [lastMessage];
364
+ }
365
+
366
+ const fileAttachments = [];
367
  let messages = '';
368
  let lastRole = null;
369
  let lastContent = '';
370
+ const search = request.model === 'grok-2-search';
371
+
372
+ // 移除<think>标签及其内容和base64图片
373
+ const removeThinkTags = (text) => {
374
+ text = text.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
375
+ text = text.replace(/!\[image\]\(data:.*?base64,.*?\)/g, '[图片]');
376
+ return text;
377
+ };
378
+
379
  const processImageUrl = async (content) => {
380
  if (content.type === 'image_url' && content.image_url.url.includes('data:image')) {
381
  const imageResponse = await this.uploadBase64Image(
 
386
  }
387
  return null;
388
  };
389
+
390
+ const processContent = async (content) => {
391
+ if (Array.isArray(content)) {
392
+ let textContent = '';
393
+ for (const item of content) {
 
 
394
  if (item.type === 'image_url') {
 
 
 
 
395
  textContent += (textContent ? '\n' : '') + "[图片]";
396
  } else if (item.type === 'text') {
397
+ textContent += (textContent ? '\n' : '') + removeThinkTags(item.text);
398
  }
399
  }
400
+ return textContent;
401
+ } else if (typeof content === 'object' && content !== null) {
402
+ if (content.type === 'image_url') {
403
+ return "[图片]";
404
+ } else if (content.type === 'text') {
405
+ return removeThinkTags(content.text);
406
+ }
407
+ }
408
+ return removeThinkTags(this.processMessageContent(content));
409
+ };
410
+
411
+ for (const current of todoMessages) {
412
+ const role = current.role === 'assistant' ? 'assistant' : 'user';
413
+ const isLastMessage = current === todoMessages[todoMessages.length - 1];
414
+
415
+ // 处理图片附件
416
+ if (isLastMessage && current.content) {
417
+ if (Array.isArray(current.content)) {
418
+ for (const item of current.content) {
419
+ if (item.type === 'image_url') {
420
+ const processedImage = await processImageUrl(item);
421
+ if (processedImage) fileAttachments.push(processedImage);
422
+ }
423
  }
424
+ } else if (current.content.type === 'image_url') {
425
+ const processedImage = await processImageUrl(current.content);
426
+ if (processedImage) fileAttachments.push(processedImage);
427
  }
 
 
428
  }
429
+
430
+ // 处理文本内容
431
+ const textContent = await processContent(current.content);
432
+
433
+ if (textContent || (isLastMessage && fileAttachments.length > 0)) {
434
+ if (role === lastRole && textContent) {
435
  lastContent += '\n' + textContent;
436
  messages = messages.substring(0, messages.lastIndexOf(`${role.toUpperCase()}: `)) +
437
  `${role.toUpperCase()}: ${lastContent}\n`;
438
  } else {
439
+ messages += `${role.toUpperCase()}: ${textContent || '[图片]'}\n`;
440
  lastContent = textContent;
441
  lastRole = role;
442
  }
 
 
443
  }
444
  }
445
+
 
 
 
 
 
 
 
 
 
446
  return {
447
  modelName: this.modelId,
448
+ message: messages.trim(),
449
+ fileAttachments: fileAttachments.slice(0, 4),
450
  imageAttachments: [],
451
  disableSearch: false,
452
  enableImageGeneration: true,
 
540
  }
541
  return result;
542
  case 'grok-3-reasoning':
543
+ if(linejosn?.isThinking && !CONFIG.SHOW_THINKING)return result;
544
+
545
  if (linejosn?.isThinking && !CONFIG.IS_THINKING) {
546
  result.token = "<think>" + token;
547
  CONFIG.IS_THINKING = true;
 
561
  let buffer = '';
562
  let fullResponse = '';
563
  const dataPromises = [];
564
+
565
+ return new Promise((resolve, reject) => {
566
  stream.on('data', async (chunk) => {
567
  buffer += chunk.toString();
568
  const lines = buffer.split('\n');
 
575
  const data = trimmedLine.substring(6);
576
  try {
577
  if (!data.trim()) continue;
578
+ if(data === "[DONE]") continue;
579
  const linejosn = JSON.parse(data);
580
  if (linejosn?.error) {
581
+ stream.destroy();
582
+ reject(new Error("RateLimitError"));
583
  return;
584
  }
585
  if (linejosn?.doImgGen || linejosn?.imageAttachmentInfo) {
 
606
  })();
607
  dataPromises.push(processPromise);
608
  } catch (error) {
 
609
  continue;
610
  }
611
  }
 
625
  }
626
  CONFIG.IS_IMG_GEN = false;
627
  CONFIG.IS_IMG_GEN2 = false;
628
+ resolve();
629
  } catch (error) {
630
+ reject(error);
631
  }
632
  });
633
+
634
  stream.on('error', (error) => {
635
+ reject(error);
 
636
  });
637
  });
638
  } catch (error) {
 
641
  CONFIG.IS_IMG_GEN2 = false;
642
  throw error;
643
  }
 
644
  }
645
 
646
  async function handleImageResponse(imageUrl) {
 
674
  }
675
  }
676
 
677
+
678
  const arrayBuffer = await imageBase64Response.arrayBuffer();
679
  const imageBuffer = Buffer.from(arrayBuffer);
680
+
681
+ if(!CONFIG.API.PICGO_KEY){
682
+ const base64Image = imageBuffer.toString('base64');
683
+ const imageContentType = imageBase64Response.headers.get('content-type');
684
+ return `![image](data:${imageContentType};base64,${base64Image})`
685
+ }
686
+
687
  const formData = new FormData();
688
 
689
  formData.append('source', imageBuffer, {
 
748
  while (retryCount < CONFIG.RETRY.MAX_ATTEMPTS) {
749
  retryCount++;
750
  const grokClient = new GrokApiClient(req.body.model);
751
+ const requestPayload = await grokClient.prepareChatRequest(req.body);
752
 
753
  if (!CONFIG.API.TEMP_COOKIE) {
754
  await Utils.get_signature();