File size: 4,582 Bytes
0d57ded
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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;