update button based on state

This commit is contained in:
2025-09-24 11:57:26 -05:00
parent 0acfcc0d08
commit b120f85ccd
2 changed files with 259 additions and 216 deletions

View File

@@ -324,6 +324,7 @@ const AsyncChat = ({
<InputAdornment position="end"> <InputAdornment position="end">
<Button <Button
component="label" component="label"
color={formik.values.file ? "success" : "inherit"}
startIcon={<AttachFile />} startIcon={<AttachFile />}
role={undefined} role={undefined}
tabIndex={-1} tabIndex={-1}

View File

@@ -1,64 +1,83 @@
import { Card, CardContent, Divider, InputAdornment, MenuItem, Select, } from "@mui/material" import {
Card,
CardContent,
Divider,
InputAdornment,
MenuItem,
Select,
} from "@mui/material";
import DashboardLayout from "../../ui-kit/examples/LayoutContainers/DashboardLayout" import DashboardLayout from "../../ui-kit/examples/LayoutContainers/DashboardLayout";
import MDBox from "../../ui-kit/components/MDBox" import MDBox from "../../ui-kit/components/MDBox";
import { useMaterialUIController } from "../../ui-kit/context" import { useMaterialUIController } from "../../ui-kit/context";
import { useContext, useEffect, useRef, useState } from "react" import { useContext, useEffect, useRef, useState } from "react";
// Images // Images
import MDTypography from "../../ui-kit/components/MDTypography" import MDTypography from "../../ui-kit/components/MDTypography";
import { CardFooter } from "react-bootstrap" import { CardFooter } from "react-bootstrap";
import MDInput from "../../ui-kit/components/MDInput" import MDInput from "../../ui-kit/components/MDInput";
import { ErrorMessage, Field, Form, Formik } from "formik" import { ErrorMessage, Field, Form, Formik } from "formik";
import MDButton from "../../ui-kit/components/MDButton" import MDButton from "../../ui-kit/components/MDButton";
import { AttachFile, Send } from "@mui/icons-material" import { AttachFile, Send } from "@mui/icons-material";
import Header2 from "../../components/Header2/Header2" import Header2 from "../../components/Header2/Header2";
import DashboardWrapperLayout from "../../components/DashboardWrapperLayout/DashboardWrapperLayout" import DashboardWrapperLayout from "../../components/DashboardWrapperLayout/DashboardWrapperLayout";
import * as Yup from 'yup'; import * as Yup from "yup";
import { Announcement, AnnouncementType, Conversation, ConversationPrompt, ConversationPromptType, ConversationType } from "../../data" import {
import { axiosInstance } from "../../../axiosApi" Announcement,
import { AxiosResponse } from "axios" AnnouncementType,
import { ConversationContext } from "../../contexts/ConversationContext" Conversation,
import Markdown from "markdown-to-jsx" ConversationPrompt,
import ConversationDetailCard from "../../components/ConversationDetailCard/ConversationDetailCard" ConversationPromptType,
import { WebSocketContext } from "../../contexts/WebSocketContext" ConversationType,
import { AccountContext } from "../../contexts/AccountContext" } from "../../data";
import { styled } from '@mui/material/styles'; import { axiosInstance } from "../../../axiosApi";
import Footer from "../../components/Footer/Footer" import { AxiosResponse } from "axios";
import { MessageContext } from "../../contexts/MessageContext" import { ConversationContext } from "../../contexts/ConversationContext";
import CustomSelect, { CustomSelectItem } from "../../components/CustomSelect/CustomSelect" import Markdown from "markdown-to-jsx";
import ConversationDetailCard from "../../components/ConversationDetailCard/ConversationDetailCard";
import { WebSocketContext } from "../../contexts/WebSocketContext";
import { AccountContext } from "../../contexts/AccountContext";
import { styled } from "@mui/material/styles";
import Footer from "../../components/Footer/Footer";
import { MessageContext } from "../../contexts/MessageContext";
import CustomSelect, {
CustomSelectItem,
} from "../../components/CustomSelect/CustomSelect";
const MODELS = ["Turbo","RAG"] const MODELS = ["Turbo", "RAG"];
type RenderMessageProps= { type RenderMessageProps = {
response: string response: string;
index: number index: number;
}; };
type AsyncChatProps = { type AsyncChatProps = {
selectedConversation: number | undefined selectedConversation: number | undefined;
conversationTitle: string conversationTitle: string;
conversations: Conversation[] conversations: Conversation[];
setConversations: React.Dispatch<React.SetStateAction<Conversation[]>> setConversations: React.Dispatch<React.SetStateAction<Conversation[]>>;
setSelectedConversation: React.Dispatch<React.SetStateAction<number | undefined>> setSelectedConversation: React.Dispatch<
drawerWidth: number; React.SetStateAction<number | undefined>
} >;
drawerWidth: number;
};
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
prompt: Yup.string().min(1, "Need to have at least one character").required("This is requried") prompt: Yup.string()
} .min(1, "Need to have at least one character")
) .required("This is requried"),
});
const VisuallyHiddenInput = styled('input')({ const VisuallyHiddenInput = styled("input")({
clip: 'rect(0 0 0 0)', clip: "rect(0 0 0 0)",
clipPath: 'inset(50%)', clipPath: "inset(50%)",
height: 1, height: 1,
overflow: 'hidden', overflow: "hidden",
position: 'absolute', position: "absolute",
bottom: 0, bottom: 0,
left: 0, left: 0,
whiteSpace: 'nowrap', whiteSpace: "nowrap",
width: 1, width: 1,
}); });
@@ -67,22 +86,21 @@ type PromptValues = {
file: Blob | null; file: Blob | null;
fileType: string | null; fileType: string | null;
modelName: string; modelName: string;
}; };
const models: CustomSelectItem[] = [ const models: CustomSelectItem[] = [
{ {
label: "General", label: "General",
value: "GENERAL" value: "GENERAL",
}, },
{ {
label: "Code", label: "Code",
value: "CODE" value: "CODE",
}, },
{ {
label: "Reasoning", label: "Reasoning",
value: "REASONING" value: "REASONING",
} },
]; ];
const AlwaysScrollToBottom = (): JSX.Element => { const AlwaysScrollToBottom = (): JSX.Element => {
@@ -91,182 +109,203 @@ const AlwaysScrollToBottom = (): JSX.Element => {
return <div ref={elementRef} />; return <div ref={elementRef} />;
}; };
const AsyncDashboardInner =({}): JSX.Element => { const AsyncDashboardInner = ({}): JSX.Element => {
const [controller, dispatch] = useMaterialUIController(); const [controller, dispatch] = useMaterialUIController();
const { const { darkMode } = controller;
darkMode, const buttonColor = darkMode ? "dark" : "light";
} = controller; const [announcements, setAnnouncement] = useState<Announcement[]>([]);
const buttonColor = darkMode? 'dark' : 'light'; const [subscribe, unsubscribe, socket, sendMessage] =
const [announcements, setAnnouncement] = useState<Announcement[]>([]); useContext(WebSocketContext);
const [subscribe, unsubscribe, socket, sendMessage] = useContext(WebSocketContext) const { account } = useContext(AccountContext);
const { account } = useContext(AccountContext)
const [isClosing, setIsClosing] = useState(false); const [isClosing, setIsClosing] = useState(false);
const {conversations, selectedConversation, setSelectedConversation} = useContext(ConversationContext); const { conversations, selectedConversation, setSelectedConversation } =
useContext(ConversationContext);
const {
conversationDetails,
setConversationDetails,
stateMessage,
isGeneratingMessage,
} = useContext(MessageContext);
const {conversationDetails, setConversationDetails, stateMessage, isGeneratingMessage} = useContext(MessageContext); const conversationRef = useRef(conversationDetails);
const conversationRef = useRef(conversationDetails) async function GetAnnouncements() {
const response: AxiosResponse<AnnouncementType[]> =
await axiosInstance.get("announcment/get/");
setAnnouncement(
response.data.map(
async function GetAnnouncements(){ (status, message) =>
const response: AxiosResponse<AnnouncementType[]> = await axiosInstance.get('announcment/get/') new Announcement({
setAnnouncement(response.data.map((status, message) => new Announcement({
status: status, status: status,
message: message message: message,
}))) }),
),
} );
const conversationTitle = conversations.find(item => item.id === selectedConversation)?.title ?? 'New Conversation';
const colorName = darkMode ? 'light' : 'dark';
const handlePromptSubmit = async ({prompt, file, fileType, modelName}: PromptValues, {resetForm}: any): Promise<void> => {
// send the prompt to be saved
try{
const tempConversations: ConversationPrompt[] = [...conversationDetails, new ConversationPrompt({message: prompt, user_created:true}), new ConversationPrompt({message: '', user_created:false})]
conversationRef.current = tempConversations
setConversationDetails(tempConversations)
// TODO: add the file here
sendMessage(prompt, selectedConversation, file, fileType, modelName)
resetForm();
}catch(e){
console.log(`error ${e}`)
// TODO: make this user friendly
}
} }
const conversationTitle =
conversations.find((item) => item.id === selectedConversation)?.title ??
"New Conversation";
const colorName = darkMode ? "light" : "dark";
const handlePromptSubmit = async (
{ prompt, file, fileType, modelName }: PromptValues,
{ resetForm }: any,
): Promise<void> => {
// send the prompt to be saved
try {
const tempConversations: ConversationPrompt[] = [
...conversationDetails,
new ConversationPrompt({ message: prompt, user_created: true }),
new ConversationPrompt({ message: "", user_created: false }),
];
return( conversationRef.current = tempConversations;
<DashboardLayout>
<Header2 />
<MDBox sx={{mt:5}}>
</MDBox>1 setConversationDetails(tempConversations);
<MDBox sx={{ margin: '0 auto', width: '80%', height: '80%', minHeight: '80%', maxHeight: '80%', align:'center'}}> // TODO: add the file here
<Card>
<CardContent>
<MDTypography variant="h3" >
{conversationTitle}
</MDTypography> sendMessage(prompt, selectedConversation, file, fileType, modelName);
</CardContent> resetForm();
<Divider /> } catch (e) {
<CardContent> console.log(`error ${e}`);
<> // TODO: make this user friendly
{conversationDetails.length > 0 ? }
conversationDetails.map((convo_detail) => };
convo_detail.message.length >0 ?
<ConversationDetailCard message={convo_detail.message} user_created={convo_detail.user_created} key={convo_detail.id}/> :
<ConversationDetailCard message={stateMessage} user_created={convo_detail.user_created} key={convo_detail.id}/>
)
:
<Markdown className='text-center' color='inherit'>Either select a previous conversation on start a new one.</Markdown>
}
<AlwaysScrollToBottom/>
</>
</CardContent>
<Divider />
<CardFooter>
<Formik
initialValues={{
prompt: '',
file: null,
fileType: null,
modelName: '',
}}
validationSchema={validationSchema}
onSubmit={handlePromptSubmit}
>
{(formik)=>
<Form>
return (
<DashboardLayout>
<Header2 />
<MDBox sx={{ mt: 5 }}></MDBox>1
<MDBox
sx={{
margin: "0 auto",
width: "80%",
height: "80%",
minHeight: "80%",
maxHeight: "80%",
align: "center",
}}
>
<Card>
<CardContent>
<MDTypography variant="h3">{conversationTitle}</MDTypography>
</CardContent>
<Divider />
<CardContent>
<>
{conversationDetails.length > 0 ? (
conversationDetails.map((convo_detail) =>
convo_detail.message.length > 0 ? (
<ConversationDetailCard
message={convo_detail.message}
user_created={convo_detail.user_created}
key={convo_detail.id}
/>
) : (
<ConversationDetailCard
message={stateMessage}
user_created={convo_detail.user_created}
key={convo_detail.id}
/>
),
)
) : (
<Markdown className="text-center" color="inherit">
Either select a previous conversation on start a new one.
</Markdown>
)}
<AlwaysScrollToBottom />
</>
</CardContent>
<Divider />
<CardFooter>
<Formik
initialValues={{
prompt: "",
file: null,
fileType: null,
modelName: "",
}}
validationSchema={validationSchema}
onSubmit={handlePromptSubmit}
>
{(formik) => (
<Form>
<Field
name={"prompt"}
fullWidth
as={MDInput}
label={"Prompt"}
errorstring={<ErrorMessage name={"prompt"} />}
size={"large"}
role={undefined}
tabIndex={-1}
variant={"outlined"}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<MDButton
component="label"
startIcon={<AttachFile />}
role={undefined}
tabIndex={-1}
color={formik.values.file ? "dark" : "light"}
>
<VisuallyHiddenInput
type="file"
accept=".csv,.xlsx,.txt"
onChange={(event) => {
const file = event.target.files?.[0];
//console.log(file)
if (file) {
formik.setFieldValue("file", file);
formik.setFieldValue("fileType", file.type);
} else {
formik.setFieldValue("file", null);
formik.setFieldValue("fileType", null);
}
}}
/>
</MDButton>
<MDButton
type={"submit"}
startIcon={<Send />}
disabled={!formik.isValid}
color={buttonColor}
>
<></>
</MDButton>
</InputAdornment>
),
}}
></Field>
</Form>
)}
</Formik>
<Field {/* <MDInput
name={"prompt"}
fullWidth
as={MDInput}
label={'Prompt'}
errorstring={<ErrorMessage name={'prompt'}/>}
size={'large'}
role={undefined}
tabIndex={-1}
variant={"outlined"}
InputProps={{
endAdornment: (
<InputAdornment position='end'>
<MDButton
component="label"
startIcon={<AttachFile/>}
role={undefined}
tabIndex={-1}
color={buttonColor}
>
<VisuallyHiddenInput
type="file"
accept='.csv,.xlsx,.txt'
onChange={(event) => {
const file = event.target.files?.[0];
//console.log(file)
if (file) {
formik.setFieldValue('file',file)
formik.setFieldValue('fileType',file.type)
} else {
formik.setFieldValue('file',null)
formik.setFieldValue('fileType',null)
}
}}
/>
</MDButton>
<MDButton
type={'submit'}
startIcon={<Send />}
disabled={!formik.isValid}
color={buttonColor}
>
<></>
</MDButton>
</InputAdornment>
)
}}
>
</Field>
</Form>
}
</Formik>
{/* <MDInput
label="Prompt" label="Prompt"
/> */} /> */}
</CardFooter> </CardFooter>
</Card> </Card>
<Footer /> <Footer />
</MDBox> </MDBox>
</DashboardLayout>
</DashboardLayout> );
) };
}
const AsyncDashboard2 = ({}): JSX.Element => { const AsyncDashboard2 = ({}): JSX.Element => {
return( return (
<DashboardWrapperLayout>
<AsyncDashboardInner />
</DashboardWrapperLayout>
);
};
<<<<<<< HEAD
<DashboardWrapperLayout> <DashboardWrapperLayout>
<AsyncDashboardInner /> <AsyncDashboardInner />
@@ -279,3 +318,6 @@ const AsyncDashboard2 = ({}): JSX.Element => {
} }
export default AsyncDashboard2 export default AsyncDashboard2
=======
export default AsyncDashboard2;
>>>>>>> b24fbf2 (update button based on state)