smart-bright-tool / components /VideoGeneratorForm.jsx
Gertie01's picture
Upload components/VideoGeneratorForm.jsx with huggingface_hub
0d57ded verified
import React, { useState, useCallback } from 'react';
const VideoGeneratorForm = ({ onGenerate }) => {
const [prompt, setPrompt] = useState('');
const [duration, setDuration] = useState(15); // Default 15 seconds
const [loading, setLoading] = useState(false);
const handleSubmit = useCallback(async (e) => {
e.preventDefault();
if (!prompt.trim()) {
alert("Please enter a text prompt.");
return;
}
setLoading(true);
onGenerate({ status: 'loading' });
try {
const response = await fetch('/api/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ prompt, duration }),
});
const data = await response.json();
if (response.ok) {
onGenerate({ status: 'success', data });
} else {
onGenerate({ status: 'error', error: data.error || 'Generation failed.' });
}
} catch (error) {
console.error('API Error:', error);
onGenerate({ status: 'error', error: 'Network error or service unavailable.' });
} finally {
setLoading(false);
}
}, [prompt, duration, onGenerate]);
return (
<form onSubmit={handleSubmit} className="p-6 bg-gray-800 rounded-xl shadow-2xl space-y-6">
<h2 className="text-2xl font-semibold text-white">Generate Video</h2>
{/* Text Prompt */}
<div>
<label htmlFor="prompt" className="block text-sm font-medium text-gray-300 mb-2">
Text Prompt (The scene description)
</label>
<textarea
id="prompt"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
rows="3"
placeholder="A majestic golden retriever wearing a tiny astronaut helmet floating through space, viewed in cinematic 4K."
className="w-full p-3 border border-gray-600 rounded-lg bg-gray-700 text-white focus:ring-purple-500 focus:border-purple-500 transition duration-150 ease-in-out"
required
aria-describedby="prompt-description"
/>
<p id="prompt-description" className="text-xs text-gray-500 mt-1">
Describe your desired video, including style, subjects, and movement.
</p>
</div>
{/* Duration Slider */}
<div>
<label htmlFor="duration" className="block text-sm font-medium text-gray-300 mb-2">
Video Duration: <span className="font-bold text-purple-400">{duration} seconds</span> (4s to 120s)
</label>
<input
type="range"
id="duration"
min="4"
max="120"
value={duration}
onChange={(e) => setDuration(Number(e.target.value))}
className="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer range-lg focus:outline-none focus:ring-2 focus:ring-purple-500"
/>
<div className="flex justify-between text-xs text-gray-500 mt-1">
<span>4s</span>
<span>120s</span>
</div>
</div>
{/* Image Upload (Placeholder) */}
<div className="border-2 border-dashed border-gray-600 p-6 rounded-lg text-center bg-gray-700/50">
<p className="text-gray-400 font-medium">Image-to-Video Input (Optional)</p>
<p className="text-sm text-gray-500 mt-1">
Drag and drop an image or click to upload (Feature placeholder).
</p>
</div>
<button
type="submit"
disabled={loading || !prompt.trim()}
className="w-full py-3 px-4 rounded-lg text-white font-semibold transition-all duration-200 ease-in-out
bg-purple-600 hover:bg-purple-700 focus:ring-4 focus:ring-purple-500 focus:ring-opacity-50
disabled:bg-gray-500 disabled:cursor-not-allowed flex justify-center items-center"
aria-live="polite"
>
{loading ? (
<>
<svg className="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Generating Video...
</>
) : (
'Start Sora 2 Generation'
)}
</button>
</form>
);
};
export default VideoGeneratorForm;