import { useState, useRef, useEffect } 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 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 { SxProps, Theme } from '@mui/material'; import JsonView from '@uiw/react-json-view'; import { ChatBubble } from './ChatBubble'; import { StyledMarkdown } from './StyledMarkdown'; import { VectorVisualizer } from './VectorVisualizer'; import { SetSnackType } from './Snack'; import { CopyBubble } from './CopyBubble'; import { Scrollable } from './Scrollable'; import { BackstoryElementProps } from './BackstoryTab'; type MessageRoles = 'assistant' | 'content' | 'error' | 'fact-check' | 'info' | 'job-description' | 'job-requirements' | 'processing' | 'qualifications' | 'resume' | 'status' | 'streaming' | 'system' | 'thinking' | 'user'; type MessageData = { role: MessageRoles, content: string, status?: string, // streaming, done, error... response?: string, disableCopy?: boolean, user?: string, title?: string, origin?: string, display?: string, /* Messages generated on the server for filler should not be shown */ id?: string, isProcessing?: boolean, actions?: string[], metadata?: MessageMetaData, expanded?: boolean, expandable?: boolean, }; interface MessageMetaData { query?: { query_embedding: number[]; vector_embedding: number[]; }, origin: string, rag: any, tools?: { tool_calls: any[], }, eval_count: number, eval_duration: number, prompt_eval_count: number, prompt_eval_duration: number, sessionId?: string, connectionBase: string, setSnack: SetSnackType, } type MessageList = MessageData[]; interface MessageProps extends BackstoryElementProps { sx?: SxProps, message: MessageData, expanded?: boolean, onExpand?: (open: boolean) => void, className?: string, }; interface MessageMetaProps { metadata: MessageMetaData, messageProps: MessageProps }; const MessageMeta = (props: MessageMetaProps) => { const { /* MessageData */ rag, tools, eval_count, eval_duration, prompt_eval_count, prompt_eval_duration, } = props.metadata || {}; const message: any = props.messageProps.message; let llm_submission: string = "<|system|>\n" llm_submission += message.system_prompt + "\n\n" llm_submission += message.context_prompt return (<> { prompt_eval_duration !== 0 && eval_duration !== 0 && <> Tokens Time (s) TPS Prompt {prompt_eval_count} {Math.round(prompt_eval_duration / 10 ** 7) / 100} {Math.round(prompt_eval_count * 10 ** 9 / prompt_eval_duration)} Response {eval_count} {Math.round(eval_duration / 10 ** 7) / 100} {Math.round(eval_count * 10 ** 9 / eval_duration)} Total {prompt_eval_count + eval_count} {Math.round((prompt_eval_duration + eval_duration) / 10 ** 7) / 100} {Math.round((prompt_eval_count + eval_count) * 10 ** 9 / (prompt_eval_duration + eval_duration))}
} { tools !== undefined && tools.tool_calls && tools.tool_calls.length !== 0 && }> Tools queried { tools.tool_calls.map((tool: any, index: number) => {index !== 0 && } {tool.name} { if (typeof (children) === "string" && children.match("\n")) { return
{children}
} }} />
) }
} { rag.map((rag: any) => ( }> Top RAG {rag.ids.length} matches from '{rag.name}' collection against embedding vector of {rag.query_embedding.length} dimensions UMAP Vector Visualization of '{rag.name}' RAG {rag.ids.map((id: number, index: number) => Doc ID: {rag.ids[index]}
Distance: {Math.round(rag.distances[index] * 100) / 100}
Type: {rag.metadatas[index].doc_type}
Chunk Len: {rag.documents[index].length}
{rag.documents[index]}
)}
)) } }> Full Response Details Copy LLM submission: { if (typeof (children) === "string" && children.match("\n")) { return
{children.trim()}
} }} />
); }; const Message = (props: MessageProps) => { const { message, submitQuery, sx, className, onExpand, expanded } = props; const [metaExpanded, setMetaExpanded] = useState(props.expanded || false); const textFieldRef = useRef(null); const handleMetaExpandClick = () => { setMetaExpanded(!metaExpanded); }; if (message === undefined) { return (<>); } if (message.content === undefined) { console.info("Message content is undefined"); return (<>); } const formattedContent = message.content.trim() || "Waiting for LLM to spool up..."; return ( {message.role !== 'user' ? : {message.content} } {(message.disableCopy === undefined || message.disableCopy === false) && ["assistant", "content"].includes(message.role) && } {message.metadata && ( )} {message.metadata && <> } ); }; export type { MessageProps, MessageList, MessageData, MessageRoles, }; export { Message, MessageMeta, };