"use client" import { useEffect, useRef, useState, useTransition } from "react" // import AutoSizer from "react-virtualized-auto-sizer" import { RenderedScene } from "@/types" import { getRender, newRender } from "@/app/engine/render" import { useStore } from "@/app/store" import { cn } from "@/lib/utils" import { getInitialRenderedScene } from "@/lib/getInitialRenderedScene" import { Progress } from "@/app/interface/progress" import { see } from "@/app/engine/caption" // import { Bubble } from "./bubble" export function Panel({ panel, className = "", width = 1, height = 1, delay = 0, }: { panel: number className?: string width?: number height?: number delay?: number }) { const font = useStore(state => state.font) const preset = useStore(state => state.preset) const setGeneratingImages = useStore(state => state.setGeneratingImages) const panelGenerationStatus = useStore(state => state.panelGenerationStatus) const isLoading = panelGenerationStatus[panel] || false const panels = useStore(state => state.panels) const prompt = panels[panel] || "" const zoomLevel = useStore(state => state.zoomLevel) // const setCaption = useStore(state => state.setCaption) // const captions = useStore(state => state.captions) // const caption = captions[panel] || "" const [_isPending, startTransition] = useTransition() const [rendered, setRendered] = useState(getInitialRenderedScene()) const renderedRef = useRef() const timeoutRef = useRef(null) // since this run in its own loop, we need to use references everywhere // but perhaps this could be refactored useEffect(() => { startTransition(async () => { // console.log("Panel prompt: "+ prompt) if (!prompt?.length) { return } if (isLoading) { return } console.log("Loading panel..") // console.log("calling:\nconst newRendered = await newRender({ prompt, preset, width, height })") console.log({ panel, prompt, width, height }) console.log("") // important: update the status, and clear the scene setGeneratingImages(panel, true) setRendered(getInitialRenderedScene()) const newRendered = await newRender({ prompt, width, height }) if (newRendered) { // console.log("newRendered:", newRendered) setRendered(renderedRef.current = newRendered) // but we are still loading! } else { setRendered(renderedRef.current = { renderId: "", status: "error", assetUrl: "", alt: "", maskUrl: "", error: "failed to fetch the data", segments: [] }) setGeneratingImages(panel, false) return } }) }, [prompt, font, width, height]) const checkStatus = () => { startTransition(async () => { clearTimeout(timeoutRef.current) if (!renderedRef.current?.renderId || renderedRef.current?.status !== "pending") { timeoutRef.current = setTimeout(checkStatus, 1000) return } try { setGeneratingImages(panel, true) // console.log(`Checking job status API for job ${renderedRef.current?.renderId}`) const newRendered = await getRender(renderedRef.current.renderId) // console.log("got a response!", newRendered) if (JSON.stringify(renderedRef.current) !== JSON.stringify(newRendered)) { console.log("updated panel:", newRendered) setRendered(renderedRef.current = newRendered) setGeneratingImages(panel, true) } // console.log("status:", newRendered.status) if (newRendered.status === "pending") { // console.log("job not finished") timeoutRef.current = setTimeout(checkStatus, 1000) } else { console.log("panel finished!") setGeneratingImages(panel, false) } } catch (err) { console.error(err) timeoutRef.current = setTimeout(checkStatus, 1000) } }) } useEffect(() => { console.log("starting timeout") // normally it should reply in < 1sec, but we could also use an interval timeoutRef.current = setTimeout(checkStatus, delay) return () => { clearTimeout(timeoutRef.current) } }, []) /* doing the captionning from the browser is expensive a simpler solution is to caption directly during SDXL generation useEffect(() => { if (!rendered.assetUrl) { return } // the asset url can evolve with time (link to a better resolution image) // however it would be costly to ask for the caption, the low resolution is enough for the semantic resolution // so we just do nothing if we already have the caption if (caption) { return } startTransition(async () => { try { const newCaption = await see({ prompt: "please caption the following image", imageBase64: rendered.assetUrl }) if (newCaption) { setCaption(newCaption) } } catch (err) { console.error(`failed to generate the caption:`, err) } }) }, [rendered.assetUrl, caption]) */ const frameClassName = cn( `w-full h-full`, `border-stone-900`, `transition-all duration-200 ease-in-out`, zoomLevel > 70 ? `border-2` : zoomLevel > 40 ? `border` : `border border-transparent`, `shadow-sm`, `rounded-sm`, `overflow-hidden`, ) if (prompt && !rendered.assetUrl) { return (
) } return (
{rendered.assetUrl && {rendered.alt}} {/* Hello, world! */}
) }