import React, { useEffect, useState, useRef, useCallback } from 'react'; import Avatar from '@mui/material/Avatar'; import Box from '@mui/material/Box'; import Tooltip from '@mui/material/Tooltip'; import Button from '@mui/material/Button'; import Paper from '@mui/material/Paper'; import IconButton from '@mui/material/IconButton'; import CancelIcon from '@mui/icons-material/Cancel'; import SendIcon from '@mui/icons-material/Send'; import PropagateLoader from 'react-spinners/PropagateLoader'; import { CandidateInfo } from './CandidateInfo'; import { Query } from '../types/types' import { Quote } from 'components/Quote'; import { streamQueryResponse, StreamQueryController } from './streamQueryResponse'; import { connectionBase } from 'Global'; import { User } from '../types/types'; import { BackstoryElementProps } from 'components/BackstoryTab'; import { BackstoryTextField, BackstoryTextFieldRef } from 'components/BackstoryTextField'; import { jsonrepair } from 'jsonrepair'; import { StyledMarkdown } from 'components/StyledMarkdown'; import { Scrollable } from './Scrollable'; import { Pulse } from 'components/Pulse'; import { useUser } from './UserContext'; interface GenerateImageProps extends BackstoryElementProps { prompt: string }; const GenerateImage = (props: GenerateImageProps) => { const { user } = useUser(); const {sessionId, setSnack, prompt} = props; const [processing, setProcessing] = useState(false); const [status, setStatus] = useState(''); const [timestamp, setTimestamp] = useState(0); const [image, setImage] = useState(''); // Only keep refs that are truly necessary const controllerRef = useRef(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: user?.username, } }, type: "image", sessionId, connectionBase, 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.timestamp) { setTimestamp(data.timestamp); } else { setTimestamp(Date.now()) } if (data.message) { setStatus(data.message); } break; } } }); }, [user, prompt, sessionId, setSnack]); if (!sessionId) { return <>; } return ( {image !== '' && {prompt}} { prompt && } {processing && { status && Generation status {status} } } ); }; export { GenerateImage };