Ezmary commited on
Commit
072de13
·
verified ·
1 Parent(s): f871a3e

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +82 -56
templates/index.html CHANGED
@@ -416,7 +416,7 @@
416
  const durationValueDisplay = document.getElementById('durationValue');
417
 
418
  // ====== تنظیمات مدل‌ها ======
419
- const VIDEO_SPACE_NAME = "mrbui1990/wan2-2-fp8da-aoti-faster";
420
  const TRANSLATOR_SPACE_NAME = "hamed744/translate-tts-aloha";
421
  const FN_INDEX_TRANSLATE_SPEAK = 1;
422
  const DEFAULT_TTS_VOICE_TRANSLATOR = "انگلیسی (آمریکا) - جنی (زن)";
@@ -427,11 +427,13 @@
427
  const DEFAULT_VIDEO_DURATION = 4.3;
428
 
429
  // --- TIMEOUTS ---
430
- const TRANSLATION_TIMEOUT = 20000; // 20 ثانیه برای ترجمه
431
 
432
  let lastAttemptedVideoPayload = null;
433
- let videoGenerationJob = null; // برای نگهداری آبجکت جاب
434
 
 
 
435
  function updateSliderStyle(slider) {
436
  const percentage = ((slider.value - slider.min) / (slider.max - slider.min)) * 100;
437
  const colorStops = `var(--accent-primary), var(--accent-secondary)`;
@@ -504,9 +506,9 @@
504
  }
505
 
506
  function initializeForm() {
507
- if (videoGenerationJob) {
508
- try { videoGenerationJob.cancel(); } catch(e) { console.warn("Could not cancel previous job:", e); }
509
- videoGenerationJob = null;
510
  }
511
  hideCriticalError();
512
  resultContainer.classList.remove('active');
@@ -527,7 +529,6 @@
527
 
528
  async function translatePersianToEnglish(persianText, { timeoutMs = TRANSLATION_TIMEOUT } = {}) {
529
  if (!persianText?.trim()) {
530
- // اگر متن خالی باشد، یک پرامیس موفق با یک رشته خالی برمی‌گردانیم تا فرآیند متوقف نشود
531
  return Promise.resolve("");
532
  }
533
 
@@ -552,7 +553,7 @@
552
 
553
  async function handleSuccessfulVideoGeneration(output) {
554
  aiLoader.style.display = 'none';
555
- if (!output?.data?.[0]?.video?.url) {
556
  showCriticalError('پاسخ دریافتی از سرور ویدیو معتبر نیست.');
557
  return;
558
  }
@@ -572,8 +573,10 @@
572
  }
573
 
574
  addStatusMessage('ویدیو آماده شد! 🎉', 'success');
575
- const videoUrl = output.data[0].video.url;
 
576
  const usedSeed = output.data[1];
 
577
  setTimeout(() => {
578
  statusSection.classList.remove('active');
579
  outputSection.classList.add('active');
@@ -648,92 +651,115 @@
648
 
649
  lastAttemptedVideoPayload = { persianPrompt, imageSourceFile: imageFile, duration };
650
 
651
- // --- START: ROBUST TRANSLATION BLOCK ---
652
- let promptForVideo = persianPrompt; // Default to Persian
653
  try {
654
  setAiLoaderText("در حال ترجمه دستور شما...");
655
  const englishPrompt = await translatePersianToEnglish(persianPrompt);
656
  if(englishPrompt){
657
  addStatusMessage(`ترجمه: ${englishPrompt}`, 'info');
658
  promptForVideo = englishPrompt;
659
- } else {
660
- addStatusMessage('دستور ساخت خالی بود، از متن فارسی استفاده می‌شود.', 'info');
661
  }
662
  } catch (e) {
663
- console.warn("Translation failed or timed out:", e.message);
664
  addStatusMessage('ترجمه ناموفق بود. با متن فارسی ادامه می‌دهیم.', 'error');
665
- // promptForVideo is already set to persianPrompt, so we just continue.
666
  }
667
- // --- END: ROBUST TRANSLATION BLOCK ---
668
 
669
- // **CRITICAL FIX**: Update UI to show progress AFTER translation attempt, regardless of outcome.
670
- setAiLoaderText("اتصال به سرور ویدیو...");
671
 
672
  try {
673
- const client = await Client.connect(VIDEO_SPACE_NAME);
674
- videoGenerationJob = client.submit(0, [
675
- imageFile,
676
- promptForVideo,
677
- 6, // steps
678
- DEFAULT_NEGATIVE_PROMPT,
679
- duration,
680
- 1, // guidance_scale
681
- 1, // guidance_scale_2
682
- 0, // seed (0 = random)
683
- true // randomize_seed
684
- ]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
685
 
686
- for await (const status of videoGenerationJob) {
687
- console.log(status); // For debugging
688
- switch (status.type) {
689
- case "estimation":
690
- setAiLoaderText(`در صف قرار گرفتید... (نفر ${status.queue_position} از ${status.queue_size})`);
691
- addStatusMessage(`در صف انتظار... زمان تخمینی: ${Math.round(status.rank_eta)} ثانیه`);
692
- setProgressBar(2);
 
 
 
693
  break;
694
- case "progress":
695
- if (status.progress_data && status.progress_data.length > 0) {
696
- const progressItem = status.progress_data[0];
697
  let percentage = 0;
698
  let progressText = "در حال پردازش...";
699
 
700
- if (progressItem.desc === "ZeroGPU init") {
701
- percentage = (progressItem.index / progressItem.length) * 20;
702
  progressText = `آماده‌سازی: ${Math.round(percentage)}%`;
703
- } else if (progressItem.unit === "steps" && progressItem.desc === null) {
704
- percentage = 20 + (progressItem.index / progressItem.length) * 80;
705
  progressText = `ساخت ویدیو: ${Math.round(percentage)}%`;
706
  }
707
  setProgressBar(percentage);
708
  setAiLoaderText(progressText);
709
  }
710
  break;
711
- case "process_starts":
712
- addStatusMessage('پردازش شروع شد...');
713
- setAiLoaderText("در حال پردازش ویدیو...");
714
- break;
715
- case "process_completed":
716
- if (status.success) {
717
  setProgressBar(100);
718
  setAiLoaderText("پردازش کامل شد!");
719
- await handleSuccessfulVideoGeneration(status.output);
720
  } else {
721
- const errorMessage = status.output?.error || "یک خطای نامشخص رخ داد.";
722
  const isGpuQuotaError = /exceeded your gpu quota/i.test(errorMessage);
723
  showCriticalError(errorMessage, isGpuQuotaError);
724
  }
725
- videoGenerationJob = null; // Clear the job after completion
726
- return;
 
727
  }
728
- }
 
 
 
 
 
 
 
729
 
730
  } catch (errorCaught) {
731
  showCriticalError(`خطای اولیه: ${errorCaught.message}`);
732
  generateButton.disabled = false;
733
  }
 
734
  };
735
 
736
-
737
  generateButton.addEventListener('click', async () => {
738
  if (generateButton.disabled) return;
739
 
 
416
  const durationValueDisplay = document.getElementById('durationValue');
417
 
418
  // ====== تنظیمات مدل‌ها ======
419
+ const VIDEO_SPACE_URL = "https://mrbui1990-wan2-2-fp8da-aoti-faster.hf.space/";
420
  const TRANSLATOR_SPACE_NAME = "hamed744/translate-tts-aloha";
421
  const FN_INDEX_TRANSLATE_SPEAK = 1;
422
  const DEFAULT_TTS_VOICE_TRANSLATOR = "انگلیسی (آمریکا) - جنی (زن)";
 
427
  const DEFAULT_VIDEO_DURATION = 4.3;
428
 
429
  // --- TIMEOUTS ---
430
+ const TRANSLATION_TIMEOUT = 20000;
431
 
432
  let lastAttemptedVideoPayload = null;
433
+ let eventSource = null; // نگه داشتن رفرنس EventSource برای بستن آن
434
 
435
+ const generateSessionHash = () => Math.random().toString(36).substring(2, 13);
436
+
437
  function updateSliderStyle(slider) {
438
  const percentage = ((slider.value - slider.min) / (slider.max - slider.min)) * 100;
439
  const colorStops = `var(--accent-primary), var(--accent-secondary)`;
 
506
  }
507
 
508
  function initializeForm() {
509
+ if (eventSource) {
510
+ eventSource.close();
511
+ eventSource = null;
512
  }
513
  hideCriticalError();
514
  resultContainer.classList.remove('active');
 
529
 
530
  async function translatePersianToEnglish(persianText, { timeoutMs = TRANSLATION_TIMEOUT } = {}) {
531
  if (!persianText?.trim()) {
 
532
  return Promise.resolve("");
533
  }
534
 
 
553
 
554
  async function handleSuccessfulVideoGeneration(output) {
555
  aiLoader.style.display = 'none';
556
+ if (!output?.data?.[0]?.video?.path) {
557
  showCriticalError('پاسخ دریافتی از سرور ویدیو معتبر نیست.');
558
  return;
559
  }
 
573
  }
574
 
575
  addStatusMessage('ویدیو آماده شد! 🎉', 'success');
576
+ const videoPath = output.data[0].video.path;
577
+ const videoUrl = `${VIDEO_SPACE_URL}gradio_api/file=${videoPath}`;
578
  const usedSeed = output.data[1];
579
+
580
  setTimeout(() => {
581
  statusSection.classList.remove('active');
582
  outputSection.classList.add('active');
 
651
 
652
  lastAttemptedVideoPayload = { persianPrompt, imageSourceFile: imageFile, duration };
653
 
654
+ let promptForVideo = persianPrompt;
 
655
  try {
656
  setAiLoaderText("در حال ترجمه دستور شما...");
657
  const englishPrompt = await translatePersianToEnglish(persianPrompt);
658
  if(englishPrompt){
659
  addStatusMessage(`ترجمه: ${englishPrompt}`, 'info');
660
  promptForVideo = englishPrompt;
 
 
661
  }
662
  } catch (e) {
663
+ console.warn("Translation failed:", e.message);
664
  addStatusMessage('ترجمه ناموفق بود. با متن فارسی ادامه می‌دهیم.', 'error');
 
665
  }
 
666
 
667
+ // === START: ROBUST DIRECT API INTERACTION ===
668
+ const sessionHash = generateSessionHash();
669
 
670
  try {
671
+ // Step 1: Upload File
672
+ setAiLoaderText("۱/۳: در حال آپلود عکس...");
673
+ const formData = new FormData();
674
+ formData.append('files', imageFile);
675
+ const uploadResponse = await fetch(`${VIDEO_SPACE_URL}gradio_api/upload`, { method: 'POST', body: formData });
676
+ if (!uploadResponse.ok) throw new Error(`خطا در آپلود: ${uploadResponse.statusText}`);
677
+ const uploadedFiles = await uploadResponse.json();
678
+ const serverFilePath = uploadedFiles[0];
679
+
680
+ // Step 2: Join Queue
681
+ setAiLoaderText("۲/۳: ارسال درخواست به صف...");
682
+ const joinPayload = {
683
+ "data": [
684
+ {"path": serverFilePath, "url": `${VIDEO_SPACE_URL}gradio_api/file=${serverFilePath}`},
685
+ promptForVideo,
686
+ 6, // steps
687
+ DEFAULT_NEGATIVE_PROMPT,
688
+ duration,
689
+ 1, // guidance_scale
690
+ 1, // guidance_scale_2
691
+ 0, // seed (0 = random)
692
+ true // randomize_seed
693
+ ],
694
+ "fn_index": 0, "session_hash": sessionHash
695
+ };
696
+ const joinResponse = await fetch(`${VIDEO_SPACE_URL}gradio_api/queue/join`, {
697
+ method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(joinPayload)
698
+ });
699
+ if (!joinResponse.ok) throw new Error(`خطا در اتصال به صف: ${joinResponse.statusText}`);
700
+
701
+ // Step 3: Listen for Data
702
+ setAiLoaderText("۳/۳: منتظر دریافت نتیجه...");
703
+ eventSource = new EventSource(`${VIDEO_SPACE_URL}gradio_api/queue/data?session_hash=${sessionHash}`);
704
 
705
+ eventSource.onmessage = (event) => {
706
+ const data = JSON.parse(event.data);
707
+ console.log(data); // For debugging
708
+
709
+ switch (data.msg) {
710
+ case 'estimation':
711
+ addStatusMessage(`در صف انتظار... زمان تخمینی: ${Math.round(data.rank_eta)} ثانیه`);
712
+ break;
713
+ case 'process_starts':
714
+ addStatusMessage('پردازش شروع شد...');
715
  break;
716
+ case 'progress':
717
+ if (data.progress_data && data.progress_data.length > 0) {
718
+ const p = data.progress_data[0];
719
  let percentage = 0;
720
  let progressText = "در حال پردازش...";
721
 
722
+ if (p.desc === "ZeroGPU init") {
723
+ percentage = (p.index / p.length) * 20;
724
  progressText = `آماده‌سازی: ${Math.round(percentage)}%`;
725
+ } else if (p.unit === "steps" && p.desc === null) {
726
+ percentage = 20 + (p.index / p.length) * 80;
727
  progressText = `ساخت ویدیو: ${Math.round(percentage)}%`;
728
  }
729
  setProgressBar(percentage);
730
  setAiLoaderText(progressText);
731
  }
732
  break;
733
+ case 'process_completed':
734
+ if (data.success) {
 
 
 
 
735
  setProgressBar(100);
736
  setAiLoaderText("پردازش کامل شد!");
737
+ handleSuccessfulVideoGeneration(data.output);
738
  } else {
739
+ const errorMessage = data.output?.error || "یک خطای نامشخص رخ داد.";
740
  const isGpuQuotaError = /exceeded your gpu quota/i.test(errorMessage);
741
  showCriticalError(errorMessage, isGpuQuotaError);
742
  }
743
+ eventSource.close();
744
+ eventSource = null;
745
+ break;
746
  }
747
+ };
748
+
749
+ eventSource.onerror = (error) => {
750
+ console.error('EventSource failed:', error);
751
+ showCriticalError("خطا در ارتباط با سرور. لطفاً اتصال اینترنت خود را بررسی کرده و مجدداً تلاش کنید.");
752
+ eventSource.close();
753
+ eventSource = null;
754
+ };
755
 
756
  } catch (errorCaught) {
757
  showCriticalError(`خطای اولیه: ${errorCaught.message}`);
758
  generateButton.disabled = false;
759
  }
760
+ // === END: ROBUST DIRECT API INTERACTION ===
761
  };
762
 
 
763
  generateButton.addEventListener('click', async () => {
764
  if (generateButton.disabled) return;
765