import React, { useRef, useEffect, useState } from 'react'; import Box from '@mui/material/Box'; import Snackbar from '@mui/material/Snackbar'; import Slide from '@mui/material/Slide'; import IconButton from '@mui/material/IconButton'; import { FaTimes } from 'react-icons/fa'; import ReactMarkdown from 'react-markdown'; import GraphDialog from './Graph'; import './ChatWindow.css'; import bot from '../../Icons/bot.png'; import copy from '../../Icons/copy.png'; import evaluate from '../../Icons/evaluate.png'; import sourcesIcon from '../../Icons/sources.png'; import graphIcon from '../../Icons/graph.png'; import user from '../../Icons/user.png'; // SlideTransition function for both entry and exit transitions. function SlideTransition(props) { return ; } function ChatWindow({ blockId, userMessage, aiAnswer, thinkingTime, thoughtLabel, sourcesRead, actions, tasks, openRightSidebar, // openLeftSidebar, isError, errorMessage }) { const answerRef = useRef(null); const [graphDialogOpen, setGraphDialogOpen] = useState(false); const [snackbarOpen, setSnackbarOpen] = useState(false); // Get the graph action from the actions prop. const graphAction = actions && actions.find(a => a.name === "graph"); // Handler for copying answer to clipboard. const handleCopy = () => { if (answerRef.current) { const textToCopy = answerRef.current.innerText || answerRef.current.textContent; navigator.clipboard.writeText(textToCopy) .then(() => { console.log('Copied to clipboard:', textToCopy); setSnackbarOpen(true); }) .catch((err) => console.error('Failed to copy text:', err)); } }; // Snackbar close handler const handleSnackbarClose = (event, reason) => { if (reason === 'clickaway') return; setSnackbarOpen(false); }; // Determine if any tokens (partial or full answer) have been received. const hasTokens = aiAnswer && aiAnswer.length > 0; // Assume streaming is in progress if thinkingTime is not set. const isStreaming = thinkingTime === null || thinkingTime === undefined; // Append a trailing cursor if streaming. const displayAnswer = hasTokens ? (isStreaming ? aiAnswer + "▌" : aiAnswer) : ""; // Helper to render the thought label. const renderThoughtLabel = () => { if (!hasTokens) { return thoughtLabel; } else { if (thoughtLabel && thoughtLabel.startsWith("Thought and searched for")) { return thoughtLabel; } return null; } }; // Helper to render sources read. const renderSourcesRead = () => { if (!sourcesRead && sourcesRead !== 0) return null; return sourcesRead; }; // When tasks first appear, automatically open the sidebar. const prevTasksRef = useRef(tasks); useEffect(() => { if (prevTasksRef.current.length === 0 && tasks && tasks.length > 0) { openRightSidebar("tasks", blockId); } prevTasksRef.current = tasks; }, [tasks, blockId, openRightSidebar]); return ( <> { !hasTokens ? ( // If no tokens, render pre-stream UI. (!isError && thoughtLabel) ? (
{/* User Message */}

{userMessage}

user icon
{/* Bot Message (pre-stream with spinner) */}
openRightSidebar("tasks", blockId)} > {thoughtLabel}
) : ( // Render without spinner (user message only)

{userMessage}

user icon
) ) : ( // Render Full Chat Message
{/* User Message */}

{userMessage}

user icon
{/* Bot Message */}
{!isError && renderThoughtLabel() && (
openRightSidebar("tasks", blockId)} > {renderThoughtLabel()}
)} {renderSourcesRead() !== null && (

Sources Read: {renderSourcesRead()}

)}
bot icon
{displayAnswer}
{!isStreaming && (
copy icon Copy
)} {actions && actions.some(a => a.name === "evaluate") && (
openRightSidebar("evaluate", blockId)}> evaluate icon Evaluate
)} {actions && actions.some(a => a.name === "sources") && (
openRightSidebar("sources", blockId)}> sources icon Sources
)} {actions && actions.some(a => a.name === "graph") && (
setGraphDialogOpen(true)}> graph icon View Graph
)}
{/* Render the GraphDialog when graphDialogOpen is true */} {graphDialogOpen && ( setGraphDialogOpen(false)} payload={graphAction ? graphAction.payload : { query: userMessage }} /> )}
)} {/* Render error container if there's an error */} {isError && (

Error

{errorMessage}

)} } /> ); } export default ChatWindow;