|
<p> </p> |
|
<style> |
|
:root { |
|
--color-primary: #667EEA; |
|
--color-secondary: #764BA2; |
|
--color-text: #2D3748; |
|
--color-text-muted: #718096; |
|
-- rozmowy: #F7FAFC; |
|
--color-border: #E2E8F0; |
|
--color-white: #FFFFFF; |
|
--color-success: #48BB78; |
|
--color-error: #F56565; |
|
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1); |
|
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1); |
|
--border-radius-md: 10px; |
|
--border-radius-lg: 16px; |
|
} |
|
|
|
* { box-sizing: border-box; margin: 0; padding: 0; } |
|
|
|
body { |
|
background-color: var(--color-white); |
|
font-family: 'Vazirmatn', sans-serif; |
|
color: var(--color-text); |
|
line-height: 1.6; |
|
} |
|
|
|
.ltx-video-creator-app { |
|
width: 100%; |
|
max-width: 500px; |
|
margin: 20px auto; |
|
padding: 0 10px; |
|
} |
|
|
|
.app-header { |
|
text-align: center; |
|
margin-bottom: 25px; |
|
} |
|
.app-header h1 { |
|
font-size: 1.9em; |
|
font-weight: 700; |
|
background: linear-gradient(45deg, var(--color-primary), var(--color-secondary)); |
|
-webkit-background-clip: text; |
|
-webkit-text-fill-color: transparent; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
margin-bottom: 8px; |
|
} |
|
.app-header h1 img { |
|
width: 32px; |
|
height: 32px; |
|
margin-left: 10px; |
|
} |
|
.app-header p { |
|
font-size: 0.95em; |
|
color: var(--color-text-muted); |
|
} |
|
|
|
.form-section-card { |
|
background-color: var(--color-white); |
|
padding: 25px; |
|
border-radius: var(--border-radius-lg); |
|
box-shadow: var(--shadow-lg); |
|
border: 1px solid var(--color-border); |
|
} |
|
|
|
.mode-selector { |
|
display: flex; |
|
background-color: var(--color-bg-light); |
|
border-radius: var(--border-radius-md); |
|
padding: 4px; |
|
margin-bottom: 20px; |
|
border: 1px solid var(--color-border); |
|
} |
|
.mode-button { |
|
flex: 1; |
|
padding: 8px 10px; |
|
background-color: transparent; |
|
border: none; |
|
cursor: pointer; |
|
font-family: inherit; |
|
font-size: 0.85rem; |
|
font-weight: 600; |
|
color: var(--color-text-muted); |
|
border-radius: 8px; |
|
transition: all 0.25s ease; |
|
} |
|
.mode-button.active { |
|
background-color: var(--color-primary); |
|
color: var(--color-white); |
|
box-shadow: 0 3px 8px rgba(102, 126, 234, 0.3); |
|
} |
|
|
|
.form-group { |
|
margin-bottom: 18px; |
|
} |
|
label { |
|
display: block; |
|
font-size: 0.8rem; |
|
text-transform: uppercase; |
|
letter-spacing: 0.5px; |
|
color: var(--color-text-muted); |
|
margin-bottom: 6px; |
|
font-weight: 600; |
|
} |
|
input[type="text"], textarea, input[type="number"] { |
|
width: 100%; |
|
padding: 11px 14px; |
|
border: 1px solid var(--color-border); |
|
border-radius: var(--border-radius-md); |
|
font-size: 0.9rem; |
|
background-color: var(--color-bg-light); |
|
color: var(--color-text); |
|
font-family: inherit; |
|
} |
|
input[type="text"]::placeholder, textarea::placeholder { |
|
color: #A0AEC0; |
|
} |
|
|
|
input[type="file"] { |
|
width: 100%; |
|
padding: 10px; |
|
border: 1px solid var(--color-border); |
|
border-radius: var(--border-radius-md); |
|
font-size: 0.9em; |
|
background-color: var(--color-bg-light); |
|
font-family: inherit; |
|
} |
|
input[type="file"]::file-selector-button { |
|
padding: 8px 15px; |
|
margin-right: 10px; |
|
background-color: #6c757d; |
|
color: white; |
|
border: none; |
|
border-radius: 7px; |
|
cursor: pointer; |
|
font-family: inherit; |
|
font-weight: 500; |
|
} |
|
input[type="file"]::file-selector-button:hover { |
|
background-color: #5a6268; |
|
} |
|
|
|
input:focus, textarea:focus { |
|
outline: none; |
|
border-color: var(--color-primary); |
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.25); |
|
background-color: var(--color-white); |
|
} |
|
textarea { |
|
min-height: 60px; |
|
resize: vertical; |
|
} |
|
.preview-image { |
|
max-width: 100%; |
|
max-height: 150px; |
|
border-radius: var(--border-radius-md); |
|
margin-top: 12px; |
|
display: none; |
|
border: 1px solid var(--color-border); |
|
object-fit: cover; |
|
box-shadow: var(--shadow-md); |
|
} |
|
|
|
.options-grid { |
|
display: grid; |
|
grid-template-columns: 1fr 1fr; |
|
gap: 10px; |
|
} |
|
.option-button { |
|
padding: 10px; |
|
font-size: 0.85em; |
|
font-weight: 500; |
|
border: 1px solid var(--color-border); |
|
border-radius: var(--border-radius-md); |
|
background-color: var(--color-bg-light); |
|
color: var(--color-text); |
|
cursor: pointer; |
|
text-align: center; |
|
font-family: inherit; |
|
} |
|
.option-button.selected { |
|
background-color: var(--color-primary); |
|
color: var(--color-white); |
|
border-color: var(--color-primary); |
|
font-weight: 600; |
|
} |
|
|
|
.flex-row { |
|
display: flex; |
|
gap: 10px; |
|
} |
|
.flex-row .form-group { |
|
flex: 1; |
|
} |
|
|
|
.button-container { |
|
text-align: center; |
|
margin-top: 25px; |
|
} |
|
#generateButton { |
|
background: linear-gradient(45deg, var(--color-primary) 0%, var(--color-secondary) 100%); |
|
color: white; |
|
padding: 13px 28px; |
|
border: none; |
|
border-radius: var(--border-radius-md); |
|
font-size: 1em; |
|
font-weight: 600; |
|
cursor: pointer; |
|
font-family: inherit; |
|
width: 100%; |
|
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3); |
|
} |
|
#generateButton:hover:not(:disabled) { |
|
transform: scale(1.02); |
|
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4); |
|
} |
|
#generateButton:disabled { |
|
background: var(--color-border); |
|
color: var(--color-text-muted); |
|
cursor: not-allowed; |
|
box-shadow: none; |
|
} |
|
|
|
.status-section, .output-section { |
|
margin-top: 25px; |
|
padding: 20px; |
|
background-color: var(--color-white); |
|
border-radius: var(--border-radius-lg); |
|
border: 1px solid var(--color-border); |
|
box-shadow: var(--shadow-md); |
|
} |
|
.status-section h2, .output-section h2 { |
|
font-size: 1.15em; |
|
color: var(--color-text); |
|
border-bottom: 1px solid var(--color-border); |
|
padding-bottom: 8px; |
|
margin-bottom: 15px; |
|
font-weight: 600; |
|
} |
|
.loader { |
|
width: 30px; |
|
height: 30px; |
|
margin: 15px auto; |
|
display: none; |
|
border-radius: 50%; |
|
border: 3px solid var(--color-bg-light); |
|
border-top-color: var(--color-primary); |
|
animation: spin 0.7s linear infinite; |
|
} |
|
@keyframes spin { to { transform: rotate(360deg); } } |
|
|
|
.progress-bar-container { |
|
width: 100%; |
|
background-color: var(--color-border); |
|
border-radius: 6px; |
|
margin: 12px 0; |
|
display: none; |
|
height: 6px; |
|
} |
|
.progress-bar { |
|
width: 0%; |
|
height: 100%; |
|
background: linear-gradient(90deg, var(--color-primary) 0%, var(--color-secondary) 100%); |
|
border-radius: 6px; |
|
} |
|
.status-messages-container { |
|
max-height: 90px; |
|
overflow-y: auto; |
|
padding-right: 5px; |
|
} |
|
.status-message { |
|
padding: 8px 12px; |
|
border-radius: var(--border-radius-md); |
|
margin-top: 8px; |
|
font-size: 0.85em; |
|
background-color: var(--color-bg-light); |
|
} |
|
.status-message.info { |
|
border-left: 3px solid var(--color-primary); |
|
background-color: #EBF4FF; |
|
color: #0D47A1; |
|
} |
|
.status-message.error { |
|
border-left: 3px solid var(--color-error); |
|
background-color: #FFEBEE; |
|
color: #C62828; |
|
} |
|
.status-message.success { |
|
border-left: 3px solid var(--color-success); |
|
background-color: #E8F5E9; |
|
color: #1B5E20; |
|
} |
|
|
|
#outputVideo { |
|
width: 100%; |
|
border-radius: var(--border-radius-md); |
|
margin-top: 10px; |
|
border: 1px solid var(--color-border); |
|
background-color: #000; |
|
} |
|
#finalSeed { |
|
font-size: 0.8em; |
|
color: var(--color-text-muted); |
|
text-align: center; |
|
margin-top: 8px; |
|
} |
|
|
|
.hidden-section { |
|
display: none !important; |
|
} |
|
|
|
@media (max-width: 480px) { |
|
.ltx-video-creator-app { |
|
padding: 0; |
|
margin: 10px auto; |
|
} |
|
.app-header h1 { |
|
font-size: 1.6em; |
|
} |
|
.form-section-card { |
|
padding: 15px; |
|
border-radius: var(--border-radius-md); |
|
} |
|
#generateButton { |
|
padding: 12px 18px; |
|
font-size: 0.95em; |
|
} |
|
} |
|
</style> |
|
<div class="ltx-video-creator-app"> |
|
<div class="app-header"> |
|
<h1><img src="https://em-content.zobj.net/thumbs/120/apple/354/film-projector_1f4fd-fe0f.png" alt="🎬" /> ویدیو ساز LTX</h1> |
|
<p>انیمیشن‌های کوتاه و جذاب خلق کنید</p> |
|
</div> |
|
<div class="form-section-card"> |
|
<div class="mode-selector"><button class="mode-button active" data-mode="image-to-video">از تصویر</button> <button class="mode-button" data-mode="text-to-video">از متن</button></div> |
|
<div id="imageToVideoSection" class="form-mode-section"> |
|
<div class="form-group"><label for="imageFile">تصویر شما</label> <input type="file" id="imageFile" accept="image/jpeg, image/png, image/webp" /> <img id="imagePreview" src="#" alt="پیش‌نمایش" class="preview-image" /></div> |
|
</div> |
|
<div id="textToVideoSection" class="form-mode-section hidden-section"> |
|
<p style="text-align: center; font-size: 0.8rem; margin-bottom: 15px; padding: 8px; background-color: var(--color-bg-light); border-radius: 7px;">در این حالت، ویدیو تنها بر اساس شرح شما ساخته می‌شود.</p> |
|
</div> |
|
<div class="form-group"><label for="prompt">شرح انیمیشن (Prompt)</label> <textarea id="prompt" rows="2" placeholder="مثال: گربه‌ای که در چمنزار می‌دود">یک موجود از داخل تصویر شروع به حرکت میکند</textarea></div> |
|
<div class="form-group"><label>مدت زمان</label> |
|
<div class="options-grid" id="durationButtonsContainer"><button class="option-button duration-button" data-api-duration="5">کوتاه (۵ ثانیه)</button> <button class="option-button duration-button selected" data-api-duration="7.8">استاندارد (۸ ثانیه)</button></div> |
|
</div> |
|
<div class="form-group"><label>نسبت تصویر خروجی</label> |
|
<div class="options-grid" id="aspectRatioButtonsContainer"><button class="option-button aspect-ratio-button selected" data-height="768" data-width="768">۱:۱ (مربع)</button> <button class="option-button aspect-ratio-button" data-height="768" data-width="432">۹:۱۶ (پرتره)</button> <button class="option-button aspect-ratio-button" data-height="432" data-width="768">۱۶:۹ (لنداسکیپ)</button> <button class="option-button aspect-ratio-button" data-height="512" data-width="704">LTX (۵۱۲×۷۰۴)</button></div> |
|
</div> |
|
<div class="form-group"><label for="negativePrompt">موارد ناخواسته (Negative Prompt)</label> <textarea id="negativePrompt" rows="2" placeholder="مثال: کیفیت پایین, متن">کیفیت پایین، تار، لرزان, متن ناخوانا</textarea></div> |
|
<div class="flex-row"> |
|
<div class="form-group"><label for="cfgScale">قدرت Prompt</label> <input type="number" id="cfgScale" value="1.0" min="1.0" max="10.0" step="0.1" /></div> |
|
<div class="form-group"><label for="seed">سید (0=تصادفی)</label> <input type="number" id="seed" value="0" min="0" /></div> |
|
</div> |
|
<div class="flex-row"> |
|
<div class="form-group"><label for="outputHeight">ارتفاع (px)</label> <input type="number" id="outputHeight" value="768" step="32" min="256" max="1280" /></div> |
|
<div class="form-group"><label for="outputWidth">عرض (px)</label> <input type="number" id="outputWidth" value="768" step="32" min="256" max="1280" /></div> |
|
</div> |
|
<div class="button-container"><button id="generateButton">🚀 تولید ویدیو</button></div> |
|
</div> |
|
<div class="status-section" id="statusSection" style="display: none;"> |
|
<h2>وضعیت پردازش</h2> |
|
<div class="loader" id="loader"></div> |
|
<div class="progress-bar-container" id="progressBarContainer"> |
|
<div class="progress-bar" id="progressBar"></div> |
|
</div> |
|
<div class="status-messages-container" id="statusMessages"></div> |
|
</div> |
|
<div class="output-section" id="outputSection" style="display: none;"> |
|
<h2>ویدیوی شما آماده است!</h2> |
|
<video width="300" height="150" id="outputVideo" controls="controls" preload="metadata" playsinline=""></video> |
|
<p id="finalSeed"> </p> |
|
</div> |
|
</div> |
|
<p> |
|
<script> |
|
const imageFileInput = document.getElementById('imageFile'); |
|
const imagePreview = document.getElementById('imagePreview'); |
|
const promptInput = document.getElementById('prompt'); |
|
const durationButtons = document.querySelectorAll('.duration-button'); |
|
const aspectRatioButtons = document.querySelectorAll('.aspect-ratio-button'); |
|
const generateButton = document.getElementById('generateButton'); |
|
const outputVideo = document.getElementById('outputVideo'); |
|
const finalSeedElement = document.getElementById('finalSeed'); |
|
const statusMessagesDiv = document.getElementById('statusMessages'); |
|
const statusSection = document.getElementById('statusSection'); |
|
const outputSection = document.getElementById('outputSection'); |
|
const loader = document.getElementById('loader'); |
|
const progressBarContainer = document.getElementById('progressBarContainer'); |
|
const progressBar = document.getElementById('progressBar'); |
|
const negativePromptInput = document.getElementById('negativePrompt'); |
|
const cfgScaleInput = document.getElementById('cfgScale'); |
|
const seedInput = document.getElementById('seed'); |
|
const outputHeightInput = document.getElementById('outputHeight'); |
|
const outputWidthInput = document.getElementById('outputWidth'); |
|
const modeButtons = document.querySelectorAll('.mode-button'); |
|
const imageToVideoSection = document.getElementById('imageToVideoSection'); |
|
const textToVideoSection = document.getElementById('textToVideoSection'); |
|
let currentGenerationMode = "image-to-video"; |
|
const SPACE_URL_BASE = "https://lightricks-ltx-video-distilled.hf.space"; |
|
let selectedApiDuration = 7.8; |
|
let currentSessionHash = ''; |
|
let uploadedImageInfo = null; |
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
document.querySelector('.duration-button.selected')?.click(); |
|
document.querySelector('.aspect-ratio-button.selected')?.click(); |
|
updateFormForMode(currentGenerationMode); |
|
}); |
|
|
|
modeButtons.forEach(button => { |
|
button.addEventListener('click', () => { |
|
modeButtons.forEach(btn => btn.classList.remove('active')); |
|
button.classList.add('active'); |
|
currentGenerationMode = button.dataset.mode; |
|
updateFormForMode(currentGenerationMode); |
|
}); |
|
}); |
|
|
|
function updateFormForMode(mode) { |
|
if (mode === "image-to-video") { |
|
imageToVideoSection.classList.remove('hidden-section'); |
|
textToVideoSection.classList.add('hidden-section'); |
|
promptInput.placeholder = "مثال: گربهای در چمنزار آفتابی میدود"; |
|
} else { |
|
imageToVideoSection.classList.add('hidden-section'); |
|
textToVideoSection.classList.remove('hidden-section'); |
|
imageFileInput.value = ''; |
|
imagePreview.style.display = 'none'; |
|
uploadedImageInfo = null; |
|
promptInput.placeholder = "مثال: یک اژدهای آتشین بر فراز قلعهای قرون وسطایی"; |
|
} |
|
} |
|
|
|
imageFileInput.addEventListener('change', function(event) { |
|
const file = event.target.files[0]; |
|
if (file) { |
|
if (!file.type.startsWith('image/')) { |
|
addStatusMessage('لطفاً یک فایل تصویری انتخاب کنید.', 'error'); |
|
imageFileInput.value = ''; |
|
imagePreview.style.display = 'none'; |
|
return; |
|
} |
|
const reader = new FileReader(); |
|
reader.onload = function(e) { |
|
imagePreview.src = e.target.result; |
|
imagePreview.style.display = 'block'; |
|
}; |
|
reader.readAsDataURL(file); |
|
uploadedImageInfo = null; |
|
} else { |
|
imagePreview.style.display = 'none'; |
|
} |
|
}); |
|
|
|
durationButtons.forEach(button => { |
|
button.addEventListener('click', () => { |
|
durationButtons.forEach(btn => btn.classList.remove('selected')); |
|
button.classList.add('selected'); |
|
selectedApiDuration = parseFloat(button.dataset.apiDuration); |
|
}); |
|
}); |
|
|
|
aspectRatioButtons.forEach(button => { |
|
button.addEventListener('click', () => { |
|
aspectRatioButtons.forEach(btn => btn.classList.remove('selected')); |
|
button.classList.add('selected'); |
|
outputHeightInput.value = button.dataset.height; |
|
outputWidthInput.value = button.dataset.width; |
|
}); |
|
}); |
|
|
|
function addStatusMessage(message, type = 'info') { |
|
statusSection.style.display = 'block'; |
|
const messageDiv = document.createElement('div'); |
|
messageDiv.className = `status-message ${type}`; |
|
messageDiv.textContent = message; |
|
statusMessagesDiv.insertBefore(messageDiv, statusMessagesDiv.firstChild); |
|
} |
|
|
|
function clearStatusAndOutput() { |
|
statusMessagesDiv.innerHTML = ''; |
|
statusSection.style.display = 'none'; |
|
outputSection.style.display = 'none'; |
|
if (outputVideo.src) URL.revokeObjectURL(outputVideo.src); |
|
outputVideo.src = ''; |
|
finalSeedElement.textContent = ''; |
|
progressBar.style.width = '0%'; |
|
progressBarContainer.style.display = 'none'; |
|
} |
|
|
|
function generateRandomHash(length = 11) { |
|
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; |
|
let result = ''; |
|
for (let i = 0; i < length; i++) { |
|
result += characters.charAt(Math.floor(Math.random() * characters.length)); |
|
} |
|
return result; |
|
} |
|
|
|
async function uploadImage(file) { |
|
addStatusMessage('۱. آمادهسازی تصویر...'); |
|
const uploadId = generateRandomHash(12); |
|
const formData = new FormData(); |
|
formData.append('files', file); |
|
try { |
|
const response = await fetch(`${SPACE_URL_BASE}/gradio_api/upload?upload_id=${uploadId}`, { |
|
method: 'POST', |
|
body: formData |
|
}); |
|
if (!response.ok) throw new Error(`خطا در آپلود (${response.status})`); |
|
const result = await response.json(); |
|
if (result && result.length > 0 && typeof result[0] === 'string') { |
|
return { |
|
path: result[0], |
|
url: `${SPACE_URL_BASE}/gradio_api/file=${result[0]}`, |
|
orig_name: file.name, |
|
size: file.size, |
|
mime_type: file.type || 'application/octet-stream', |
|
meta: { "_type": "gradio.FileData" } |
|
}; |
|
} |
|
throw new Error('پاسخ آپلود نامعتبر.'); |
|
} catch (error) { |
|
addStatusMessage(`خطا در آپلود: ${error.message}`, 'error'); |
|
return null; |
|
} |
|
} |
|
|
|
async function submitToQueue(payload) { |
|
addStatusMessage('۲. ارسال درخواست به سرور...'); |
|
try { |
|
const response = await fetch(`${SPACE_URL_BASE}/gradio_api/queue/join`, { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify(payload) |
|
}); |
|
if (!response.ok) throw new Error(`خطا در ارسال به صف (${response.status})`); |
|
return await response.json(); |
|
} catch (error) { |
|
addStatusMessage(`خطا در ارتباط با سرور: ${error.message}`, 'error'); |
|
return null; |
|
} |
|
} |
|
|
|
function listenForResults(eventId) { |
|
addStatusMessage('۳. در حال تولید ویدیو...'); |
|
const eventSource = new EventSource(`${SPACE_URL_BASE}/gradio_api/queue/data?session_hash=${currentSessionHash}`); |
|
|
|
eventSource.onmessage = function(event) { |
|
const data = JSON.parse(event.data); |
|
if (data.event_id !== eventId && data.msg !== "queue_full") return; |
|
switch (data.msg) { |
|
case "process_starts": |
|
addStatusMessage('عملیات در سرور آغاز شد.'); |
|
progressBarContainer.style.display = 'block'; |
|
progressBar.style.width = '0%'; |
|
break; |
|
case "progress": |
|
if (data.progress_data && data.progress_data.length > 0) { |
|
const progress = Math.round((data.progress_data[0].progress || 0) * 100); |
|
progressBar.style.width = `${progress}%`; |
|
} |
|
break; |
|
case "process_completed": |
|
eventSource.close(); |
|
loader.style.display = 'none'; |
|
generateButton.disabled = false; |
|
progressBar.style.width = '100%'; |
|
if (data.success && data.output?.data?.[0]?.video?.url) { |
|
addStatusMessage('ویدیو با موفقیت ساخته شد! 🎉', 'success'); |
|
outputSection.style.display = 'block'; |
|
outputVideo.src = data.output.data[0].video.url; |
|
outputVideo.load(); |
|
finalSeedElement.textContent = data.output.data[1] ? `سید نهایی: ${data.output.data[1]}` : ''; |
|
} else { |
|
addStatusMessage('تولید ویدیو ناموفق بود.', 'error'); |
|
} |
|
break; |
|
case "queue_full": |
|
addStatusMessage('سرور مشغول است، لطفاً کمی بعد تلاش کنید.', 'error'); |
|
eventSource.close(); |
|
loader.style.display = 'none'; |
|
generateButton.disabled = false; |
|
break; |
|
} |
|
}; |
|
|
|
eventSource.onerror = function() { |
|
addStatusMessage('خطا در ارتباط با سرور.', 'error'); |
|
eventSource.close(); |
|
loader.style.display = 'none'; |
|
generateButton.disabled = false; |
|
}; |
|
} |
|
|
|
generateButton.addEventListener('click', async () => { |
|
clearStatusAndOutput(); |
|
const imageFile = imageFileInput.files[0]; |
|
|
|
if (currentGenerationMode === "image-to-video" && !imageFile) { |
|
addStatusMessage('لطفاً ابتدا یک تصویر انتخاب کنید.', 'error'); |
|
return; |
|
} |
|
if (!promptInput.value.trim()) { |
|
addStatusMessage('لطفاً متن راهنما (Prompt) را وارد کنید.', 'error'); |
|
return; |
|
} |
|
|
|
generateButton.disabled = true; |
|
loader.style.display = 'block'; |
|
current |
|
|
|
SessionHash = generateRandomHash(); |
|
|
|
if (currentGenerationMode === "image-to-video") { |
|
uploadedImageInfo = await uploadImage(imageFile); |
|
if (!uploadedImageInfo) { |
|
generateButton.disabled = false; |
|
loader.style.display = 'none'; |
|
return; |
|
} |
|
} else { |
|
uploadedImageInfo = null; |
|
} |
|
|
|
const userSeed = parseInt(seedInput.value); |
|
const generationPayload = { |
|
fn_index: 5, |
|
data: [ |
|
promptInput.value, |
|
negativePromptInput.value, |
|
uploadedImageInfo, |
|
(currentGenerationMode === "image-to-video" ? null : ""), |
|
parseInt(outputHeightInput.value), |
|
parseInt(outputWidthInput.value), |
|
currentGenerationMode, |
|
selectedApiDuration, |
|
9, |
|
(userSeed > 0) ? userSeed : Math.floor(Math.random() * (2**32 - 1)), |
|
(userSeed <= 0), |
|
parseFloat(cfgScaleInput.value), |
|
true |
|
], |
|
session_hash: currentSessionHash |
|
}; |
|
|
|
const joinResponse = await submitToQueue(generationPayload); |
|
if (joinResponse && joinResponse.event_id) { |
|
listenForResults(joinResponse.event_id); |
|
} else { |
|
addStatusMessage('ارسال درخواست به سرور ناموفق بود.', 'error'); |
|
generateButton.disabled = false; |
|
loader.style.display = 'none'; |
|
} |
|
}); |
|
</script> |
|
</p> |