Spaces:
Runtime error
Runtime error
| /** @jsxImportSource @emotion/react */ | |
| "use client"; | |
| import Dropzone, { uploadImageAtom } from "@/components/dropzone"; | |
| import { css } from "@emotion/react"; | |
| import { Button } from "antd"; | |
| import { useAtom, useAtomValue, atom } from "jotai"; | |
| import Header from "@/components/header"; | |
| import { | |
| DownloadOutlined, | |
| ReloadOutlined, | |
| SyncOutlined, | |
| } from "@ant-design/icons"; | |
| import { useEffect, useState } from "react"; | |
| import StyleCard from "./style-card"; | |
| const STYLEs = [ | |
| { | |
| style: "anime", | |
| name: "Anime", | |
| }, | |
| { | |
| style: "3d", | |
| name: "3D", | |
| }, | |
| { | |
| style: "handdrawn", | |
| name: "Handdrawn", | |
| }, | |
| { | |
| style: "sketch", | |
| name: "Sketch", | |
| }, | |
| { | |
| style: "artstyle", | |
| name: "Art Style", | |
| }, | |
| { | |
| style: "sd-design", | |
| name: "SD Design", | |
| }, | |
| { | |
| style: "sd-illustration", | |
| name: "SD Illustrate", | |
| }, | |
| ]; | |
| const generatedImageAtom = atom<string | null>(null); | |
| export default function Home() { | |
| const uploadImage = useAtomValue(uploadImageAtom); | |
| const [generatedImage, setGeneratedImage] = useAtom(generatedImageAtom); | |
| const [loading, setLoading] = useState(false); | |
| const [pickedStyle, setPickedStyle] = useState("anime"); | |
| useEffect(() => { | |
| setGeneratedImage(null); | |
| }, [uploadImage]); | |
| const handleTransform = async () => { | |
| if (!uploadImage) return; | |
| setLoading(true); | |
| const res = await fetch("/api/style-transform", { | |
| method: "POST", | |
| body: JSON.stringify({ | |
| style: pickedStyle, | |
| pic: uploadImage.split(",")[1], | |
| }), | |
| }) | |
| .then((res) => res.json()) | |
| .finally(() => setLoading(false)); | |
| setGeneratedImage(`data:image/jpeg;base64,${res.image}`); | |
| }; | |
| return ( | |
| <> | |
| <main className="min-h-screen container mx-auto pb-8"> | |
| <Header /> | |
| <div className="flex flex-col items-center mx-auto px-4"> | |
| <h1 className="text-5xl font-bold text-center mt-4 mb-8"> | |
| AI Art Generator | |
| </h1> | |
| <div className="flex flex-col items-center gap-4 max-w-4xl"> | |
| <Dropzone /> | |
| <div className="flex justify-center w-full space-x-4 p-2 overflow-x-auto"> | |
| {STYLEs.map((style) => ( | |
| <StyleCard | |
| key={style.name} | |
| styleName={style.name} | |
| selected={style.style === pickedStyle} | |
| onClick={() => setPickedStyle(style.style)} | |
| /> | |
| ))} | |
| </div> | |
| {generatedImage ? ( | |
| <div className="relative flex justify-center items-center w-[600px] h-[400px]"> | |
| <div className="absolute top-0 right-0 translate-x-[100%] flex flex-col pl-1 gap-1 text-xl text-gray-800"> | |
| <ReloadOutlined | |
| className="cursor-pointer hover:scale-125" | |
| onClick={() => handleTransform()} | |
| /> | |
| <DownloadOutlined | |
| className="cursor-pointer hover:scale-125" | |
| onClick={() => { | |
| const a = document.createElement("a"); | |
| a.href = generatedImage; | |
| a.download = "generated.jpg"; | |
| a.click(); | |
| }} | |
| /> | |
| </div> | |
| {loading && ( | |
| <SyncOutlined | |
| spin | |
| className="absolute text-9xl text-gray-700 opacity-60" | |
| /> | |
| )} | |
| <img | |
| className="object-contain object-top w-full h-full" | |
| src={generatedImage} | |
| alt="generated image" | |
| /> | |
| </div> | |
| ) : ( | |
| <Button | |
| className="w-[200px] h-[80px] text-2xl text-white rounded-lg" | |
| css={css` | |
| background: linear-gradient( | |
| 106.28deg, | |
| rgb(133, 96, 250) 0%, | |
| rgb(68, 211, 239) 90.81% | |
| ) !important; | |
| `} | |
| disabled={!uploadImage} | |
| onClick={handleTransform} | |
| loading={loading} | |
| > | |
| Generate! | |
| </Button> | |
| )} | |
| </div> | |
| </div> | |
| </main> | |
| </> | |
| ); | |
| } | |