import { useCallback, useContext, useEffect } from 'react'; import { useTranslation } from 'next-i18next'; import { useCreateReducer } from '@/hooks/useCreateReducer'; import { DEFAULT_SYSTEM_PROMPT, DEFAULT_TEMPERATURE } from '@/utils/app/const'; import { saveConversation, saveConversations } from '@/utils/app/conversation'; import { saveFolders } from '@/utils/app/folders'; import { exportData, importData } from '@/utils/app/importExport'; import { Conversation } from '@/types/chat'; import { LatestExportFormat, SupportedExportFormats } from '@/types/export'; import { OllamaModels } from '@/types/ollama'; import HomeContext from '@/pages/api/home/home.context'; import { ChatFolders } from './components/ChatFolders'; import { ChatbarSettings } from './components/ChatbarSettings'; import { Conversations } from './components/Conversations'; import Sidebar from '../Sidebar'; import ChatbarContext from './Chatbar.context'; import { ChatbarInitialState, initialState } from './Chatbar.state'; import { v4 as uuidv4 } from 'uuid'; export const Chatbar = () => { const { t } = useTranslation('sidebar'); const chatBarContextValue = useCreateReducer({ initialState, }); const { state: { conversations, showChatbar, defaultModelId, folders }, dispatch: homeDispatch, handleCreateFolder, handleNewConversation, handleUpdateConversation, } = useContext(HomeContext); const { state: { searchTerm, filteredConversations }, dispatch: chatDispatch, } = chatBarContextValue; const handleExportData = () => { exportData(); }; const handleImportConversations = (data: SupportedExportFormats) => { const { history, folders, prompts }: LatestExportFormat = importData(data); homeDispatch({ field: 'conversations', value: history }); homeDispatch({ field: 'selectedConversation', value: history[history.length - 1], }); homeDispatch({ field: 'folders', value: folders }); homeDispatch({ field: 'prompts', value: prompts }); window.location.reload(); }; const handleClearConversations = () => { defaultModelId && homeDispatch({ field: 'selectedConversation', value: { id: uuidv4(), name: t('New Conversation'), messages: [], model: OllamaModels[defaultModelId], prompt: DEFAULT_SYSTEM_PROMPT, temperature: DEFAULT_TEMPERATURE, folderId: null, }, }); homeDispatch({ field: 'conversations', value: [] }); localStorage.removeItem('conversationHistory'); localStorage.removeItem('selectedConversation'); const updatedFolders = folders.filter((f) => f.type !== 'chat'); homeDispatch({ field: 'folders', value: updatedFolders }); saveFolders(updatedFolders); }; const handleDeleteConversation = (conversation: Conversation) => { const updatedConversations = conversations.filter( (c) => c.id !== conversation.id, ); homeDispatch({ field: 'conversations', value: updatedConversations }); chatDispatch({ field: 'searchTerm', value: '' }); saveConversations(updatedConversations); if (updatedConversations.length > 0) { homeDispatch({ field: 'selectedConversation', value: updatedConversations[updatedConversations.length - 1], }); saveConversation(updatedConversations[updatedConversations.length - 1]); } else { defaultModelId && homeDispatch({ field: 'selectedConversation', value: { id: uuidv4(), name: t('New Conversation'), messages: [], model: OllamaModels[defaultModelId], prompt: DEFAULT_SYSTEM_PROMPT, temperature: DEFAULT_TEMPERATURE, folderId: null, }, }); localStorage.removeItem('selectedConversation'); } }; const handleToggleChatbar = () => { homeDispatch({ field: 'showChatbar', value: !showChatbar }); localStorage.setItem('showChatbar', JSON.stringify(!showChatbar)); }; const handleDrop = (e: any) => { if (e.dataTransfer) { const conversation = JSON.parse(e.dataTransfer.getData('conversation')); handleUpdateConversation(conversation, { key: 'folderId', value: 0 }); chatDispatch({ field: 'searchTerm', value: '' }); e.target.style.background = 'none'; } }; useEffect(() => { if (searchTerm) { chatDispatch({ field: 'filteredConversations', value: conversations.filter((conversation) => { const searchable = conversation.name.toLocaleLowerCase() + ' ' + conversation.messages.map((message) => message.content).join(' '); return searchable.toLowerCase().includes(searchTerm.toLowerCase()); }), }); } else { chatDispatch({ field: 'filteredConversations', value: conversations, }); } }, [searchTerm, conversations, chatDispatch]); return ( side={'left'} isOpen={showChatbar} addItemButtonTitle={t('New chat')} itemComponent={} folderComponent={} items={filteredConversations} searchTerm={searchTerm} handleSearchTerm={(searchTerm: string) => chatDispatch({ field: 'searchTerm', value: searchTerm }) } toggleOpen={handleToggleChatbar} handleCreateItem={handleNewConversation} handleCreateFolder={() => handleCreateFolder(t('New folder'), 'chat')} handleDrop={handleDrop} footerComponent={} /> ); };