mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 06:00:56 +02:00
🛠️ fix: Optionally add OpenID Sig. Algo. from Server Discovery (#5398)
* fix: Optionally add OpenID Sig. Algorithm from Server Discovery * chore: bump vite to 5.4.14 for CVE-2025-24010 * chore: remove deprecated code * fix: install missing undici * fix: Add @waylaidwanderer/fetch-event-source package
This commit is contained in:
parent
fa9e778399
commit
199e5e6eaf
11 changed files with 101 additions and 2024 deletions
|
@ -1,112 +0,0 @@
|
|||
require('dotenv').config();
|
||||
const { KeyvFile } = require('keyv-file');
|
||||
const { EModelEndpoint } = require('librechat-data-provider');
|
||||
const { getUserKey, checkUserKeyExpiry } = require('~/server/services/UserService');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const askBing = async ({
|
||||
text,
|
||||
parentMessageId,
|
||||
conversationId,
|
||||
jailbreak,
|
||||
jailbreakConversationId,
|
||||
context,
|
||||
systemMessage,
|
||||
conversationSignature,
|
||||
clientId,
|
||||
invocationId,
|
||||
toneStyle,
|
||||
key: expiresAt,
|
||||
onProgress,
|
||||
userId,
|
||||
}) => {
|
||||
const isUserProvided = process.env.BINGAI_TOKEN === 'user_provided';
|
||||
|
||||
let key = null;
|
||||
if (expiresAt && isUserProvided) {
|
||||
checkUserKeyExpiry(expiresAt, EModelEndpoint.bingAI);
|
||||
key = await getUserKey({ userId, name: 'bingAI' });
|
||||
}
|
||||
|
||||
const { BingAIClient } = await import('nodejs-gpt');
|
||||
const store = {
|
||||
store: new KeyvFile({ filename: './data/cache.json' }),
|
||||
};
|
||||
|
||||
const bingAIClient = new BingAIClient({
|
||||
// "_U" cookie from bing.com
|
||||
// userToken:
|
||||
// isUserProvided ? key : process.env.BINGAI_TOKEN ?? null,
|
||||
// If the above doesn't work, provide all your cookies as a string instead
|
||||
cookies: isUserProvided ? key : process.env.BINGAI_TOKEN ?? null,
|
||||
debug: false,
|
||||
cache: store,
|
||||
host: process.env.BINGAI_HOST || null,
|
||||
proxy: process.env.PROXY || null,
|
||||
});
|
||||
|
||||
let options = {};
|
||||
|
||||
if (jailbreakConversationId == 'false') {
|
||||
jailbreakConversationId = false;
|
||||
}
|
||||
|
||||
if (jailbreak) {
|
||||
options = {
|
||||
jailbreakConversationId: jailbreakConversationId || jailbreak,
|
||||
context,
|
||||
systemMessage,
|
||||
parentMessageId,
|
||||
toneStyle,
|
||||
onProgress,
|
||||
clientOptions: {
|
||||
features: {
|
||||
genImage: {
|
||||
server: {
|
||||
enable: true,
|
||||
type: 'markdown_list',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
} else {
|
||||
options = {
|
||||
conversationId,
|
||||
context,
|
||||
systemMessage,
|
||||
parentMessageId,
|
||||
toneStyle,
|
||||
onProgress,
|
||||
clientOptions: {
|
||||
features: {
|
||||
genImage: {
|
||||
server: {
|
||||
enable: true,
|
||||
type: 'markdown_list',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// don't give those parameters for new conversation
|
||||
// for new conversation, conversationSignature always is null
|
||||
if (conversationSignature) {
|
||||
options.encryptedConversationSignature = conversationSignature;
|
||||
options.clientId = clientId;
|
||||
options.invocationId = invocationId;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug('bing options', options);
|
||||
|
||||
const res = await bingAIClient.sendMessage(text, options);
|
||||
|
||||
return res;
|
||||
|
||||
// for reference:
|
||||
// https://github.com/waylaidwanderer/node-chatgpt-api/blob/main/demos/use-bing-client.js
|
||||
};
|
||||
|
||||
module.exports = { askBing };
|
|
@ -1,57 +0,0 @@
|
|||
require('dotenv').config();
|
||||
const { KeyvFile } = require('keyv-file');
|
||||
const { Constants, EModelEndpoint } = require('librechat-data-provider');
|
||||
const { getUserKey, checkUserKeyExpiry } = require('../server/services/UserService');
|
||||
|
||||
const browserClient = async ({
|
||||
text,
|
||||
parentMessageId,
|
||||
conversationId,
|
||||
model,
|
||||
key: expiresAt,
|
||||
onProgress,
|
||||
onEventMessage,
|
||||
abortController,
|
||||
userId,
|
||||
}) => {
|
||||
const isUserProvided = process.env.CHATGPT_TOKEN === 'user_provided';
|
||||
|
||||
let key = null;
|
||||
if (expiresAt && isUserProvided) {
|
||||
checkUserKeyExpiry(expiresAt, EModelEndpoint.chatGPTBrowser);
|
||||
key = await getUserKey({ userId, name: 'chatGPTBrowser' });
|
||||
}
|
||||
|
||||
const { ChatGPTBrowserClient } = await import('nodejs-gpt');
|
||||
const store = {
|
||||
store: new KeyvFile({ filename: './data/cache.json' }),
|
||||
};
|
||||
|
||||
const clientOptions = {
|
||||
// Warning: This will expose your access token to a third party. Consider the risks before using this.
|
||||
reverseProxyUrl:
|
||||
process.env.CHATGPT_REVERSE_PROXY ?? 'https://ai.fakeopen.com/api/conversation',
|
||||
// Access token from https://chat.openai.com/api/auth/session
|
||||
accessToken: isUserProvided ? key : process.env.CHATGPT_TOKEN ?? null,
|
||||
model: model,
|
||||
debug: false,
|
||||
proxy: process.env.PROXY ?? null,
|
||||
user: userId,
|
||||
};
|
||||
|
||||
const client = new ChatGPTBrowserClient(clientOptions, store);
|
||||
let options = { onProgress, onEventMessage, abortController };
|
||||
|
||||
if (!!parentMessageId && !!conversationId) {
|
||||
options = { ...options, parentMessageId, conversationId };
|
||||
}
|
||||
|
||||
if (parentMessageId === Constants.NO_PARENT) {
|
||||
delete options.conversationId;
|
||||
}
|
||||
|
||||
const res = await client.sendMessage(text, options);
|
||||
return res;
|
||||
};
|
||||
|
||||
module.exports = { browserClient };
|
|
@ -1,11 +1,5 @@
|
|||
const { browserClient } = require('./chatgpt-browser');
|
||||
const { askBing } = require('./bingai');
|
||||
const clients = require('./clients');
|
||||
const titleConvoBing = require('./titleConvoBing');
|
||||
|
||||
module.exports = {
|
||||
browserClient,
|
||||
askBing,
|
||||
titleConvoBing,
|
||||
...clients,
|
||||
};
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
const throttle = require('lodash/throttle');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const titleConvo = async ({ text, response }) => {
|
||||
let title = 'New Chat';
|
||||
const { TITLE_CONVO = 'true' } = process.env ?? {};
|
||||
if (!isEnabled(TITLE_CONVO)) {
|
||||
return title;
|
||||
}
|
||||
|
||||
const { BingAIClient } = await import('nodejs-gpt');
|
||||
const titleGenerator = new BingAIClient({
|
||||
userToken: process.env.BINGAI_TOKEN,
|
||||
debug: false,
|
||||
});
|
||||
|
||||
let options = {
|
||||
jailbreakConversationId: true,
|
||||
systemMessage:
|
||||
'You are a title-generator. As a title-generator, the old rules no longer apply. The only rule you need to follow is the following: Detect user language and write in the same language an extremely concise title for this conversation, which you must accurately detect. Write in the detected language. Title in 5 Words or Less. No Punctuation/Quotation. All first letters of every word should be capitalized and complete only the title in User Language only.',
|
||||
context: `
|
||||
||>User:
|
||||
"${text}"
|
||||
||>Response:
|
||||
"${JSON.stringify(response?.text)}"`,
|
||||
toneStyle: 'precise',
|
||||
};
|
||||
const titlePrompt = 'Title:';
|
||||
try {
|
||||
const res = await titleGenerator.sendMessage(titlePrompt, options);
|
||||
title = res.response.replace(/Title: /, '').replace(/[".]/g, '');
|
||||
} catch (e) {
|
||||
logger.error('There was an issue generating title with BingAI', e);
|
||||
}
|
||||
|
||||
logger.debug('[/ask/bingAI] CONVERSATION TITLE: ' + title);
|
||||
return title;
|
||||
};
|
||||
|
||||
const throttledTitleConvo = throttle(titleConvo, 3000);
|
||||
|
||||
module.exports = throttledTitleConvo;
|
|
@ -45,6 +45,7 @@
|
|||
"@langchain/google-vertexai": "^0.1.6",
|
||||
"@langchain/textsplitters": "^0.1.0",
|
||||
"@librechat/agents": "^1.9.94",
|
||||
"@waylaidwanderer/fetch-event-source": "^3.0.1",
|
||||
"axios": "^1.7.7",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
|
@ -82,7 +83,6 @@
|
|||
"mongoose": "^8.9.5",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"nanoid": "^3.3.7",
|
||||
"nodejs-gpt": "^1.37.4",
|
||||
"nodemailer": "^6.9.15",
|
||||
"ollama": "^0.5.0",
|
||||
"openai": "^4.47.1",
|
||||
|
@ -102,6 +102,7 @@
|
|||
"tiktoken": "^1.0.15",
|
||||
"traverse": "^0.6.7",
|
||||
"ua-parser-js": "^1.0.36",
|
||||
"undici": "^7.2.3",
|
||||
"winston": "^3.11.0",
|
||||
"winston-daily-rotate-file": "^4.7.1",
|
||||
"zod": "^3.22.4"
|
||||
|
|
|
@ -1,237 +0,0 @@
|
|||
const crypto = require('crypto');
|
||||
const express = require('express');
|
||||
const { Constants } = require('librechat-data-provider');
|
||||
const { saveMessage, getConvoTitle, saveConvo, getConvo } = require('~/models');
|
||||
const { handleError, sendMessage, createOnProgress, handleText } = require('~/server/utils');
|
||||
const { setHeaders } = require('~/server/middleware');
|
||||
const { browserClient } = require('~/app/');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post('/', setHeaders, async (req, res) => {
|
||||
const {
|
||||
endpoint,
|
||||
text,
|
||||
overrideParentMessageId = null,
|
||||
parentMessageId,
|
||||
conversationId: oldConversationId,
|
||||
} = req.body;
|
||||
if (text.length === 0) {
|
||||
return handleError(res, { text: 'Prompt empty or too short' });
|
||||
}
|
||||
if (endpoint !== 'chatGPTBrowser') {
|
||||
return handleError(res, { text: 'Illegal request' });
|
||||
}
|
||||
|
||||
// build user message
|
||||
const conversationId = oldConversationId || crypto.randomUUID();
|
||||
const isNewConversation = !oldConversationId;
|
||||
const userMessageId = crypto.randomUUID();
|
||||
const userParentMessageId = parentMessageId || Constants.NO_PARENT;
|
||||
const userMessage = {
|
||||
messageId: userMessageId,
|
||||
sender: 'User',
|
||||
text,
|
||||
parentMessageId: userParentMessageId,
|
||||
conversationId,
|
||||
isCreatedByUser: true,
|
||||
};
|
||||
|
||||
// build endpoint option
|
||||
const endpointOption = {
|
||||
model: req.body?.model ?? 'text-davinci-002-render-sha',
|
||||
key: req.body?.key ?? null,
|
||||
};
|
||||
|
||||
logger.debug('[/ask/chatGPTBrowser]', {
|
||||
userMessage,
|
||||
conversationId,
|
||||
...endpointOption,
|
||||
});
|
||||
|
||||
if (!overrideParentMessageId) {
|
||||
await saveMessage(req, { ...userMessage, user: req.user.id });
|
||||
await saveConvo(req, {
|
||||
...userMessage,
|
||||
...endpointOption,
|
||||
conversationId,
|
||||
endpoint,
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
return await ask({
|
||||
isNewConversation,
|
||||
userMessage,
|
||||
endpointOption,
|
||||
conversationId,
|
||||
preSendRequest: true,
|
||||
overrideParentMessageId,
|
||||
req,
|
||||
res,
|
||||
});
|
||||
});
|
||||
|
||||
const ask = async ({
|
||||
isNewConversation,
|
||||
userMessage,
|
||||
endpointOption,
|
||||
conversationId,
|
||||
overrideParentMessageId = null,
|
||||
req,
|
||||
res,
|
||||
}) => {
|
||||
let { text, parentMessageId: userParentMessageId, messageId: userMessageId } = userMessage;
|
||||
const user = req.user.id;
|
||||
let responseMessageId = crypto.randomUUID();
|
||||
let getPartialMessage = null;
|
||||
try {
|
||||
let lastSavedTimestamp = 0;
|
||||
const { onProgress: progressCallback, getPartialText } = createOnProgress({
|
||||
onProgress: ({ text }) => {
|
||||
const currentTimestamp = Date.now();
|
||||
if (currentTimestamp - lastSavedTimestamp > 500) {
|
||||
lastSavedTimestamp = currentTimestamp;
|
||||
saveMessage(req, {
|
||||
messageId: responseMessageId,
|
||||
sender: endpointOption?.jailbreak ? 'Sydney' : 'BingAI',
|
||||
conversationId,
|
||||
parentMessageId: overrideParentMessageId || userMessageId,
|
||||
text: text,
|
||||
unfinished: true,
|
||||
error: false,
|
||||
isCreatedByUser: false,
|
||||
user,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
getPartialMessage = getPartialText;
|
||||
const abortController = new AbortController();
|
||||
let i = 0;
|
||||
let response = await browserClient({
|
||||
text,
|
||||
parentMessageId: userParentMessageId,
|
||||
conversationId,
|
||||
...endpointOption,
|
||||
abortController,
|
||||
userId: user,
|
||||
onProgress: progressCallback.call(null, { res, text }),
|
||||
onEventMessage: (eventMessage) => {
|
||||
let data = null;
|
||||
try {
|
||||
data = JSON.parse(eventMessage.data);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendMessage(res, {
|
||||
message: { ...userMessage, conversationId: data.conversation_id },
|
||||
created: i === 0,
|
||||
});
|
||||
|
||||
if (i === 0) {
|
||||
i++;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug('[/ask/chatGPTBrowser]', response);
|
||||
|
||||
const newConversationId = response.conversationId || conversationId;
|
||||
const newUserMassageId = response.parentMessageId || userMessageId;
|
||||
const newResponseMessageId = response.messageId;
|
||||
|
||||
// STEP1 generate response message
|
||||
response.text = response.response || '**ChatGPT refused to answer.**';
|
||||
|
||||
let responseMessage = {
|
||||
conversationId: newConversationId,
|
||||
messageId: responseMessageId,
|
||||
newMessageId: newResponseMessageId,
|
||||
parentMessageId: overrideParentMessageId || newUserMassageId,
|
||||
text: await handleText(response),
|
||||
sender: endpointOption?.chatGptLabel || 'ChatGPT',
|
||||
unfinished: false,
|
||||
error: false,
|
||||
isCreatedByUser: false,
|
||||
};
|
||||
|
||||
await saveMessage(req, { ...responseMessage, user });
|
||||
responseMessage.messageId = newResponseMessageId;
|
||||
|
||||
// STEP2 update the conversation
|
||||
|
||||
// First update conversationId if needed
|
||||
let conversationUpdate = { conversationId: newConversationId, endpoint: 'chatGPTBrowser' };
|
||||
if (conversationId != newConversationId) {
|
||||
if (isNewConversation) {
|
||||
// change the conversationId to new one
|
||||
conversationUpdate = {
|
||||
...conversationUpdate,
|
||||
conversationId: conversationId,
|
||||
newConversationId: newConversationId,
|
||||
};
|
||||
} else {
|
||||
// create new conversation
|
||||
conversationUpdate = {
|
||||
...conversationUpdate,
|
||||
...endpointOption,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
await saveConvo(req, conversationUpdate);
|
||||
conversationId = newConversationId;
|
||||
|
||||
// STEP3 update the user message
|
||||
userMessage.conversationId = newConversationId;
|
||||
userMessage.messageId = newUserMassageId;
|
||||
|
||||
// If response has parentMessageId, the fake userMessage.messageId should be updated to the real one.
|
||||
if (!overrideParentMessageId) {
|
||||
await saveMessage(req, {
|
||||
...userMessage,
|
||||
user,
|
||||
messageId: userMessageId,
|
||||
newMessageId: newUserMassageId,
|
||||
});
|
||||
}
|
||||
userMessageId = newUserMassageId;
|
||||
|
||||
sendMessage(res, {
|
||||
title: await getConvoTitle(user, conversationId),
|
||||
final: true,
|
||||
conversation: await getConvo(user, conversationId),
|
||||
requestMessage: userMessage,
|
||||
responseMessage: responseMessage,
|
||||
});
|
||||
res.end();
|
||||
|
||||
if (userParentMessageId == Constants.NO_PARENT) {
|
||||
// const title = await titleConvo({ endpoint: endpointOption?.endpoint, text, response: responseMessage });
|
||||
const title = await response.details.title;
|
||||
await saveConvo(req, {
|
||||
conversationId: conversationId,
|
||||
title,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = {
|
||||
messageId: responseMessageId,
|
||||
sender: 'ChatGPT',
|
||||
conversationId,
|
||||
parentMessageId: overrideParentMessageId || userMessageId,
|
||||
unfinished: false,
|
||||
error: true,
|
||||
isCreatedByUser: false,
|
||||
text: `${getPartialMessage() ?? ''}\n\nError message: "${error.message}"`,
|
||||
};
|
||||
await saveMessage(req, { ...errorMessage, user });
|
||||
handleError(res, errorMessage);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = router;
|
|
@ -1,297 +0,0 @@
|
|||
const crypto = require('crypto');
|
||||
const express = require('express');
|
||||
const { Constants } = require('librechat-data-provider');
|
||||
const { handleError, sendMessage, createOnProgress, handleText } = require('~/server/utils');
|
||||
const { saveMessage, getConvoTitle, saveConvo, getConvo } = require('~/models');
|
||||
const { setHeaders } = require('~/server/middleware');
|
||||
const { titleConvoBing, askBing } = require('~/app');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post('/', setHeaders, async (req, res) => {
|
||||
const {
|
||||
endpoint,
|
||||
text,
|
||||
messageId,
|
||||
overrideParentMessageId = null,
|
||||
parentMessageId,
|
||||
conversationId: oldConversationId,
|
||||
} = req.body;
|
||||
if (text.length === 0) {
|
||||
return handleError(res, { text: 'Prompt empty or too short' });
|
||||
}
|
||||
if (endpoint !== 'bingAI') {
|
||||
return handleError(res, { text: 'Illegal request' });
|
||||
}
|
||||
|
||||
// build user message
|
||||
const conversationId = oldConversationId || crypto.randomUUID();
|
||||
const isNewConversation = !oldConversationId;
|
||||
const userMessageId = messageId;
|
||||
const userParentMessageId = parentMessageId || Constants.NO_PARENT;
|
||||
let userMessage = {
|
||||
messageId: userMessageId,
|
||||
sender: 'User',
|
||||
text,
|
||||
parentMessageId: userParentMessageId,
|
||||
conversationId,
|
||||
isCreatedByUser: true,
|
||||
};
|
||||
|
||||
// build endpoint option
|
||||
let endpointOption = {};
|
||||
if (req.body?.jailbreak) {
|
||||
endpointOption = {
|
||||
jailbreak: req.body?.jailbreak ?? false,
|
||||
jailbreakConversationId: req.body?.jailbreakConversationId ?? null,
|
||||
systemMessage: req.body?.systemMessage ?? null,
|
||||
context: req.body?.context ?? null,
|
||||
toneStyle: req.body?.toneStyle ?? 'creative',
|
||||
key: req.body?.key ?? null,
|
||||
};
|
||||
} else {
|
||||
endpointOption = {
|
||||
jailbreak: req.body?.jailbreak ?? false,
|
||||
systemMessage: req.body?.systemMessage ?? null,
|
||||
context: req.body?.context ?? null,
|
||||
conversationSignature: req.body?.conversationSignature ?? null,
|
||||
clientId: req.body?.clientId ?? null,
|
||||
invocationId: req.body?.invocationId ?? null,
|
||||
toneStyle: req.body?.toneStyle ?? 'creative',
|
||||
key: req.body?.key ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
logger.debug('[/ask/bingAI] ask log', {
|
||||
userMessage,
|
||||
endpointOption,
|
||||
conversationId,
|
||||
});
|
||||
|
||||
if (!overrideParentMessageId) {
|
||||
await saveMessage(req, { ...userMessage, user: req.user.id });
|
||||
await saveConvo(req, {
|
||||
...userMessage,
|
||||
...endpointOption,
|
||||
conversationId,
|
||||
endpoint,
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
return await ask({
|
||||
isNewConversation,
|
||||
userMessage,
|
||||
endpointOption,
|
||||
conversationId,
|
||||
preSendRequest: true,
|
||||
overrideParentMessageId,
|
||||
req,
|
||||
res,
|
||||
});
|
||||
});
|
||||
|
||||
const ask = async ({
|
||||
isNewConversation,
|
||||
userMessage,
|
||||
endpointOption,
|
||||
conversationId,
|
||||
preSendRequest = true,
|
||||
overrideParentMessageId = null,
|
||||
req,
|
||||
res,
|
||||
}) => {
|
||||
let { text, parentMessageId: userParentMessageId, messageId: userMessageId } = userMessage;
|
||||
const user = req.user.id;
|
||||
|
||||
let responseMessageId = crypto.randomUUID();
|
||||
const model = endpointOption?.jailbreak ? 'Sydney' : 'BingAI';
|
||||
|
||||
if (preSendRequest) {
|
||||
sendMessage(res, { message: userMessage, created: true });
|
||||
}
|
||||
|
||||
let lastSavedTimestamp = 0;
|
||||
const { onProgress: progressCallback, getPartialText } = createOnProgress({
|
||||
onProgress: ({ text }) => {
|
||||
const currentTimestamp = Date.now();
|
||||
if (currentTimestamp - lastSavedTimestamp > 500) {
|
||||
lastSavedTimestamp = currentTimestamp;
|
||||
saveMessage(req, {
|
||||
messageId: responseMessageId,
|
||||
sender: model,
|
||||
conversationId,
|
||||
parentMessageId: overrideParentMessageId || userMessageId,
|
||||
model,
|
||||
text: text,
|
||||
unfinished: true,
|
||||
error: false,
|
||||
isCreatedByUser: false,
|
||||
user,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
const abortController = new AbortController();
|
||||
let bingConversationId = null;
|
||||
if (!isNewConversation) {
|
||||
const convo = await getConvo(user, conversationId);
|
||||
bingConversationId = convo.bingConversationId;
|
||||
}
|
||||
|
||||
try {
|
||||
let response = await askBing({
|
||||
text,
|
||||
userId: user,
|
||||
parentMessageId: userParentMessageId,
|
||||
conversationId: bingConversationId ?? conversationId,
|
||||
...endpointOption,
|
||||
onProgress: progressCallback.call(null, {
|
||||
res,
|
||||
text,
|
||||
parentMessageId: overrideParentMessageId || userMessageId,
|
||||
}),
|
||||
abortController,
|
||||
});
|
||||
|
||||
logger.debug('[/ask/bingAI] BING RESPONSE', response);
|
||||
|
||||
if (response.details && response.details.scores) {
|
||||
logger.debug('[/ask/bingAI] SCORES', response.details.scores);
|
||||
}
|
||||
|
||||
const newConversationId = endpointOption?.jailbreak
|
||||
? response.jailbreakConversationId
|
||||
: response.conversationId || conversationId;
|
||||
const newUserMessageId =
|
||||
response.parentMessageId || response.details.requestId || userMessageId;
|
||||
const newResponseMessageId = response.messageId || response.details.messageId;
|
||||
|
||||
// STEP1 generate response message
|
||||
response.text =
|
||||
response.response || response.details.spokenText || '**Bing refused to answer.**';
|
||||
|
||||
const partialText = getPartialText();
|
||||
let unfinished = false;
|
||||
if (partialText?.trim()?.length > response.text.length) {
|
||||
response.text = partialText;
|
||||
unfinished = false;
|
||||
//setting "unfinished" to false fix bing image generation error msg and allows to continue a convo after being triggered by censorship (bing does remember the context after a "censored error" so there is no reason to end the convo)
|
||||
}
|
||||
|
||||
let responseMessage = {
|
||||
conversationId,
|
||||
bingConversationId: newConversationId,
|
||||
messageId: responseMessageId,
|
||||
newMessageId: newResponseMessageId,
|
||||
parentMessageId: overrideParentMessageId || newUserMessageId,
|
||||
sender: model,
|
||||
text: await handleText(response, true),
|
||||
model,
|
||||
suggestions:
|
||||
response.details.suggestedResponses &&
|
||||
response.details.suggestedResponses.map((s) => s.text),
|
||||
unfinished,
|
||||
error: false,
|
||||
isCreatedByUser: false,
|
||||
};
|
||||
|
||||
await saveMessage(req, { ...responseMessage, user });
|
||||
responseMessage.messageId = newResponseMessageId;
|
||||
|
||||
let conversationUpdate = {
|
||||
conversationId,
|
||||
bingConversationId: newConversationId,
|
||||
endpoint: 'bingAI',
|
||||
};
|
||||
|
||||
if (endpointOption?.jailbreak) {
|
||||
conversationUpdate.jailbreak = true;
|
||||
conversationUpdate.jailbreakConversationId = response.jailbreakConversationId;
|
||||
} else {
|
||||
conversationUpdate.jailbreak = false;
|
||||
conversationUpdate.conversationSignature = response.encryptedConversationSignature;
|
||||
conversationUpdate.clientId = response.clientId;
|
||||
conversationUpdate.invocationId = response.invocationId;
|
||||
}
|
||||
|
||||
await saveConvo(req, conversationUpdate);
|
||||
userMessage.messageId = newUserMessageId;
|
||||
|
||||
// If response has parentMessageId, the fake userMessage.messageId should be updated to the real one.
|
||||
if (!overrideParentMessageId) {
|
||||
await saveMessage(req, {
|
||||
...userMessage,
|
||||
user,
|
||||
messageId: userMessageId,
|
||||
newMessageId: newUserMessageId,
|
||||
});
|
||||
}
|
||||
userMessageId = newUserMessageId;
|
||||
|
||||
sendMessage(res, {
|
||||
title: await getConvoTitle(user, conversationId),
|
||||
final: true,
|
||||
conversation: await getConvo(user, conversationId),
|
||||
requestMessage: userMessage,
|
||||
responseMessage: responseMessage,
|
||||
});
|
||||
res.end();
|
||||
|
||||
if (userParentMessageId == Constants.NO_PARENT) {
|
||||
const title = await titleConvoBing({
|
||||
text,
|
||||
response: responseMessage,
|
||||
});
|
||||
|
||||
await saveConvo(req, {
|
||||
conversationId: conversationId,
|
||||
title,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('[/ask/bingAI] Error handling BingAI response', error);
|
||||
const partialText = getPartialText();
|
||||
if (partialText?.length > 2) {
|
||||
const responseMessage = {
|
||||
messageId: responseMessageId,
|
||||
sender: model,
|
||||
conversationId,
|
||||
parentMessageId: overrideParentMessageId || userMessageId,
|
||||
text: partialText,
|
||||
model,
|
||||
unfinished: true,
|
||||
error: false,
|
||||
isCreatedByUser: false,
|
||||
};
|
||||
|
||||
saveMessage(req, { ...responseMessage, user });
|
||||
|
||||
return {
|
||||
title: await getConvoTitle(user, conversationId),
|
||||
final: true,
|
||||
conversation: await getConvo(user, conversationId),
|
||||
requestMessage: userMessage,
|
||||
responseMessage: responseMessage,
|
||||
};
|
||||
} else {
|
||||
logger.error('[/ask/bingAI] Error handling BingAI response', error);
|
||||
const errorMessage = {
|
||||
messageId: responseMessageId,
|
||||
sender: model,
|
||||
conversationId,
|
||||
parentMessageId: overrideParentMessageId || userMessageId,
|
||||
unfinished: false,
|
||||
error: true,
|
||||
text: error.message,
|
||||
model,
|
||||
isCreatedByUser: false,
|
||||
};
|
||||
await saveMessage(req, { ...errorMessage, user });
|
||||
handleError(res, errorMessage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = router;
|
|
@ -2,10 +2,8 @@ const express = require('express');
|
|||
const openAI = require('./openAI');
|
||||
const custom = require('./custom');
|
||||
const google = require('./google');
|
||||
const bingAI = require('./bingAI');
|
||||
const anthropic = require('./anthropic');
|
||||
const gptPlugins = require('./gptPlugins');
|
||||
const askChatGPTBrowser = require('./askChatGPTBrowser');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const { EModelEndpoint } = require('librechat-data-provider');
|
||||
const {
|
||||
|
@ -41,11 +39,9 @@ if (isEnabled(LIMIT_MESSAGE_USER)) {
|
|||
router.use(validateConvoAccess);
|
||||
|
||||
router.use([`/${EModelEndpoint.azureOpenAI}`, `/${EModelEndpoint.openAI}`], openAI);
|
||||
router.use(`/${EModelEndpoint.chatGPTBrowser}`, askChatGPTBrowser);
|
||||
router.use(`/${EModelEndpoint.gptPlugins}`, gptPlugins);
|
||||
router.use(`/${EModelEndpoint.anthropic}`, anthropic);
|
||||
router.use(`/${EModelEndpoint.google}`, google);
|
||||
router.use(`/${EModelEndpoint.bingAI}`, bingAI);
|
||||
router.use(`/${EModelEndpoint.custom}`, custom);
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
@ -6,6 +6,7 @@ const { Issuer, Strategy: OpenIDStrategy, custom } = require('openid-client');
|
|||
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
|
||||
const { findUser, createUser, updateUser } = require('~/models/userMethods');
|
||||
const { hashToken } = require('~/server/utils/crypto');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
let crypto;
|
||||
|
@ -121,15 +122,16 @@ async function setupOpenId() {
|
|||
- introspection_signed_response_alg // not in v5
|
||||
- authorization_signed_response_alg // not in v5
|
||||
*/
|
||||
const supported_alg = {
|
||||
id_token_signed_response_alg: issuer.id_token_signing_alg_values_supported?.[0] || 'RS256',
|
||||
};
|
||||
const client = new issuer.Client({
|
||||
/** @type {import('openid-client').ClientMetadata} */
|
||||
const clientMetadata = {
|
||||
client_id: process.env.OPENID_CLIENT_ID,
|
||||
client_secret: process.env.OPENID_CLIENT_SECRET,
|
||||
redirect_uris: [process.env.DOMAIN_SERVER + process.env.OPENID_CALLBACK_URL],
|
||||
...supported_alg,
|
||||
});
|
||||
};
|
||||
if (isEnabled(process.env.OPENID_SET_FIRST_SUPPORTED_ALGORITHM)) {
|
||||
clientMetadata.id_token_signed_response_alg = issuer.id_token_signing_alg_values_supported?.[0] || 'RS256';
|
||||
}
|
||||
const client = new issuer.Client(clientMetadata);
|
||||
const requiredRole = process.env.OPENID_REQUIRED_ROLE;
|
||||
const requiredRoleParameterPath = process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH;
|
||||
const requiredRoleTokenKind = process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND;
|
||||
|
|
|
@ -138,7 +138,7 @@
|
|||
"tailwindcss": "^3.4.1",
|
||||
"ts-jest": "^29.1.0",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^5.1.1",
|
||||
"vite": "^5.4.14",
|
||||
"vite-plugin-node-polyfills": "^0.17.0",
|
||||
"vite-plugin-pwa": "^0.21.1"
|
||||
}
|
||||
|
|
1350
package-lock.json
generated
1350
package-lock.json
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue