From f36b3522fd8a07221ebb2a04eb0dc181577be870 Mon Sep 17 00:00:00 2001 From: ahmetselman Date: Thu, 12 Dec 2024 15:10:51 +0100 Subject: [PATCH] fix: refactoring & code quality --- src/components/Chatbot/Chatbot.tsx | 4 +-- src/domain/contexts/ChatbotContext.tsx | 31 ++++++++++++---- .../ExtractPdfText.ts} | 13 +++++-- .../DownloadPortalOperations.tsx | 36 ------------------- 4 files changed, 36 insertions(+), 48 deletions(-) rename src/operations/{pdf/DownloadPortalOperations.ts => chatbot/ExtractPdfText.ts} (62%) diff --git a/src/components/Chatbot/Chatbot.tsx b/src/components/Chatbot/Chatbot.tsx index fbb8f199..01fefda4 100644 --- a/src/components/Chatbot/Chatbot.tsx +++ b/src/components/Chatbot/Chatbot.tsx @@ -194,7 +194,7 @@ export default function HungerMapChatbot() { return (
{chats[currentChatIndex].messages.length === 0 ? (
-

{WELCOME_MESSAGE}

+

{WELCOME_MESSAGE}

{SUB_WELCOME_MESSAGE}

{DEFAULT_PROMPT.map((prompt) => ( diff --git a/src/domain/contexts/ChatbotContext.tsx b/src/domain/contexts/ChatbotContext.tsx index cca22c38..8148f402 100644 --- a/src/domain/contexts/ChatbotContext.tsx +++ b/src/domain/contexts/ChatbotContext.tsx @@ -29,7 +29,9 @@ export function ChatbotProvider({ children }: { children: ReactNode }) { const [isSidebarOpen, setIsSidebarOpen] = useState(false); const [chats, setChats] = useState(ChatbotOperations.loadChatsFromStorage()); - // Save chats to localStorage whenever they change + /** + * Saves chats to localStorage whenever they change + */ useEffect(() => { ChatbotOperations.saveChatsToStorage(chats); }, [chats]); @@ -39,6 +41,11 @@ export function ChatbotProvider({ children }: { children: ReactNode }) { setIsOpen(true); }; + /** + * Starts a new chat, either with a provided chat object or a default one. + * @param newChat - Optional chat object to start with. + * @param openNewChat - Optional flag to determine if the new chat should be opened immediately. + */ const startNewChat = (newChat?: IChat, openNewChat?: boolean) => { let chatToAdd: IChat; @@ -70,23 +77,33 @@ export function ChatbotProvider({ children }: { children: ReactNode }) { } }; - const chatWithReport = async (countryName: string, report: string) => { + /** + * Initiates a chat with a report based on the provided country name and report content. + * If a chat for that specific already exists, it opens that chat; otherwise, it creates a new one. + * @param countryName - The name of the country related to the report. + * @param reportURL - The URL of the report to be processed. + */ + const chatWithReport = async (countryName: string, reportURL: string) => { const reportChatIndex = chats.findIndex((chat) => chat.title === `Report ${countryName}`); const reportChatExists = reportChatIndex !== -1; + if (reportChatExists) { openChat(reportChatIndex); return; } - // Use dynamic import for client-side PDF text extraction - const { extractClientSidePdfText } = await import('@/operations/pdf/DownloadPortalOperations'); - const reportText = await extractClientSidePdfText(report); - // const reportText = await DownloadPortalOperations.extractTextFromPdf(await report); + const { extractPdfText } = await import('@/operations/chatbot/ExtractPdfText'); + let reportText; + try { + reportText = await extractPdfText(reportURL); + } catch { + reportText = ''; + } const assistantMessage = { id: crypto.randomUUID(), content: reportText - ? `Hey, how can I help you with this report about ${reportText}?` + ? `Hey, how can I help you with this report about ${countryName}?` : `Hey, unfortunately I'm currently unable to answer questions about this report. You can try it later or chat with me about other things!`, role: SenderRole.ASSISTANT, }; diff --git a/src/operations/pdf/DownloadPortalOperations.ts b/src/operations/chatbot/ExtractPdfText.ts similarity index 62% rename from src/operations/pdf/DownloadPortalOperations.ts rename to src/operations/chatbot/ExtractPdfText.ts index 8d9dfb1c..6aaa2dc7 100644 --- a/src/operations/pdf/DownloadPortalOperations.ts +++ b/src/operations/chatbot/ExtractPdfText.ts @@ -4,7 +4,15 @@ import { pdfjs } from 'react-pdf'; pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`; -export const extractClientSidePdfText = async (url: string): Promise => { +/** + * Extracts text from a PDF document located at the specified URL. + * This function retrieves the text content from each page of the PDF + * and concatenates it into a single string, which is then returned. + * + * @param url - The URL of the PDF document to extract text from. + * @returns A promise that resolves to the extracted text or undefined if an error occurs. + */ +export const extractPdfText = async (url: string): Promise => { try { const pdf = await pdfjs.getDocument(url).promise; let fullText = ''; @@ -31,7 +39,6 @@ export const extractClientSidePdfText = async (url: string): Promise => return fullText.trim(); } catch (error) { - console.error('Error extracting text from PDF:', error); - return 'error during extraction'; + throw new Error(`Error extracting text from PDF: ${error}`); } }; diff --git a/src/operations/download-portal/DownloadPortalOperations.tsx b/src/operations/download-portal/DownloadPortalOperations.tsx index b02e469b..b1c3d153 100644 --- a/src/operations/download-portal/DownloadPortalOperations.tsx +++ b/src/operations/download-portal/DownloadPortalOperations.tsx @@ -6,8 +6,6 @@ import { CountryCodesData } from '@/domain/entities/country/CountryCodesData'; import { ICountryData } from '@/domain/entities/download/Country'; import { CustomTableColumns } from '@/domain/props/CustomTableProps'; -// pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`; - export class DownloadPortalOperations { static getColumns(): CustomTableColumns { return [ @@ -128,38 +126,4 @@ export class DownloadPortalOperations { DownloadPortalOperations.handlePreview(country.url.summary, setPdfFile, setError); toggleModal(); } - - /* - static async extractTextFromPdf(url: string): Promise { - try { - const pdf = await pdfjs.getDocument(url).promise; - let fullText = ''; - const pagePromises: Promise[] = []; - - for (let i = 1; i <= pdf.numPages; i += 1) { - pagePromises.push( - pdf.getPage(i).then(async (page) => { - const textContent = await page.getTextContent(); - return textContent.items - .map((item) => { - if ('str' in item) { - return item.str; - } - return ''; - }) - .join(' '); - }) - ); - } - - const pageTexts = await Promise.all(pagePromises); - fullText = pageTexts.join('\n'); - - return fullText.trim(); - } catch (error) { - console.error('Error extracting text from PDF:', error); - return 'error during extraction'; - } - } - */ }