Spaces:
Paused
Paused
| import { useEffect, useRef } from 'react'; | |
| import { GetServerSideProps } from 'next'; | |
| import { useTranslation } from 'next-i18next'; | |
| import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; | |
| import Head from 'next/head'; | |
| import { useCreateReducer } from '@/hooks/useCreateReducer'; | |
| import { | |
| cleanConversationHistory, | |
| cleanSelectedConversation, | |
| } from '@/utils/app/clean'; | |
| import { DEFAULT_SYSTEM_PROMPT, DEFAULT_TEMPERATURE } from '@/utils/app/const'; | |
| import { | |
| saveConversation, | |
| saveConversations, | |
| updateConversation, | |
| } from '@/utils/app/conversation'; | |
| import { getSettings } from '@/utils/app/settings'; | |
| import { Conversation } from '@/types/chat'; | |
| import { KeyValuePair } from '@/types/data'; | |
| import { OpenAIModelID, OpenAIModels, fallbackModelID } from '@/types/openai'; | |
| import { Chat } from '@/components/Chat/Chat'; | |
| import HomeContext from './home.context'; | |
| import { HomeInitialState, initialState } from './home.state'; | |
| import { v4 as uuidv4 } from 'uuid'; | |
| interface Props { | |
| serverSideApiKeyIsSet: boolean; | |
| serverSidePluginKeysSet: boolean; | |
| defaultModelId: OpenAIModelID; | |
| } | |
| const Home = ({ | |
| serverSideApiKeyIsSet, | |
| serverSidePluginKeysSet, | |
| defaultModelId, | |
| }: Props) => { | |
| const { t } = useTranslation('chat'); | |
| const contextValue = useCreateReducer<HomeInitialState>({ | |
| initialState, | |
| }); | |
| const { | |
| state: { | |
| apiKey, | |
| lightMode, | |
| folders, | |
| conversations, | |
| selectedConversation, | |
| prompts, | |
| temperature, | |
| }, | |
| dispatch, | |
| } = contextValue; | |
| const stopConversationRef = useRef<boolean>(false); | |
| const handleSelectConversation = (conversation: Conversation) => { | |
| dispatch({ | |
| field: 'selectedConversation', | |
| value: conversation, | |
| }); | |
| saveConversation(conversation); | |
| }; | |
| // CONVERSATION OPERATIONS -------------------------------------------- | |
| const handleNewConversation = () => { | |
| const lastConversation = conversations[conversations.length - 1]; | |
| const newConversation: Conversation = { | |
| id: uuidv4(), | |
| name: t('New Conversation'), | |
| messages: [], | |
| model: lastConversation?.model || { | |
| id: OpenAIModels[defaultModelId].id, | |
| name: OpenAIModels[defaultModelId].name, | |
| maxLength: OpenAIModels[defaultModelId].maxLength, | |
| tokenLimit: OpenAIModels[defaultModelId].tokenLimit, | |
| }, | |
| prompt: DEFAULT_SYSTEM_PROMPT, | |
| temperature: lastConversation?.temperature ?? DEFAULT_TEMPERATURE, | |
| folderId: null, | |
| }; | |
| const updatedConversations = [...conversations, newConversation]; | |
| dispatch({ field: 'selectedConversation', value: newConversation }); | |
| dispatch({ field: 'conversations', value: updatedConversations }); | |
| saveConversation(newConversation); | |
| saveConversations(updatedConversations); | |
| dispatch({ field: 'loading', value: false }); | |
| }; | |
| const handleUpdateConversation = ( | |
| conversation: Conversation, | |
| data: KeyValuePair, | |
| ) => { | |
| const updatedConversation = { | |
| ...conversation, | |
| [data.key]: data.value, | |
| }; | |
| const { single, all } = updateConversation( | |
| updatedConversation, | |
| conversations, | |
| ); | |
| dispatch({ field: 'selectedConversation', value: single }); | |
| dispatch({ field: 'conversations', value: all }); | |
| }; | |
| // EFFECTS -------------------------------------------- | |
| useEffect(() => { | |
| if (window.innerWidth < 640) { | |
| dispatch({ field: 'showChatbar', value: false }); | |
| } | |
| }, [selectedConversation]); | |
| useEffect(() => { | |
| defaultModelId && | |
| dispatch({ field: 'defaultModelId', value: defaultModelId }); | |
| serverSideApiKeyIsSet && | |
| dispatch({ | |
| field: 'serverSideApiKeyIsSet', | |
| value: serverSideApiKeyIsSet, | |
| }); | |
| serverSidePluginKeysSet && | |
| dispatch({ | |
| field: 'serverSidePluginKeysSet', | |
| value: serverSidePluginKeysSet, | |
| }); | |
| }, [defaultModelId, serverSideApiKeyIsSet, serverSidePluginKeysSet]); | |
| // ON LOAD -------------------------------------------- | |
| useEffect(() => { | |
| const settings = getSettings(); | |
| if (settings?.theme) { | |
| dispatch({ | |
| field: 'lightMode', | |
| value: settings.theme, | |
| }); | |
| } | |
| dispatch({ field: 'apiKey', value: "test" }); | |
| const pluginKeys = localStorage.getItem('pluginKeys'); | |
| if (serverSidePluginKeysSet) { | |
| dispatch({ field: 'pluginKeys', value: [] }); | |
| localStorage.removeItem('pluginKeys'); | |
| } else if (pluginKeys) { | |
| dispatch({ field: 'pluginKeys', value: pluginKeys }); | |
| } | |
| if (window.innerWidth < 640) { | |
| dispatch({ field: 'showChatbar', value: false }); | |
| dispatch({ field: 'showPromptbar', value: false }); | |
| } | |
| const showChatbar = localStorage.getItem('showChatbar'); | |
| if (showChatbar) { | |
| dispatch({ field: 'showChatbar', value: showChatbar === 'true' }); | |
| } | |
| const showPromptbar = localStorage.getItem('showPromptbar'); | |
| if (showPromptbar) { | |
| dispatch({ field: 'showPromptbar', value: showPromptbar === 'true' }); | |
| } | |
| const folders = localStorage.getItem('folders'); | |
| if (folders) { | |
| dispatch({ field: 'folders', value: JSON.parse(folders) }); | |
| } | |
| const prompts = localStorage.getItem('prompts'); | |
| if (prompts) { | |
| dispatch({ field: 'prompts', value: JSON.parse(prompts) }); | |
| } | |
| const conversationHistory = localStorage.getItem('conversationHistory'); | |
| if (conversationHistory) { | |
| const parsedConversationHistory: Conversation[] = | |
| JSON.parse(conversationHistory); | |
| const cleanedConversationHistory = cleanConversationHistory( | |
| parsedConversationHistory, | |
| ); | |
| dispatch({ field: 'conversations', value: cleanedConversationHistory }); | |
| } | |
| const selectedConversation = localStorage.getItem('selectedConversation'); | |
| if (selectedConversation) { | |
| const parsedSelectedConversation: Conversation = | |
| JSON.parse(selectedConversation); | |
| const cleanedSelectedConversation = cleanSelectedConversation( | |
| parsedSelectedConversation, | |
| ); | |
| dispatch({ | |
| field: 'selectedConversation', | |
| value: cleanedSelectedConversation, | |
| }); | |
| } else { | |
| const lastConversation = conversations[conversations.length - 1]; | |
| dispatch({ | |
| field: 'selectedConversation', | |
| value: { | |
| id: uuidv4(), | |
| name: t('New Conversation'), | |
| messages: [], | |
| model: OpenAIModels[defaultModelId], | |
| prompt: DEFAULT_SYSTEM_PROMPT, | |
| temperature: lastConversation?.temperature ?? DEFAULT_TEMPERATURE, | |
| folderId: null, | |
| }, | |
| }); | |
| } | |
| }, [ | |
| defaultModelId, | |
| dispatch, | |
| serverSideApiKeyIsSet, | |
| serverSidePluginKeysSet, | |
| ]); | |
| return ( | |
| <HomeContext.Provider | |
| value={{ | |
| ...contextValue, | |
| handleNewConversation, | |
| handleSelectConversation, | |
| handleUpdateConversation, | |
| }} | |
| > | |
| <Head> | |
| <title>Chatbot Mini</title> | |
| <meta name="description" content="Mini chatbot UI" /> | |
| <meta | |
| name="viewport" | |
| content="height=device-height ,width=device-width, initial-scale=1, user-scalable=no" | |
| /> | |
| <link rel="icon" href="/favicon.ico" /> | |
| </Head> | |
| <main | |
| className={`flex h-screen w-screen flex-col text-sm text-white dark:text-white ${lightMode}`} | |
| > | |
| <div className="flex h-full w-full pt-[48px] sm:pt-0"> | |
| <div className="flex flex-1"> | |
| <Chat stopConversationRef={stopConversationRef} /> | |
| </div> | |
| </div> | |
| </main> | |
| </HomeContext.Provider> | |
| ); | |
| }; | |
| export default Home; | |
| export const getServerSideProps: GetServerSideProps = async ({ locale }) => { | |
| const defaultModelId = | |
| (process.env.DEFAULT_MODEL && | |
| Object.values(OpenAIModelID).includes( | |
| process.env.DEFAULT_MODEL as OpenAIModelID, | |
| ) && | |
| process.env.DEFAULT_MODEL) || | |
| fallbackModelID; | |
| let serverSidePluginKeysSet = false; | |
| const googleApiKey = process.env.GOOGLE_API_KEY; | |
| const googleCSEId = process.env.GOOGLE_CSE_ID; | |
| if (googleApiKey && googleCSEId) { | |
| serverSidePluginKeysSet = true; | |
| } | |
| return { | |
| props: { | |
| serverSideApiKeyIsSet: !!process.env.OPENAI_API_KEY, | |
| defaultModelId, | |
| serverSidePluginKeysSet, | |
| ...(await serverSideTranslations(locale ?? 'en', [ | |
| 'common', | |
| 'chat', | |
| 'sidebar', | |
| 'markdown', | |
| 'promptbar', | |
| 'settings', | |
| ])), | |
| }, | |
| }; | |
| }; | |