import { useState, useRef } from 'react'; import Divider from '@mui/material/Divider'; import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import Card from '@mui/material/Card'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import IconButton from '@mui/material/IconButton'; import CardContent from '@mui/material/CardContent'; import CardActions from '@mui/material/CardActions'; import Collapse from '@mui/material/Collapse'; import Typography from '@mui/material/Typography'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { ExpandMore } from './ExpandMore'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import CheckIcon from '@mui/icons-material/Check'; import { ChatBubble } from './ChatBubble'; import { StyledMarkdown } from './StyledMarkdown'; import { Tooltip } from '@mui/material'; import { VectorVisualizer } from './VectorVisualizer'; import { SeverityType } from './Snack'; type MessageRoles = 'info' | 'user' | 'assistant' | 'system'; type MessageData = { role: MessageRoles, content: string, user?: string, type?: string, id?: string, isProcessing?: boolean, metadata?: MessageMetaProps }; interface MessageMetaProps { query?: { query_embedding: number[]; vector_embedding: number[]; }, rag: any, tools: any[], eval_count: number, eval_duration: number, prompt_eval_count: number, prompt_eval_duration: number, sessionId?: string, connectionBase: string, setSnack: (message: string, severity: SeverityType) => void, } type MessageList = MessageData[]; interface MessageProps { message?: MessageData, isFullWidth?: boolean, submitQuery?: (text: string) => void, sessionId?: string, connectionBase: string, setSnack: (message: string, severity: SeverityType) => void, }; interface ChatQueryInterface { text: string, submitQuery?: (text: string) => void } const MessageMeta = ({ ...props }: MessageMetaProps) => { return (<> Below is the LLM performance of this query. Note that if tools are called, the entire context is processed for each separate tool request by the LLM. This can dramatically increase the total time for a response. Tokens Time (s) TPS Prompt {props.prompt_eval_count} {Math.round(props.prompt_eval_duration / 10 ** 7) / 100} {Math.round(props.prompt_eval_count * 10 ** 9 / props.prompt_eval_duration)} Response {props.eval_count} {Math.round(props.eval_duration / 10 ** 7) / 100} {Math.round(props.eval_count * 10 ** 9 / props.eval_duration)} Total {props.prompt_eval_count + props.eval_count} {Math.round((props.prompt_eval_duration + props.eval_duration) / 10 ** 7) / 100} {Math.round((props.prompt_eval_count + props.eval_count) * 10 ** 9 / (props.prompt_eval_duration + props.eval_duration))} { props.tools !== undefined && props.tools.length !== 0 && }> Tools queried {props.tools.map((tool: any, index: number) => {index !== 0 && } {tool.tool} {JSON.stringify(tool.result, null, 2)} )} } { props?.rag?.name !== undefined && <> }> Top RAG {props.rag.ids.length} matches from '{props.rag.name}' collection against embedding vector of {props.rag.query_embedding.length} dimensions {props.rag.ids.map((id: number, index: number) => {index !== 0 && } Doc ID: {props.rag.ids[index].slice(-10)} Similarity: {Math.round(props.rag.distances[index] * 100) / 100} Type: {props.rag.metadatas[index].doc_type} Chunk Len: {props.rag.documents[index].length} {props.rag.documents[index]} )} }> UMAP Vector Visualization of RAG > } > ); }; const ChatQuery = ({ text, submitQuery }: ChatQueryInterface) => { if (submitQuery === undefined) { return ({text}); } return ( theme.palette.custom.highlight, // Golden Ochre (#D4A017) borderColor: theme => theme.palette.custom.highlight, m: 1 }} size="small" onClick={(e: any) => { console.log(text); submitQuery(text); }}> {text} ); } const Message = ({ message, submitQuery, isFullWidth, sessionId, setSnack, connectionBase }: MessageProps) => { const [expanded, setExpanded] = useState(false); const [copied, setCopied] = useState(false); const textFieldRef = useRef(null); const handleCopy = () => { if (message === undefined || message.content === undefined) { return; } navigator.clipboard.writeText(message.content.trim()).then(() => { setCopied(true); setTimeout(() => setCopied(false), 2000); // Reset after 2 seconds }); }; const handleExpandClick = () => { setExpanded(!expanded); }; if (message === undefined) { return (<>>); } if (message.content === undefined) { console.info("Message content is undefined"); return (<>>); } const formattedContent = message.content.trim(); return ( {copied ? : } {message.role !== 'user' ? : {message.content} } {message.metadata && <> LLM information for this query >} ); }; export type { MessageProps, MessageList, ChatQueryInterface, MessageMetaProps, MessageData, MessageRoles }; export { Message, ChatQuery, MessageMeta };