"use client" import { useEffect, useRef, useTransition } from "react" import { cn } from "@/lib/utils" import { TopMenu } from "../interface/top-menu" import { fonts } from "@/lib/fonts" import { useStore } from "../store" import { BottomBar } from "../interface/bottom-bar" import { SphericalImage } from "../interface/spherical-image" import { getRender, newRender } from "../engine/render" import { RenderedScene } from "@/types" import { getPost, postToCommunity } from "../engine/community" import { useSearchParams } from "next/navigation" export default function GeneratePage() { const searchParams = useSearchParams() const [_isPending, startTransition] = useTransition() const postId = (searchParams.get("postId") as string) || "" const prompt = useStore(state => state.prompt) const setPrompt = useStore(state => state.setPrompt) const setRendered = useStore(state => state.setRendered) const renderedScene = useStore(state => state.renderedScene) const isLoading = useStore(state => state.isLoading) const setLoading = useStore(state => state.setLoading) // keep a ref in sync const renderedRef = useRef() const renderedKey = JSON.stringify(renderedScene) useEffect(() => { renderedRef.current = renderedScene }, [renderedKey]) const timeoutRef = useRef(null) const delay = 3000 // react to prompt changes useEffect(() => { if (!prompt) { return } // to prevent loading a new prompt if we are already loading // (eg. the initial one, from a community post) // if (isLoading) { return } startTransition(async () => { try { const rendered = await newRender({ prompt, clearCache: true }) setRendered(rendered) } catch (err) { console.error(err) } finally { } }) }, [prompt]) // important: we need to react to preset changes too const checkStatus = () => { startTransition(async () => { clearTimeout(timeoutRef.current) if (renderedRef.current?.status === "completed") { console.log("rendering job is already completed") return } if (!renderedRef.current?.renderId || renderedRef.current?.status !== "pending") { timeoutRef.current = setTimeout(checkStatus, delay) return } try { // console.log(`Checking job status API for job ${renderedRef.current?.renderId}`) const newRendered = await getRender(renderedRef.current.renderId) if (!newRendered) { throw new Error(`getRender failed`) } // console.log("got a response!", newRendered) if (JSON.stringify(renderedRef.current) !== JSON.stringify(newRendered)) { // console.log("updated panel:", newRendered) setRendered(renderedRef.current = newRendered) } // console.log("status:", newRendered.status) if (newRendered.status === "pending") { console.log("job not finished") timeoutRef.current = setTimeout(checkStatus, delay) } else if (newRendered.status === "error" || (newRendered.status === "completed" && !newRendered.assetUrl?.length)) { console.log(`panorama got an error and/or an empty asset url :/ "${newRendered.error}", but let's try to recover..`) setLoading(false) } else { console.log("panorama finished:", newRendered) try { await postToCommunity({ prompt, model: "jbilcke-hf/sdxl-panorama", assetUrl: newRendered.assetUrl, }) } catch (err) { console.log("failed to post to community, but it's no big deal") } setRendered(newRendered) setLoading(false) } } catch (err) { console.error(err) timeoutRef.current = setTimeout(checkStatus, delay) } }) } useEffect(() => { // console.log("starting timeout") clearTimeout(timeoutRef.current) // normally it should reply in < 1sec, but we could also use an interval timeoutRef.current = setTimeout(checkStatus, delay) return () => { clearTimeout(timeoutRef.current) } }, [prompt]) useEffect(() => { if (!postId) { return } setLoading(true) startTransition(async () => { try { console.log(`loading post ${postId}`) const post = await getPost(postId) // setting the prompt here will mess-up with everything // normally this shouldn't trigger the normal prompt update workflow, // because we are set the app to "is loading" // setPrompt(post.prompt) setRendered({ renderId: postId, status: "completed", assetUrl: post.assetUrl, alt: post.prompt, error: "", maskUrl: "", segments: [] }) setLoading(false) } catch (err) { console.error("failed to get post: ", err) setLoading(false) } }) }, [postId]) return (
{renderedScene.assetUrl ? {}) as any} debug={true} /> : null}
{isLoading ? 'Generating metaverse location in the latent space..' : ''}
) }