Update templates/index.html
Browse files- templates/index.html +47 -37
templates/index.html
CHANGED
|
@@ -351,7 +351,9 @@
|
|
| 351 |
|
| 352 |
(function() {
|
| 353 |
let isProcessing = false;
|
|
|
|
| 354 |
|
|
|
|
| 355 |
let userSubscriptionStatus = 'free';
|
| 356 |
let userFingerprint = null;
|
| 357 |
let countdownInterval = null;
|
|
@@ -470,7 +472,6 @@
|
|
| 470 |
document.getElementById('upgrade-button').addEventListener('click', () => {
|
| 471 |
parent.postMessage({ type: 'NAVIGATE_TO_PREMIUM' }, '*');
|
| 472 |
});
|
| 473 |
-
|
| 474 |
const resultContainer = document.getElementById('result-container');
|
| 475 |
const imageFileInput = document.getElementById('imageFile');
|
| 476 |
const imagePreview = document.getElementById('imagePreview');
|
|
@@ -499,8 +500,8 @@
|
|
| 499 |
const DEFAULT_PROMPT_TEXT = "";
|
| 500 |
const TRANSPARENT_PIXEL_SRC = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
| 501 |
const DEFAULT_VIDEO_DURATION = 4.3;
|
| 502 |
-
const GLOBAL_TIMEOUT = 150000;
|
| 503 |
-
const QUEUE_TIMEOUT = 45000;
|
| 504 |
|
| 505 |
let lastAttemptedVideoPayload = null;
|
| 506 |
|
|
@@ -586,6 +587,10 @@
|
|
| 586 |
imageDropZone.classList.remove('has-image');
|
| 587 |
promptInput.value = DEFAULT_PROMPT_TEXT;
|
| 588 |
isProcessing = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 589 |
generateButton.disabled = false;
|
| 590 |
durationSlider.value = DEFAULT_VIDEO_DURATION;
|
| 591 |
durationValueDisplay.textContent = `${parseFloat(DEFAULT_VIDEO_DURATION).toFixed(1)} ثانیه`;
|
|
@@ -716,63 +721,68 @@
|
|
| 716 |
|
| 717 |
lastAttemptedVideoPayload = { persianPrompt, imageSourceFile: imageFile, duration };
|
| 718 |
|
|
|
|
|
|
|
| 719 |
try {
|
| 720 |
const englishPrompt = await translatePersianToEnglish(persianPrompt);
|
| 721 |
addStatusMessage(`ترجمه: ${englishPrompt}`, 'info');
|
| 722 |
|
| 723 |
-
// --- START: NEW ROBUST LOGIC ---
|
| 724 |
const client = await Client.connect(VIDEO_SPACE_NAME);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 725 |
|
| 726 |
-
const videoGenerationPromise =
|
| 727 |
let hasStartedProcessing = false;
|
| 728 |
-
let
|
| 729 |
|
| 730 |
-
|
| 731 |
if (!hasStartedProcessing) {
|
| 732 |
-
|
| 733 |
-
|
| 734 |
}
|
| 735 |
}, QUEUE_TIMEOUT);
|
| 736 |
|
| 737 |
-
|
| 738 |
-
|
| 739 |
-
|
| 740 |
-
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
|
| 744 |
-
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
|
|
|
|
|
|
| 751 |
}
|
| 752 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 753 |
|
| 754 |
-
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
});
|
| 758 |
-
});
|
| 759 |
|
| 760 |
-
const
|
| 761 |
-
|
| 762 |
-
reject(new Error('پردازش بیش از حد طولانی شد (Global Timeout).'));
|
| 763 |
-
}, GLOBAL_TIMEOUT);
|
| 764 |
-
});
|
| 765 |
|
| 766 |
-
const result = await Promise.race([videoGenerationPromise, globalTimeoutPromise]);
|
| 767 |
-
// --- END: NEW ROBUST LOGIC ---
|
| 768 |
-
|
| 769 |
await handleSuccessfulVideoGeneration(result);
|
| 770 |
|
| 771 |
} catch (errorCaught) {
|
|
|
|
| 772 |
const isTranslationErr = errorCaught.message.toLowerCase().includes("مترجم");
|
| 773 |
showCriticalError(`خطا: ${errorCaught.message}`, isTranslationErr);
|
| 774 |
} finally {
|
| 775 |
isProcessing = false;
|
|
|
|
| 776 |
if (!document.getElementById('upgrade-button').style.display || document.getElementById('upgrade-button').style.display === 'none') {
|
| 777 |
generateButton.disabled = false;
|
| 778 |
}
|
|
|
|
| 351 |
|
| 352 |
(function() {
|
| 353 |
let isProcessing = false;
|
| 354 |
+
let currentJob = null; // --- NEW: To hold the current job for cancellation
|
| 355 |
|
| 356 |
+
// ... (بقیه کدهای کمکی مثل getBrowserFingerprint و مدیریت اعتبار اینجا بدون تغییر قرار میگیرند) ...
|
| 357 |
let userSubscriptionStatus = 'free';
|
| 358 |
let userFingerprint = null;
|
| 359 |
let countdownInterval = null;
|
|
|
|
| 472 |
document.getElementById('upgrade-button').addEventListener('click', () => {
|
| 473 |
parent.postMessage({ type: 'NAVIGATE_TO_PREMIUM' }, '*');
|
| 474 |
});
|
|
|
|
| 475 |
const resultContainer = document.getElementById('result-container');
|
| 476 |
const imageFileInput = document.getElementById('imageFile');
|
| 477 |
const imagePreview = document.getElementById('imagePreview');
|
|
|
|
| 500 |
const DEFAULT_PROMPT_TEXT = "";
|
| 501 |
const TRANSPARENT_PIXEL_SRC = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
| 502 |
const DEFAULT_VIDEO_DURATION = 4.3;
|
| 503 |
+
const GLOBAL_TIMEOUT = 150000;
|
| 504 |
+
const QUEUE_TIMEOUT = 45000;
|
| 505 |
|
| 506 |
let lastAttemptedVideoPayload = null;
|
| 507 |
|
|
|
|
| 587 |
imageDropZone.classList.remove('has-image');
|
| 588 |
promptInput.value = DEFAULT_PROMPT_TEXT;
|
| 589 |
isProcessing = false;
|
| 590 |
+
if(currentJob) {
|
| 591 |
+
currentJob.cancel();
|
| 592 |
+
currentJob = null;
|
| 593 |
+
}
|
| 594 |
generateButton.disabled = false;
|
| 595 |
durationSlider.value = DEFAULT_VIDEO_DURATION;
|
| 596 |
durationValueDisplay.textContent = `${parseFloat(DEFAULT_VIDEO_DURATION).toFixed(1)} ثانیه`;
|
|
|
|
| 721 |
|
| 722 |
lastAttemptedVideoPayload = { persianPrompt, imageSourceFile: imageFile, duration };
|
| 723 |
|
| 724 |
+
let globalTimeout;
|
| 725 |
+
|
| 726 |
try {
|
| 727 |
const englishPrompt = await translatePersianToEnglish(persianPrompt);
|
| 728 |
addStatusMessage(`ترجمه: ${englishPrompt}`, 'info');
|
| 729 |
|
|
|
|
| 730 |
const client = await Client.connect(VIDEO_SPACE_NAME);
|
| 731 |
+
currentJob = client.submit(0, [
|
| 732 |
+
imageFile, englishPrompt, 6, DEFAULT_NEGATIVE_PROMPT,
|
| 733 |
+
duration, 1, 1, 0, true
|
| 734 |
+
]);
|
| 735 |
|
| 736 |
+
const videoGenerationPromise = (async () => {
|
| 737 |
let hasStartedProcessing = false;
|
| 738 |
+
let queueTimeout;
|
| 739 |
|
| 740 |
+
queueTimeout = setTimeout(() => {
|
| 741 |
if (!hasStartedProcessing) {
|
| 742 |
+
currentJob?.cancel();
|
| 743 |
+
throw new Error("Server is busy or no GPU available (Queue Timeout). لطفا مجددا تلاش کنید.");
|
| 744 |
}
|
| 745 |
}, QUEUE_TIMEOUT);
|
| 746 |
|
| 747 |
+
let finalResult = null;
|
| 748 |
+
for await (const status of currentJob) {
|
| 749 |
+
if (status.type === "status") {
|
| 750 |
+
if (status.stage === "pending" || status.stage === "queued") {
|
| 751 |
+
setAiLoaderText(`در صف پردازش... (نفر ${status.queue_position || '?'})`);
|
| 752 |
+
} else if (status.stage === "generating" || status.stage === "iterating") {
|
| 753 |
+
if (!hasStartedProcessing) {
|
| 754 |
+
hasStartedProcessing = true;
|
| 755 |
+
clearTimeout(queueTimeout);
|
| 756 |
+
}
|
| 757 |
+
setAiLoaderText("در حال ساخت فریمهای ویدیو...");
|
| 758 |
+
} else if (status.stage === "error") {
|
| 759 |
+
throw new Error(status.message || "خطای نامشخص در سرور");
|
| 760 |
+
}
|
| 761 |
+
} else if (status.type === "data") {
|
| 762 |
+
finalResult = status;
|
| 763 |
}
|
| 764 |
+
}
|
| 765 |
+
|
| 766 |
+
clearTimeout(queueTimeout);
|
| 767 |
+
return finalResult;
|
| 768 |
+
})();
|
| 769 |
|
| 770 |
+
globalTimeout = setTimeout(() => {
|
| 771 |
+
currentJob?.cancel();
|
| 772 |
+
}, GLOBAL_TIMEOUT);
|
|
|
|
|
|
|
| 773 |
|
| 774 |
+
const result = await videoGenerationPromise;
|
| 775 |
+
clearTimeout(globalTimeout);
|
|
|
|
|
|
|
|
|
|
| 776 |
|
|
|
|
|
|
|
|
|
|
| 777 |
await handleSuccessfulVideoGeneration(result);
|
| 778 |
|
| 779 |
} catch (errorCaught) {
|
| 780 |
+
clearTimeout(globalTimeout);
|
| 781 |
const isTranslationErr = errorCaught.message.toLowerCase().includes("مترجم");
|
| 782 |
showCriticalError(`خطا: ${errorCaught.message}`, isTranslationErr);
|
| 783 |
} finally {
|
| 784 |
isProcessing = false;
|
| 785 |
+
currentJob = null;
|
| 786 |
if (!document.getElementById('upgrade-button').style.display || document.getElementById('upgrade-button').style.display === 'none') {
|
| 787 |
generateButton.disabled = false;
|
| 788 |
}
|