'use client'; import React, { useState, useEffect, useCallback } from 'react'; import { useMorphikChat } from '@/hooks/useMorphikChat'; import { ChatMessage, Folder } from '@/components/types'; import { generateUUID } from '@/lib/utils'; import { Settings, Spin, ArrowUp } from './icons'; import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; import { Switch } from '@/components/ui/switch'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { PreviewMessage } from './ChatMessages'; import { Textarea } from '@/components/ui/textarea'; import { Slider } from '@/components/ui/slider'; interface ChatSectionProps { apiBaseUrl: string; authToken: string | null; initialMessages?: ChatMessage[]; isReadonly?: boolean; } /** * ChatSection component using Vercel-style UI */ const ChatSection: React.FC = ({ apiBaseUrl, authToken, initialMessages = [], isReadonly = false }) => { // Generate a unique chat ID if not provided const chatId = generateUUID(); // Initialize our custom hook const { messages, input, setInput, status, handleSubmit, queryOptions, updateQueryOption } = useMorphikChat(chatId, apiBaseUrl, authToken, initialMessages); // State for settings visibility const [showSettings, setShowSettings] = useState(false); const [availableGraphs, setAvailableGraphs] = useState([]); const [loadingGraphs, setLoadingGraphs] = useState(false); const [loadingFolders, setLoadingFolders] = useState(false); const [folders, setFolders] = useState([]); // Fetch available graphs for dropdown const fetchGraphs = useCallback(async () => { if (!apiBaseUrl) return; setLoadingGraphs(true); try { console.log(`Fetching graphs from: ${apiBaseUrl}/graphs`); const response = await fetch(`${apiBaseUrl}/graphs`, { headers: { ...(authToken ? { 'Authorization': `Bearer ${authToken}` } : {}) } }); if (!response.ok) { throw new Error(`Failed to fetch graphs: ${response.status} ${response.statusText}`); } const graphsData = await response.json(); console.log('Graphs data received:', graphsData); if (Array.isArray(graphsData)) { setAvailableGraphs(graphsData.map((graph: { name: string }) => graph.name)); } else { console.error('Expected array for graphs data but received:', typeof graphsData); } } catch (err) { console.error('Error fetching available graphs:', err); } finally { setLoadingGraphs(false); } }, [apiBaseUrl, authToken]); // Fetch folders const fetchFolders = useCallback(async () => { if (!apiBaseUrl) return; setLoadingFolders(true); try { console.log(`Fetching folders from: ${apiBaseUrl}/folders`); const response = await fetch(`${apiBaseUrl}/folders`, { headers: { ...(authToken ? { 'Authorization': `Bearer ${authToken}` } : {}) } }); if (!response.ok) { throw new Error(`Failed to fetch folders: ${response.status} ${response.statusText}`); } const foldersData = await response.json(); console.log('Folders data received:', foldersData); if (Array.isArray(foldersData)) { setFolders(foldersData); } else { console.error('Expected array for folders data but received:', typeof foldersData); } } catch (err) { console.error('Error fetching folders:', err); } finally { setLoadingFolders(false); } }, [apiBaseUrl, authToken]); // Fetch graphs and folders when component mounts useEffect(() => { // Define a function to handle data fetching const fetchData = async () => { if (authToken || apiBaseUrl.includes('localhost')) { console.log('ChatSection: Fetching data with auth token:', !!authToken); await fetchGraphs(); await fetchFolders(); } }; fetchData(); }, [authToken, apiBaseUrl, fetchGraphs, fetchFolders]); // Text area ref and adjustment functions const textareaRef = React.useRef(null); React.useEffect(() => { if (textareaRef.current) { adjustHeight(); } }, []); const adjustHeight = () => { if (textareaRef.current) { textareaRef.current.style.height = 'auto'; textareaRef.current.style.height = `${textareaRef.current.scrollHeight + 2}px`; } }; const resetHeight = () => { if (textareaRef.current) { textareaRef.current.style.height = 'auto'; } }; const handleInput = (event: React.ChangeEvent) => { setInput(event.target.value); adjustHeight(); }; const submitForm = () => { handleSubmit(); resetHeight(); if (textareaRef.current) { textareaRef.current.focus(); } }; // Messages container ref for scrolling const messagesContainerRef = React.useRef(null); const messagesEndRef = React.useRef(null); // Scroll to bottom when messages change React.useEffect(() => { if (messagesEndRef.current) { messagesEndRef.current.scrollIntoView({ behavior: 'smooth' }); } }, [messages]); return (
{/* Chat Header

Morphik Chat

*/} {/* Messages Area */}
{messages.length === 0 && (

Welcome to Morphik Chat

Ask a question about your documents to get started.

)}
{messages.map((message) => ( ))} {status === 'submitted' && messages.length > 0 && messages[messages.length - 1].role === 'user' && (
Thinking...
) }
{/* Input Area */}
{ e.preventDefault(); handleSubmit(e); }} >