Ezmary commited on
Commit
b141e4b
·
verified ·
1 Parent(s): 0d87ed4

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +393 -312
index.html CHANGED
@@ -3,424 +3,505 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>مولد ویدیو با Hugging Face</title>
 
 
7
  <style>
8
- :root {
9
- --bg-color: #121212;
10
- --surface-color: #1e1e1e;
11
- --primary-color: #03dac6;
12
- --primary-variant-color: #3700b3;
13
- --on-bg-color: #e0e0e0;
14
- --on-surface-color: #ffffff;
15
- --error-color: #cf6679;
16
  }
17
-
18
- @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap');
19
-
20
  body {
21
- font-family: 'Vazirmatn', sans-serif;
22
- background-color: var(--bg-color);
23
- color: var(--on-bg-color);
24
- margin: 0;
25
- padding: 20px;
26
- display: flex;
27
- justify-content: center;
28
- align-items: flex-start;
29
  min-height: 100vh;
 
30
  }
31
-
32
  .container {
33
- width: 100%;
34
- max-width: 800px;
35
- background-color: var(--surface-color);
36
- border-radius: 12px;
37
- padding: 25px;
38
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
39
  }
40
-
41
- h1 {
42
  text-align: center;
43
- color: var(--on-surface-color);
 
 
 
 
 
44
  margin-bottom: 10px;
 
45
  }
46
-
47
- p.subtitle {
48
- text-align: center;
49
- margin-top: 0;
50
- margin-bottom: 25px;
51
- color: #aaa;
52
  }
53
-
54
- .token-section {
 
 
 
 
55
  margin-bottom: 25px;
 
 
56
  }
57
-
 
 
 
 
 
 
 
 
 
 
 
 
58
  .form-group {
59
  margin-bottom: 20px;
60
  }
61
-
62
  label {
63
  display: block;
64
  margin-bottom: 8px;
65
- font-weight: bold;
66
- font-size: 1rem;
67
  }
68
-
69
- input[type="text"],
70
- input[type="password"],
71
- textarea {
72
  width: 100%;
73
- padding: 12px;
74
- background-color: #2c2c2c;
75
- border: 1px solid #444;
76
  border-radius: 8px;
77
- color: var(--on-bg-color);
 
 
78
  font-size: 1rem;
79
- box-sizing: border-box;
80
- transition: border-color 0.3s, box-shadow 0.3s;
81
  }
82
-
83
- input[type="text"]:focus,
84
- input[type="password"]:focus,
85
- textarea:focus {
86
  outline: none;
87
- border-color: var(--primary-color);
88
- box-shadow: 0 0 0 3px rgba(3, 218, 198, 0.2);
89
  }
90
 
91
- input::placeholder, textarea::placeholder {
92
- color: #777;
93
- }
94
-
95
- .tabs {
96
- display: flex;
97
- border-bottom: 1px solid #444;
98
- margin-bottom: 20px;
99
  }
100
-
101
- .tab-button {
102
- padding: 10px 20px;
103
- cursor: pointer;
 
 
 
 
104
  border: none;
105
- background-color: transparent;
106
- color: #aaa;
107
  font-size: 1rem;
108
- font-family: 'Vazirmatn', sans-serif;
109
- font-weight: bold;
110
- border-bottom: 3px solid transparent;
111
- transition: color 0.3s, border-color 0.3s;
112
- }
113
-
114
- .tab-button.active {
115
- color: var(--primary-color);
116
- border-bottom-color: var(--primary-color);
117
  }
118
-
119
- .tab-content {
120
- display: none;
 
121
  }
122
-
123
- .tab-content.active {
124
- display: block;
125
  }
126
-
127
- button {
128
- background-color: var(--primary-color);
129
- color: #000;
130
- border: none;
131
- padding: 12px 20px;
132
- border-radius: 8px;
133
- font-size: 1rem;
134
- font-weight: bold;
135
- font-family: 'Vazirmatn', sans-serif;
136
- cursor: pointer;
137
- transition: background-color 0.3s, transform 0.1s;
138
- width: 100%;
139
  }
140
-
141
- button:hover:not(:disabled) {
142
- background-color: #03c0b1;
143
  }
144
 
145
- button:active:not(:disabled) {
146
- transform: scale(0.98);
 
 
147
  }
148
-
149
- button:disabled {
150
- background-color: #555;
151
- color: #999;
152
- cursor: not-allowed;
153
  }
154
-
155
  .result-container {
156
- margin-top: 25px;
157
- padding: 15px;
158
- background-color: #2c2c2c;
159
- border-radius: 8px;
160
- min-height: 50px;
 
 
 
 
 
 
 
161
  display: flex;
162
- justify-content: center;
163
  align-items: center;
 
 
164
  }
165
-
166
- video, img#imagePreview {
167
  max-width: 100%;
 
168
  border-radius: 8px;
169
  }
170
 
171
- #imagePreview {
172
- max-height: 250px;
 
 
173
  }
174
-
175
- .loader {
176
- border: 4px solid #f3f3f3;
177
- border-top: 4px solid var(--primary-color);
 
178
  border-radius: 50%;
179
- width: 30px;
180
- height: 30px;
181
  animation: spin 1s linear infinite;
 
182
  }
183
-
184
  @keyframes spin {
185
- 0% { transform: rotate(0deg); }
186
- 100% { transform: rotate(360deg); }
187
  }
188
-
189
- .status-message {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  margin-top: 15px;
191
  text-align: center;
192
- color: #ccc;
193
  }
194
-
195
- .error-message {
196
- color: var(--error-color);
197
- font-weight: bold;
 
 
198
  }
199
 
200
- input[type="file"] {
201
- display: none;
 
 
 
202
  }
203
-
204
- .file-label {
205
- display: inline-block;
206
- padding: 10px 15px;
207
- background-color: #333;
208
- border: 1px dashed #666;
209
  border-radius: 8px;
210
- cursor: pointer;
211
- text-align: center;
212
- width: 100%;
213
- box-sizing: border-box;
214
- transition: background-color 0.3s;
215
  }
216
- .file-label:hover {
217
- background-color: #444;
 
 
 
 
 
 
 
218
  }
219
-
220
  </style>
221
  </head>
222
  <body>
223
-
224
  <div class="container">
225
- <h1>مولد ویدیو با Hugging Face</h1>
226
- <p class="subtitle">ویدیوهای خلاقانه از متن یا تصویر بسازید</p>
227
-
228
- <div class="token-section form-group">
229
- <label for="hfToken">کلید توکن Hugging Face</label>
230
- <input type="password" id="hfToken" placeholder="توکن خود را اینجا وارد کنید (مثال: hf_...)">
231
- </div>
232
-
233
- <div class="tabs">
234
- <button class="tab-button active" onclick="openTab('textToVideo')">ساخت ویدیو از متن</button>
235
- <button class="tab-button" onclick="openTab('imageToVideo')">ساخت ویدیو از تصویر</button>
236
- </div>
237
-
238
- <!-- Tab Content: Text to Video -->
239
- <div id="textToVideo" class="tab-content active">
240
- <div class="form-group">
241
- <label for="textPrompt">توصیف ویدیو (Prompt)</label>
242
- <textarea id="textPrompt" rows="4" placeholder="مثال: A young man walking on the street"></textarea>
243
  </div>
244
- <button id="generateTextBtn">ساخت ویدیو</button>
245
- <div class="result-container" id="textResultContainer">
246
- <span>نتیجه در اینجا نمایش داده می‌شود</span>
 
247
  </div>
248
- <div class="status-message" id="textStatus"></div>
249
  </div>
250
-
251
- <!-- Tab Content: Image to Video -->
252
- <div id="imageToVideo" class="tab-content">
253
- <div class="form-group">
254
- <label for="imageFile">انتخاب تصویر</label>
255
- <input type="file" id="imageFile" accept="image/*">
256
- <label for="imageFile" class="file-label">برای انتخاب تصویر کلیک کنید</label>
 
 
 
 
 
 
 
 
 
 
257
  </div>
258
- <div class="form-group" id="imagePreviewContainer" style="display: none;">
259
- <label>پیش‌نمایش تصویر</label>
260
- <div class="result-container">
261
- <img id="imagePreview" src="" alt="Image Preview">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  </div>
263
  </div>
264
- <div class="form-group">
265
- <label for="imagePrompt">توصیف حرکت (Prompt)</label>
266
- <input type="text" id="imagePrompt" placeholder="مثال: The cat starts to dance">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  </div>
268
- <button id="generateImageBtn">ساخت ویدیو</button>
269
- <div class="result-container" id="imageResultContainer">
270
- <span>نتیجه در اینجا نمایش داده می‌شود</span>
 
271
  </div>
272
- <div class="status-message" id="imageStatus"></div>
 
 
 
273
  </div>
274
  </div>
275
 
276
- <script type="module">
277
- // Import the HfInference class from the CDN
278
- import { HfInference } from "https://cdn.jsdelivr.net/npm/@huggingface/[email protected]/+esm";
279
-
280
- // DOM Elements
281
- const hfTokenInput = document.getElementById('hfToken');
282
-
283
- // Text-to-Video elements
284
- const textPrompt = document.getElementById('textPrompt');
285
- const generateTextBtn = document.getElementById('generateTextBtn');
286
- const textResultContainer = document.getElementById('textResultContainer');
287
- const textStatus = document.getElementById('textStatus');
288
-
289
- // Image-to-Video elements
290
- const imageFile = document.getElementById('imageFile');
291
- const imagePrompt = document.getElementById('imagePrompt');
292
- const generateImageBtn = document.getElementById('generateImageBtn');
293
- const imageResultContainer = document.getElementById('imageResultContainer');
294
- const imageStatus = document.getElementById('imageStatus');
295
- const imagePreviewContainer = document.getElementById('imagePreviewContainer');
296
- const imagePreview = document.getElementById('imagePreview');
297
-
298
- // --- Tab Management ---
299
- window.openTab = function(tabName) {
300
- const tabContents = document.querySelectorAll('.tab-content');
301
- tabContents.forEach(content => content.classList.remove('active'));
302
-
303
- const tabButtons = document.querySelectorAll('.tab-button');
304
- tabButtons.forEach(button => button.classList.remove('active'));
305
-
306
- document.getElementById(tabName).classList.add('active');
307
- event.currentTarget.classList.add('active');
308
- }
309
 
310
- // --- Image Preview ---
311
- imageFile.addEventListener('change', () => {
312
- const file = imageFile.files[0];
313
  if (file) {
314
  const reader = new FileReader();
315
- reader.onload = (e) => {
316
- imagePreview.src = e.target.result;
317
- imagePreviewContainer.style.display = 'block';
318
  };
319
  reader.readAsDataURL(file);
320
- } else {
321
- imagePreviewContainer.style.display = 'none';
322
  }
323
  });
324
-
325
- // --- Helper Functions ---
326
- function getHfClient() {
327
- const token = hfTokenInput.value.trim();
328
- if (!token) {
329
- alert('لطفاً کلید توکن Hugging Face خود را وارد کنید.');
330
- return null;
331
- }
332
- return new HfInference(token);
333
- }
334
-
335
- function showLoading(container, statusEl, buttonEl) {
336
- container.innerHTML = '<div class="loader"></div>';
337
- statusEl.className = 'status-message';
338
- statusEl.textContent = 'در حال ساخت ویدیو... این فرآیند ممکن است چند دقیقه طول بکشد. لطفاً صبور باشید.';
339
- buttonEl.disabled = true;
340
- }
341
-
342
- function showResult(container, statusEl, buttonEl, videoBlob) {
343
- const videoUrl = URL.createObjectURL(videoBlob);
344
- container.innerHTML = `<video controls src="${videoUrl}"></video>`;
345
- statusEl.textContent = 'ویدیو با موفقیت ساخته شد!';
346
- buttonEl.disabled = false;
347
- }
348
-
349
- function showError(container, statusEl, buttonEl, error) {
350
- container.innerHTML = '<span>خطا در ساخت ویدیو</span>';
351
- statusEl.className = 'status-message error-message';
352
- statusEl.textContent = `خطا: ${error.message}`;
353
- buttonEl.disabled = false;
354
- }
355
-
356
- // --- Event Listeners for Generation ---
357
 
358
- // Text-to-Video Generation
359
- generateTextBtn.addEventListener('click', async () => {
360
- const hf = getHfClient();
361
- if (!hf) return;
 
 
362
 
363
- const prompt = textPrompt.value.trim();
364
- if (!prompt) {
365
- alert('لطفاً توصیف ویدیو را وارد کنید.');
366
  return;
367
  }
368
-
369
- showLoading(textResultContainer, textStatus, generateTextBtn);
370
-
 
 
371
  try {
372
- const videoBlob = await hf.textToVideo({
 
 
 
 
373
  provider: "fal-ai",
374
  model: "akhaliq/veo3.1-fast",
375
- inputs: prompt,
376
  });
377
- showResult(textResultContainer, textStatus, generateTextBtn, videoBlob);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  } catch (error) {
379
- console.error("Text-to-Video Error:", error);
380
- showError(textResultContainer, textStatus, generateTextBtn, error);
 
381
  }
382
  });
383
-
384
- // Image-to-Video Generation (CORRECTED)
385
- generateImageBtn.addEventListener('click', async () => {
386
- const hf = getHfClient();
387
- if (!hf) return;
388
-
389
- const file = imageFile.files[0];
390
- if (!file) {
391
- alert('لطفاً یک تصویر انتخاب کنید.');
392
  return;
393
  }
394
 
395
- const prompt = imagePrompt.value.trim();
396
- if (!prompt) {
397
- alert('لطفاً توصیف حرکت را وارد کنید.');
398
  return;
399
  }
400
 
401
- showLoading(imageResultContainer, imageStatus, generateImageBtn);
402
-
 
 
403
  try {
404
- // CORRECTED: Use the generic 'request' method
405
- const videoBlob = await hf.request({
406
- task: "image-to-video",
 
 
 
 
 
 
407
  model: "akhaliq/veo3.1-fast-image-to-video",
408
- data: file, // The library handles the File object
409
- parameters: {
410
- prompt: prompt,
411
- provider: "fal-ai"
412
- }
413
  });
414
-
415
- // The result of hf.request is directly the blob
416
- showResult(imageResultContainer, imageStatus, generateImageBtn, videoBlob);
417
-
 
 
 
 
 
 
 
 
 
 
 
 
 
418
  } catch (error) {
419
- console.error("Image-to-Video Error:", error);
420
- showError(imageResultContainer, imageStatus, generateImageBtn, error);
 
421
  }
422
  });
423
-
 
 
 
 
 
 
 
 
 
 
424
  </script>
425
  </body>
426
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ساخت ویدیو با هوش مصنوعی - Hugging Face</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
+ <script src="https://cdn.jsdelivr.net/npm/@huggingface/[email protected]"></script>
9
  <style>
10
+ * {
11
+ margin: 0;
12
+ padding: 0;
13
+ box-sizing: border-box;
14
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 
 
 
15
  }
16
+
 
 
17
  body {
18
+ background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
19
+ color: #fff;
 
 
 
 
 
 
20
  min-height: 100vh;
21
+ padding: 20px;
22
  }
23
+
24
  .container {
25
+ max-width: 1200px;
26
+ margin: 0 auto;
 
 
 
 
27
  }
28
+
29
+ header {
30
  text-align: center;
31
+ padding: 30px 0;
32
+ margin-bottom: 30px;
33
+ }
34
+
35
+ h1 {
36
+ font-size: 2.5rem;
37
  margin-bottom: 10px;
38
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
39
  }
40
+
41
+ .subtitle {
42
+ font-size: 1.2rem;
43
+ opacity: 0.9;
 
 
44
  }
45
+
46
+ .card {
47
+ background: rgba(255, 255, 255, 0.1);
48
+ backdrop-filter: blur(10px);
49
+ border-radius: 15px;
50
+ padding: 25px;
51
  margin-bottom: 25px;
52
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
53
+ border: 1px solid rgba(255, 255, 255, 0.2);
54
  }
55
+
56
+ .card-title {
57
+ display: flex;
58
+ align-items: center;
59
+ margin-bottom: 20px;
60
+ font-size: 1.5rem;
61
+ }
62
+
63
+ .card-title i {
64
+ margin-left: 10px;
65
+ font-size: 1.8rem;
66
+ }
67
+
68
  .form-group {
69
  margin-bottom: 20px;
70
  }
71
+
72
  label {
73
  display: block;
74
  margin-bottom: 8px;
75
+ font-weight: 500;
 
76
  }
77
+
78
+ input, textarea, select {
 
 
79
  width: 100%;
80
+ padding: 12px 15px;
 
 
81
  border-radius: 8px;
82
+ border: 1px solid rgba(255, 255, 255, 0.3);
83
+ background: rgba(255, 255, 255, 0.1);
84
+ color: #fff;
85
  font-size: 1rem;
86
+ transition: all 0.3s ease;
 
87
  }
88
+
89
+ input:focus, textarea:focus, select:focus {
 
 
90
  outline: none;
91
+ border-color: #4dabf7;
92
+ box-shadow: 0 0 0 3px rgba(77, 171, 247, 0.3);
93
  }
94
 
95
+ textarea {
96
+ min-height: 120px;
97
+ resize: vertical;
 
 
 
 
 
98
  }
99
+
100
+ .btn {
101
+ display: inline-flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ padding: 12px 25px;
105
+ background: linear-gradient(45deg, #ff6b6b, #ff8e53);
106
+ color: white;
107
  border: none;
108
+ border-radius: 8px;
 
109
  font-size: 1rem;
110
+ font-weight: 600;
111
+ cursor: pointer;
112
+ transition: all 0.3s ease;
113
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
 
 
 
 
 
114
  }
115
+
116
+ .btn:hover {
117
+ transform: translateY(-2px);
118
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
119
  }
120
+
121
+ .btn i {
122
+ margin-right: 8px;
123
  }
124
+
125
+ .btn-primary {
126
+ background: linear-gradient(45deg, #4dabf7, #3bc9db);
 
 
 
 
 
 
 
 
 
 
127
  }
128
+
129
+ .btn-success {
130
+ background: linear-gradient(45deg, #51cf66, #94d82d);
131
  }
132
 
133
+ .flex-container {
134
+ display: flex;
135
+ gap: 25px;
136
+ flex-wrap: wrap;
137
  }
138
+
139
+ .flex-item {
140
+ flex: 1;
141
+ min-width: 300px;
 
142
  }
143
+
144
  .result-container {
145
+ display: none;
146
+ text-align: center;
147
+ padding: 20px;
148
+ }
149
+
150
+ .video-preview {
151
+ width: 100%;
152
+ max-width: 600px;
153
+ height: 300px;
154
+ background: rgba(0, 0, 0, 0.3);
155
+ border-radius: 10px;
156
+ margin: 20px auto;
157
  display: flex;
 
158
  align-items: center;
159
+ justify-content: center;
160
+ overflow: hidden;
161
  }
162
+
163
+ .video-preview video {
164
  max-width: 100%;
165
+ max-height: 100%;
166
  border-radius: 8px;
167
  }
168
 
169
+ .loading {
170
+ display: none;
171
+ text-align: center;
172
+ padding: 20px;
173
  }
174
+
175
+ .spinner {
176
+ width: 50px;
177
+ height: 50px;
178
+ border: 5px solid rgba(255, 255, 255, 0.3);
179
  border-radius: 50%;
180
+ border-top-color: #4dabf7;
 
181
  animation: spin 1s linear infinite;
182
+ margin: 0 auto 15px;
183
  }
184
+
185
  @keyframes spin {
186
+ to { transform: rotate(360deg); }
 
187
  }
188
+
189
+ .file-input-container {
190
+ position: relative;
191
+ overflow: hidden;
192
+ display: inline-block;
193
+ width: 100%;
194
+ }
195
+
196
+ .file-input-container input[type=file] {
197
+ position: absolute;
198
+ left: 0;
199
+ top: 0;
200
+ opacity: 0;
201
+ width: 100%;
202
+ height: 100%;
203
+ cursor: pointer;
204
+ }
205
+
206
+ .file-input-label {
207
+ display: flex;
208
+ align-items: center;
209
+ justify-content: center;
210
+ padding: 12px;
211
+ background: rgba(255, 255, 255, 0.1);
212
+ border: 2px dashed rgba(255, 255, 255, 0.3);
213
+ border-radius: 8px;
214
+ cursor: pointer;
215
+ transition: all 0.3s ease;
216
+ }
217
+
218
+ .file-input-label:hover {
219
+ background: rgba(255, 255, 255, 0.2);
220
+ }
221
+
222
+ .file-input-label i {
223
+ margin-left: 8px;
224
+ font-size: 1.5rem;
225
+ }
226
+
227
+ .image-preview {
228
  margin-top: 15px;
229
  text-align: center;
 
230
  }
231
+
232
+ .image-preview img {
233
+ max-width: 100%;
234
+ max-height: 200px;
235
+ border-radius: 8px;
236
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
237
  }
238
 
239
+ .instructions {
240
+ margin-top: 30px;
241
+ font-size: 0.9rem;
242
+ opacity: 0.8;
243
+ line-height: 1.6;
244
  }
245
+
246
+ .error {
247
+ background: rgba(255, 0, 0, 0.2);
248
+ border: 1px solid rgba(255, 0, 0, 0.5);
 
 
249
  border-radius: 8px;
250
+ padding: 15px;
251
+ margin: 15px 0;
252
+ display: none;
 
 
253
  }
254
+
255
+ @media (max-width: 768px) {
256
+ .flex-container {
257
+ flex-direction: column;
258
+ }
259
+
260
+ h1 {
261
+ font-size: 2rem;
262
+ }
263
  }
 
264
  </style>
265
  </head>
266
  <body>
 
267
  <div class="container">
268
+ <header>
269
+ <h1>ساخت ویدیو با هوش مصنوعی</h1>
270
+ <p class="subtitle">تبدیل متن و تصویر به ویدیو با استفاده از مدل VEO از Hugging Face</p>
271
+ </header>
272
+
273
+ <div class="card">
274
+ <div class="card-title">
275
+ <i class="fas fa-key"></i>
276
+ <h2>تنظیمات احراز هویت</h2>
 
 
 
 
 
 
 
 
 
277
  </div>
278
+ <div class="form-group">
279
+ <label for="token">توکن Hugging Face</label>
280
+ <input type="text" id="token" placeholder="توکن خود را اینجا وارد کنید" required>
281
+ <p class="instructions">برای استفاده از این سرویس، نیاز به یک توکن معتبر از Hugging Face دارید. اگر توکن ندارید، از <a href="https://huggingface.co/settings/tokens" target="_blank" style="color: #4dabf7;">این لینک</a> می‌توانید ایجاد کنید.</p>
282
  </div>
 
283
  </div>
284
+
285
+ <div class="flex-container">
286
+ <div class="flex-item">
287
+ <div class="card">
288
+ <div class="card-title">
289
+ <i class="fas fa-font"></i>
290
+ <h2>تبدیل متن به ویدیو</h2>
291
+ </div>
292
+ <div class="form-group">
293
+ <label for="text-input">متن خود را وارد کنید</label>
294
+ <textarea id="text-input" placeholder="مثلاً: یک مرد جوان در خیابان در حال راه رفتن است"></textarea>
295
+ </div>
296
+ <button class="btn btn-primary" id="text-to-video-btn">
297
+ <i class="fas fa-film"></i>
298
+ ساخت ویدیو از متن
299
+ </button>
300
+ </div>
301
  </div>
302
+
303
+ <div class="flex-item">
304
+ <div class="card">
305
+ <div class="card-title">
306
+ <i class="fas fa-image"></i>
307
+ <h2>تبدیل تصویر به ویدیو</h2>
308
+ </div>
309
+ <div class="form-group">
310
+ <label for="image-input">تصویر خود را انتخاب کنید</label>
311
+ <div class="file-input-container">
312
+ <div class="file-input-label">
313
+ <i class="fas fa-cloud-upload-alt"></i>
314
+ <span>انتخاب تصویر</span>
315
+ </div>
316
+ <input type="file" id="image-input" accept="image/*">
317
+ </div>
318
+ <div class="image-preview" id="image-preview"></div>
319
+ </div>
320
+ <div class="form-group">
321
+ <label for="image-prompt">توضیح برای ویدیو (اختیاری)</label>
322
+ <input type="text" id="image-prompt" placeholder="مثلاً: گربه شروع به رقصیدن می‌کند">
323
+ </div>
324
+ <button class="btn btn-success" id="image-to-video-btn">
325
+ <i class="fas fa-video"></i>
326
+ ساخت ویدیو از تصویر
327
+ </button>
328
  </div>
329
  </div>
330
+ </div>
331
+
332
+ <div class="loading" id="loading">
333
+ <div class="spinner"></div>
334
+ <p>در حال ساخت ویدیو، لطفاً منتظر بمانید...</p>
335
+ <p class="instructions">این فرآیند ممکن است چند دقیقه طول بکشد</p>
336
+ </div>
337
+
338
+ <div class="error" id="error-message">
339
+ <i class="fas fa-exclamation-triangle"></i>
340
+ <span id="error-text">خطایی رخ داده است</span>
341
+ </div>
342
+
343
+ <div class="card result-container" id="result-container">
344
+ <div class="card-title">
345
+ <i class="fas fa-check-circle"></i>
346
+ <h2>ویدیو شما آماده است!</h2>
347
  </div>
348
+ <div class="video-preview" id="video-preview">
349
+ <video controls id="generated-video">
350
+ مرورگر شما از تگ ویدیو پشتیبانی نمی‌کند.
351
+ </video>
352
  </div>
353
+ <button class="btn btn-primary" id="download-btn">
354
+ <i class="fas fa-download"></i>
355
+ دانلود ویدیو
356
+ </button>
357
  </div>
358
  </div>
359
 
360
+ <script>
361
+ // عناصر DOM
362
+ const tokenInput = document.getElementById('token');
363
+ const textInput = document.getElementById('text-input');
364
+ const imageInput = document.getElementById('image-input');
365
+ const imagePrompt = document.getElementById('image-prompt');
366
+ const textToVideoBtn = document.getElementById('text-to-video-btn');
367
+ const imageToVideoBtn = document.getElementById('image-to-video-btn');
368
+ const loading = document.getElementById('loading');
369
+ const resultContainer = document.getElementById('result-container');
370
+ const videoPreview = document.getElementById('video-preview');
371
+ const generatedVideo = document.getElementById('generated-video');
372
+ const downloadBtn = document.getElementById('download-btn');
373
+ const imagePreview = document.getElementById('image-preview');
374
+ const errorMessage = document.getElementById('error-message');
375
+ const errorText = document.getElementById('error-text');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
 
377
+ // پیش‌نمایش تصویر آپلود شده
378
+ imageInput.addEventListener('change', function(e) {
379
+ const file = e.target.files[0];
380
  if (file) {
381
  const reader = new FileReader();
382
+ reader.onload = function(e) {
383
+ imagePreview.innerHTML = `<img src="${e.target.result}" alt="تصویر آپلود شده">`;
 
384
  };
385
  reader.readAsDataURL(file);
 
 
386
  }
387
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
 
389
+ // تبدیل متن به ویدیو
390
+ textToVideoBtn.addEventListener('click', async function() {
391
+ if (!tokenInput.value) {
392
+ showError('لطفاً توکن Hugging Face خود را وارد کنید');
393
+ return;
394
+ }
395
 
396
+ if (!textInput.value) {
397
+ showError('لطفاً متنی برای تبدیل به ویدیو وارد کنید');
 
398
  return;
399
  }
400
+
401
+ hideError();
402
+ loading.style.display = 'block';
403
+ resultContainer.style.display = 'none';
404
+
405
  try {
406
+ // استفاده از کتابخانه Hugging Face Inference
407
+ const { InferenceClient } = window.HfInference;
408
+ const client = new InferenceClient(tokenInput.value);
409
+
410
+ const videoBlob = await client.textToVideo({
411
  provider: "fal-ai",
412
  model: "akhaliq/veo3.1-fast",
413
+ inputs: textInput.value,
414
  });
415
+
416
+ // نمایش ویدیوی تولید شده
417
+ const videoUrl = URL.createObjectURL(videoBlob);
418
+ generatedVideo.src = videoUrl;
419
+ loading.style.display = 'none';
420
+ resultContainer.style.display = 'block';
421
+
422
+ // تنظیم لینک دانلود
423
+ downloadBtn.onclick = function() {
424
+ const a = document.createElement('a');
425
+ a.href = videoUrl;
426
+ a.download = `text-to-video-${Date.now()}.mp4`;
427
+ document.body.appendChild(a);
428
+ a.click();
429
+ document.body.removeChild(a);
430
+ };
431
+
432
  } catch (error) {
433
+ console.error('خطا در ساخت ویدیو:', error);
434
+ showError('خطا در ساخت ویدیو: ' + error.message);
435
+ loading.style.display = 'none';
436
  }
437
  });
438
+
439
+ // تبدیل تصویر به ویدیو
440
+ imageToVideoBtn.addEventListener('click', async function() {
441
+ if (!tokenInput.value) {
442
+ showError('لطفاً توکن Hugging Face خود را وارد کنید');
 
 
 
 
443
  return;
444
  }
445
 
446
+ if (!imageInput.files[0]) {
447
+ showError('لطفاً تصویری برای تبدیل به ویدیو انتخاب کنید');
 
448
  return;
449
  }
450
 
451
+ hideError();
452
+ loading.style.display = 'block';
453
+ resultContainer.style.display = 'none';
454
+
455
  try {
456
+ // تبدیل تصویر به Blob
457
+ const imageFile = imageInput.files[0];
458
+
459
+ // استفاده از کتابخانه Hugging Face Inference
460
+ const { InferenceClient } = window.HfInference;
461
+ const client = new InferenceClient(tokenInput.value);
462
+
463
+ const videoBlob = await client.imageToVideo({
464
+ provider: "fal-ai",
465
  model: "akhaliq/veo3.1-fast-image-to-video",
466
+ inputs: imageFile,
467
+ parameters: {
468
+ prompt: imagePrompt.value || "The image comes to life"
469
+ },
 
470
  });
471
+
472
+ // نمایش ویدیوی تولید شده
473
+ const videoUrl = URL.createObjectURL(videoBlob);
474
+ generatedVideo.src = videoUrl;
475
+ loading.style.display = 'none';
476
+ resultContainer.style.display = 'block';
477
+
478
+ // تنظیم لینک دانلود
479
+ downloadBtn.onclick = function() {
480
+ const a = document.createElement('a');
481
+ a.href = videoUrl;
482
+ a.download = `image-to-video-${Date.now()}.mp4`;
483
+ document.body.appendChild(a);
484
+ a.click();
485
+ document.body.removeChild(a);
486
+ };
487
+
488
  } catch (error) {
489
+ console.error('خطا در ساخت ویدیو:', error);
490
+ showError('خطا در ساخت ویدیو: ' + error.message);
491
+ loading.style.display = 'none';
492
  }
493
  });
494
+
495
+ // نمایش خطا
496
+ function showError(message) {
497
+ errorText.textContent = message;
498
+ errorMessage.style.display = 'block';
499
+ }
500
+
501
+ // پنهان کردن خطا
502
+ function hideError() {
503
+ errorMessage.style.display = 'none';
504
+ }
505
  </script>
506
  </body>
507
  </html>