backstory/frontend/src/components/GenerateImage.tsx

134 lines
4.8 KiB
TypeScript

import React, { useEffect, useState, useRef } from 'react';
import Box from '@mui/material/Box';
import PropagateLoader from 'react-spinners/PropagateLoader';
import { Quote } from 'components/Quote';
import { BackstoryElementProps } from 'components/BackstoryTab';
import { useUser } from 'hooks/useUser';
import { Candidate, ChatSession } from 'types/types';
import { useSecureAuth } from 'hooks/useSecureAuth';
interface GenerateImageProps extends BackstoryElementProps {
prompt: string;
chatSession: ChatSession;
};
const GenerateImage = (props: GenerateImageProps) => {
const { user } = useSecureAuth();
const { setSnack, chatSession, prompt } = props;
const [processing, setProcessing] = useState<boolean>(false);
const [status, setStatus] = useState<string>('');
const [image, setImage] = useState<string>('');
const name = (user?.userType === 'candidate' ? (user as Candidate).username : user?.email) || '';
// Only keep refs that are truly necessary
const controllerRef = useRef<string>(null);
// Effect to trigger profile generation when user data is ready
useEffect(() => {
if (controllerRef.current) {
console.log("Controller already active, skipping profile generation");
return;
}
if (!prompt) {
return;
}
setStatus('Starting image generation...');
setProcessing(true);
const start = Date.now();
// controllerRef.current = streamQueryResponse({
// query: {
// prompt: prompt,
// agentOptions: {
// username: name,
// }
// },
// type: "image",
// onComplete: (msg) => {
// switch (msg.status) {
// case "partial":
// case "done":
// if (msg.status === "done") {
// if (!msg.response) {
// setSnack("Image generation failed", "error");
// } else {
// setImage(msg.response);
// }
// setProcessing(false);
// controllerRef.current = null;
// }
// break;
// case "error":
// console.log(`Error generating profile: ${msg.response} after ${Date.now() - start}`);
// setSnack(msg.response || "", "error");
// setProcessing(false);
// controllerRef.current = null;
// break;
// default:
// let data: any = {};
// try {
// data = typeof msg.response === 'string' ? JSON.parse(msg.response) : msg.response;
// } catch (e) {
// data = { message: msg.response };
// }
// if (msg.status !== "heartbeat") {
// console.log(data);
// }
// if (data.message) {
// setStatus(data.message);
// }
// break;
// }
// }
// });
}, [user, prompt, setSnack]);
if (!chatSession) {
return <></>;
}
return (
<Box className="GenerateImage" sx={{
display: "flex",
flexDirection: "column",
flexGrow: 1,
gap: 1,
maxWidth: { xs: '100%', md: '700px', lg: '1024px' },
minHeight: "max-content",
}}>
{image !== '' && <img alt={prompt} src={`${image}/${chatSession.id}`} />}
{ prompt &&
<Quote size={processing ? "normal" : "small"} quote={prompt} sx={{ "& *": { color: "#2E2E2E !important" }}}/>
}
{processing &&
<Box sx={{
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
m: 0,
gap: 1,
minHeight: "min-content",
mb: 2
}}>
{ status &&
<Box sx={{ display: "flex", flexDirection: "column"}}>
<Box sx={{ fontSize: "0.5rem"}}>Generation status</Box>
<Box sx={{ fontWeight: "bold"}}>{status}</Box>
</Box>
}
<PropagateLoader
size="10px"
loading={processing}
color="white"
aria-label="Loading Spinner"
data-testid="loader"
/>
</Box>
}
</Box>);
};
export {
GenerateImage
};