Update templates/index.html
Browse files- templates/index.html +47 -44
templates/index.html
CHANGED
|
@@ -20,6 +20,8 @@
|
|
| 20 |
--accent-primary-hover: #3553D6;
|
| 21 |
--accent-primary-glow: rgba(74, 108, 250, 0.25);
|
| 22 |
--accent-secondary: #0FD4A8;
|
|
|
|
|
|
|
| 23 |
--success-color: #38A169;
|
| 24 |
--danger-color: #e53e3e;
|
| 25 |
--danger-color-hover: #c53030;
|
|
@@ -50,6 +52,7 @@
|
|
| 50 |
@keyframes background-pan { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
|
| 51 |
@keyframes igadlmAlphaV2fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
|
| 52 |
@keyframes fill-progress { from { width: 0%; } to { width: 100%; } }
|
|
|
|
| 53 |
|
| 54 |
body { font-family: var(--app-font); background-color: var(--app-bg); color: var(--text-primary); margin: 0; padding: 2.5rem 1rem; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; }
|
| 55 |
.container { max-width: 820px; width: 100%; }
|
|
@@ -68,10 +71,6 @@
|
|
| 68 |
h1 { font-size: 2.8rem; font-weight: 800; margin: 0; background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; letter-spacing: -1px; }
|
| 69 |
.subtitle { font-size: 1.1rem; color: var(--text-secondary); margin-top: 0.5rem; }
|
| 70 |
.instruction { font-size: 0.95rem; color: var(--text-tertiary); margin-top: 0.75rem; font-weight: 500; }
|
| 71 |
-
/* [جدید] استایل برای متن زیرنویس نسخه */
|
| 72 |
-
.header-version-info { margin-top: 1rem; font-size: 0.9rem; color: var(--text-tertiary); }
|
| 73 |
-
.header-version-info span { font-weight: 600; color: var(--text-secondary); }
|
| 74 |
-
|
| 75 |
main { padding: 3rem; background-color: var(--panel-bg); border-radius: var(--radius-card); box-shadow: var(--shadow-xl); border: 1px solid var(--panel-border); animation: fadeIn 0.8s 0.3s ease-out backwards; }
|
| 76 |
.form-group { margin-bottom: 2.5rem; }
|
| 77 |
.form-group:last-child { margin-bottom: 0; }
|
|
@@ -141,14 +140,16 @@
|
|
| 141 |
.gpu-error-actions .action-button.back-button:hover:not(:disabled) { background-color: var(--input-bg); }
|
| 142 |
.gpu-error-actions .action-button.retry-button { background: linear-gradient(60deg, var(--igadlm-alpha-color-primary) 0%, var(--igadlm-alpha-color-secondary) 100%); color: white; flex-grow: 1; }
|
| 143 |
.gpu-error-actions .action-button.retry-button:hover:not(:disabled) { background: linear-gradient(60deg, var(--igadlm-alpha-color-primary-darker) 0%, var(--igadlm-alpha-color-secondary-darker) 100%); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
#credit-info-section { margin-top: 1.5rem; margin-bottom: 0.5rem; padding: 1rem; background-color: var(--input-bg); border-radius: var(--radius-input); text-align: center; font-size: 0.95rem; font-weight: 500; color: var(--text-secondary); border: 1px solid var(--input-border); display: none; }
|
| 145 |
#upgrade-button { margin-top: 1rem; width: 100%; padding: 1rem; font-size: 1.1rem; font-weight: 700; background: linear-gradient(95deg, #FFD54F, #FFC107 100%); color: #212529; border: none; border-radius: var(--radius-btn); cursor: pointer; box-shadow: 0 8px 20px -5px rgba(255, 193, 7, 0.3); display: none; }
|
| 146 |
|
| 147 |
-
@media (max-width: 768px) {
|
| 148 |
-
main { padding: 1.5rem; } h1 { font-size: 2.2rem; }
|
| 149 |
-
.generator-container { height: 250px; }
|
| 150 |
-
.text-overlay { font-size: 18px; }
|
| 151 |
-
}
|
| 152 |
</style>
|
| 153 |
</head>
|
| 154 |
<body>
|
|
@@ -169,11 +170,9 @@
|
|
| 169 |
</div>
|
| 170 |
<h1>استودیو ویدیو هوش مصنوعی</h1>
|
| 171 |
<p class="subtitle">تصاویر خود را با قدرت هوش مصنوعی به ویدیو سینمایی تبدیل کنید</p>
|
| 172 |
-
<
|
| 173 |
-
<
|
| 174 |
-
<div
|
| 175 |
-
<span>نسخه رایگان</span> و <span>نسخه نامحدود</span>
|
| 176 |
-
</div>
|
| 177 |
</div>
|
| 178 |
</header>
|
| 179 |
|
|
@@ -255,7 +254,7 @@
|
|
| 255 |
import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
|
| 256 |
|
| 257 |
(function() {
|
| 258 |
-
// === START: بخش
|
| 259 |
let userSubscriptionStatus = 'free'; // 'free' or 'paid'
|
| 260 |
let userFingerprint = null;
|
| 261 |
let countdownInterval = null;
|
|
@@ -287,15 +286,21 @@
|
|
| 287 |
const creditInfoDiv = document.getElementById('credit-info-section');
|
| 288 |
const upgradeBtn = document.getElementById('upgrade-button');
|
| 289 |
const genBtn = document.getElementById('generateButton');
|
|
|
|
| 290 |
|
| 291 |
if (status === 'paid') {
|
|
|
|
|
|
|
| 292 |
creditInfoDiv.style.display = 'none';
|
| 293 |
upgradeBtn.style.display = 'none';
|
| 294 |
genBtn.disabled = false;
|
| 295 |
if(countdownInterval) clearInterval(countdownInterval);
|
| 296 |
} else {
|
|
|
|
|
|
|
| 297 |
checkFreeUserCredit();
|
| 298 |
}
|
|
|
|
| 299 |
}
|
| 300 |
|
| 301 |
async function checkFreeUserCredit() {
|
|
@@ -368,7 +373,7 @@
|
|
| 368 |
document.getElementById('upgrade-button').addEventListener('click', () => {
|
| 369 |
parent.postMessage({ type: 'NAVIGATE_TO_PREMIUM' }, '*');
|
| 370 |
});
|
| 371 |
-
// === END: بخش
|
| 372 |
|
| 373 |
|
| 374 |
// DOM Elements
|
|
@@ -410,7 +415,6 @@
|
|
| 410 |
showCriticalError("اطلاعات کافی برای تلاش مجدد وجود ندارد. لطفاً از نو شروع کنید.");
|
| 411 |
return;
|
| 412 |
}
|
| 413 |
-
promptInput.value = lastAttemptedVideoPayload.persianPrompt;
|
| 414 |
generateButton.click();
|
| 415 |
}
|
| 416 |
|
|
@@ -513,10 +517,29 @@
|
|
| 513 |
return;
|
| 514 |
}
|
| 515 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 516 |
addStatusMessage('ویدیو آماده شد! 🎉', 'success');
|
| 517 |
const videoUrl = result.data[0].video.url;
|
| 518 |
const usedSeed = result.data[1];
|
| 519 |
-
|
| 520 |
setTimeout(() => {
|
| 521 |
statusSection.classList.remove('active');
|
| 522 |
outputSection.classList.add('active');
|
|
@@ -524,27 +547,6 @@
|
|
| 524 |
finalSeedElement.textContent = `Seed: ${usedSeed}`;
|
| 525 |
prepareCustomDownloadLink(videoUrl);
|
| 526 |
}, 300);
|
| 527 |
-
|
| 528 |
-
// [تغییر اصلی] کسر اعتبار فقط پس از موفقیت
|
| 529 |
-
if (userSubscriptionStatus === 'free') {
|
| 530 |
-
try {
|
| 531 |
-
const response = await fetch('/api/use-credit', {
|
| 532 |
-
method: 'POST',
|
| 533 |
-
headers: {'Content-Type': 'application/json'},
|
| 534 |
-
body: JSON.stringify({ fingerprint: userFingerprint })
|
| 535 |
-
});
|
| 536 |
-
if (response.ok) {
|
| 537 |
-
console.log('Credit used successfully.');
|
| 538 |
-
// بروزرسانی نمایش اعتبار باقیمانده
|
| 539 |
-
checkFreeUserCredit();
|
| 540 |
-
} else {
|
| 541 |
-
console.warn('Could not use credit after successful generation.');
|
| 542 |
-
}
|
| 543 |
-
} catch (err) {
|
| 544 |
-
console.error('Error while using credit:', err);
|
| 545 |
-
}
|
| 546 |
-
}
|
| 547 |
-
|
| 548 |
generateButton.disabled = false;
|
| 549 |
}
|
| 550 |
|
|
@@ -615,14 +617,16 @@
|
|
| 615 |
negative_prompt: DEFAULT_NEGATIVE_PROMPT, duration_seconds: DEFAULT_VIDEO_DURATION,
|
| 616 |
guidance_scale: 1, guidance_scale_2: 1, seed: 0, randomize_seed: true
|
| 617 |
});
|
| 618 |
-
|
|
|
|
|
|
|
|
|
|
| 619 |
} catch (errorCaught) {
|
| 620 |
const isTranslationErr = errorCaught.message.toLowerCase().includes("مترجم");
|
| 621 |
showCriticalError(`خطا: ${errorCaught.message}`, isTranslationErr);
|
| 622 |
}
|
| 623 |
};
|
| 624 |
|
| 625 |
-
// [تغییر اصلی] بازنویسی منطق دکمه ساخت ویدیو
|
| 626 |
generateButton.addEventListener('click', async () => {
|
| 627 |
if (generateButton.disabled) return;
|
| 628 |
|
|
@@ -637,9 +641,8 @@
|
|
| 637 |
body: JSON.stringify({ fingerprint: userFingerprint })
|
| 638 |
});
|
| 639 |
const result = await response.json();
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
checkFreeUserCredit(); // UI را با پیام اتمام اعتبار آپدیت میکند
|
| 643 |
return;
|
| 644 |
}
|
| 645 |
// اگر اعتبار داشت، فرآیند ساخت را شروع میکنیم
|
|
|
|
| 20 |
--accent-primary-hover: #3553D6;
|
| 21 |
--accent-primary-glow: rgba(74, 108, 250, 0.25);
|
| 22 |
--accent-secondary: #0FD4A8;
|
| 23 |
+
--accent-premium: #FFC107;
|
| 24 |
+
--accent-premium-glow: rgba(255, 193, 7, 0.3);
|
| 25 |
--success-color: #38A169;
|
| 26 |
--danger-color: #e53e3e;
|
| 27 |
--danger-color-hover: #c53030;
|
|
|
|
| 52 |
@keyframes background-pan { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
|
| 53 |
@keyframes igadlmAlphaV2fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
|
| 54 |
@keyframes fill-progress { from { width: 0%; } to { width: 100%; } }
|
| 55 |
+
@keyframes badge-fade-in { from { opacity: 0; transform: translateY(-10px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
|
| 56 |
|
| 57 |
body { font-family: var(--app-font); background-color: var(--app-bg); color: var(--text-primary); margin: 0; padding: 2.5rem 1rem; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; }
|
| 58 |
.container { max-width: 820px; width: 100%; }
|
|
|
|
| 71 |
h1 { font-size: 2.8rem; font-weight: 800; margin: 0; background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; letter-spacing: -1px; }
|
| 72 |
.subtitle { font-size: 1.1rem; color: var(--text-secondary); margin-top: 0.5rem; }
|
| 73 |
.instruction { font-size: 0.95rem; color: var(--text-tertiary); margin-top: 0.75rem; font-weight: 500; }
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
main { padding: 3rem; background-color: var(--panel-bg); border-radius: var(--radius-card); box-shadow: var(--shadow-xl); border: 1px solid var(--panel-border); animation: fadeIn 0.8s 0.3s ease-out backwards; }
|
| 75 |
.form-group { margin-bottom: 2.5rem; }
|
| 76 |
.form-group:last-child { margin-bottom: 0; }
|
|
|
|
| 140 |
.gpu-error-actions .action-button.back-button:hover:not(:disabled) { background-color: var(--input-bg); }
|
| 141 |
.gpu-error-actions .action-button.retry-button { background: linear-gradient(60deg, var(--igadlm-alpha-color-primary) 0%, var(--igadlm-alpha-color-secondary) 100%); color: white; flex-grow: 1; }
|
| 142 |
.gpu-error-actions .action-button.retry-button:hover:not(:disabled) { background: linear-gradient(60deg, var(--igadlm-alpha-color-primary-darker) 0%, var(--igadlm-alpha-color-secondary-darker) 100%); }
|
| 143 |
+
|
| 144 |
+
/* بخش جدید: استایلهای مربوط به اعتبار و اشتراک */
|
| 145 |
+
#subscription-status-badge { display: none; padding: 6px 16px; border-radius: 20px; font-size: 0.9em; font-weight: 700; margin-top: 1.25rem; letter-spacing: 0.5px; animation: badge-fade-in 0.6s 0.5s ease-out backwards; }
|
| 146 |
+
#subscription-status-badge.free-badge { background: linear-gradient(45deg, #6c757d, #495057); color: white; box-shadow: 0 4px 10px rgba(108, 117, 125, 0.3); }
|
| 147 |
+
#subscription-status-badge.paid-badge { background: linear-gradient(45deg, var(--accent-premium), #ffca2c); color: #333; box-shadow: 0 4px 10px var(--accent-premium-glow); }
|
| 148 |
+
|
| 149 |
#credit-info-section { margin-top: 1.5rem; margin-bottom: 0.5rem; padding: 1rem; background-color: var(--input-bg); border-radius: var(--radius-input); text-align: center; font-size: 0.95rem; font-weight: 500; color: var(--text-secondary); border: 1px solid var(--input-border); display: none; }
|
| 150 |
#upgrade-button { margin-top: 1rem; width: 100%; padding: 1rem; font-size: 1.1rem; font-weight: 700; background: linear-gradient(95deg, #FFD54F, #FFC107 100%); color: #212529; border: none; border-radius: var(--radius-btn); cursor: pointer; box-shadow: 0 8px 20px -5px rgba(255, 193, 7, 0.3); display: none; }
|
| 151 |
|
| 152 |
+
@media (max-width: 768px) { main { padding: 1.5rem; } h1 { font-size: 2.2rem; } .generator-container { height: 250px; } .text-overlay { font-size: 18px; } }
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
</style>
|
| 154 |
</head>
|
| 155 |
<body>
|
|
|
|
| 170 |
</div>
|
| 171 |
<h1>استودیو ویدیو هوش مصنوعی</h1>
|
| 172 |
<p class="subtitle">تصاویر خود را با قدرت هوش مصنوعی به ویدیو سینمایی تبدیل کنید</p>
|
| 173 |
+
<!-- بخش جدید: متن راهنما و بج وضعیت اشتراک -->
|
| 174 |
+
<p class="instruction">ابتدا تصویر خود را با فلاکس پرو تولید کنید و بعد تصویر خود را اینجا آپلود کرده و ویدیوی خود را بسازید.</p>
|
| 175 |
+
<div id="subscription-status-badge" style="display:inline-block;"></div>
|
|
|
|
|
|
|
| 176 |
</div>
|
| 177 |
</header>
|
| 178 |
|
|
|
|
| 254 |
import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
|
| 255 |
|
| 256 |
(function() {
|
| 257 |
+
// === START: بخش مدیریت اعتبار و ارتباط با والد ===
|
| 258 |
let userSubscriptionStatus = 'free'; // 'free' or 'paid'
|
| 259 |
let userFingerprint = null;
|
| 260 |
let countdownInterval = null;
|
|
|
|
| 286 |
const creditInfoDiv = document.getElementById('credit-info-section');
|
| 287 |
const upgradeBtn = document.getElementById('upgrade-button');
|
| 288 |
const genBtn = document.getElementById('generateButton');
|
| 289 |
+
const subscriptionBadge = document.getElementById('subscription-status-badge');
|
| 290 |
|
| 291 |
if (status === 'paid') {
|
| 292 |
+
subscriptionBadge.textContent = 'نسخه نامحدود';
|
| 293 |
+
subscriptionBadge.className = 'paid-badge';
|
| 294 |
creditInfoDiv.style.display = 'none';
|
| 295 |
upgradeBtn.style.display = 'none';
|
| 296 |
genBtn.disabled = false;
|
| 297 |
if(countdownInterval) clearInterval(countdownInterval);
|
| 298 |
} else {
|
| 299 |
+
subscriptionBadge.textContent = 'نسخه رایگان';
|
| 300 |
+
subscriptionBadge.className = 'free-badge';
|
| 301 |
checkFreeUserCredit();
|
| 302 |
}
|
| 303 |
+
subscriptionBadge.style.display = 'inline-block';
|
| 304 |
}
|
| 305 |
|
| 306 |
async function checkFreeUserCredit() {
|
|
|
|
| 373 |
document.getElementById('upgrade-button').addEventListener('click', () => {
|
| 374 |
parent.postMessage({ type: 'NAVIGATE_TO_PREMIUM' }, '*');
|
| 375 |
});
|
| 376 |
+
// === END: بخش مدیریت اعتبار ===
|
| 377 |
|
| 378 |
|
| 379 |
// DOM Elements
|
|
|
|
| 415 |
showCriticalError("اطلاعات کافی برای تلاش مجدد وجود ندارد. لطفاً از نو شروع کنید.");
|
| 416 |
return;
|
| 417 |
}
|
|
|
|
| 418 |
generateButton.click();
|
| 419 |
}
|
| 420 |
|
|
|
|
| 517 |
return;
|
| 518 |
}
|
| 519 |
|
| 520 |
+
// === تغییر اصلی: کسر اعتبار بعد از موفقیت ===
|
| 521 |
+
if (userSubscriptionStatus === 'free') {
|
| 522 |
+
try {
|
| 523 |
+
addStatusMessage('ویدیو ساخته شد، در حال ثبت اعتبار...', 'info');
|
| 524 |
+
const creditResponse = await fetch('/api/use-credit', {
|
| 525 |
+
method: 'POST',
|
| 526 |
+
headers: {'Content-Type': 'application/json'},
|
| 527 |
+
body: JSON.stringify({ fingerprint: userFingerprint })
|
| 528 |
+
});
|
| 529 |
+
if (!creditResponse.ok) {
|
| 530 |
+
console.warn("Credit deduction failed AFTER video generation.");
|
| 531 |
+
}
|
| 532 |
+
// UI را با تعداد اعتبار جدید بروزرسانی میکنیم
|
| 533 |
+
checkFreeUserCredit();
|
| 534 |
+
} catch (creditError) {
|
| 535 |
+
console.error("Critical error deducting credit:", creditError);
|
| 536 |
+
}
|
| 537 |
+
}
|
| 538 |
+
// === پایان تغییر ===
|
| 539 |
+
|
| 540 |
addStatusMessage('ویدیو آماده شد! 🎉', 'success');
|
| 541 |
const videoUrl = result.data[0].video.url;
|
| 542 |
const usedSeed = result.data[1];
|
|
|
|
| 543 |
setTimeout(() => {
|
| 544 |
statusSection.classList.remove('active');
|
| 545 |
outputSection.classList.add('active');
|
|
|
|
| 547 |
finalSeedElement.textContent = `Seed: ${usedSeed}`;
|
| 548 |
prepareCustomDownloadLink(videoUrl);
|
| 549 |
}, 300);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 550 |
generateButton.disabled = false;
|
| 551 |
}
|
| 552 |
|
|
|
|
| 617 |
negative_prompt: DEFAULT_NEGATIVE_PROMPT, duration_seconds: DEFAULT_VIDEO_DURATION,
|
| 618 |
guidance_scale: 1, guidance_scale_2: 1, seed: 0, randomize_seed: true
|
| 619 |
});
|
| 620 |
+
|
| 621 |
+
// حالا این تابع مسئول کسر اعتبار هم هست
|
| 622 |
+
await handleSuccessfulVideoGeneration(result);
|
| 623 |
+
|
| 624 |
} catch (errorCaught) {
|
| 625 |
const isTranslationErr = errorCaught.message.toLowerCase().includes("مترجم");
|
| 626 |
showCriticalError(`خطا: ${errorCaught.message}`, isTranslationErr);
|
| 627 |
}
|
| 628 |
};
|
| 629 |
|
|
|
|
| 630 |
generateButton.addEventListener('click', async () => {
|
| 631 |
if (generateButton.disabled) return;
|
| 632 |
|
|
|
|
| 641 |
body: JSON.stringify({ fingerprint: userFingerprint })
|
| 642 |
});
|
| 643 |
const result = await response.json();
|
| 644 |
+
if(result.limit_reached) {
|
| 645 |
+
updateUIForSubscriptionStatus('free'); // UI را با پیام اتمام اعتبار آپدیت میکند
|
|
|
|
| 646 |
return;
|
| 647 |
}
|
| 648 |
// اگر اعتبار داشت، فرآیند ساخت را شروع میکنیم
|