From e044f9c639f7c29072f5dc1f3fbd862716bdd7ad Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 14 May 2025 11:31:31 -0700 Subject: [PATCH] Reformatted all content to black --- frontend/src/App.css | 4 + frontend/src/BackstoryTextField.tsx | 1 - frontend/src/ChatBubble.tsx | 2 +- frontend/src/Conversation.tsx | 115 +- frontend/src/Message.tsx | 74 +- frontend/src/ResumeBuilderPage.tsx | 31 +- frontend/src/StyledMarkdown.css | 9 + frontend/src/StyledMarkdown.tsx | 10 +- src/server.py | 587 ++++--- src/tests/test-agent.py | 22 +- src/tests/test-context-routing.py | 86 +- src/tests/test-context.py | 18 +- src/tests/test-message.py | 8 +- src/tests/test-metrics.py | 8 +- src/utils/__init__.py | 59 +- src/utils/agents/__init__.py | 14 +- src/utils/agents/base.py | 302 ++-- src/utils/agents/chat.py | 56 +- src/utils/agents/fact_check.py | 88 +- src/utils/agents/job_description.py | 2313 +++++++++++++++++---------- src/utils/agents/resume.py | 150 +- src/utils/agents/types.py | 51 +- src/utils/chroma.py | 122 -- src/utils/chunk.py | 88 - src/utils/context.py | 115 +- src/utils/conversation.py | 23 +- src/utils/defines.py | 16 +- src/utils/full.py | 468 ------ src/utils/message.py | 74 +- src/utils/metrics.py | 156 +- src/utils/rag.py | 504 +++--- src/utils/setup_logging.py | 23 +- src/utils/tools/__init__.py | 8 +- src/utils/tools/basetools.py | 371 +++-- 34 files changed, 3223 insertions(+), 2753 deletions(-) delete mode 100644 src/utils/chroma.py delete mode 100644 src/utils/chunk.py delete mode 100644 src/utils/full.py diff --git a/frontend/src/App.css b/frontend/src/App.css index 4331fa7..4928e12 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -88,6 +88,10 @@ button { flex-grow: 1; } +.MessageContent div > p:first-child { + margin-top: 0; +} + .MenuCard.MuiCard-root { display: flex; flex-direction: column; diff --git a/frontend/src/BackstoryTextField.tsx b/frontend/src/BackstoryTextField.tsx index edddfb8..9046a42 100644 --- a/frontend/src/BackstoryTextField.tsx +++ b/frontend/src/BackstoryTextField.tsx @@ -30,7 +30,6 @@ const BackstoryTextField = React.forwardRef(null); const [editValue, setEditValue] = useState(value); - console.log({ value, placeholder, editValue }); // Sync editValue with prop value if it changes externally useEffect(() => { setEditValue(value || ""); diff --git a/frontend/src/ChatBubble.tsx b/frontend/src/ChatBubble.tsx index bb82895..80be313 100644 --- a/frontend/src/ChatBubble.tsx +++ b/frontend/src/ChatBubble.tsx @@ -158,7 +158,7 @@ function ChatBubble(props: ChatBubbleProps) { }; // Render Accordion for expandable content - if (expandable || (role === 'content' && title)) { + if (expandable || title) { // Determine if Accordion is controlled const isControlled = typeof expanded === 'boolean' && typeof onExpand === 'function'; diff --git a/frontend/src/Conversation.tsx b/frontend/src/Conversation.tsx index f21dfdb..91e4a92 100644 --- a/frontend/src/Conversation.tsx +++ b/frontend/src/Conversation.tsx @@ -1,13 +1,15 @@ import React, { useState, useImperativeHandle, forwardRef, useEffect, useRef, useCallback } from 'react'; import Typography from '@mui/material/Typography'; import Tooltip from '@mui/material/Tooltip'; +import IconButton from '@mui/material/IconButton'; import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; import SendIcon from '@mui/icons-material/Send'; +import CancelIcon from '@mui/icons-material/Cancel'; import { SxProps, Theme } from '@mui/material'; import PropagateLoader from "react-spinners/PropagateLoader"; -import { Message, MessageList, MessageData } from './Message'; +import { Message, MessageList, BackstoryMessage } from './Message'; import { ContextStatus } from './ContextStatus'; import { Scrollable } from './Scrollable'; import { DeleteConfirmation } from './DeleteConfirmation'; @@ -17,7 +19,7 @@ import { BackstoryTextField, BackstoryTextFieldRef } from './BackstoryTextField' import { BackstoryElementProps } from './BackstoryTab'; import { connectionBase } from './Global'; -const loadingMessage: MessageData = { "role": "status", "content": "Establishing connection with server..." }; +const loadingMessage: BackstoryMessage = { "role": "status", "content": "Establishing connection with server..." }; type ConversationMode = 'chat' | 'job_description' | 'resume' | 'fact_check'; @@ -25,24 +27,6 @@ interface ConversationHandle { submitQuery: (prompt: string, options?: QueryOptions) => void; fetchHistory: () => void; } -interface BackstoryMessage { - prompt: string; - preamble: {}; - status: string; - full_content: string; - response: string; // Set when status === 'done' or 'error' - chunk: string; // Used when status === 'streaming' - metadata: { - rag: { documents: [] }; - tools: string[]; - eval_count: number; - eval_duration: number; - prompt_eval_count: number; - prompt_eval_duration: number; - }; - actions: string[]; - timestamp: string; -}; interface ConversationProps extends BackstoryElementProps { className?: string, // Override default className @@ -59,7 +43,7 @@ interface ConversationProps extends BackstoryElementProps { messageFilter?: ((messages: MessageList) => MessageList) | undefined, // Filter callback to determine which Messages to display in Conversation messages?: MessageList, // sx?: SxProps, - onResponse?: ((message: MessageData) => void) | undefined, // Event called when a query completes (provides messages) + onResponse?: ((message: BackstoryMessage) => void) | undefined, // Event called when a query completes (provides messages) }; const Conversation = forwardRef(({ @@ -87,8 +71,8 @@ const Conversation = forwardRef(({ const [countdown, setCountdown] = useState(0); const [conversation, setConversation] = useState([]); const [filteredConversation, setFilteredConversation] = useState([]); - const [processingMessage, setProcessingMessage] = useState(undefined); - const [streamingMessage, setStreamingMessage] = useState(undefined); + const [processingMessage, setProcessingMessage] = useState(undefined); + const [streamingMessage, setStreamingMessage] = useState(undefined); const timerRef = useRef(null); const [contextStatus, setContextStatus] = useState({ context_used: 0, max_context: 0 }); const [contextWarningShown, setContextWarningShown] = useState(false); @@ -96,6 +80,7 @@ const Conversation = forwardRef(({ const conversationRef = useRef([]); const viewableElementRef = useRef(null); const backstoryTextRef = useRef(null); + const stopRef = useRef(false); // Keep the ref updated whenever items changes useEffect(() => { @@ -181,14 +166,25 @@ const Conversation = forwardRef(({ const backstoryMessages: BackstoryMessage[] = messages; - setConversation(backstoryMessages.flatMap((backstoryMessage: BackstoryMessage) => [{ - role: 'user', - content: backstoryMessage.prompt || "", - }, { - ...backstoryMessage, - role: backstoryMessage.status === "done" ? "assistant" : backstoryMessage.status, + setConversation(backstoryMessages.flatMap((backstoryMessage: BackstoryMessage) => { + if (backstoryMessage.status === "partial") { + return [{ + ...backstoryMessage, + role: "assistant", + content: backstoryMessage.response || "", + expanded: false, + expandable: true, + }] + } + return [{ + role: 'user', + content: backstoryMessage.prompt || "", + }, { + ...backstoryMessage, + role: ['done'].includes(backstoryMessage.status || "") ? "assistant" : backstoryMessage.status, content: backstoryMessage.response || "", - }] as MessageList)); + }] as MessageList; + })); setNoInteractions(false); } setProcessingMessage(undefined); @@ -294,6 +290,11 @@ const Conversation = forwardRef(({ } }; + const cancelQuery = () => { + console.log("Stop query"); + stopRef.current = true; + }; + const sendQuery = async (request: string, options?: QueryOptions) => { request = request.trim(); @@ -308,6 +309,8 @@ const Conversation = forwardRef(({ return; } + stopRef.current = false; + setNoInteractions(false); setConversation([ @@ -325,12 +328,10 @@ const Conversation = forwardRef(({ try { setProcessing(true); - // Create a unique ID for the processing message - const processingId = Date.now().toString(); // Add initial processing message setProcessingMessage( - { role: 'status', content: 'Submitting request...', id: processingId, isProcessing: true } + { role: 'status', content: 'Submitting request...', disableCopy: true } ); // Add a small delay to ensure React has time to update the UI @@ -379,17 +380,20 @@ const Conversation = forwardRef(({ switch (update.status) { case 'done': - console.log('Done processing:', update); - stopCountdown(); - setStreamingMessage(undefined); - setProcessingMessage(undefined); + case 'partial': + if (update.status === 'done') stopCountdown(); + if (update.status === 'done') setStreamingMessage(undefined); + if (update.status === 'done') setProcessingMessage(undefined); const backstoryMessage: BackstoryMessage = update; setConversation([ ...conversationRef.current, { ...backstoryMessage, role: 'assistant', origin: type, + prompt: ['done', 'partial'].includes(update.status) ? update.prompt : '', content: backstoryMessage.response || "", + expanded: update.status === "done" ? true : false, + expandable: true, }] as MessageList); // Add a small delay to ensure React has time to update the UI await new Promise(resolve => setTimeout(resolve, 0)); @@ -424,9 +428,9 @@ const Conversation = forwardRef(({ // Update processing message with immediate re-render if (update.status === "streaming") { streaming_response += update.chunk - setStreamingMessage({ role: update.status, content: streaming_response }); + setStreamingMessage({ role: update.status, content: streaming_response, disableCopy: true }); } else { - setProcessingMessage({ role: update.status, content: update.response }); + setProcessingMessage({ role: update.status, content: update.response, disableCopy: true }); /* Reset stream on non streaming message */ streaming_response = "" } @@ -437,12 +441,11 @@ const Conversation = forwardRef(({ } } - while (true) { + while (!stopRef.current) { const { done, value } = await reader.read(); if (done) { break; } - const chunk = decoder.decode(value, { stream: true }); // Process each complete line immediately @@ -470,26 +473,32 @@ const Conversation = forwardRef(({ } } + if (stopRef.current) { + await reader.cancel(); + setProcessingMessage(undefined); + setStreamingMessage(undefined); + setSnack("Processing cancelled", "warning"); + } stopCountdown(); setProcessing(false); + stopRef.current = false; } catch (error) { console.error('Fetch error:', error); setSnack("Unable to process query", "error"); - setProcessingMessage({ role: 'error', content: "Unable to process query" }); + setProcessingMessage({ role: 'error', content: "Unable to process query", disableCopy: true }); setTimeout(() => { setProcessingMessage(undefined); }, 5000); - + stopRef.current = false; setProcessing(false); stopCountdown(); - // Add a small delay to ensure React has time to update the UI - await new Promise(resolve => setTimeout(resolve, 0)); + return; } }; return ( (({ + + { /* This span is used to wrap the IconButton to ensure Tooltip works even when disabled */} + { cancelQuery(); }} + sx={{ display: "flex", margin: 'auto 0px' }} + size="large" + edge="start" + disabled={stopRef.current || sessionId === undefined || processing === false} + > + + + + {(noInteractions || !hideDefaultPrompts) && defaultPrompts !== undefined && defaultPrompts.length && diff --git a/frontend/src/Message.tsx b/frontend/src/Message.tsx index 74b01cf..517d1d7 100644 --- a/frontend/src/Message.tsx +++ b/frontend/src/Message.tsx @@ -47,11 +47,18 @@ type MessageRoles = 'thinking' | 'user'; -type MessageData = { +type BackstoryMessage = { + // Only two required fields role: MessageRoles, content: string, - status?: string, // streaming, done, error... - response?: string, + // Rest are optional + prompt?: string; + preamble?: {}; + status?: string; + full_content?: string; + response?: string; // Set when status === 'done', 'partial', or 'error' + chunk?: string; // Used when status === 'streaming' + timestamp?: string; disableCopy?: boolean, user?: string, title?: string, @@ -84,11 +91,11 @@ interface MessageMetaData { setSnack: SetSnackType, } -type MessageList = MessageData[]; +type MessageList = BackstoryMessage[]; interface MessageProps extends BackstoryElementProps { sx?: SxProps, - message: MessageData, + message: BackstoryMessage, expanded?: boolean, onExpand?: (open: boolean) => void, className?: string, @@ -237,7 +244,7 @@ const MessageMeta = (props: MessageMetaProps) => { }; const Message = (props: MessageProps) => { - const { message, submitQuery, sx, className, onExpand, expanded, sessionId, setSnack } = props; + const { message, submitQuery, sx, className, onExpand, sessionId, setSnack } = props; const [metaExpanded, setMetaExpanded] = useState(false); const textFieldRef = useRef(null); @@ -254,14 +261,16 @@ const Message = (props: MessageProps) => { return (<>); } - const formattedContent = message.content.trim() || "Waiting for LLM to spool up..."; + const formattedContent = message.content.trim(); + if (formattedContent === "") { + return (<>); + } return ( { ...sx, }}> - {message.role !== 'user' ? - - - - : - - {message.content} - - } + + + - {(message.disableCopy === undefined || message.disableCopy === false) && ["assistant", "content"].includes(message.role) && } + {(message.disableCopy === undefined || message.disableCopy === false) && } {message.metadata && (