mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
Merge branch 'main' into dano/react-query-typescript
This commit is contained in:
commit
285351bb53
13 changed files with 153 additions and 125 deletions
|
|
@ -41,6 +41,11 @@ OPENAI_KEY=
|
||||||
# Leave it and BINGAI_USER_TOKEN blank to disable this endpoint.
|
# Leave it and BINGAI_USER_TOKEN blank to disable this endpoint.
|
||||||
BINGAI_TOKEN=
|
BINGAI_TOKEN=
|
||||||
|
|
||||||
|
# BingAI Host:
|
||||||
|
# Necessary for some people in different countries, e.g. China (https://cn.bing.com)
|
||||||
|
# Leave it blank to use default server.
|
||||||
|
# BINGAI_HOST="https://cn.bing.com"
|
||||||
|
|
||||||
# BingAI User defined Token
|
# BingAI User defined Token
|
||||||
# Allow user to set their own token by client
|
# Allow user to set their own token by client
|
||||||
# Uncomment this to enable this feature.
|
# Uncomment this to enable this feature.
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ const askBing = async ({
|
||||||
// cookies: '',
|
// cookies: '',
|
||||||
debug: false,
|
debug: false,
|
||||||
cache: store,
|
cache: store,
|
||||||
|
host: process.env.BINGAI_HOST || null,
|
||||||
proxy: process.env.PROXY || null
|
proxy: process.env.PROXY || null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,49 +18,38 @@ const proxyEnvToAxiosProxy = proxyString => {
|
||||||
|
|
||||||
const titleConvo = async ({ endpoint, text, response }) => {
|
const titleConvo = async ({ endpoint, text, response }) => {
|
||||||
let title = 'New Chat';
|
let title = 'New Chat';
|
||||||
const messages = [
|
const ChatGPTClient = (await import('@waylaidwanderer/chatgpt-api')).default;
|
||||||
{
|
|
||||||
role: 'system',
|
|
||||||
content:
|
|
||||||
// `You are a title-generator with one job: giving a conversation, detect the language and titling the conversation provided by a user, using the same language. The requirement are: 1. If possible, generate in 5 words or less, 2. Using title case, 3. must give the title using the language as the user said. 4. Don't refer to the participants of the conversation. 5. Do not include punctuation or quotation marks. 6. Your response should be in title case, exclusively containing the title. 7. don't say anything except the title.
|
|
||||||
`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.
|
|
||||||
|
|
||||||
||>User:
|
|
||||||
"${text}"
|
|
||||||
||>Response:
|
|
||||||
"${JSON.stringify(response?.text)}"
|
|
||||||
|
|
||||||
||>Title:`
|
|
||||||
}
|
|
||||||
// {
|
|
||||||
// role: 'user',
|
|
||||||
// content: `User:\n "${text}"\n\n${model}: \n"${JSON.stringify(response?.text)}"\n\n`
|
|
||||||
// }
|
|
||||||
];
|
|
||||||
|
|
||||||
// console.log('Title Prompt', messages[0]);
|
|
||||||
|
|
||||||
const request = {
|
|
||||||
model: 'gpt-3.5-turbo',
|
|
||||||
messages,
|
|
||||||
temperature: 0,
|
|
||||||
presence_penalty: 0,
|
|
||||||
frequency_penalty: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
// console.log('REQUEST', request);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const configuration = new Configuration({
|
const instructionsPayload = {
|
||||||
apiKey: process.env.OPENAI_KEY
|
role: 'system',
|
||||||
});
|
content: `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 or Quotation. All first letters of every word should be capitalized and complete only the title in User Language only.
|
||||||
const openai = new OpenAIApi(configuration);
|
|
||||||
const completion = await openai.createChatCompletion(request, {
|
|
||||||
proxy: proxyEnvToAxiosProxy(process.env.PROXY || null)
|
|
||||||
});
|
|
||||||
|
|
||||||
//eslint-disable-next-line
|
||>User:
|
||||||
title = completion.data.choices[0].message.content.replace(/["\.]/g, '');
|
"${text}"
|
||||||
|
||>Response:
|
||||||
|
"${JSON.stringify(response?.text)}"
|
||||||
|
|
||||||
|
||>Title:`
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
reverseProxyUrl: process.env.OPENAI_REVERSE_PROXY || null,
|
||||||
|
proxy: process.env.PROXY || null
|
||||||
|
};
|
||||||
|
|
||||||
|
const titleGenClientOptions = JSON.parse(JSON.stringify(options));
|
||||||
|
|
||||||
|
titleGenClientOptions.modelOptions = {
|
||||||
|
model: 'gpt-3.5-turbo',
|
||||||
|
temperature: 0,
|
||||||
|
presence_penalty: 0,
|
||||||
|
frequency_penalty: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const titleGenClient = new ChatGPTClient(process.env.OPENAI_KEY, titleGenClientOptions);
|
||||||
|
const result = await titleGenClient.getCompletion([instructionsPayload], null);
|
||||||
|
title = result.choices[0].message.content.replace(/\s+/g, ' ').trim();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
console.log('There was an issue generating title, see error above');
|
console.log('There was an issue generating title, see error above');
|
||||||
|
|
|
||||||
|
|
@ -35,21 +35,21 @@ router.post('/', async (req, res) => {
|
||||||
let endpointOption = {};
|
let endpointOption = {};
|
||||||
if (req.body?.jailbreak)
|
if (req.body?.jailbreak)
|
||||||
endpointOption = {
|
endpointOption = {
|
||||||
jailbreak: req.body?.jailbreak || false,
|
jailbreak: req.body?.jailbreak ?? false,
|
||||||
jailbreakConversationId: req.body?.jailbreakConversationId || null,
|
jailbreakConversationId: req.body?.jailbreakConversationId ?? null,
|
||||||
systemMessage: req.body?.systemMessage || null,
|
systemMessage: req.body?.systemMessage ?? null,
|
||||||
context: req.body?.context || null,
|
context: req.body?.context ?? null,
|
||||||
toneStyle: req.body?.toneStyle || 'fast'
|
toneStyle: req.body?.toneStyle ?? 'fast'
|
||||||
};
|
};
|
||||||
else
|
else
|
||||||
endpointOption = {
|
endpointOption = {
|
||||||
jailbreak: req.body?.jailbreak || false,
|
jailbreak: req.body?.jailbreak ?? false,
|
||||||
systemMessage: req.body?.systemMessage || null,
|
systemMessage: req.body?.systemMessage ?? null,
|
||||||
context: req.body?.context || null,
|
context: req.body?.context ?? null,
|
||||||
conversationSignature: req.body?.conversationSignature || null,
|
conversationSignature: req.body?.conversationSignature ?? null,
|
||||||
clientId: req.body?.clientId || null,
|
clientId: req.body?.clientId ?? null,
|
||||||
invocationId: req.body?.invocationId || null,
|
invocationId: req.body?.invocationId ?? null,
|
||||||
toneStyle: req.body?.toneStyle || 'fast'
|
toneStyle: req.body?.toneStyle ?? 'fast'
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('ask log', {
|
console.log('ask log', {
|
||||||
|
|
@ -122,31 +122,23 @@ const ask = async ({
|
||||||
|
|
||||||
console.log('BING RESPONSE', response);
|
console.log('BING RESPONSE', response);
|
||||||
|
|
||||||
|
const newConversationId = endpointOption?.jailbreak
|
||||||
|
? response.jailbreakConversationId
|
||||||
|
: response.conversationId || conversationId;
|
||||||
|
const newUserMassageId = response.parentMessageId || response.details.requestId || userMessageId;
|
||||||
|
const newResponseMessageId = response.messageId || response.details.messageId;
|
||||||
|
|
||||||
// STEP1 generate response message
|
// STEP1 generate response message
|
||||||
response.text = response.response || response.details.spokenText || '**Bing refused to answer.**';
|
response.text = response.response || response.details.spokenText || '**Bing refused to answer.**';
|
||||||
|
|
||||||
let responseMessage = {
|
let responseMessage = {
|
||||||
|
conversationId: newConversationId,
|
||||||
|
messageId: newResponseMessageId,
|
||||||
|
parentMessageId: overrideParentMessageId || newUserMassageId,
|
||||||
|
sender: endpointOption?.jailbreak ? 'Sydney' : 'BingAI',
|
||||||
text: await handleText(response, true),
|
text: await handleText(response, true),
|
||||||
suggestions:
|
suggestions: response.details.suggestedResponses && response.details.suggestedResponses.map(s => s.text)
|
||||||
response.details.suggestedResponses && response.details.suggestedResponses.map(s => s.text),
|
|
||||||
jailbreak: endpointOption?.jailbreak
|
|
||||||
};
|
};
|
||||||
// // response.text = await handleText(response, true);
|
|
||||||
// response.suggestions =
|
|
||||||
// response.details.suggestedResponses && response.details.suggestedResponses.map(s => s.text);
|
|
||||||
|
|
||||||
if (endpointOption?.jailbreak) {
|
|
||||||
responseMessage.conversationId = response.jailbreakConversationId;
|
|
||||||
responseMessage.messageId = response.messageId || response.details.messageId;
|
|
||||||
responseMessage.parentMessageId = overrideParentMessageId || response.parentMessageId || userMessageId;
|
|
||||||
responseMessage.sender = 'Sydney';
|
|
||||||
} else {
|
|
||||||
responseMessage.conversationId = response.conversationId;
|
|
||||||
responseMessage.messageId = response.messageId || response.details.messageId;
|
|
||||||
responseMessage.parentMessageId =
|
|
||||||
overrideParentMessageId || response.parentMessageId || response.details.requestId || userMessageId;
|
|
||||||
responseMessage.sender = 'BingAI';
|
|
||||||
}
|
|
||||||
|
|
||||||
await saveMessage(responseMessage);
|
await saveMessage(responseMessage);
|
||||||
|
|
||||||
|
|
@ -159,14 +151,22 @@ const ask = async ({
|
||||||
// Attition: the api will also create new conversationId while using invalid userMessage.parentMessageId,
|
// Attition: the api will also create new conversationId while using invalid userMessage.parentMessageId,
|
||||||
// but in this situation, don't change the conversationId, but create new convo.
|
// but in this situation, don't change the conversationId, but create new convo.
|
||||||
|
|
||||||
let conversationUpdate = { conversationId, endpoint: 'bingAI' };
|
let conversationUpdate = { conversationId: newConversationId, endpoint: 'bingAI' };
|
||||||
if (conversationId != responseMessage.conversationId && isNewConversation)
|
if (conversationId != newConversationId)
|
||||||
conversationUpdate = {
|
if (isNewConversation) {
|
||||||
...conversationUpdate,
|
// change the conversationId to new one
|
||||||
conversationId: conversationId,
|
conversationUpdate = {
|
||||||
newConversationId: responseMessage.conversationId || conversationId
|
...conversationUpdate,
|
||||||
};
|
conversationId: conversationId,
|
||||||
conversationId = responseMessage.conversationId || conversationId;
|
newConversationId: newConversationId
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// create new conversation
|
||||||
|
conversationUpdate = {
|
||||||
|
...conversationUpdate,
|
||||||
|
...endpointOption
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (endpointOption?.jailbreak) {
|
if (endpointOption?.jailbreak) {
|
||||||
conversationUpdate.jailbreak = true;
|
conversationUpdate.jailbreak = true;
|
||||||
|
|
@ -179,17 +179,16 @@ const ask = async ({
|
||||||
}
|
}
|
||||||
|
|
||||||
await saveConvo(req?.session?.user?.username, conversationUpdate);
|
await saveConvo(req?.session?.user?.username, conversationUpdate);
|
||||||
|
conversationId = newConversationId;
|
||||||
|
|
||||||
// STEP3 update the user message
|
// STEP3 update the user message
|
||||||
userMessage.conversationId = conversationId;
|
userMessage.conversationId = newConversationId;
|
||||||
userMessage.messageId = responseMessage.parentMessageId;
|
userMessage.messageId = newUserMassageId;
|
||||||
|
|
||||||
// If response has parentMessageId, the fake userMessage.messageId should be updated to the real one.
|
// If response has parentMessageId, the fake userMessage.messageId should be updated to the real one.
|
||||||
if (!overrideParentMessageId) {
|
if (!overrideParentMessageId)
|
||||||
const oldUserMessageId = userMessageId;
|
await saveMessage({ ...userMessage, messageId: userMessageId, newMessageId: newUserMassageId });
|
||||||
await saveMessage({ ...userMessage, messageId: oldUserMessageId, newMessageId: userMessage.messageId });
|
userMessageId = newUserMassageId;
|
||||||
}
|
|
||||||
userMessageId = userMessage.messageId;
|
|
||||||
|
|
||||||
sendMessage(res, {
|
sendMessage(res, {
|
||||||
title: await getConvoTitle(req?.session?.user?.username, conversationId),
|
title: await getConvoTitle(req?.session?.user?.username, conversationId),
|
||||||
|
|
@ -223,4 +222,4 @@ const ask = async ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import EndpointItem from './EndpointItem';
|
import EndpointItem from './EndpointItem.jsx';
|
||||||
|
|
||||||
export default function EndpointItems({ endpoints, onSelect }) {
|
export default function EndpointItems({ endpoints, onSelect }) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { DropdownMenuRadioItem } from '../../ui/DropdownMenu.tsx';
|
import { DropdownMenuRadioItem } from '../../ui/DropdownMenu.tsx';
|
||||||
import EditIcon from '../../svg/EditIcon';
|
import EditIcon from '../../svg/EditIcon.jsx';
|
||||||
import TrashIcon from '../../svg/TrashIcon';
|
import TrashIcon from '../../svg/TrashIcon.jsx';
|
||||||
import getIcon from '~/utils/getIcon';
|
import getIcon from '~/utils/getIcon';
|
||||||
|
|
||||||
export default function PresetItem({ preset = {}, value, onSelect, onChangePreset, onDeletePreset }) {
|
export default function PresetItem({ preset = {}, value, onSelect, onChangePreset, onDeletePreset }) {
|
||||||
|
|
@ -47,7 +47,7 @@ export default function PresetItem({ preset = {}, value, onSelect, onChangePrese
|
||||||
<small className="ml-2">({getPresetTitle()})</small>
|
<small className="ml-2">({getPresetTitle()})</small>
|
||||||
<div className="flex w-4 flex-1" />
|
<div className="flex w-4 flex-1" />
|
||||||
<button
|
<button
|
||||||
className="invisible m-0 p-2 mr-1 rounded-md text-gray-400 hover:text-gray-700 group-hover:visible dark:text-gray-400 dark:hover:text-gray-200 "
|
className="invisible m-0 mr-1 rounded-md p-2 text-gray-400 hover:text-gray-700 group-hover:visible dark:text-gray-400 dark:hover:text-gray-200 "
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
onChangePreset(preset);
|
onChangePreset(preset);
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PresetItem from './PresetItem';
|
import PresetItem from './PresetItem.jsx';
|
||||||
|
|
||||||
export default function PresetItems({ presets, onSelect, onChangePreset, onDeletePreset }) {
|
export default function PresetItems({ presets, onSelect, onChangePreset, onDeletePreset }) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useRecoilValue, useRecoilState } from 'recoil';
|
import { useRecoilValue, useRecoilState } from 'recoil';
|
||||||
import EditPresetDialog from '../../Endpoints/EditPresetDialog';
|
import EditPresetDialog from '../../Endpoints/EditPresetDialog.jsx';
|
||||||
import EndpointItems from './EndpointItems';
|
import EndpointItems from './EndpointItems.jsx';
|
||||||
import PresetItems from './PresetItems';
|
import PresetItems from './PresetItems.jsx';
|
||||||
import FileUpload from './FileUpload';
|
import FileUpload from './FileUpload.jsx';
|
||||||
import getIcon from '~/utils/getIcon';
|
import getIcon from '~/utils/getIcon';
|
||||||
import { useDeletePresetMutation, useCreatePresetMutation } from '~/data-provider';
|
import manualSWR, { handleFileSelected } from '~/utils/fetchers';
|
||||||
|
|
||||||
import { Button } from '../../ui/Button.tsx';
|
import { Button } from '../../ui/Button.tsx';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
|
@ -16,34 +17,33 @@ import {
|
||||||
DropdownMenuTrigger
|
DropdownMenuTrigger
|
||||||
} from '../../ui/DropdownMenu.tsx';
|
} from '../../ui/DropdownMenu.tsx';
|
||||||
import { Dialog, DialogTrigger } from '../../ui/Dialog.tsx';
|
import { Dialog, DialogTrigger } from '../../ui/Dialog.tsx';
|
||||||
import DialogTemplate from '../../ui/DialogTemplate';
|
import DialogTemplate from '../../ui/DialogTemplate.jsx';
|
||||||
|
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
||||||
export default function NewConversationMenu() {
|
export default function NewConversationMenu() {
|
||||||
|
// const [modelSave, setModelSave] = useState(false);
|
||||||
const [menuOpen, setMenuOpen] = useState(false);
|
const [menuOpen, setMenuOpen] = useState(false);
|
||||||
const [presetModelVisible, setPresetModelVisible] = useState(false);
|
const [presetModelVisible, setPresetModelVisible] = useState(false);
|
||||||
const [preset, setPreset] = useState(false);
|
const [preset, setPreset] = useState(false);
|
||||||
|
|
||||||
|
// const models = useRecoilValue(store.models);
|
||||||
const availableEndpoints = useRecoilValue(store.availableEndpoints);
|
const availableEndpoints = useRecoilValue(store.availableEndpoints);
|
||||||
|
// const setCustomGPTModels = useSetRecoilState(store.customGPTModels);
|
||||||
const [presets, setPresets] = useRecoilState(store.presets);
|
const [presets, setPresets] = useRecoilState(store.presets);
|
||||||
|
|
||||||
const conversation = useRecoilValue(store.conversation) || {};
|
const conversation = useRecoilValue(store.conversation) || {};
|
||||||
const { endpoint, conversationId } = conversation;
|
const { endpoint, conversationId } = conversation;
|
||||||
|
// const { model, promptPrefix, chatGptLabel, conversationId } = conversation;
|
||||||
const { newConversation } = store.useConversation();
|
const { newConversation } = store.useConversation();
|
||||||
|
|
||||||
const deletePresetsMutation = useDeletePresetMutation();
|
const { trigger: clearPresetsTrigger } = manualSWR(`/api/presets/delete`, 'post', res => {
|
||||||
const createPresetMutation = useCreatePresetMutation();
|
console.log(res);
|
||||||
|
setPresets(res.data);
|
||||||
|
});
|
||||||
|
|
||||||
const importPreset = jsonData => {
|
const importPreset = jsonData => {
|
||||||
createPresetMutation.mutate({...jsonData}, {
|
handleFileSelected(jsonData).then(setPresets);
|
||||||
onSuccess: (data) => {
|
|
||||||
setPresets(data);
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
console.error('Error uploading the preset:', error);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// update the default model when availableModels changes
|
// update the default model when availableModels changes
|
||||||
|
|
@ -65,6 +65,7 @@ export default function NewConversationMenu() {
|
||||||
setMenuOpen(false);
|
setMenuOpen(false);
|
||||||
|
|
||||||
if (!newEndpoint) return;
|
if (!newEndpoint) return;
|
||||||
|
// else if (newEndpoint === endpoint) return;
|
||||||
else {
|
else {
|
||||||
newConversation({}, { endpoint: newEndpoint });
|
newConversation({}, { endpoint: newEndpoint });
|
||||||
}
|
}
|
||||||
|
|
@ -74,6 +75,7 @@ export default function NewConversationMenu() {
|
||||||
const onSelectPreset = newPreset => {
|
const onSelectPreset = newPreset => {
|
||||||
setMenuOpen(false);
|
setMenuOpen(false);
|
||||||
if (!newPreset) return;
|
if (!newPreset) return;
|
||||||
|
// else if (newEndpoint === endpoint) return;
|
||||||
else {
|
else {
|
||||||
newConversation({}, newPreset);
|
newConversation({}, newPreset);
|
||||||
}
|
}
|
||||||
|
|
@ -84,12 +86,8 @@ export default function NewConversationMenu() {
|
||||||
setPreset(preset);
|
setPreset(preset);
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearAllPresets = () => {
|
const clearPreset = () => {
|
||||||
deletePresetsMutation.mutate({arg: {}});
|
clearPresetsTrigger({});
|
||||||
};
|
|
||||||
|
|
||||||
const onDeletePreset = preset => {
|
|
||||||
deletePresetsMutation.mutate({arg: preset});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const icon = getIcon({
|
const icon = getIcon({
|
||||||
|
|
@ -101,7 +99,9 @@ export default function NewConversationMenu() {
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog
|
||||||
|
// onOpenChange={onOpenChange}
|
||||||
|
>
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
open={menuOpen}
|
open={menuOpen}
|
||||||
onOpenChange={setMenuOpen}
|
onOpenChange={setMenuOpen}
|
||||||
|
|
@ -109,9 +109,13 @@ export default function NewConversationMenu() {
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className={`absolute top-[0.25px] mb-0 ml-1 items-center rounded-md border-0 p-1 outline-none focus:ring-0 focus:ring-offset-0 disabled:top-[0.25px] dark:data-[state=open]:bg-opacity-50 md:top-1 md:left-1 md:ml-0 md:pl-1 md:disabled:top-1`}
|
// style={{backgroundColor: 'rgb(16, 163, 127)'}}
|
||||||
|
className={`group relative mt-[-8px] mb-[-12px] ml-0 items-center rounded-md border-0 p-1 outline-none focus:ring-0 focus:ring-offset-0 dark:data-[state=open]:bg-opacity-50 md:left-1 md:ml-[-12px] md:pl-1`}
|
||||||
>
|
>
|
||||||
{icon}
|
{icon}
|
||||||
|
<span className="max-w-0 overflow-hidden whitespace-nowrap px-0 text-slate-600 transition-all group-hover:max-w-[80px] group-hover:px-2 group-data-[state=open]:max-w-[80px] group-data-[state=open]:px-2 dark:text-slate-300">
|
||||||
|
New Topic
|
||||||
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent
|
<DropdownMenuContent
|
||||||
|
|
@ -146,6 +150,7 @@ export default function NewConversationMenu() {
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className="h-auto bg-transparent px-2 py-1 text-xs font-medium font-normal text-red-700 hover:bg-slate-200 hover:text-red-700 dark:bg-transparent dark:text-red-400 dark:hover:bg-gray-800 dark:hover:text-red-400"
|
className="h-auto bg-transparent px-2 py-1 text-xs font-medium font-normal text-red-700 hover:bg-slate-200 hover:text-red-700 dark:bg-transparent dark:text-red-400 dark:hover:bg-gray-800 dark:hover:text-red-400"
|
||||||
|
// onClick={clearPreset}
|
||||||
>
|
>
|
||||||
Clear All
|
Clear All
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -154,7 +159,7 @@ export default function NewConversationMenu() {
|
||||||
title="Clear presets"
|
title="Clear presets"
|
||||||
description="Are you sure you want to clear all presets? This is irreversible."
|
description="Are you sure you want to clear all presets? This is irreversible."
|
||||||
selection={{
|
selection={{
|
||||||
selectHandler: clearAllPresets,
|
selectHandler: clearPreset,
|
||||||
selectClasses: 'bg-red-600 hover:bg-red-700 dark:hover:bg-red-800 text-white',
|
selectClasses: 'bg-red-600 hover:bg-red-700 dark:hover:bg-red-800 text-white',
|
||||||
selectText: 'Clear'
|
selectText: 'Clear'
|
||||||
}}
|
}}
|
||||||
|
|
@ -171,7 +176,7 @@ export default function NewConversationMenu() {
|
||||||
presets={presets}
|
presets={presets}
|
||||||
onSelect={onSelectPreset}
|
onSelect={onSelectPreset}
|
||||||
onChangePreset={onChangePreset}
|
onChangePreset={onChangePreset}
|
||||||
onDeletePreset={onDeletePreset}
|
onDeletePreset={clearPresetsTrigger}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DropdownMenuLabel className="dark:text-gray-300">No preset yet.</DropdownMenuLabel>
|
<DropdownMenuLabel className="dark:text-gray-300">No preset yet.</DropdownMenuLabel>
|
||||||
|
|
@ -5,7 +5,7 @@ import OpenAIOptions from './OpenAIOptions';
|
||||||
import ChatGPTOptions from './ChatGPTOptions';
|
import ChatGPTOptions from './ChatGPTOptions';
|
||||||
import BingAIOptions from './BingAIOptions';
|
import BingAIOptions from './BingAIOptions';
|
||||||
// import BingStyles from './BingStyles';
|
// import BingStyles from './BingStyles';
|
||||||
import NewConversationMenu from './Endpoints/NewConversationMenu';
|
import NewConversationMenu from './NewConversationMenu';
|
||||||
import Footer from './Footer';
|
import Footer from './Footer';
|
||||||
import TextareaAutosize from 'react-textarea-autosize';
|
import TextareaAutosize from 'react-textarea-autosize';
|
||||||
import { useMessageHandler } from '../../utils/handleSubmit';
|
import { useMessageHandler } from '../../utils/handleSubmit';
|
||||||
|
|
@ -139,7 +139,7 @@ export default function TextChat({ isSearchView = false }) {
|
||||||
<form className="stretch mx-2 flex flex-row gap-3 last:mb-2 md:pt-2 md:last:mb-6 lg:mx-auto lg:max-w-3xl lg:pt-6">
|
<form className="stretch mx-2 flex flex-row gap-3 last:mb-2 md:pt-2 md:last:mb-6 lg:mx-auto lg:max-w-3xl lg:pt-6">
|
||||||
<div className="relative flex h-full flex-1 md:flex-col">
|
<div className="relative flex h-full flex-1 md:flex-col">
|
||||||
<div
|
<div
|
||||||
className={`relative flex flex-grow flex-col rounded-md border border-black/10 ${
|
className={`relative flex flex-grow flex-row rounded-md border border-black/10 ${
|
||||||
disabled ? 'bg-gray-100' : 'bg-white'
|
disabled ? 'bg-gray-100' : 'bg-white'
|
||||||
} py-2 shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 ${
|
} py-2 shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 ${
|
||||||
disabled ? 'dark:bg-gray-900' : 'dark:bg-gray-700'
|
disabled ? 'dark:bg-gray-900' : 'dark:bg-gray-700'
|
||||||
|
|
@ -160,7 +160,7 @@ export default function TextChat({ isSearchView = false }) {
|
||||||
onCompositionEnd={handleCompositionEnd}
|
onCompositionEnd={handleCompositionEnd}
|
||||||
placeholder={getPlaceholderText()}
|
placeholder={getPlaceholderText()}
|
||||||
disabled={disabled || isNotAppendable}
|
disabled={disabled || isNotAppendable}
|
||||||
className="m-0 h-auto max-h-52 resize-none overflow-auto border-0 bg-transparent p-0 pl-12 pr-8 leading-6 placeholder:text-sm placeholder:text-gray-600 focus:outline-none focus:ring-0 focus-visible:ring-0 dark:bg-transparent dark:placeholder:text-gray-500 md:pl-8"
|
className="m-0 flex h-auto max-h-52 flex-1 resize-none overflow-auto border-0 bg-transparent p-0 pl-2 pr-12 leading-6 placeholder:text-sm placeholder:text-gray-600 focus:outline-none focus:ring-0 focus-visible:ring-0 dark:bg-transparent dark:placeholder:text-gray-500 md:pl-2"
|
||||||
/>
|
/>
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
submitMessage={submitMessage}
|
submitMessage={submitMessage}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
"ESNext"
|
"ESNext"
|
||||||
],
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": false,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import type { Plugin } from "vite";
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
|
@ -19,11 +20,20 @@ export default defineConfig({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [react()],
|
plugins: [react(), sourcemapExclude({ excludeNodeModules: true }),],
|
||||||
publicDir: './public',
|
publicDir: './public',
|
||||||
build: {
|
build: {
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
outDir: './dist'
|
outDir: './dist',
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks: (id) => {
|
||||||
|
if (id.includes("node_modules")) {
|
||||||
|
return "vendor";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|
@ -31,3 +41,22 @@ export default defineConfig({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interface SourcemapExclude {
|
||||||
|
excludeNodeModules?: boolean;
|
||||||
|
}
|
||||||
|
export function sourcemapExclude(opts?: SourcemapExclude): Plugin {
|
||||||
|
return {
|
||||||
|
name: "sourcemap-exclude",
|
||||||
|
transform(code: string, id: string) {
|
||||||
|
if (opts?.excludeNodeModules && id.includes("node_modules")) {
|
||||||
|
return {
|
||||||
|
code,
|
||||||
|
// https://github.com/rollup/rollup/blob/master/docs/plugin-development/index.md#source-code-transformations
|
||||||
|
map: { mappings: "" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue