/** * ChatInterface Component * * Main chat interface for interacting with the data analysis AI. * Handles message input, sending queries, and displaying responses. * * DYNAMIC SUGGESTIONS: * Generates relevant sample prompts based on the uploaded file's columns. * Updates automatically when a different file is uploaded. */ import { useState, useCallback, useMemo } from 'react'; import type { Message, FileMetadata, QueryResponse } from '../types'; import MessageList from './MessageList'; interface ChatInterfaceProps { messages: Message[]; onSendMessage: (content: string) => Promise; isLoading: boolean; fileUploaded: FileMetadata | null; } /** * Generate dynamic sample prompts based on file columns. * Creates relevant suggestions that match the actual data. */ function generateDynamicPrompts(columns: string[]): string[] { if (!columns || columns.length === 0) { return [ 'How many rows are in this dataset?', 'What columns are available?', 'Show summary statistics', 'What is the data about?', ]; } const prompts: string[] = []; // Find potential categorical columns (common patterns) const categoryPatterns = ['category', 'type', 'region', 'state', 'country', 'segment', 'department', 'status', 'company', 'name']; const numericPatterns = ['sales', 'profit', 'revenue', 'amount', 'price', 'quantity', 'count', 'total', 'cost']; const datePatterns = ['date', 'year', 'month', 'time', 'period']; // Find matching columns const categoryCol = columns.find(c => categoryPatterns.some(p => c.toLowerCase().includes(p))); const numericCol = columns.find(c => numericPatterns.some(p => c.toLowerCase().includes(p))); const dateCol = columns.find(c => datePatterns.some(p => c.toLowerCase().includes(p))); // Generate prompts based on found columns if (numericCol && categoryCol) { prompts.push(`Show total ${numericCol} by ${categoryCol}`); prompts.push(`What are the top 5 ${categoryCol}s by ${numericCol}?`); } if (categoryCol) { prompts.push(`Create a pie chart by ${categoryCol}`); } if (numericCol && dateCol) { prompts.push(`How has ${numericCol} changed over time?`); } // Add generic prompts if we don't have enough if (prompts.length < 2) { prompts.push(`How many rows are in this dataset?`); } if (prompts.length < 3 && columns.length > 0) { prompts.push(`Show distribution of ${columns[0]}`); } if (prompts.length < 4) { prompts.push(`Show summary statistics`); } // Return up to 4 prompts return prompts.slice(0, 4); } export function ChatInterface({ messages, onSendMessage, isLoading, fileUploaded, }: ChatInterfaceProps) { const [input, setInput] = useState(''); const handleSubmit = useCallback( async (e: React.FormEvent) => { e.preventDefault(); const trimmedInput = input.trim(); if (!trimmedInput || isLoading || !fileUploaded) return; setInput(''); await onSendMessage(trimmedInput); }, [input, isLoading, fileUploaded, onSendMessage] ); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSubmit(e); } }; const isDisabled = !fileUploaded || isLoading; // DYNAMIC: Generate sample prompts based on file columns // Updates automatically when different file is uploaded const samplePrompts = useMemo(() => { if (fileUploaded?.columns) { return generateDynamicPrompts(fileUploaded.columns); } return [ 'How many rows are in this dataset?', 'What columns are available?', 'Show summary statistics', 'What is the data about?', ]; }, [fileUploaded?.columns]); // FOLLOW-UP SUGGESTIONS: Generate based on last analysis // Shows after a chart/analysis is displayed const followUpSuggestions = useMemo(() => { if (messages.length === 0) return []; // Find last assistant message with chart const lastAssistantMsg = [...messages].reverse().find( m => m.role === 'assistant' && m.chartConfig ); if (!lastAssistantMsg?.chartConfig) return []; const suggestions: string[] = []; const chartType = lastAssistantMsg.chartConfig.type; // Suggest different chart types if (chartType !== 'pie') { suggestions.push('Show as pie chart'); } if (chartType !== 'bar') { suggestions.push('Show as bar chart'); } if (chartType !== 'line') { suggestions.push('Show as line chart'); } // Suggest limit changes suggestions.push('Top 10 instead'); suggestions.push('Show more'); return suggestions.slice(0, 4); }, [messages]); const handleSamplePrompt = (prompt: string) => { if (!isDisabled) { setInput(prompt); } }; return (
{/* Header */}

Chat with your Data

{fileUploaded ? `Analyzing: ${fileUploaded.filename}` : 'Upload a file to start asking questions'}

{/* Messages Area */}
{messages.length === 0 && fileUploaded && !isLoading ? (

Ready to analyze your data!

Ask questions about your {fileUploaded.filename}

{/* Sample prompts */}

Try these prompts

{samplePrompts.map((prompt) => ( ))}
) : ( )}
{/* Follow-up Suggestions - shown after analysis */} {followUpSuggestions.length > 0 && !isLoading && messages.length > 0 && (

Quick follow-ups:

{followUpSuggestions.map((suggestion) => ( ))}
)} {/* Input Area */}
setInput(e.target.value)} onKeyDown={handleKeyDown} placeholder={ fileUploaded ? 'Ask a question about your data...' : 'Upload a file first to start chatting' } className="input-field flex-1" disabled={isDisabled} />
{/* File not uploaded warning */} {!fileUploaded && (

Please upload a CSV or XLSX file to start chatting

)}
); } export default ChatInterface;