How to upload a file with Nextjs and Zod and run it through a replicate.com model

665 Views Asked by At

I am trying to use a replicate model that takes image and text as a prompt , but I can't make the file upload work here is my page.tsx:

"use client";
import * as z from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import axios from "axios";
import { Home } from "lucide-react";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { useState } from "react";
import { useRef } from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Card, CardFooter } from "@/components/ui/card";
import { Form, FormControl, FormField, FormItem } from "@/components/ui/form";
import downloadPhoto from "@/public/downolad";
import appendNewToName from "@/public/newname";
import { formSchema } from "@/app/(dashboard)/(routes)/product/constants";
import Heading from "@/components/heading";
import { Empty } from "@/components/empty";
import { Loader } from "@/components/loader";

const ProductPage = () => {
  const router = useRouter();
  const [images, setImages] = useState<string[]>([]);
  const InputRef = useRef(null);
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      prompt: "",
    },
  });

  const isLoading = form.formState.isSubmitting;

  const onSubmit = async (values: z.infer<typeof formSchema>) => {
    try {
      setImages([]);
      const prompt= values.prompt
      const formdata = new FormData
      formdata.append("prompt", prompt)
      formdata.append('inputimage', InputRef.current.files[0])
      const response = await axios.post("/api/product", formData);

      console.log(response.data);
      setImages(response.data);
      form.reset();
    } catch (error) {
      console.log(error);
    } finally {
      router.refresh();
    }
  };

  return (
    <div>
      <Heading
        title="Interior"
        description="Generate Interior Design with AI"
        icon={Home}
        iconColor="text-emerald-300"
      />
      <div className="px-4 lg:px-8">
        <div>
          <Form {...form}>
            <form
              onSubmit={form.handleSubmit(onSubmit)}
              className="rouned-lg border w-full p-4 px-3 md:px-6 focus-within:shadow-sm grid grid-cols-12 gap-2"
            >
              <FormField
                name="prompt"
                render={({ field }) => (
                  <FormItem className="col-span-12 lg:col-span-10">
                    <FormControl className="m-0 p-0">
                      <Input
                        className="border-0 outline-none focus-visible:ring-0 focus-visible:ring-transparent"
                        disabled={isLoading}
                        placeholder="A dark bathroom"
                        {...field}
                      />
                    </FormControl>
                  </FormItem>
                )}
              />
              <FormField
                name="image"
                render={({ field }) => (
                  <FormItem className="col-span-12 lg:col-span-10">
                    <FormControl className="m-0 p-0">
                      <Input
                        className="border-0 outline-none focus-visible:ring-0 focus-visible:ring-transparent"
                        disabled={isLoading}
                        {...field}
                        type="file"
                        ref={InputRef}
                        accept="image/*"
                      />
                    </FormControl>
                  </FormItem>
                )}
              />

              <Button
                className="col-span-12 lg:col-span-2 w-full"
                disabled={isLoading}
              >
                Generate
              </Button>
            </form>
          </Form>
        </div>
        <div className="space-y-4 mt-4">
          {isLoading && (
            <div className="p-20">
              <Loader />
            </div>
          )}

          {images.length === 0 && !isLoading && (
            <Empty label="No images generated" />
          )}
          <div className=" flex items-center">
            {images.map((src) => (
              <Card key={src} className="rounded-lg block m-auto">
                <div className="relative aspect-square">
                  <img alt="image" src={src} width={300} height={300} />
                </div>
                <CardFooter className="p-2">
                  <Button
                    variant="secondary"
                    className="w-50 border-black border-2 block m-auto hover:bg-slate-600 hover:text-white"
                    onClick={() => downloadPhoto(src, appendNewToName(src))}
                  >
                    <h1 className="block m-auto w-20 ">DOWNLOAD</h1>
                  </Button>
                </CardFooter>
              </Card>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
};

export default ProductPage;

My constants.ts with zod:

import * as z from "zod";

export const formSchema = z.object({
    prompt: z.string().min(1, {
        message: "Image Prompt is required",
    }),
    file: z.instanceof(File)
});

And my route.ts:

import { NextResponse } from 'next/server';
import { auth } from '@clerk/nextjs';
import Replicate from "replicate";

const replicate = new Replicate({
  auth: process.env.REPLICATE_API_TOKEN!,
});

export async function POST(req: Request) {
  try {
    const { userId } = auth();
    const body = await req.json();
    const prompt = body.prompt;
    const inputImage = body.inputimage; // Change from body.prompt to body.inputimage

    if (!userId) {
      return new NextResponse('Unauthorized', { status: 401 });
    }

    if (!prompt) {
      return new NextResponse('Prompt is required', { status: 400 });
    }

    if (!inputImage) {
      return new NextResponse('Input image is required', { status: 400 });
    }

    const response = await replicate.run(
      "logerzhu/ad-inpaint:b1c17d148455c1fda435ababe9ab1e03bc0d917cc3cf4251916f22c45c83c7df",
      {
        input: {
          image_path: inputImage,
          prompt: prompt,
        }
      }
    );
      
    return  NextResponse.json(await response);
  } catch (error) {
    console.error('[VIDEO ERROR]', error);
    return new NextResponse('Internal error', { status: 500 });
  }
}

I had tried so many ways but none of them work so please somebody help me?Please if somebody helps me to use zod because that is my way to show the loader.I know that my code has many errors

0

There are 0 best solutions below