Spaces:
Sleeping
Sleeping
Update index.js
Browse files
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:
|
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(
|
352 |
}
|
353 |
-
|
354 |
-
|
355 |
-
let
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
356 |
let messages = '';
|
357 |
let lastRole = null;
|
358 |
let lastContent = '';
|
359 |
-
|
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 |
-
|
373 |
-
|
374 |
-
|
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 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
393 |
}
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
}
|
398 |
-
} else {
|
399 |
-
textContent = this.processMessageContent(current.content);
|
400 |
}
|
401 |
-
|
402 |
-
|
|
|
|
|
|
|
|
|
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 |
-
|
|
|
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 |
-
|
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 ``
|
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();
|