BarBar288's picture
Upload 122 files
27127dd verified
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Button } from './ui/button';
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from './ui/form';
import { Input } from './ui/input';
import { cn } from '@/lib/utils';
import { Card } from './ui/card';
import { Loader2 } from 'lucide-react';
// Define form schema
const formSchema = z.object({
prompt: z.string().min(1, {
message: 'Prompt is required',
}).max(1000, {
message: 'Prompt must be less than 1000 characters',
}),
model: z.enum(["Wan-AI/Wan2.1-T2V-14B"]).default("Wan-AI/Wan2.1-T2V-14B"),
});
type FormValues = z.infer<typeof formSchema>;
export default function VideoGenerator() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [videoUrl, setVideoUrl] = useState<string | null>(null);
// Default form values
const defaultValues: FormValues = {
prompt: '',
model: "Wan-AI/Wan2.1-T2V-14B",
};
// Initialize form
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues,
});
// Handle form submission
const onSubmit = async (data: FormValues) => {
setIsLoading(true);
setError(null);
try {
const response = await fetch('/api/generate-video', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Failed to generate video');
}
const result = await response.json();
setVideoUrl(result.videoUrl);
} catch (err: any) {
setError(err.message || 'An error occurred while generating the video');
console.error('Error generating video:', err);
} finally {
setIsLoading(false);
}
};
return (
<div className="w-full space-y-8">
<Card className="p-6">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<FormField
control={form.control}
name="prompt"
render={({ field }) => (
<FormItem>
<FormLabel>Prompt</FormLabel>
<FormControl>
<Input
placeholder="A young man walking on the street"
{...field}
/>
</FormControl>
<FormDescription>
Describe the video you want to generate.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button
type="submit"
className="w-full"
disabled={isLoading}
>
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Generating video...
</>
) : 'Generate Video'}
</Button>
</form>
</Form>
</Card>
{error && (
<div className="p-4 text-sm border border-red-200 bg-red-50 text-red-800 rounded-md">
{error}
</div>
)}
<div className={cn("flex flex-col items-center justify-center",
videoUrl ? "bg-gray-50 dark:bg-gray-900" : "bg-gray-100 dark:bg-gray-800")}>
{videoUrl ? (
<div className="relative w-full">
<video
src={videoUrl}
controls
className="rounded-md object-contain max-h-[600px] mx-auto"
/>
<div className="mt-4 flex justify-center">
<Button
variant="outline"
onClick={() => window.open(videoUrl, '_blank')}
className="mr-2"
>
Open in New Tab
</Button>
<Button
variant="outline"
onClick={() => {
const a = document.createElement('a');
a.href = videoUrl;
a.download = 'generated-video.mp4';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}}
>
Download
</Button>
</div>
</div>
) : (
<Card className="w-full h-full flex items-center justify-center p-8 border-dashed">
<div className="text-center">
<p className="text-muted-foreground">
Your generated video will appear here
</p>
</div>
</Card>
)}
</div>
</div>
);
}