From 7bbf89728e51054db686f9c568e86d885cdba39e Mon Sep 17 00:00:00 2001 From: ahmetselman Date: Sun, 8 Dec 2024 16:20:17 +0100 Subject: [PATCH 01/14] feat: implement report chat functionality & add chatbot to toolbar --- package.json | 2 + src/app/providers.tsx | 27 +- src/components/Chatbot/Chatbot.tsx | 64 +++-- src/components/Chatbot/ChatbotSidebar.tsx | 2 +- .../DownloadPortal/CountryReports.tsx | 2 + src/components/Topbar/Topbar.tsx | 12 +- src/domain/contexts/ChatbotContext.tsx | 128 ++++++++++ .../entities/chatbot/BackendCommunication.ts | 2 +- src/domain/entities/chatbot/Chatbot.ts | 2 + src/domain/props/ChatbotSidebarProps.tsx | 2 +- .../repositories/ChatbotRepositoryImpl.ts | 1 + .../DownloadPortalOperations.tsx | 20 +- yarn.lock | 232 +++++++++++++++++- 13 files changed, 448 insertions(+), 48 deletions(-) create mode 100644 src/domain/contexts/ChatbotContext.tsx diff --git a/package.json b/package.json index 7c11e178..bb6bfe93 100644 --- a/package.json +++ b/package.json @@ -72,8 +72,10 @@ "react-leaflet-cluster": "^2.1.0", "react-markdown": "^9.0.1", "react-pdf": "^9.1.1", + "react-pdftotext": "^1.3.4", "rehype-sanitize": "^6.0.0", "remark-gfm": "^4.0.0", + "sharp": "^0.33.5", "tailwind-variants": "0.1.20", "uuid": "^11.0.3" }, diff --git a/src/app/providers.tsx b/src/app/providers.tsx index 6d961ea9..21a92606 100644 --- a/src/app/providers.tsx +++ b/src/app/providers.tsx @@ -5,11 +5,12 @@ import { QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { useRouter } from 'next/navigation'; import { ThemeProvider as NextThemesProvider } from 'next-themes'; -import type { ThemeProviderProps } from 'next-themes/dist/types.d.ts'; +import type { ThemeProviderProps } from 'next-themes/dist/types'; import * as React from 'react'; import { cachedQueryClient } from '@/config/queryClient'; import { AccordionsModalProvider } from '@/domain/contexts/AccodionsModalContext'; +import { ChatbotProvider } from '@/domain/contexts/ChatbotContext'; import { SelectedAlertProvider } from '@/domain/contexts/SelectedAlertContext'; import { SelectedCountryIdProvider } from '@/domain/contexts/SelectedCountryIdContext'; import { SelectedMapProvider } from '@/domain/contexts/SelectedMapContext'; @@ -28,17 +29,19 @@ export function Providers({ children, themeProps }: ProvidersProps) { - - - - - - {children} - - - - - + + + + + + + {children} + + + + + + diff --git a/src/components/Chatbot/Chatbot.tsx b/src/components/Chatbot/Chatbot.tsx index a6919133..fbb8f199 100644 --- a/src/components/Chatbot/Chatbot.tsx +++ b/src/components/Chatbot/Chatbot.tsx @@ -24,29 +24,37 @@ import { TYPING_PLACEHOLDER, WELCOME_MESSAGE, } from '@/domain/constant/chatbot/Chatbot'; +import { useChatbot } from '@/domain/contexts/ChatbotContext'; import { APIError } from '@/domain/entities/chatbot/BackendCommunication'; -import { IChat } from '@/domain/entities/chatbot/Chatbot'; import { SenderRole } from '@/domain/enums/SenderRole'; import ChatbotRepository from '@/domain/repositories/ChatbotRepository'; import ChatbotOperations from '@/operations/chatbot/Chatbot'; -import { useMediaQuery } from '@/utils/resolution'; import TypingDots from '../TypingText/TypingDot'; import ChatbotSidebar from './ChatbotSidebar'; export default function HungerMapChatbot() { const chatbot = container.resolve('ChatbotRepository'); - const [isOpen, setIsOpen] = useState(false); + const { + chats, + setChats, + currentChatIndex, + setCurrentChatIndex, + startNewChat, + isOpen, + isMobile, + isSidebarOpen, + setIsOpen, + setIsSidebarOpen, + } = useChatbot(); + const [isFullScreen, setIsFullScreen] = useState(false); - const [isSidebarOpen, setIsSidebarOpen] = useState(false); const [isUserMessageSent, setIsUserMessageSent] = useState(false); - const [chats, setChats] = useState([{ id: 1, title: 'Chat 1', messages: [], isTyping: false }]); - const [currentChatIndex, setCurrentChatIndex] = useState(0); const [input, setInput] = useState(''); const [isResponseAnimated, setIsResponseAnimated] = useState(true); + const inputRef = useRef(null); const chatEndRef = useRef(null); - const isMobile = useMediaQuery('(max-width: 640px)'); const toggleChat = (): void => { if (isMobile) { @@ -64,15 +72,6 @@ export default function HungerMapChatbot() { } }; - const startNewChat = (): void => { - const newChat: IChat = { id: chats.length + 1, title: `Chat ${chats.length + 1}`, messages: [], isTyping: false }; - setChats([...chats, newChat]); - setCurrentChatIndex(chats.length); - if (isMobile) { - setIsSidebarOpen(false); - } - }; - const setTypingStatus = (chatIndex: number, isTyping: boolean): void => { setChats((prevChats) => prevChats.map((chat, index) => (index === chatIndex ? { ...chat, isTyping } : chat))); }; @@ -97,8 +96,17 @@ export default function HungerMapChatbot() { const previousMessages = chats[currentChatIndex].messages; let aiResponse = ''; try { - const response = await chatbot.sendMessage(text, { previous_messages: previousMessages }); - aiResponse = response.response; + if (chats[currentChatIndex].isReportStarter && chats[currentChatIndex].context) { + aiResponse = ( + await chatbot.sendMessage(text, { + previous_messages: previousMessages, + context: chats[currentChatIndex].context, + }) + ).response; + chats[currentChatIndex].isReportStarter = false; + } else { + aiResponse = (await chatbot.sendMessage(text, { previous_messages: previousMessages })).response; + } } catch (err) { if (err instanceof APIError) { aiResponse = `Ups! Unfortunately, it seems like there was a problem connecting to the server...\n ${err.status}: ${err.message}`; @@ -165,7 +173,7 @@ export default function HungerMapChatbot() { // use to scroll to the end of the chat when new messages are added useEffect(() => { - chatEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + chatEndRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }, [chats, currentChatIndex]); // listen to isOpen and isMobile to set isFullScreen @@ -186,7 +194,7 @@ export default function HungerMapChatbot() { return (
@@ -267,16 +274,14 @@ export default function HungerMapChatbot() { {chats[currentChatIndex].messages.length === 0 ? (
-

{WELCOME_MESSAGE}

-

{SUB_WELCOME_MESSAGE}

+

{WELCOME_MESSAGE}

+

{SUB_WELCOME_MESSAGE}

{DEFAULT_PROMPT.map((prompt) => (