diff --git a/app-frontend/react/package.json b/app-frontend/react/package.json index 99941f1..4dbfab3 100644 --- a/app-frontend/react/package.json +++ b/app-frontend/react/package.json @@ -11,10 +11,10 @@ "test": "vitest" }, "dependencies": { - "@mantine/charts": "7.13.4", - "@mantine/core": "^7.13.4", - "@mantine/hooks": "^7.13.4", - "@mantine/notifications": "^7.13.4", + "@mantine/charts": "7.17.2", + "@mantine/core": "^7.17.2", + "@mantine/hooks": "^7.17.2", + "@mantine/notifications": "^7.17.2", "@microsoft/fetch-event-source": "^2.0.1", "@reduxjs/toolkit": "^2.2.5", "@tabler/icons-react": "3.7.0", diff --git a/app-frontend/react/src/components/Conversation/Conversation.tsx b/app-frontend/react/src/components/Conversation/Conversation.tsx index 59eed2d..2021102 100644 --- a/app-frontend/react/src/components/Conversation/Conversation.tsx +++ b/app-frontend/react/src/components/Conversation/Conversation.tsx @@ -1,134 +1,132 @@ -import { KeyboardEventHandler, SyntheticEvent, useEffect, useRef, useState } from 'react' -import styleClasses from "./conversation.module.scss" -import { ActionIcon, Group, rem, Slider, Stack, Text, Textarea, Title, Tooltip } from '@mantine/core' -import { IconArrowRight, IconFilePlus, IconMessagePlus } from '@tabler/icons-react' -import { conversationSelector, doConversation, newConversation } from '../../redux/Conversation/ConversationSlice' -import { ConversationMessage } from '../Message/conversationMessage' -import { useAppDispatch, useAppSelector } from '../../redux/store' -import { Message, MessageRole } from '../../redux/Conversation/Conversation' -import { UiFeatures } from '../../common/Sandbox' -import { getCurrentTimeStamp } from '../../common/util' -import { useDisclosure } from '@mantine/hooks' -import DataSource from './DataSource' -import { ConversationSideBar } from './ConversationSideBar' +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 -type ConversationProps = { - title: string - enabledUiFeatures: UiFeatures -} - -const Conversation = ({ title, enabledUiFeatures }: ConversationProps) => { - const [prompt, setPrompt] = useState("") - const [systemPrompt, setSystemPrompt] = useState("You are a helpful assistant.") - const promptInputRef = useRef(null) - const [fileUploadOpened, { open: openFileUpload, close: closeFileUpload }] = useDisclosure(false) +import { KeyboardEventHandler, SyntheticEvent, useEffect, useRef, useState } from 'react'; +import styleClasses from "./conversation.module.scss"; +import { ActionIcon, Button, Collapse, Group, rem, Slider, Stack, Text, Textarea, Title, Tooltip } from '@mantine/core'; +import { IconArrowRight, IconChevronDown, IconChevronUp, IconFilePlus, IconMessagePlus } from '@tabler/icons-react'; - const { conversations, onGoingResult, selectedConversationId } = useAppSelector(conversationSelector) - const dispatch = useAppDispatch() - const selectedConversation = conversations.find(x => x.conversationId === selectedConversationId) - const scrollViewport = useRef(null) +import { conversationSelector, doConversation, newConversation, isAgentSelector, getCurrentAgentSteps } from '../../redux/Conversation/ConversationSlice'; +import { ConversationMessage } from '../Message/conversationMessage'; +import { useAppDispatch, useAppSelector } from '../../redux/store'; +import { Message, MessageRole } from '../../redux/Conversation/Conversation'; +import { UiFeatures } from '../../common/Sandbox'; +import { getCurrentTimeStamp } from '../../common/util'; +import { useDisclosure } from '@mantine/hooks'; +import DataSource from './DataSource'; +import { ConversationSideBar } from './ConversationSideBar'; - const [tokenLimit, setTokenLimit] = useState(50) - const [temperature, setTemperature] = useState(0.30) +type ConversationProps = { + title: string; + enabledUiFeatures: UiFeatures; +}; - // State for tracking tokens and message processing time - const [messageTokenData, setMessageTokenData] = useState<{ [key: string]: { tokens: number; rate: number, time: number } }>({}) +const Conversation = ({ title, enabledUiFeatures }: ConversationProps) => { + const [prompt, setPrompt] = useState(""); + const [systemPrompt, setSystemPrompt] = useState("You are a helpful assistant."); + const promptInputRef = useRef(null); + const [fileUploadOpened, { open: openFileUpload, close: closeFileUpload }] = useDisclosure(false); - const [currentMessageIndex, setCurrentMessageIndex] = useState(-1) - - // New state to track the start time for calculating tokens per second - const [startTime, setStartTime] = useState(null) + const { conversations, onGoingResult, selectedConversationId } = useAppSelector(conversationSelector); + const isAgent = useAppSelector(isAgentSelector); + const dispatch = useAppDispatch(); + const selectedConversation = conversations.find(x => x.conversationId === selectedConversationId); + const scrollViewport = useRef(null); - // New state to manage the assistant's message placeholder - const [isAssistantTyping, setIsAssistantTyping] = useState(false) + const [tokenLimit, setTokenLimit] = useState(50); + const [temperature, setTemperature] = useState(0.30); - const toSend = "Enter" + const [messageTokenData, setMessageTokenData] = useState<{ [key: string]: { tokens: number; rate: number; time: number } }>({}); + const [currentMessageIndex, setCurrentMessageIndex] = useState(-1); + const [startTime, setStartTime] = useState(null); + const [isAssistantTyping, setIsAssistantTyping] = useState(false); + const [showInferenceParams, setShowInferenceParams] = useState(true); - // const systemPrompt: Partial = { - // role: MessageRole.System, - // content: "You are a helpful assistant", - // } + const toSend = "Enter"; const handleSubmit = () => { const userPrompt: Message = { role: MessageRole.User, content: prompt, time: getCurrentTimeStamp(), - } - - let messages: Partial[] = [] + }; + + let messages: Partial[] = []; if (selectedConversation) { messages = selectedConversation.Messages.map((message) => { - return { role: message.role, content: message.content } - }) + return { role: message.role, content: message.content }; + }); } - - messages = [{ role: MessageRole.System, content: systemPrompt }, ...messages] - - // Initialize token data for the new message + + messages = [{ role: MessageRole.System, content: systemPrompt }, ...messages]; + setMessageTokenData((prev) => ({ ...prev, [`${selectedConversationId}-${selectedConversation?.Messages.length}`]: { tokens: 0, rate: 0, time: 0 }, - })) - - // Set the current message index for tracking - setCurrentMessageIndex(selectedConversation?.Messages.length || 0) - + })); + + setCurrentMessageIndex(selectedConversation?.Messages.length || 0); + doConversation({ - conversationId: selectedConversationId, - userPrompt, - messages, - maxTokens: tokenLimit, - temperature: temperature, - model: "Intel/neural-chat-7b-v3-3", - }) - setPrompt("") - setStartTime(Date.now()) // Set start time when the user submits the message - setIsAssistantTyping(true) // Show the assistant's typing placeholder immediately - } + conversationId: selectedConversationId, + userPrompt, + messages, + maxTokens: tokenLimit, + temperature: temperature, + model: "Intel/neural-chat-7b-v3-3", + }); + setPrompt(""); + setStartTime(Date.now()); + setIsAssistantTyping(true); + }; const scrollToBottom = () => { - scrollViewport.current!.scrollTo({ top: scrollViewport.current!.scrollHeight }) - } + scrollViewport.current!.scrollTo({ top: scrollViewport.current!.scrollHeight }); + }; useEffect(() => { - // Update token data for the current message if (onGoingResult && startTime && currentMessageIndex !== -1) { - const tokenLength = onGoingResult.split(" ").length // Estimate tokens based on words - const currentTimestamp = Date.now() - - const elapsedTime = (currentTimestamp - startTime) / 1000 // seconds - const tokenRate = elapsedTime > 0 ? tokenLength / elapsedTime : 0 - - // Update token data for the current message + let tokenLength: number; + if (isAgent) { + const currentSteps = getCurrentAgentSteps(); + const allContent = currentSteps.flatMap(step => step.content).join(" "); + tokenLength = allContent.split(" ").length; + } else { + tokenLength = onGoingResult.split(" ").length; + } + + const currentTimestamp = Date.now(); + const elapsedTime = (currentTimestamp - startTime) / 1000; + const tokenRate = elapsedTime > 0 ? tokenLength / elapsedTime : 0; + setMessageTokenData((prev) => ({ ...prev, [`${selectedConversationId}-${currentMessageIndex}`]: { tokens: tokenLength, rate: tokenRate, time: elapsedTime }, - })) - - setIsAssistantTyping(false) + })); + + setIsAssistantTyping(false); } - - scrollToBottom() - }, [onGoingResult, startTime, selectedConversation?.Messages, currentMessageIndex]) + + scrollToBottom(); + }, [onGoingResult, startTime, selectedConversation?.Messages, currentMessageIndex, isAgent]); const handleKeyDown: KeyboardEventHandler = (event) => { if (!event.shiftKey && event.key === toSend) { - handleSubmit() + handleSubmit(); setTimeout(() => { - setPrompt("") - }, 1) + setPrompt(""); + }, 1); } - } + }; const handleNewConversation = () => { - dispatch(newConversation()) - } + dispatch(newConversation()); + }; const handleChange = (event: SyntheticEvent) => { - event.preventDefault() - setPrompt((event.target as HTMLTextAreaElement).value) - } + event.preventDefault(); + setPrompt((event.target as HTMLTextAreaElement).value); + }; return (
@@ -140,11 +138,10 @@ const Conversation = ({ title, enabledUiFeatures }: ConversationProps) => { {selectedConversation && selectedConversation?.Messages.length > 0 && ( - + )} - { )} {selectedConversation?.Messages.map((message, index) => { - const messageKey = `${selectedConversationId}-${index-1}` - const tokenData = messageTokenData[messageKey] - const elapsedTime = tokenData?.time ?? 0 - const tokens = tokenData?.tokens ?? 0 - const rate = tokenData?.rate ?? 0 - - console.log("Message: ", message, "Message Key: ", messageKey, "Token Data: ", tokenData) + const messageKey = `${selectedConversationId}-${index - 1}`; + const tokenData = messageTokenData[messageKey]; + const elapsedTime = tokenData?.time ?? 0; + const tokens = tokenData?.tokens ?? 0; + const rate = tokenData?.rate ?? 0; return ( { elapsedTime={message.role === MessageRole.Assistant ? elapsedTime : undefined} tokenCount={message.role === MessageRole.Assistant ? tokens : undefined} tokenRate={message.role === MessageRole.Assistant ? rate : undefined} + agentSteps={message.agentSteps || []} /> - ) + ); })} {selectedConversation && isAssistantTyping && ( @@ -193,10 +189,11 @@ const Conversation = ({ title, enabledUiFeatures }: ConversationProps) => { key={`_ai_placeholder`} date={Date.now()} human={false} - message={"..."} // Placeholder text while the response is being generated - elapsedTime={0} // Start with 0 seconds - tokenCount={0} // Start with 0 tokens - tokenRate={0} // Start with 0 tokens per second + message={"..."} + elapsedTime={0} + tokenCount={0} + tokenRate={0} + agentSteps={getCurrentAgentSteps()} /> )} @@ -209,27 +206,41 @@ const Conversation = ({ title, enabledUiFeatures }: ConversationProps) => { elapsedTime={messageTokenData[`${selectedConversationId}-${currentMessageIndex}`]?.time} tokenCount={messageTokenData[`${selectedConversationId}-${currentMessageIndex}`]?.tokens} tokenRate={messageTokenData[`${selectedConversationId}-${currentMessageIndex}`]?.rate} + agentSteps={getCurrentAgentSteps()} /> - )} + )}
- - Inference Settings - Token Limit: {tokenLimit} - - Temperature: {temperature.toFixed(2)} - -