mirror of
https://github.com/NovaOSS/nova-betterchat.git
synced 2024-11-25 22:53:59 +01:00
parent
59466e987a
commit
4fa5c14734
12
src/App.tsx
12
src/App.tsx
|
@ -6,38 +6,30 @@ import Menu from './components/Menu';
|
|||
import ConfigMenu from './components/ConfigMenu';
|
||||
|
||||
import useSaveToLocalStorage from '@hooks/useSaveToLocalStorage';
|
||||
import useUpdateCharts from '@hooks/useUpdateChats';
|
||||
import useInitialiseNewChat from '@hooks/useInitialiseNewChat';
|
||||
|
||||
import { ChatInterface } from '@type/chat';
|
||||
|
||||
function App() {
|
||||
useSaveToLocalStorage();
|
||||
useUpdateCharts();
|
||||
const initialiseNewChat = useInitialiseNewChat();
|
||||
|
||||
const [setChats, setMessages, setCurrentChatIndex] = useStore((state) => [
|
||||
state.setChats,
|
||||
state.setMessages,
|
||||
state.setCurrentChatIndex,
|
||||
]);
|
||||
const setChats = useStore((state) => state.setChats);
|
||||
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
|
||||
|
||||
useEffect(() => {
|
||||
// localStorage.removeItem('chats');
|
||||
const storedChats = localStorage.getItem('chats');
|
||||
if (storedChats) {
|
||||
try {
|
||||
const chats: ChatInterface[] = JSON.parse(storedChats);
|
||||
if (chats.length > 0) {
|
||||
setChats(chats);
|
||||
setMessages(chats[0].messages);
|
||||
setCurrentChatIndex(0);
|
||||
} else {
|
||||
initialiseNewChat();
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
setChats([]);
|
||||
setMessages([]);
|
||||
setCurrentChatIndex(-1);
|
||||
console.log(e);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { createRef, useState } from 'react';
|
||||
import React from 'react';
|
||||
import ScrollToBottom from 'react-scroll-to-bottom';
|
||||
import useStore from '@store/store';
|
||||
|
||||
|
@ -11,11 +11,15 @@ import CrossIcon from '@icon/CrossIcon';
|
|||
import useSubmit from '@hooks/useSubmit';
|
||||
|
||||
const ChatContent = () => {
|
||||
const [messages, inputRole, setError] = useStore((state) => [
|
||||
state.messages,
|
||||
state.inputRole,
|
||||
state.setError,
|
||||
]);
|
||||
const inputRole = useStore((state) => state.inputRole);
|
||||
const setError = useStore((state) => state.setError);
|
||||
const messages = useStore((state) =>
|
||||
state.chats ? state.chats[state.currentChatIndex].messages : []
|
||||
);
|
||||
const stickyIndex = useStore((state) =>
|
||||
state.chats ? state.chats[state.currentChatIndex].messages.length : 0
|
||||
);
|
||||
|
||||
const { handleSubmit, error } = useSubmit();
|
||||
|
||||
return (
|
||||
|
@ -38,7 +42,12 @@ const ChatContent = () => {
|
|||
<NewMessageButton messageIndex={index} />
|
||||
</>
|
||||
))}
|
||||
<Message role={inputRole} content='' messageIndex={-1} sticky />
|
||||
<Message
|
||||
role={inputRole}
|
||||
content=''
|
||||
messageIndex={stickyIndex}
|
||||
sticky
|
||||
/>
|
||||
|
||||
{error !== '' && (
|
||||
<div className='relative bg-red-600/50 p-2 rounded-sm w-3/5 mt-3'>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import useStore from '@store/store';
|
||||
|
||||
import Avatar from './Avatar';
|
||||
import MessageContent from './MessageContent';
|
||||
|
@ -14,7 +13,8 @@ import RoleSelector from './RoleSelector';
|
|||
// };
|
||||
const backgroundStyle = ['dark:bg-gray-800', 'bg-gray-50 dark:bg-[#444654]'];
|
||||
|
||||
const Message = ({
|
||||
const Message = React.memo(
|
||||
({
|
||||
role,
|
||||
content,
|
||||
messageIndex,
|
||||
|
@ -25,14 +25,10 @@ const Message = ({
|
|||
messageIndex: number;
|
||||
sticky?: boolean;
|
||||
}) => {
|
||||
const stickyIndex = useStore((state) => state.messages.length);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`w-full border-b border-black/10 dark:border-gray-900/50 text-gray-800 dark:text-gray-100 group ${
|
||||
sticky
|
||||
? backgroundStyle[stickyIndex % 2]
|
||||
: backgroundStyle[messageIndex % 2]
|
||||
backgroundStyle[messageIndex % 2]
|
||||
}`}
|
||||
key={
|
||||
messageIndex !== -1
|
||||
|
@ -58,6 +54,7 @@ const Message = ({
|
|||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export default Message;
|
||||
|
|
|
@ -17,7 +17,7 @@ import DownChevronArrow from '@icon/DownChevronArrow';
|
|||
|
||||
import useSubmit from '@hooks/useSubmit';
|
||||
|
||||
import { MessageInterface } from '@type/chat';
|
||||
import { ChatInterface } from '@type/chat';
|
||||
|
||||
import PopupModal from '@components/PopupModal';
|
||||
|
||||
|
@ -56,7 +56,8 @@ const MessageContent = ({
|
|||
);
|
||||
};
|
||||
|
||||
const ContentView = ({
|
||||
const ContentView = React.memo(
|
||||
({
|
||||
role,
|
||||
content,
|
||||
setIsEdit,
|
||||
|
@ -67,24 +68,29 @@ const ContentView = ({
|
|||
setIsEdit: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
messageIndex: number;
|
||||
}) => {
|
||||
const { handleSubmit, error } = useSubmit();
|
||||
const { handleSubmit } = useSubmit();
|
||||
|
||||
const [isDelete, setIsDelete] = useState<boolean>(false);
|
||||
const [copied, setCopied] = useState<boolean>(false);
|
||||
|
||||
const [messages, setMessages] = useStore((state) => [
|
||||
state.messages,
|
||||
state.setMessages,
|
||||
]);
|
||||
const currentChatIndex = useStore((state) => state.currentChatIndex);
|
||||
const setChats = useStore((state) => state.setChats);
|
||||
const lastMessageIndex = useStore((state) =>
|
||||
state.chats ? state.chats[state.currentChatIndex].messages.length - 1 : 0
|
||||
);
|
||||
|
||||
const handleDelete = () => {
|
||||
const updatedMessages = JSON.parse(JSON.stringify(messages));
|
||||
updatedMessages.splice(messageIndex, 1);
|
||||
setMessages(updatedMessages);
|
||||
const updatedChats: ChatInterface[] = JSON.parse(
|
||||
JSON.stringify(useStore.getState().chats)
|
||||
);
|
||||
updatedChats[currentChatIndex].messages.splice(messageIndex, 1);
|
||||
setChats(updatedChats);
|
||||
};
|
||||
|
||||
const handleMove = (direction: 'up' | 'down') => {
|
||||
const updatedMessages = JSON.parse(JSON.stringify(messages));
|
||||
const updatedChats: ChatInterface[] = JSON.parse(
|
||||
JSON.stringify(useStore.getState().chats)
|
||||
);
|
||||
const updatedMessages = updatedChats[currentChatIndex].messages;
|
||||
const temp = updatedMessages[messageIndex];
|
||||
if (direction === 'up') {
|
||||
updatedMessages[messageIndex] = updatedMessages[messageIndex - 1];
|
||||
|
@ -93,13 +99,16 @@ const ContentView = ({
|
|||
updatedMessages[messageIndex] = updatedMessages[messageIndex + 1];
|
||||
updatedMessages[messageIndex + 1] = temp;
|
||||
}
|
||||
setMessages(updatedMessages);
|
||||
setChats(updatedChats);
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
const updatedMessages = JSON.parse(JSON.stringify(messages));
|
||||
const updatedChats: ChatInterface[] = JSON.parse(
|
||||
JSON.stringify(useStore.getState().chats)
|
||||
);
|
||||
const updatedMessages = updatedChats[currentChatIndex].messages;
|
||||
updatedMessages.splice(updatedMessages.length - 1, 1);
|
||||
setMessages(updatedMessages);
|
||||
setChats(updatedChats);
|
||||
handleSubmit();
|
||||
};
|
||||
|
||||
|
@ -177,13 +186,13 @@ const ContentView = ({
|
|||
<div className='flex justify-end gap-2 w-full mt-2'>
|
||||
{isDelete || (
|
||||
<>
|
||||
{role === 'assistant' && messageIndex === messages?.length - 1 && (
|
||||
{role === 'assistant' && messageIndex === lastMessageIndex && (
|
||||
<RefreshButton onClick={handleRefresh} />
|
||||
)}
|
||||
{messageIndex !== 0 && (
|
||||
<UpButton onClick={() => handleMove('up')} />
|
||||
)}
|
||||
{messageIndex !== messages?.length - 1 && (
|
||||
{messageIndex !== lastMessageIndex && (
|
||||
<DownButton onClick={() => handleMove('down')} />
|
||||
)}
|
||||
|
||||
|
@ -207,7 +216,8 @@ const ContentView = ({
|
|||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const MessageButton = ({
|
||||
onClick,
|
||||
|
@ -286,11 +296,9 @@ const EditView = ({
|
|||
messageIndex: number;
|
||||
sticky?: boolean;
|
||||
}) => {
|
||||
const [messages, setMessages, inputRole] = useStore((state) => [
|
||||
state.messages,
|
||||
state.setMessages,
|
||||
state.inputRole,
|
||||
]);
|
||||
const inputRole = useStore((state) => state.inputRole);
|
||||
const setChats = useStore((state) => state.setChats);
|
||||
const currentChatIndex = useStore((state) => state.currentChatIndex);
|
||||
|
||||
const [_content, _setContent] = useState<string>(content);
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
|
@ -319,9 +327,10 @@ const EditView = ({
|
|||
|
||||
const handleSave = () => {
|
||||
if (_content === '') return;
|
||||
const updatedMessages: MessageInterface[] = JSON.parse(
|
||||
JSON.stringify(messages)
|
||||
const updatedChats: ChatInterface[] = JSON.parse(
|
||||
JSON.stringify(useStore.getState().chats)
|
||||
);
|
||||
const updatedMessages = updatedChats[currentChatIndex].messages;
|
||||
if (sticky) {
|
||||
updatedMessages.push({ role: inputRole, content: _content });
|
||||
_setContent('');
|
||||
|
@ -330,26 +339,29 @@ const EditView = ({
|
|||
updatedMessages[messageIndex].content = _content;
|
||||
setIsEdit(false);
|
||||
}
|
||||
setMessages(updatedMessages);
|
||||
setChats(updatedChats);
|
||||
};
|
||||
|
||||
const { handleSubmit } = useSubmit();
|
||||
const handleSaveAndSubmit = () => {
|
||||
if (_content == '') return;
|
||||
const updatedMessages: MessageInterface[] = JSON.parse(
|
||||
JSON.stringify(messages)
|
||||
const updatedChats: ChatInterface[] = JSON.parse(
|
||||
JSON.stringify(useStore.getState().chats)
|
||||
);
|
||||
const updatedMessages = updatedChats[currentChatIndex].messages;
|
||||
if (sticky) {
|
||||
updatedMessages.push({ role: inputRole, content: _content });
|
||||
_setContent('');
|
||||
setMessages(updatedMessages);
|
||||
resetTextAreaHeight();
|
||||
} else {
|
||||
updatedMessages[messageIndex].content = _content;
|
||||
const _updatedMessages = updatedMessages.slice(0, messageIndex + 1);
|
||||
setMessages(_updatedMessages);
|
||||
updatedChats[currentChatIndex].messages = updatedMessages.slice(
|
||||
0,
|
||||
messageIndex + 1
|
||||
);
|
||||
setIsEdit(false);
|
||||
}
|
||||
setChats(updatedChats);
|
||||
handleSubmit();
|
||||
};
|
||||
|
||||
|
|
|
@ -3,27 +3,17 @@ import useStore from '@store/store';
|
|||
|
||||
import PlusIcon from '@icon/PlusIcon';
|
||||
|
||||
import { ChatInterface, MessageInterface } from '@type/chat';
|
||||
import { ChatInterface } from '@type/chat';
|
||||
import { defaultSystemMessage } from '@constants/chat';
|
||||
|
||||
const NewMessageButton = ({ messageIndex }: { messageIndex: number }) => {
|
||||
const [
|
||||
messages,
|
||||
chats,
|
||||
setMessages,
|
||||
currentChatIndex,
|
||||
setChats,
|
||||
setCurrentChatIndex,
|
||||
] = useStore((state) => [
|
||||
state.messages,
|
||||
state.chats,
|
||||
state.setMessages,
|
||||
state.currentChatIndex,
|
||||
state.setChats,
|
||||
state.setCurrentChatIndex,
|
||||
]);
|
||||
const NewMessageButton = React.memo(
|
||||
({ messageIndex }: { messageIndex: number }) => {
|
||||
const setChats = useStore((state) => state.setChats);
|
||||
const currentChatIndex = useStore((state) => state.currentChatIndex);
|
||||
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
|
||||
|
||||
const addChat = () => {
|
||||
const chats = useStore.getState().chats;
|
||||
if (chats) {
|
||||
const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats));
|
||||
let titleIndex = 1;
|
||||
|
@ -39,7 +29,6 @@ const NewMessageButton = ({ messageIndex }: { messageIndex: number }) => {
|
|||
messages: [{ role: 'system', content: defaultSystemMessage }],
|
||||
});
|
||||
setChats(updatedChats);
|
||||
setMessages(updatedChats[0].messages);
|
||||
setCurrentChatIndex(0);
|
||||
}
|
||||
};
|
||||
|
@ -48,14 +37,14 @@ const NewMessageButton = ({ messageIndex }: { messageIndex: number }) => {
|
|||
if (currentChatIndex === -1) {
|
||||
addChat();
|
||||
} else {
|
||||
const updatedMessages: MessageInterface[] = JSON.parse(
|
||||
JSON.stringify(messages)
|
||||
const updatedChats: ChatInterface[] = JSON.parse(
|
||||
JSON.stringify(useStore.getState().chats)
|
||||
);
|
||||
updatedMessages.splice(messageIndex + 1, 0, {
|
||||
updatedChats[currentChatIndex].messages.splice(messageIndex + 1, 0, {
|
||||
content: '',
|
||||
role: 'user',
|
||||
});
|
||||
setMessages(updatedMessages);
|
||||
setChats(updatedChats);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -69,6 +58,7 @@ const NewMessageButton = ({ messageIndex }: { messageIndex: number }) => {
|
|||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export default NewMessageButton;
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
|||
import useStore from '@store/store';
|
||||
|
||||
import DownChevronArrow from '@icon/DownChevronArrow';
|
||||
import { MessageInterface, Role, roles } from '@type/chat';
|
||||
import { ChatInterface, Role, roles } from '@type/chat';
|
||||
|
||||
const RoleSelector = ({
|
||||
role,
|
||||
|
@ -13,11 +13,9 @@ const RoleSelector = ({
|
|||
messageIndex: number;
|
||||
sticky?: boolean;
|
||||
}) => {
|
||||
const [messages, setMessages, setInputRole] = useStore((state) => [
|
||||
state.messages,
|
||||
state.setMessages,
|
||||
state.setInputRole,
|
||||
]);
|
||||
const setInputRole = useStore((state) => state.setInputRole);
|
||||
const setChats = useStore((state) => state.setChats);
|
||||
const currentChatIndex = useStore((state) => state.currentChatIndex);
|
||||
|
||||
const [dropDown, setDropDown] = useState<boolean>(false);
|
||||
|
||||
|
@ -46,11 +44,12 @@ const RoleSelector = ({
|
|||
className='px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white cursor-pointer'
|
||||
onClick={() => {
|
||||
if (!sticky) {
|
||||
const updatedMessages: MessageInterface[] = JSON.parse(
|
||||
JSON.stringify(messages)
|
||||
const updatedChats: ChatInterface[] = JSON.parse(
|
||||
JSON.stringify(useStore.getState().chats)
|
||||
);
|
||||
updatedMessages[messageIndex].role = r;
|
||||
setMessages(updatedMessages);
|
||||
updatedChats[currentChatIndex].messages[messageIndex].role =
|
||||
r;
|
||||
setChats(updatedChats);
|
||||
} else {
|
||||
setInputRole(r);
|
||||
}
|
||||
|
@ -66,5 +65,4 @@ const RoleSelector = ({
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RoleSelector;
|
||||
|
|
|
@ -5,15 +5,12 @@ import CrossIcon2 from '@icon/CrossIcon2';
|
|||
import { validateApiKey } from '@api/customApi';
|
||||
|
||||
const ConfigMenu = () => {
|
||||
const [apiKey, setApiKey, apiFree, setApiFree, openConfig, setOpenConfig] =
|
||||
useStore((state) => [
|
||||
state.apiKey,
|
||||
state.setApiKey,
|
||||
state.apiFree,
|
||||
state.setApiFree,
|
||||
state.openConfig,
|
||||
state.setOpenConfig,
|
||||
]);
|
||||
const apiKey = useStore((state) => state.apiKey);
|
||||
const setApiKey = useStore((state) => state.setApiKey);
|
||||
const apiFree = useStore((state) => state.apiFree);
|
||||
const setApiFree = useStore((state) => state.setApiFree);
|
||||
const openConfig = useStore((state) => state.openConfig);
|
||||
const setOpenConfig = useStore((state) => state.setOpenConfig);
|
||||
|
||||
const [_apiKey, _setApiKey] = useState<string>(apiKey || '');
|
||||
const [error, setError] = useState<boolean>(false);
|
||||
|
|
|
@ -10,11 +10,8 @@ import CrossIcon from '@icon/CrossIcon';
|
|||
import useInitialiseNewChat from '@hooks/useInitialiseNewChat';
|
||||
|
||||
const ChatHistoryList = () => {
|
||||
const [chats, setCurrentChatIndex, setMessages] = useStore((state) => [
|
||||
state.chats,
|
||||
state.setCurrentChatIndex,
|
||||
state.setMessages,
|
||||
]);
|
||||
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
|
||||
const chats = useStore((state) => state.chats);
|
||||
|
||||
return (
|
||||
<div className='flex-col flex-1 overflow-y-auto border-b border-white/20'>
|
||||
|
@ -27,7 +24,6 @@ const ChatHistoryList = () => {
|
|||
chatIndex={index}
|
||||
onClick={() => {
|
||||
setCurrentChatIndex(index);
|
||||
setMessages(chats[index].messages);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
@ -66,14 +62,9 @@ const ChatHistory = ({
|
|||
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||
}) => {
|
||||
const initialiseNewChat = useInitialiseNewChat();
|
||||
const [chats, setChats, currentChatIndex, setMessages, setCurrentChatIndex] =
|
||||
useStore((state) => [
|
||||
state.chats,
|
||||
state.setChats,
|
||||
state.currentChatIndex,
|
||||
state.setMessages,
|
||||
state.setCurrentChatIndex,
|
||||
]);
|
||||
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
|
||||
const setChats = useStore((state) => state.setChats);
|
||||
const currentChatIndex = useStore((state) => state.currentChatIndex);
|
||||
|
||||
const [isDelete, setIsDelete] = useState<boolean>(false);
|
||||
const [isEdit, setIsEdit] = useState<boolean>(false);
|
||||
|
@ -83,7 +74,7 @@ const ChatHistory = ({
|
|||
|
||||
const handleTick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
const updatedChats = JSON.parse(JSON.stringify(chats));
|
||||
const updatedChats = JSON.parse(JSON.stringify(useStore.getState().chats));
|
||||
if (isEdit) {
|
||||
updatedChats[chatIndex].title = _title;
|
||||
setChats(updatedChats);
|
||||
|
@ -92,7 +83,6 @@ const ChatHistory = ({
|
|||
updatedChats.splice(chatIndex, 1);
|
||||
if (updatedChats.length > 0) {
|
||||
setCurrentChatIndex(0);
|
||||
setMessages(updatedChats[0].messages);
|
||||
setChats(updatedChats);
|
||||
} else {
|
||||
initialiseNewChat();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import useStore from '@store/store';
|
||||
|
||||
import NewChat from './NewChat';
|
||||
import ChatHistoryList from './ChatHistoryList';
|
||||
|
|
|
@ -4,10 +4,8 @@ import useStore from '@store/store';
|
|||
import PersonIcon from '@icon/PersonIcon';
|
||||
|
||||
const Config = () => {
|
||||
const [apiFree, setOpenConfig] = useStore((state) => [
|
||||
state.apiFree,
|
||||
state.setOpenConfig,
|
||||
]);
|
||||
const apiFree = useStore((state) => state.apiFree);
|
||||
const setOpenConfig = useStore((state) => state.setOpenConfig);
|
||||
|
||||
return (
|
||||
<a
|
||||
|
|
|
@ -1,20 +1,10 @@
|
|||
import React from 'react';
|
||||
import useStore from '@store/store';
|
||||
|
||||
import PlusIcon from '@icon/PlusIcon';
|
||||
|
||||
import useAddChat from '@hooks/useAddChat';
|
||||
|
||||
const NewChat = () => {
|
||||
const [chats, setChats, setCurrentChatIndex, setMessages] = useStore(
|
||||
(state) => [
|
||||
state.chats,
|
||||
state.setChats,
|
||||
state.setCurrentChatIndex,
|
||||
state.setMessages,
|
||||
]
|
||||
);
|
||||
|
||||
const addChat = useAddChat();
|
||||
|
||||
return (
|
||||
|
|
|
@ -5,10 +5,12 @@ import PlusIcon from '@icon/PlusIcon';
|
|||
import useAddChat from '@hooks/useAddChat';
|
||||
|
||||
const MobileBar = () => {
|
||||
const [chats, currentChatIndex] = useStore((state) => [
|
||||
state.chats,
|
||||
state.currentChatIndex,
|
||||
]);
|
||||
const chatTitle = useStore((state) =>
|
||||
state.chats && state.chats.length > 0
|
||||
? state.chats[state.currentChatIndex].title
|
||||
: 'New Chat'
|
||||
);
|
||||
|
||||
const addChat = useAddChat();
|
||||
|
||||
return (
|
||||
|
@ -42,11 +44,7 @@ const MobileBar = () => {
|
|||
<line x1='3' y1='18' x2='21' y2='18'></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 className='flex-1 text-center text-base font-normal'>
|
||||
{chats && chats.length > 0
|
||||
? chats[currentChatIndex]?.title
|
||||
: 'New Chat'}
|
||||
</h1>
|
||||
<h1 className='flex-1 text-center text-base font-normal'>{chatTitle}</h1>
|
||||
<button type='button' className='px-3 text-gray-400' onClick={addChat}>
|
||||
<PlusIcon className='h-6 w-6' />
|
||||
</button>
|
||||
|
|
|
@ -4,16 +4,11 @@ import { defaultSystemMessage } from '@constants/chat';
|
|||
import { ChatInterface } from '@type/chat';
|
||||
|
||||
const useAddChat = () => {
|
||||
const [chats, setChats, setCurrentChatIndex, setMessages] = useStore(
|
||||
(state) => [
|
||||
state.chats,
|
||||
state.setChats,
|
||||
state.setCurrentChatIndex,
|
||||
state.setMessages,
|
||||
]
|
||||
);
|
||||
const setChats = useStore((state) => state.setChats);
|
||||
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
|
||||
|
||||
const addChat = () => {
|
||||
const chats = useStore.getState().chats;
|
||||
if (chats) {
|
||||
const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats));
|
||||
let titleIndex = 1;
|
||||
|
@ -29,7 +24,6 @@ const useAddChat = () => {
|
|||
messages: [{ role: 'system', content: defaultSystemMessage }],
|
||||
});
|
||||
setChats(updatedChats);
|
||||
setMessages(updatedChats[0].messages);
|
||||
setCurrentChatIndex(0);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,11 +4,8 @@ import { MessageInterface } from '@type/chat';
|
|||
import { defaultSystemMessage } from '@constants/chat';
|
||||
|
||||
const useInitialiseNewChat = () => {
|
||||
const [setChats, setMessages, setCurrentChatIndex] = useStore((state) => [
|
||||
state.setChats,
|
||||
state.setMessages,
|
||||
state.setCurrentChatIndex,
|
||||
]);
|
||||
const setChats = useStore((state) => state.setChats);
|
||||
const setCurrentChatIndex = useStore((state) => state.setCurrentChatIndex);
|
||||
|
||||
const initialiseNewChat = () => {
|
||||
const message: MessageInterface = {
|
||||
|
@ -21,7 +18,6 @@ const useInitialiseNewChat = () => {
|
|||
messages: [message],
|
||||
},
|
||||
]);
|
||||
setMessages([message]);
|
||||
setCurrentChatIndex(0);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import useStore from '@store/store';
|
||||
|
||||
const useSaveToLocalStorage = () => {
|
||||
const chats = useStore((state) => state.chats);
|
||||
const chatsRef = useRef(useStore.getState().chats);
|
||||
|
||||
useEffect(() => {
|
||||
if (chats) localStorage.setItem('chats', JSON.stringify(chats));
|
||||
}, [chats]);
|
||||
const unsubscribe = useStore.subscribe((state) => {
|
||||
if (chatsRef && chatsRef.current !== state.chats) {
|
||||
chatsRef.current = state.chats;
|
||||
localStorage.setItem('chats', JSON.stringify(state.chats));
|
||||
}
|
||||
});
|
||||
|
||||
return unsubscribe;
|
||||
}, []);
|
||||
};
|
||||
|
||||
export default useSaveToLocalStorage;
|
||||
|
|
|
@ -1,48 +1,45 @@
|
|||
import React from 'react';
|
||||
import useStore from '@store/store';
|
||||
import { MessageInterface } from '@type/chat';
|
||||
import { ChatInterface } from '@type/chat';
|
||||
import { getChatCompletionStream as getChatCompletionStreamFree } from '@api/freeApi';
|
||||
import { getChatCompletionStream as getChatCompletionStreamCustom } from '@api/customApi';
|
||||
import { parseEventSource } from '@api/helper';
|
||||
|
||||
const useSubmit = () => {
|
||||
const [
|
||||
error,
|
||||
setError,
|
||||
apiFree,
|
||||
apiKey,
|
||||
setMessages,
|
||||
setGenerating,
|
||||
generating,
|
||||
] = useStore((state) => [
|
||||
state.error,
|
||||
state.setError,
|
||||
state.apiFree,
|
||||
state.apiKey,
|
||||
state.setMessages,
|
||||
state.setGenerating,
|
||||
state.generating,
|
||||
]);
|
||||
const error = useStore((state) => state.error);
|
||||
const setError = useStore((state) => state.setError);
|
||||
const apiFree = useStore((state) => state.apiFree);
|
||||
const apiKey = useStore((state) => state.apiKey);
|
||||
const setGenerating = useStore((state) => state.setGenerating);
|
||||
const generating = useStore((state) => state.generating);
|
||||
const currentChatIndex = useStore((state) => state.currentChatIndex);
|
||||
const setChats = useStore((state) => state.setChats);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (generating) return;
|
||||
const messages = useStore.getState().messages;
|
||||
const chats = useStore.getState().chats;
|
||||
if (generating || !chats) return;
|
||||
|
||||
const updatedMessages: MessageInterface[] = JSON.parse(
|
||||
JSON.stringify(messages)
|
||||
);
|
||||
const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats));
|
||||
|
||||
updatedMessages.push({ role: 'assistant', content: '' });
|
||||
updatedChats[currentChatIndex].messages.push({
|
||||
role: 'assistant',
|
||||
content: '',
|
||||
});
|
||||
|
||||
setMessages(updatedMessages);
|
||||
setChats(updatedChats);
|
||||
setGenerating(true);
|
||||
let stream;
|
||||
|
||||
try {
|
||||
if (apiFree) {
|
||||
stream = await getChatCompletionStreamFree(messages);
|
||||
stream = await getChatCompletionStreamFree(
|
||||
chats[currentChatIndex].messages
|
||||
);
|
||||
} else if (apiKey) {
|
||||
stream = await getChatCompletionStreamCustom(apiKey, messages);
|
||||
stream = await getChatCompletionStreamCustom(
|
||||
apiKey,
|
||||
chats[currentChatIndex].messages
|
||||
);
|
||||
}
|
||||
|
||||
if (stream) {
|
||||
|
@ -65,11 +62,12 @@ const useSubmit = () => {
|
|||
}
|
||||
}, '');
|
||||
|
||||
const updatedMessages: MessageInterface[] = JSON.parse(
|
||||
JSON.stringify(useStore.getState().messages)
|
||||
const updatedChats: ChatInterface[] = JSON.parse(
|
||||
JSON.stringify(useStore.getState().chats)
|
||||
);
|
||||
const updatedMessages = updatedChats[currentChatIndex].messages;
|
||||
updatedMessages[updatedMessages.length - 1].content += resultString;
|
||||
setMessages(updatedMessages);
|
||||
setChats(updatedChats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import useStore from '@store/store';
|
||||
import { ChatInterface, MessageInterface } from '@type/chat';
|
||||
|
||||
const useUpdateCharts = () => {
|
||||
const [chats, messages, setChats, currentChatIndex] = useStore((state) => [
|
||||
state.chats,
|
||||
state.messages,
|
||||
state.setChats,
|
||||
state.currentChatIndex,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentChatIndex !== -1 && chats && chats.length > 0) {
|
||||
const updatedChats: ChatInterface[] = JSON.parse(JSON.stringify(chats));
|
||||
const updatedMessages: MessageInterface[] = JSON.parse(
|
||||
JSON.stringify(messages)
|
||||
);
|
||||
updatedChats[currentChatIndex].messages = updatedMessages;
|
||||
setChats(updatedChats);
|
||||
}
|
||||
}, [messages]);
|
||||
};
|
||||
|
||||
export default useUpdateCharts;
|
Loading…
Reference in a new issue