Hamed744 commited on
Commit
521762e
·
verified ·
1 Parent(s): 13ecfd1

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +1054 -19
index.html CHANGED
@@ -1,19 +1,1054 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fa" dir="rtl">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ساخت ویدیو هوشمند LTX | تبدیل تصویر و متن به انیمیشن</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link href="https://cdn.jsdelivr.net/gh/rastikerdar/[email protected]/Vazirmatn-font-face.css" rel="stylesheet">
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ @keyframes float {
12
+ 0% { transform: translateY(0px); }
13
+ 50% { transform: translateY(-8px); }
14
+ 100% { transform: translateY(0px); }
15
+ }
16
+
17
+ @keyframes gradientFlow {
18
+ 0% { background-position: 0% 50%; }
19
+ 50% { background-position: 100% 50%; }
20
+ 100% { background-position: 0% 50%; }
21
+ }
22
+
23
+ @keyframes fadeIn {
24
+ from { opacity: 0; transform: translateY(10px); }
25
+ to { opacity: 1; transform: translateY(0); }
26
+ }
27
+
28
+ @keyframes pulseGlow {
29
+ 0% { box-shadow: 0 0 0 0 rgba(139, 92, 246, 0.4); }
30
+ 70% { box-shadow: 0 0 0 12px rgba(139, 92, 246, 0); }
31
+ 100% { box-shadow: 0 0 0 0 rgba(139, 92, 246, 0); }
32
+ }
33
+
34
+ .animate-float {
35
+ animation: float 6s ease-in-out infinite;
36
+ }
37
+
38
+ .gradient-animate {
39
+ background-size: 300% 300%;
40
+ animation: gradientFlow 12s ease infinite;
41
+ }
42
+
43
+ .animate-fade-in {
44
+ animation: fadeIn 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
45
+ }
46
+
47
+ .pulse-glow {
48
+ animation: pulseGlow 2s infinite;
49
+ }
50
+
51
+ .glass-morphism {
52
+ background: rgba(255, 255, 255, 0.05);
53
+ backdrop-filter: blur(16px);
54
+ -webkit-backdrop-filter: blur(16px);
55
+ border: 1px solid rgba(255, 255, 255, 0.08);
56
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15);
57
+ }
58
+
59
+ .option-card {
60
+ transition: all 0.4s cubic-bezier(0.68, -0.6, 0.32, 1.6);
61
+ transform-style: preserve-3d;
62
+ }
63
+
64
+ .option-card:hover {
65
+ transform: translateY(-6px) scale(1.02);
66
+ }
67
+
68
+ .option-card.selected {
69
+ transform: translateY(-4px);
70
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.2), 0 10px 10px -5px rgba(0, 0, 0, 0.1);
71
+ }
72
+
73
+ .file-drop-area {
74
+ transition: all 0.3s ease;
75
+ }
76
+
77
+ .file-drop-area.drag-over {
78
+ border-color: #8b5cf6;
79
+ background: rgba(139, 92, 246, 0.08);
80
+ }
81
+
82
+ .progress-track {
83
+ background: linear-gradient(90deg, #8b5cf6 0%, #6366f1 100%);
84
+ background-size: 200% 100%;
85
+ animation: gradientFlow 4s ease infinite;
86
+ }
87
+
88
+ .text-gradient {
89
+ background-clip: text;
90
+ -webkit-background-clip: text;
91
+ color: transparent;
92
+ }
93
+
94
+ .status-message {
95
+ animation: fadeIn 0.4s cubic-bezier(0.16, 1, 0.3, 1);
96
+ }
97
+
98
+ .video-container {
99
+ perspective: 1000px;
100
+ }
101
+
102
+ .video-wrapper {
103
+ transform-style: preserve-3d;
104
+ transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
105
+ }
106
+
107
+ .video-wrapper:hover {
108
+ transform: rotateX(2deg) rotateY(2deg) scale(1.02);
109
+ }
110
+
111
+ /* New button styles */
112
+ .primary-btn {
113
+ background: linear-gradient(135deg, #7c3aed 0%, #5b21b6 100%);
114
+ color: white;
115
+ transition: all 0.3s ease;
116
+ }
117
+
118
+ .primary-btn:hover {
119
+ background: linear-gradient(135deg, #6d28d9 0%, #4c1d95 100%);
120
+ transform: translateY(-2px);
121
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
122
+ }
123
+
124
+ .secondary-btn {
125
+ background: rgba(255, 255, 255, 0.05);
126
+ border: 1px solid rgba(255, 255, 255, 0.1);
127
+ color: #e2e8f0;
128
+ transition: all 0.3s ease;
129
+ }
130
+
131
+ .secondary-btn:hover {
132
+ background: rgba(255, 255, 255, 0.1);
133
+ border-color: rgba(255, 255, 255, 0.2);
134
+ }
135
+
136
+ .accent-btn {
137
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
138
+ color: white;
139
+ transition: all 0.3s ease;
140
+ }
141
+
142
+ .accent-btn:hover {
143
+ background: linear-gradient(135deg, #0d9b6c 0%, #047857 100%);
144
+ }
145
+
146
+ .tab-btn {
147
+ position: relative;
148
+ overflow: hidden;
149
+ }
150
+
151
+ .tab-btn::after {
152
+ content: '';
153
+ position: absolute;
154
+ bottom: 0;
155
+ left: 0;
156
+ right: 0;
157
+ height: 2px;
158
+ background: linear-gradient(90deg, #7c3aed 0%, #5b21b6 100%);
159
+ transform: scaleX(0);
160
+ transition: transform 0.3s ease;
161
+ transform-origin: left;
162
+ }
163
+
164
+ .tab-btn.active::after {
165
+ transform: scaleX(1);
166
+ }
167
+ </style>
168
+ </head>
169
+ <body class="min-h-screen bg-gray-950 text-gray-100 font-sans overflow-x-hidden">
170
+ <!-- Clean Background -->
171
+ <div class="fixed inset-0 -z-10 bg-gradient-to-br from-gray-950 to-gray-900"></div>
172
+
173
+ <div class="container mx-auto px-4 py-12 max-w-4xl relative">
174
+ <!-- Header Section -->
175
+ <div class="text-center mb-16 animate-fade-in" style="animation-delay: 0.1s;">
176
+ <div class="inline-flex items-center justify-center p-5 rounded-2xl glass-morphism mb-6 shadow-lg">
177
+ <i class="fas fa-film text-4xl text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-indigo-400"></i>
178
+ </div>
179
+ <h1 class="text-4xl font-bold mb-4 flex items-center justify-center">
180
+ <span class="text-gradient bg-gradient-to-r from-purple-300 via-indigo-300 to-blue-300">ساخت ویدیو هوشمند</span>
181
+ <span class="text-gradient bg-gradient-to-r from-purple-400 to-pink-400 mr-3">LTX</span>
182
+ </h1>
183
+ <p class="text-lg text-gray-300 max-w-2xl mx-auto leading-relaxed">
184
+ با فناوری هوش مصنوعی، تصاویر و متون خود را به انیمیشن‌های خیره‌کننده تبدیل کنید
185
+ </p>
186
+ </div>
187
+
188
+ <!-- Main Card -->
189
+ <div class="glass-morphism rounded-3xl overflow-hidden shadow-2xl mb-10 animate-fade-in" style="animation-delay: 0.2s;">
190
+ <!-- Mode Selector -->
191
+ <div class="flex border-b border-gray-700/50">
192
+ <button class="mode-button tab-btn flex-1 py-5 font-medium text-sm uppercase tracking-wider transition-all duration-300 relative overflow-hidden group active" data-mode="image-to-video">
193
+ <span class="relative z-10 flex items-center justify-center">
194
+ <i class="fas fa-image ml-2 text-purple-300"></i>
195
+ تصویر به ویدیو
196
+ </span>
197
+ </button>
198
+ <button class="mode-button tab-btn flex-1 py-5 font-medium text-sm uppercase tracking-wider transition-all duration-300 relative overflow-hidden group" data-mode="text-to-video">
199
+ <span class="relative z-10 flex items-center justify-center">
200
+ <i class="fas fa-font ml-2 text-gray-400 group-hover:text-gray-300 transition-colors"></i>
201
+ متن به ویدیو
202
+ </span>
203
+ </button>
204
+ </div>
205
+
206
+ <!-- Form Content -->
207
+ <div class="p-8">
208
+ <!-- Image to Video Section -->
209
+ <div id="imageToVideoSection" class="form-mode-section">
210
+ <div class="mb-8">
211
+ <label for="imageFile" class="block text-sm font-medium mb-3 text-gray-300 flex items-center">
212
+ <i class="fas fa-image mr-2 text-purple-300"></i>
213
+ انتخاب تصویر
214
+ </label>
215
+ <div class="file-drop-area relative border-2 border-dashed border-gray-700 rounded-2xl p-10 text-center cursor-pointer transition-all duration-300 hover:border-purple-400 bg-gray-800/30" id="fileUploadArea">
216
+ <input type="file" id="imageFile" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer" accept="image/jpeg, image/png, image/webp" />
217
+ <div class="flex flex-col items-center justify-center">
218
+ <div class="w-16 h-16 rounded-full bg-gradient-to-br from-purple-500/20 to-indigo-500/20 flex items-center justify-center mb-4">
219
+ <i class="fas fa-cloud-upload-alt text-2xl text-purple-300"></i>
220
+ </div>
221
+ <p class="text-sm text-gray-300 mb-1">فایل را اینجا رها کنید یا برای انتخاب کلیک کنید</p>
222
+ <p class="text-xs text-gray-500">فرمت‌های پشتیبانی شده: JPG, PNG, WebP</p>
223
+ </div>
224
+ </div>
225
+ <img id="imagePreview" src="#" alt="پیش‌نمایش" class="mt-5 rounded-xl shadow-lg w-full max-h-72 object-contain hidden mx-auto border border-gray-700/50" />
226
+ </div>
227
+ </div>
228
+
229
+ <!-- Text to Video Section -->
230
+ <div id="textToVideoSection" class="form-mode-section hidden">
231
+ <div class="mb-8 text-center py-5 px-6 rounded-xl bg-gradient-to-r from-purple-900/30 to-indigo-900/30 border border-purple-500/20 shadow-inner">
232
+ <div class="flex items-center justify-center">
233
+ <i class="fas fa-info-circle text-purple-300 mr-3"></i>
234
+ <span class="text-sm text-purple-100">در این حالت، ویدیو فقط بر اساس متن راهنما ساخته می‌شود.</span>
235
+ </div>
236
+ </div>
237
+ </div>
238
+
239
+ <!-- Prompt Section -->
240
+ <div class="mb-8">
241
+ <label for="prompt" class="block text-sm font-medium mb-3 text-gray-300 flex items-center">
242
+ <i class="fas fa-magic mr-2 text-indigo-300"></i>
243
+ شرح انیمیشن (Prompt)
244
+ </label>
245
+ <div class="relative">
246
+ <textarea id="prompt" rows="3" class="w-full px-5 py-4 bg-gray-800/40 border border-gray-700 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-purple-500 text-gray-200 placeholder-gray-500 transition-all duration-300 shadow-inner" placeholder="مثال: گربه‌ای که به آرامی پلک می‌زند">یک موجود از داخل تصویر شروع به حرکت می‌کند</textarea>
247
+ <div class="absolute bottom-4 left-4 text-xs text-gray-500 flex items-center">
248
+ <i class="fas fa-lightbulb mr-1 text-yellow-300/70"></i>
249
+ <span>توضیحات دقیق‌تر = نتیجه بهتر</span>
250
+ </div>
251
+ </div>
252
+ </div>
253
+
254
+ <!-- Duration Options -->
255
+ <div class="mb-8">
256
+ <label class="block text-sm font-medium mb-3 text-gray-300 flex items-center">
257
+ <i class="fas fa-clock mr-2 text-blue-300"></i>
258
+ مدت زمان
259
+ </label>
260
+ <div class="grid grid-cols-2 gap-4">
261
+ <button class="option-card duration-button p-4 rounded-xl bg-gray-800/50 border border-gray-700 text-gray-200 hover:border-purple-400 flex flex-col items-center relative overflow-hidden" data-api-duration="5">
262
+ <div class="w-10 h-10 rounded-full bg-purple-500/10 flex items-center justify-center mb-2">
263
+ <i class="fas fa-hourglass-start text-purple-300"></i>
264
+ </div>
265
+ <span class="font-medium">کوتاه</span>
266
+ <span class="text-xs text-gray-400 mt-1">۵ ثانیه</span>
267
+ <div class="absolute inset-0 bg-gradient-to-br from-purple-500/5 to-indigo-500/5 opacity-0 hover:opacity-100 transition-opacity duration-300"></div>
268
+ </button>
269
+ <button class="option-card duration-button p-4 rounded-xl bg-gradient-to-br from-purple-900/30 to-indigo-900/30 border border-purple-500/30 text-purple-100 hover:border-purple-400 flex flex-col items-center relative selected" data-api-duration="7.8">
270
+ <div class="w-10 h-10 rounded-full bg-purple-500/20 flex items-center justify-center mb-2">
271
+ <i class="fas fa-hourglass-half text-purple-200"></i>
272
+ </div>
273
+ <span class="font-medium">استاندارد</span>
274
+ <span class="text-xs text-purple-300 mt-1">۸ ثانیه</span>
275
+ <div class="absolute inset-0 bg-gradient-to-br from-purple-500/10 to-indigo-500/10 opacity-0 hover:opacity-100 transition-opacity duration-300"></div>
276
+ </button>
277
+ </div>
278
+ </div>
279
+
280
+ <!-- Advanced Settings Toggle -->
281
+ <button id="advancedSettingsToggle" class="w-full py-4 px-5 mb-6 rounded-xl bg-gray-800/50 border border-gray-700 text-gray-300 hover:bg-gray-700/50 hover:text-white transition-all duration-300 flex items-center justify-between group">
282
+ <span class="flex items-center">
283
+ <i class="fas fa-cog mr-3 text-purple-300 group-hover:animate-spin"></i>
284
+ تنظیمات پیشرفته
285
+ </span>
286
+ <i class="fas fa-chevron-down text-gray-400 transition-transform duration-300 group-hover:text-purple-300"></i>
287
+ </button>
288
+
289
+ <!-- Advanced Settings -->
290
+ <div id="advancedSettings" class="hidden bg-gradient-to-br from-gray-800/30 to-gray-900/30 rounded-2xl p-6 mb-8 border border-gray-700/50 shadow-inner">
291
+ <div class="mb-8">
292
+ <label class="block text-sm font-medium mb-3 text-gray-300 flex items-center">
293
+ <i class="fas fa-crop-alt mr-2 text-green-300"></i>
294
+ نسبت تصویر
295
+ </label>
296
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-3">
297
+ <button class="option-card aspect-ratio-button p-3 rounded-xl bg-gradient-to-br from-purple-900/30 to-indigo-900/30 border border-purple-500/30 text-purple-100 hover:border-purple-400 flex flex-col items-center selected" data-height="768" data-width="768">
298
+ <i class="fas fa-square text-xl mb-1"></i>
299
+ <span class="text-sm">مربع</span>
300
+ <span class="text-xs text-purple-300 mt-1">۱:۱</span>
301
+ </button>
302
+ <button class="option-card aspect-ratio-button p-3 rounded-xl bg-gray-800/50 border border-gray-700 text-gray-200 hover:border-purple-400 flex flex-col items-center" data-height="768" data-width="432">
303
+ <i class="fas fa-mobile-alt text-xl mb-1"></i>
304
+ <span class="text-sm">پرتره</span>
305
+ <span class="text-xs text-gray-400 mt-1">۹:۱۶</span>
306
+ </button>
307
+ <button class="option-card aspect-ratio-button p-3 rounded-xl bg-gray-800/50 border border-gray-700 text-gray-200 hover:border-purple-400 flex flex-col items-center" data-height="432" data-width="768">
308
+ <i class="fas fa-desktop text-xl mb-1"></i>
309
+ <span class="text-sm">لنداسکیپ</span>
310
+ <span class="text-xs text-gray-400 mt-1">۱۶:۹</span>
311
+ </button>
312
+ <button class="option-card aspect-ratio-button p-3 rounded-xl bg-gray-800/50 border border-gray-700 text-gray-200 hover:border-purple-400 flex flex-col items-center" data-height="512" data-width="704">
313
+ <i class="fas fa-expand text-xl mb-1"></i>
314
+ <span class="text-sm">پیش‌فرض</span>
315
+ <span class="text-xs text-gray-400 mt-1">LTX</span>
316
+ </button>
317
+ </div>
318
+ </div>
319
+
320
+ <div class="mb-8">
321
+ <label for="negativePrompt" class="block text-sm font-medium mb-3 text-gray-300 flex items-center">
322
+ <i class="fas fa-ban mr-2 text-red-300"></i>
323
+ متن راهنمای منفی
324
+ </label>
325
+ <textarea id="negativePrompt" rows="2" class="w-full px-5 py-4 bg-gray-800/40 border border-gray-700 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-purple-500 text-gray-200 placeholder-gray-500 transition-all duration-300 shadow-inner">کیفیت پایین، تار، لرزان</textarea>
326
+ </div>
327
+
328
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
329
+ <div>
330
+ <label for="cfgScale" class="block text-sm font-medium mb-3 text-gray-300 flex items-center">
331
+ <i class="fas fa-sliders-h mr-2 text-blue-300"></i>
332
+ مقیاس CFG
333
+ </label>
334
+ <div class="relative">
335
+ <input type="number" id="cfgScale" value="1.0" min="1.0" max="10.0" step="0.1" class="w-full px-5 py-3 bg-gray-800/40 border border-gray-700 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-purple-500 text-gray-200 transition-all duration-300 shadow-inner" />
336
+ <div class="absolute left-4 top-3 text-gray-500">
337
+ <i class="fas fa-adjust"></i>
338
+ </div>
339
+ </div>
340
+ </div>
341
+ <div>
342
+ <label for="seed" class="block text-sm font-medium mb-3 text-gray-300 flex items-center">
343
+ <i class="fas fa-dice mr-2 text-yellow-300"></i>
344
+ سید تصادفی
345
+ </label>
346
+ <div class="relative">
347
+ <input type="number" id="seed" value="0" min="0" class="w-full px-5 py-3 bg-gray-800/40 border border-gray-700 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-purple-500 text-gray-200 transition-all duration-300 shadow-inner" />
348
+ <div class="absolute left-4 top-3 text-gray-500">
349
+ <i class="fas fa-random"></i>
350
+ </div>
351
+ </div>
352
+ </div>
353
+ </div>
354
+
355
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
356
+ <div>
357
+ <label for="outputHeight" class="block text-sm font-medium mb-3 text-gray-300 flex items-center">
358
+ <i class="fas fa-arrows-alt-v mr-2 text-green-300"></i>
359
+ ارتفاع (پیکسل)
360
+ </label>
361
+ <div class="relative">
362
+ <input type="number" id="outputHeight" value="768" step="32" min="256" max="1280" class="w-full px-5 py-3 bg-gray-800/40 border border-gray-700 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-purple-500 text-gray-200 transition-all duration-300 shadow-inner" />
363
+ <div class="absolute left-4 top-3 text-gray-500">
364
+ <i class="fas fa-ruler-vertical"></i>
365
+ </div>
366
+ </div>
367
+ </div>
368
+ <div>
369
+ <label for="outputWidth" class="block text-sm font-medium mb-3 text-gray-300 flex items-center">
370
+ <i class="fas fa-arrows-alt-h mr-2 text-blue-300"></i>
371
+ عرض (پیکسل)
372
+ </label>
373
+ <div class="relative">
374
+ <input type="number" id="outputWidth" value="768" step="32" min="256" max="1280" class="w-full px-5 py-3 bg-gray-800/40 border border-gray-700 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-purple-500 text-gray-200 transition-all duration-300 shadow-inner" />
375
+ <div class="absolute left-4 top-3 text-gray-500">
376
+ <i class="fas fa-ruler-horizontal"></i>
377
+ </div>
378
+ </div>
379
+ </div>
380
+ </div>
381
+ </div>
382
+
383
+ <!-- Generate Button -->
384
+ <div class="text-center mt-10">
385
+ <button id="generateButton" class="primary-btn w-full py-5 px-8 rounded-2xl text-lg font-bold shadow-lg hover:shadow-xl group relative overflow-hidden">
386
+ <span class="relative z-10 flex items-center justify-center">
387
+ <i class="fas fa-magic mr-3 transform group-hover:rotate-12 transition-transform"></i>
388
+ ساخت ویدیو هوشمند
389
+ </span>
390
+ </button>
391
+ </div>
392
+ </div>
393
+ </div>
394
+
395
+ <!-- Status Section -->
396
+ <div id="statusSection" class="glass-morphism rounded-3xl overflow-hidden shadow-2xl mb-10 hidden animate-fade-in">
397
+ <div class="p-8">
398
+ <h2 class="text-xl font-bold mb-6 flex items-center">
399
+ <div class="w-10 h-10 rounded-full bg-gradient-to-r from-purple-500/20 to-indigo-500/20 flex items-center justify-center mr-3">
400
+ <i class="fas fa-spinner fa-spin text-purple-300"></i>
401
+ </div>
402
+ <span class="text-gradient bg-gradient-to-r from-purple-200 to-indigo-200">در حال پردازش درخواست</span>
403
+ </h2>
404
+
405
+ <div class="mb-6">
406
+ <div class="flex justify-between text-sm mb-2">
407
+ <span class="text-gray-300">پیشرفت عملیات</span>
408
+ <span id="progressPercent" class="text-purple-300 font-medium">0%</span>
409
+ </div>
410
+ <div class="w-full h-2.5 bg-gray-800 rounded-full overflow-hidden">
411
+ <div id="progressBar" class="h-full rounded-full progress-track" style="width: 0%"></div>
412
+ </div>
413
+ </div>
414
+
415
+ <div id="statusMessages" class="space-y-3 max-h-60 overflow-y-auto pr-2">
416
+ <!-- Status messages will appear here -->
417
+ </div>
418
+ </div>
419
+ </div>
420
+
421
+ <!-- Output Section -->
422
+ <div id="outputSection" class="glass-morphism rounded-3xl overflow-hidden shadow-2xl hidden animate-fade-in">
423
+ <div class="p-8">
424
+ <h2 class="text-xl font-bold mb-6 flex items-center">
425
+ <div class="w-10 h-10 rounded-full bg-gradient-to-r from-green-500/20 to-teal-500/20 flex items-center justify-center mr-3">
426
+ <i class="fas fa-check text-green-300"></i>
427
+ </div>
428
+ <span class="text-gradient bg-gradient-to-r from-green-200 to-teal-200">ویدیوی شما آماده شد!</span>
429
+ </h2>
430
+
431
+ <div class="video-container mb-6">
432
+ <div class="video-wrapper bg-gray-900 rounded-xl overflow-hidden shadow-lg">
433
+ <video id="outputVideo" controls preload="metadata" playsinline class="w-full"></video>
434
+ </div>
435
+ </div>
436
+
437
+ <div class="flex flex-col md:flex-row justify-between items-center">
438
+ <p id="finalSeed" class="text-sm text-gray-400 mb-4 md:mb-0">
439
+ <!-- Final seed will appear here -->
440
+ </p>
441
+
442
+ <div class="flex space-x-3 rtl:space-x-reverse">
443
+ <button id="downloadButton" class="accent-btn py-2.5 px-5 rounded-xl flex items-center shadow hover:shadow-md">
444
+ <i class="fas fa-download mr-2"></i>
445
+ دانلود ویدیو
446
+ </button>
447
+ <button id="newGenerationButton" class="secondary-btn py-2.5 px-5 rounded-xl flex items-center">
448
+ <i class="fas fa-redo mr-2"></i>
449
+ ساخت جدید
450
+ </button>
451
+ </div>
452
+ </div>
453
+ </div>
454
+ </div>
455
+
456
+ <!-- Footer -->
457
+ <div class="text-center text-gray-500 text-sm mt-16">
458
+ <p class="flex items-center justify-center">
459
+ ساخته شده با
460
+ <i class="fas fa-heart text-pink-400 mx-2 animate-pulse"></i>
461
+ توسط تیم LTX
462
+ </p>
463
+ <p class="mt-2 text-gray-600">نسخه ۲.۰ | فناوری هوش مصنوعی پیشرفته</p>
464
+ </div>
465
+ </div>
466
+
467
+ <script>
468
+ // DOM Elements
469
+ const imageFileInput = document.getElementById('imageFile');
470
+ const imagePreview = document.getElementById('imagePreview');
471
+ const promptInput = document.getElementById('prompt');
472
+ const durationButtons = document.querySelectorAll('.duration-button');
473
+ const aspectRatioButtons = document.querySelectorAll('.aspect-ratio-button');
474
+ const generateButton = document.getElementById('generateButton');
475
+ const outputVideo = document.getElementById('outputVideo');
476
+ const finalSeedElement = document.getElementById('finalSeed');
477
+ const statusMessagesDiv = document.getElementById('statusMessages');
478
+ const statusSection = document.getElementById('statusSection');
479
+ const outputSection = document.getElementById('outputSection');
480
+ const progressBar = document.getElementById('progressBar');
481
+ const progressPercent = document.getElementById('progressPercent');
482
+ const downloadButton = document.getElementById('downloadButton');
483
+ const newGenerationButton = document.getElementById('newGenerationButton');
484
+
485
+ const advancedSettingsToggle = document.getElementById('advancedSettingsToggle');
486
+ const advancedSettingsDiv = document.getElementById('advancedSettings');
487
+ const negativePromptInput = document.getElementById('negativePrompt');
488
+ const cfgScaleInput = document.getElementById('cfgScale');
489
+ const seedInput = document.getElementById('seed');
490
+ const outputHeightInput = document.getElementById('outputHeight');
491
+ const outputWidthInput = document.getElementById('outputWidth');
492
+
493
+ const modeButtons = document.querySelectorAll('.mode-button');
494
+ const imageToVideoSection = document.getElementById('imageToVideoSection');
495
+ const textToVideoSection = document.getElementById('textToVideoSection');
496
+ const fileUploadArea = document.getElementById('fileUploadArea');
497
+
498
+ // Constants
499
+ const SPACE_URL_BASE = "https://lightricks-ltx-video-distilled.hf.space";
500
+ const FN_INDEX_GENERATE = 5;
501
+ let selectedApiDuration = 7.8;
502
+
503
+ // Variables
504
+ let currentSessionHash = '';
505
+ let uploadedImageInfo = null;
506
+ let currentGenerationMode = "image-to-video";
507
+ let currentProgressPhase = 0;
508
+ let totalUnitsInPhase = 0;
509
+ let completedUnitsInPhase = 0;
510
+
511
+ // Initialize
512
+ document.addEventListener('DOMContentLoaded', () => {
513
+ // Set default selections
514
+ document.querySelector('.duration-button.selected')?.dispatchEvent(new Event('click'));
515
+ document.querySelector('.aspect-ratio-button.selected')?.dispatchEvent(new Event('click'));
516
+ updateFormForMode(currentGenerationMode);
517
+
518
+ // Set up drag and drop for file upload
519
+ setupDragAndDrop();
520
+ });
521
+
522
+ // Drag and Drop Setup
523
+ function setupDragAndDrop() {
524
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
525
+ fileUploadArea.addEventListener(eventName, preventDefaults, false);
526
+ });
527
+
528
+ function preventDefaults(e) {
529
+ e.preventDefault();
530
+ e.stopPropagation();
531
+ }
532
+
533
+ ['dragenter', 'dragover'].forEach(eventName => {
534
+ fileUploadArea.addEventListener(eventName, highlight, false);
535
+ });
536
+
537
+ ['dragleave', 'drop'].forEach(eventName => {
538
+ fileUploadArea.addEventListener(eventName, unhighlight, false);
539
+ });
540
+
541
+ function highlight() {
542
+ fileUploadArea.classList.add('drag-over');
543
+ playHoverSound();
544
+ }
545
+
546
+ function unhighlight() {
547
+ fileUploadArea.classList.remove('drag-over');
548
+ }
549
+
550
+ fileUploadArea.addEventListener('drop', handleDrop, false);
551
+
552
+ function handleDrop(e) {
553
+ const dt = e.dataTransfer;
554
+ const files = dt.files;
555
+
556
+ if (files.length > 0) {
557
+ imageFileInput.files = files;
558
+ imageFileInput.dispatchEvent(new Event('change'));
559
+ playSuccessSound();
560
+ }
561
+ }
562
+ }
563
+
564
+ // Event listeners for mode buttons
565
+ modeButtons.forEach(button => {
566
+ button.addEventListener('click', () => {
567
+ // Update active state
568
+ modeButtons.forEach(btn => {
569
+ btn.classList.remove('active');
570
+ btn.querySelector('i').classList.remove('text-purple-300');
571
+ btn.querySelector('i').classList.add('text-gray-400');
572
+ });
573
+
574
+ button.classList.add('active');
575
+ button.querySelector('i').classList.remove('text-gray-400');
576
+ button.querySelector('i').classList.add('text-purple-300');
577
+
578
+ // Update mode
579
+ currentGenerationMode = button.dataset.mode;
580
+ updateFormForMode(currentGenerationMode);
581
+
582
+ // Play click sound
583
+ playClickSound();
584
+ });
585
+ });
586
+
587
+ // Advanced settings toggle
588
+ advancedSettingsToggle.addEventListener('click', () => {
589
+ const isOpen = advancedSettingsDiv.classList.contains('hidden');
590
+
591
+ if (isOpen) {
592
+ advancedSettingsDiv.classList.remove('hidden');
593
+ advancedSettingsToggle.querySelector('i').classList.remove('fa-chevron-down');
594
+ advancedSettingsToggle.querySelector('i').classList.add('fa-chevron-up');
595
+ } else {
596
+ advancedSettingsDiv.classList.add('hidden');
597
+ advancedSettingsToggle.querySelector('i').classList.remove('fa-chevron-up');
598
+ advancedSettingsToggle.querySelector('i').classList.add('fa-chevron-down');
599
+ }
600
+
601
+ // Play click sound
602
+ playClickSound();
603
+ });
604
+
605
+ // Image file input change
606
+ imageFileInput.addEventListener('change', function(event) {
607
+ const file = event.target.files[0];
608
+ if (file) {
609
+ // Validate file type
610
+ if (!file.type.startsWith('image/')) {
611
+ addStatusMessage('لطفاً یک فایل تصویری (JPG, PNG, WebP) انتخاب کنید.', 'error');
612
+ imageFileInput.value = '';
613
+ imagePreview.style.display = 'none';
614
+ playErrorSound();
615
+ return;
616
+ }
617
+
618
+ // Show preview
619
+ const reader = new FileReader();
620
+ reader.onload = function(e) {
621
+ imagePreview.src = e.target.result;
622
+ imagePreview.style.display = 'block';
623
+ imagePreview.classList.add('animate-fade-in');
624
+
625
+ // Add success message
626
+ addStatusMessage('تصویر با موفقیت آپلود شد!', 'success');
627
+ playSuccessSound();
628
+ }
629
+ reader.readAsDataURL(file);
630
+ uploadedImageInfo = null;
631
+ } else {
632
+ imagePreview.style.display = 'none';
633
+ }
634
+ });
635
+
636
+ // Duration buttons
637
+ durationButtons.forEach(button => {
638
+ button.addEventListener('click', () => {
639
+ // Update selection
640
+ durationButtons.forEach(btn => {
641
+ btn.classList.remove('selected', 'bg-gradient-to-br', 'from-purple-900/30', 'to-indigo-900/30', 'border-purple-500/30', 'text-purple-100');
642
+ btn.classList.add('bg-gray-800/50', 'border-gray-700', 'text-gray-200');
643
+ });
644
+
645
+ button.classList.add('selected', 'bg-gradient-to-br', 'from-purple-900/30', 'to-indigo-900/30', 'border-purple-500/30', 'text-purple-100');
646
+ button.classList.remove('bg-gray-800/50', 'border-gray-700', 'text-gray-200');
647
+
648
+ selectedApiDuration = parseFloat(button.dataset.apiDuration);
649
+
650
+ // Play click sound
651
+ playClickSound();
652
+ });
653
+ });
654
+
655
+ // Aspect ratio buttons
656
+ aspectRatioButtons.forEach(button => {
657
+ button.addEventListener('click', () => {
658
+ // Update selection
659
+ aspectRatioButtons.forEach(btn => {
660
+ btn.classList.remove('selected', 'bg-gradient-to-br', 'from-purple-900/30', 'to-indigo-900/30', 'border-purple-500/30', 'text-purple-100');
661
+ btn.classList.add('bg-gray-800/50', 'border-gray-700', 'text-gray-200');
662
+ });
663
+
664
+ button.classList.add('selected', 'bg-gradient-to-br', 'from-purple-900/30', 'to-indigo-900/30', 'border-purple-500/30', 'text-purple-100');
665
+ button.classList.remove('bg-gray-800/50', 'border-gray-700', 'text-gray-200');
666
+
667
+ outputHeightInput.value = button.dataset.height;
668
+ outputWidthInput.value = button.dataset.width;
669
+
670
+ // Play click sound
671
+ playClickSound();
672
+ });
673
+ });
674
+
675
+ // New generation button
676
+ newGenerationButton.addEventListener('click', () => {
677
+ outputSection.classList.add('hidden');
678
+ window.scrollTo({
679
+ top: 0,
680
+ behavior: 'smooth'
681
+ });
682
+ playClickSound();
683
+ });
684
+
685
+ // Update form for selected mode
686
+ function updateFormForMode(mode) {
687
+ if (mode === "image-to-video") {
688
+ imageToVideoSection.classList.remove('hidden');
689
+ textToVideoSection.classList.add('hidden');
690
+ promptInput.placeholder = "مثال: گربه‌ای که به آرامی پلک می‌زند";
691
+ } else if (mode === "text-to-video") {
692
+ imageToVideoSection.classList.add('hidden');
693
+ textToVideoSection.classList.remove('hidden');
694
+ imageFileInput.value = '';
695
+ imagePreview.style.display = 'none';
696
+ uploadedImageInfo = null;
697
+ promptInput.placeholder = "مثال: یک اژدهای آتشی که بر فراز قلعه پرواز می‌کند";
698
+ }
699
+ }
700
+
701
+ // Add status message
702
+ function addStatusMessage(message, type = 'info') {
703
+ statusSection.classList.remove('hidden');
704
+
705
+ const messageDiv = document.createElement('div');
706
+ messageDiv.className = `status-message p-4 rounded-lg text-sm flex items-start ${type === 'error' ?
707
+ 'bg-gradient-to-r from-red-900/30 to-pink-900/20 text-red-100 border-r-2 border-red-400' :
708
+ type === 'success' ?
709
+ 'bg-gradient-to-r from-green-900/30 to-teal-900/20 text-green-100 border-r-2 border-green-400' :
710
+ 'bg-gradient-to-r from-blue-900/30 to-indigo-900/20 text-blue-100 border-r-2 border-blue-400'}`;
711
+
712
+ const icon = document.createElement('i');
713
+ icon.className = type === 'error' ? 'fas fa-exclamation-circle mt-0.5 mr-3 text-red-300' :
714
+ type === 'success' ? 'fas fa-check-circle mt-0.5 mr-3 text-green-300' :
715
+ 'fas fa-info-circle mt-0.5 mr-3 text-blue-300';
716
+
717
+ const text = document.createElement('span');
718
+ text.textContent = message;
719
+
720
+ messageDiv.appendChild(icon);
721
+ messageDiv.appendChild(text);
722
+
723
+ if (statusMessagesDiv.firstChild) {
724
+ statusMessagesDiv.insertBefore(messageDiv, statusMessagesDiv.firstChild);
725
+ } else {
726
+ statusMessagesDiv.appendChild(messageDiv);
727
+ }
728
+
729
+ // Auto-scroll to top
730
+ statusMessagesDiv.scrollTop = 0;
731
+ }
732
+
733
+ // Clear status and output
734
+ function clearStatusAndOutput() {
735
+ statusMessagesDiv.innerHTML = '';
736
+ statusSection.classList.add('hidden');
737
+ outputSection.classList.add('hidden');
738
+
739
+ if (outputVideo.src) {
740
+ URL.revokeObjectURL(outputVideo.src);
741
+ }
742
+
743
+ outputVideo.src = '';
744
+ finalSeedElement.textContent = '';
745
+ progressBar.style.width = '0%';
746
+ progressPercent.textContent = '0%';
747
+ }
748
+
749
+ // Generate random hash
750
+ function generateRandomHash(length = 11) {
751
+ const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
752
+ let result = '';
753
+
754
+ for (let i = 0; i < length; i++) {
755
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
756
+ }
757
+
758
+ return result;
759
+ }
760
+
761
+ // Upload image
762
+ async function uploadImage(file) {
763
+ addStatusMessage('۱. آماده‌سازی تصویر...');
764
+
765
+ const uploadId = generateRandomHash(12);
766
+ const formData = new FormData();
767
+ formData.append('files', file);
768
+
769
+ try {
770
+ const response = await fetch(`${SPACE_URL_BASE}/gradio_api/upload?upload_id=${uploadId}`, {
771
+ method: 'POST',
772
+ body: formData
773
+ });
774
+
775
+ if (!response.ok) {
776
+ throw new Error(`خطا در آپلود (${response.status})`);
777
+ }
778
+
779
+ const result = await response.json();
780
+
781
+ if (result && result.length > 0 && typeof result[0] === 'string') {
782
+ return {
783
+ path: result[0],
784
+ url: `${SPACE_URL_BASE}/gradio_api/file=${result[0]}`,
785
+ orig_name: file.name,
786
+ size: file.size,
787
+ mime_type: file.type || 'application/octet-stream',
788
+ meta: { "_type": "gradio.FileData" }
789
+ };
790
+ } else {
791
+ throw new Error('پاسخ آپلود نامعتبر.');
792
+ }
793
+ } catch (error) {
794
+ addStatusMessage(`خطا در آپلود: ${error.message}`, 'error');
795
+ console.error('Upload error:', error);
796
+ return null;
797
+ }
798
+ }
799
+
800
+ // Submit to queue
801
+ async function submitToQueue(payload) {
802
+ addStatusMessage('۲. ارسال درخواست به سرور...');
803
+
804
+ try {
805
+ const response = await fetch(`${SPACE_URL_BASE}/gradio_api/queue/join`, {
806
+ method: 'POST',
807
+ headers: { 'Content-Type': 'application/json' },
808
+ body: JSON.stringify(payload)
809
+ });
810
+
811
+ if (!response.ok) {
812
+ const errorText = await response.text();
813
+ throw new Error(`خطا در ارسال به صف (${response.status}) - ${errorText.substring(0,100)}`);
814
+ }
815
+
816
+ return await response.json();
817
+ } catch (error) {
818
+ addStatusMessage(`خطا در ارتباط با سرور: ${error.message}`, 'error');
819
+ console.error('Queue join error:', error);
820
+ return null;
821
+ }
822
+ }
823
+
824
+ // Update progress bar
825
+ function updateVisualProgress(progressDataArray) {
826
+ if (!progressDataArray || progressDataArray.length === 0) return;
827
+
828
+ const pInfo = progressDataArray[0];
829
+
830
+ if (pInfo.desc === "Saving video") {
831
+ if (currentProgressPhase !== 1) {
832
+ currentProgressPhase = 1;
833
+ addStatusMessage("مرحله نهایی: ذخیره ویدیو...");
834
+ }
835
+
836
+ const progress = Math.round((pInfo.progress || 0) * 100);
837
+ progressBar.style.width = `${progress}%`;
838
+ progressPercent.textContent = `${progress}%`;
839
+ } else if (pInfo.length && pInfo.index !== null) {
840
+ if (currentProgressPhase !== 0 || pInfo.index === 0) {
841
+ if (pInfo.index === 0) {
842
+ currentProgressPhase = 0;
843
+ totalUnitsInPhase = pInfo.length;
844
+ completedUnitsInPhase = 0;
845
+ addStatusMessage(`شروع پردازش (${totalUnitsInPhase} گام)...`);
846
+ }
847
+ }
848
+
849
+ completedUnitsInPhase = pInfo.index + 1;
850
+ const progress = Math.round((completedUnitsInPhase / totalUnitsInPhase) * 100);
851
+ progressBar.style.width = `${progress}%`;
852
+ progressPercent.textContent = `${progress}%`;
853
+ }
854
+ }
855
+
856
+ // Listen for results
857
+ function listenForResults(eventId) {
858
+ addStatusMessage('۳. در حال تولید ویدیو...');
859
+
860
+ const eventSource = new EventSource(`${SPACE_URL_BASE}/gradio_api/queue/data?session_hash=${currentSessionHash}`);
861
+ currentProgressPhase = -1;
862
+
863
+ eventSource.onmessage = function(event) {
864
+ const data = JSON.parse(event.data);
865
+
866
+ if (data.event_id !== eventId && data.msg !== "queue_full") return;
867
+
868
+ switch (data.msg) {
869
+ case "process_starts":
870
+ addStatusMessage('عملیات در سرور آغاز شد.');
871
+ progressBar.style.width = '0%';
872
+ progressPercent.textContent = '0%';
873
+ break;
874
+
875
+ case "progress":
876
+ updateVisualProgress(data.progress_data);
877
+ break;
878
+
879
+ case "process_completed":
880
+ eventSource.close();
881
+ generateButton.disabled = false;
882
+ generateButton.innerHTML = '<i class="fas fa-magic mr-2"></i> ساخت ویدیو هوشمند';
883
+ progressBar.style.width = '100%';
884
+ progressPercent.textContent = '100%';
885
+
886
+ if (data.success && data.output?.data?.[0]?.video?.url) {
887
+ addStatusMessage('ویدیو با موفقیت ساخته شد! 🎉', 'success');
888
+ outputSection.classList.remove('hidden');
889
+
890
+ // Scroll to output section
891
+ setTimeout(() => {
892
+ outputSection.scrollIntoView({ behavior: 'smooth' });
893
+ }, 500);
894
+
895
+ outputVideo.src = data.output.data[0].video.url;
896
+ outputVideo.load();
897
+
898
+ // Set up download button
899
+ downloadButton.onclick = function() {
900
+ const a = document.createElement('a');
901
+ a.href = data.output.data[0].video.url;
902
+ a.download = `ltx-video-${new Date().toISOString().slice(0,10)}.mp4`;
903
+ document.body.appendChild(a);
904
+ a.click();
905
+ document.body.removeChild(a);
906
+ playSuccessSound();
907
+ };
908
+
909
+ outputVideo.play().catch(e => {
910
+ addStatusMessage("برای مشاهده، دکمه پخش ویدیو را بزنید.", "info");
911
+ });
912
+
913
+ finalSeedElement.textContent = data.output.data[1] ? `سید نهایی: ${data.output.data[1]}` : '';
914
+
915
+ // Play completion sound
916
+ playCompletionSound();
917
+ } else {
918
+ const errorMsg = data.output?.error || data.error || "خطای نامشخص در تکمیل فرآیند.";
919
+ addStatusMessage(`تولید ویدیو ناموفق بود: ${errorMsg}`, 'error');
920
+ console.error('Process completed with error:', data);
921
+ playErrorSound();
922
+ }
923
+ break;
924
+
925
+ case "queue_full":
926
+ addStatusMessage('سرور مشغول است، لطفا کمی بعد تلاش کنید.', 'error');
927
+ eventSource.close();
928
+ generateButton.disabled = false;
929
+ generateButton.innerHTML = '<i class="fas fa-magic mr-2"></i> ساخت ویدیو هوشمند';
930
+ playErrorSound();
931
+ break;
932
+ }
933
+ };
934
+
935
+ eventSource.onerror = function(error) {
936
+ addStatusMessage('خطا در ارتباط با سرور. اتصال خود را بررسی کنید.', 'error');
937
+ console.error('EventSource error:', error);
938
+ eventSource.close();
939
+ generateButton.disabled = false;
940
+ generateButton.innerHTML = '<i class="fas fa-magic mr-2"></i> ساخت ویدیو هوشمند';
941
+ playErrorSound();
942
+ };
943
+ }
944
+
945
+ // Generate button click
946
+ generateButton.addEventListener('click', async () => {
947
+ clearStatusAndOutput();
948
+
949
+ const imageFile = imageFileInput.files[0];
950
+
951
+ // Validate inputs
952
+ if (currentGenerationMode === "image-to-video" && !imageFile) {
953
+ addStatusMessage('لطفاً ابتدا یک تصویر انتخاب کنید.', 'error');
954
+ playErrorSound();
955
+ return;
956
+ }
957
+
958
+ if (!promptInput.value.trim()) {
959
+ addStatusMessage('لطفاً متن راهنما (Prompt) را وارد کنید.', 'error');
960
+ playErrorSound();
961
+ return;
962
+ }
963
+
964
+ // Disable button and show loading state
965
+ generateButton.disabled = true;
966
+ generateButton.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> در حال پردازش...';
967
+ statusSection.classList.remove('hidden');
968
+
969
+ // Generate session hash
970
+ currentSessionHash = generateRandomHash();
971
+
972
+ // Upload image if in image-to-video mode
973
+ if (currentGenerationMode === "image-to-video") {
974
+ uploadedImageInfo = await uploadImage(imageFile);
975
+
976
+ if (!uploadedImageInfo) {
977
+ generateButton.disabled = false;
978
+ generateButton.innerHTML = '<i class="fas fa-magic mr-2"></i> ساخت ویدیو هوشمند';
979
+ return;
980
+ }
981
+ } else {
982
+ uploadedImageInfo = null;
983
+ }
984
+
985
+ // Prepare payload
986
+ const userSeed = parseInt(seedInput.value);
987
+
988
+ const generationPayload = {
989
+ fn_index: FN_INDEX_GENERATE,
990
+ data: [
991
+ promptInput.value,
992
+ negativePromptInput.value,
993
+ uploadedImageInfo,
994
+ (currentGenerationMode === "image-to-video" ? null : ""),
995
+ parseInt(outputHeightInput.value),
996
+ parseInt(outputWidthInput.value),
997
+ currentGenerationMode,
998
+ selectedApiDuration,
999
+ 9,
1000
+ (userSeed > 0) ? userSeed : Math.floor(Math.random() * (2**32 -1)),
1001
+ (userSeed <= 0),
1002
+ parseFloat(cfgScaleInput.value),
1003
+ true
1004
+ ],
1005
+ event_data: null,
1006
+ session_hash: currentSessionHash,
1007
+ };
1008
+
1009
+ // Submit to queue
1010
+ const joinResponse = await submitToQueue(generationPayload);
1011
+
1012
+ if (joinResponse && joinResponse.event_id) {
1013
+ listenForResults(joinResponse.event_id);
1014
+ } else {
1015
+ addStatusMessage('ارسال درخواست به سرور ناموفق بود.', 'error');
1016
+ generateButton.disabled = false;
1017
+ generateButton.innerHTML = '<i class="fas fa-magic mr-2"></i> ساخت ویدیو هوشمند';
1018
+ playErrorSound();
1019
+ }
1020
+ });
1021
+
1022
+ // Sound effects
1023
+ function playClickSound() {
1024
+ const audio = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-select-click-1109.mp3');
1025
+ audio.volume = 0.2;
1026
+ audio.play().catch(e => console.log('Audio play failed:', e));
1027
+ }
1028
+
1029
+ function playHoverSound() {
1030
+ const audio = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-arcade-game-jump-coin-216.mp3');
1031
+ audio.volume = 0.1;
1032
+ audio.play().catch(e => console.log('Audio play failed:', e));
1033
+ }
1034
+
1035
+ function playSuccessSound() {
1036
+ const audio = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-correct-answer-tone-2870.mp3');
1037
+ audio.volume = 0.2;
1038
+ audio.play().catch(e => console.log('Audio play failed:', e));
1039
+ }
1040
+
1041
+ function playErrorSound() {
1042
+ const audio = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-warning-alarm-688.mp3');
1043
+ audio.volume = 0.1;
1044
+ audio.play().catch(e => console.log('Audio play failed:', e));
1045
+ }
1046
+
1047
+ function playCompletionSound() {
1048
+ const audio = new Audio('https://assets.mixkit.co/sfx/preview/mixkit-achievement-bell-600.mp3');
1049
+ audio.volume = 0.2;
1050
+ audio.play().catch(e => console.log('Audio play failed:', e));
1051
+ }
1052
+ </script>
1053
+ </body>
1054
+ </html>