Update index.html
Browse files- index.html +160 -39
index.html
CHANGED
|
@@ -11,32 +11,50 @@
|
|
| 11 |
.card { margin-bottom: 20px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
|
| 12 |
.loader { border: 4px solid #f3f3f3; border-top: 4px solid #0d6efd; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; display: none; margin-bottom: 10px; }
|
| 13 |
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
|
| 14 |
-
#videoResult { width: 100%; max-width:
|
| 15 |
.form-label { font-weight: bold; font-size: 0.9em; margin-top: 10px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
</style>
|
| 17 |
</head>
|
| 18 |
<body>
|
| 19 |
|
| 20 |
-
<div class="container">
|
| 21 |
<h2 class="text-center mb-4 text-primary">LTX 2.3 10Eros - تبدیل تصویر به ویدیو</h2>
|
| 22 |
-
<p class="text-center text-muted">ا
|
| 23 |
|
| 24 |
<div class="row">
|
| 25 |
<!-- ستون تنظیمات -->
|
| 26 |
-
<div class="col-lg-
|
| 27 |
<div class="card p-4">
|
| 28 |
<h5 class="mb-3">تنظیمات اصلی و API</h5>
|
| 29 |
|
| 30 |
<label class="form-label">Hugging Face Token (الزامی برای جلوگیری از خطا)</label>
|
| 31 |
<input type="text" id="hf_token" class="form-control" placeholder="hf_...">
|
| 32 |
|
| 33 |
-
<label class="form-label">تصویر اصلی (الزامی) [image_path]</label>
|
| 34 |
<input type="file" id="image_path" class="form-control" accept="image/*">
|
| 35 |
|
| 36 |
-
<label class="form-label">پرامپت اصلی (الزامی) [prompt]</label>
|
| 37 |
-
<textarea id="prompt" class="form-control" rows="
|
|
|
|
|
|
|
| 38 |
|
| 39 |
-
<label class="form-label">پرامپت منفی [negative_prompt]</label>
|
| 40 |
<textarea id="negative_prompt" class="form-control" rows="2">captions, music, transition, VR, bad quality, subtitles, text, watermark, overlay effects, cartoon, childish, ugly, text, blur, logo, static, low quality, noise, mutant, horror, film grain</textarea>
|
| 41 |
|
| 42 |
<div class="row mt-3">
|
|
@@ -61,18 +79,21 @@
|
|
| 61 |
</div>
|
| 62 |
</div>
|
| 63 |
|
| 64 |
-
<!-- ستون خروجی -->
|
| 65 |
-
<div class="col-lg-
|
| 66 |
<div class="card p-4 text-center sticky-top" style="top: 20px;">
|
| 67 |
<h5 class="mb-3">تولید ویدیو</h5>
|
| 68 |
<button id="generateBtn" class="btn btn-success w-100 py-3 mb-3 text-white fw-bold">شروع تولید (Generate)</button>
|
| 69 |
|
| 70 |
<div class="d-flex justify-content-center"><div id="loader" class="loader"></div></div>
|
| 71 |
-
<div id="statusText" class="text-secondary small
|
| 72 |
|
|
|
|
| 73 |
<video id="videoResult" controls></video>
|
| 74 |
-
|
| 75 |
<div id="seedResult" class="mt-3 text-info small"></div>
|
|
|
|
|
|
|
|
|
|
| 76 |
</div>
|
| 77 |
</div>
|
| 78 |
</div>
|
|
@@ -83,13 +104,14 @@
|
|
| 83 |
<script type="module">
|
| 84 |
import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
|
| 85 |
|
| 86 |
-
//
|
| 87 |
const formSchema = [
|
| 88 |
// گروه: Resolution
|
| 89 |
{ group: "رزولوشن و ابعاد", id: "max_width", type: "number", val: 1120 },
|
| 90 |
{ group: "رزولوشن و ابعاد", id: "max_height", type: "number", val: 1344 },
|
| 91 |
{ group: "رزولوشن و ابعاد", id: "target_mp", type: "number", val: 1.15, step: 0.05 },
|
| 92 |
-
|
|
|
|
| 93 |
{ group: "رزولوشن و ابعاد", id: "custom_res_enabled", type: "checkbox", val: false },
|
| 94 |
|
| 95 |
// گروه: Targeting (شخصیت و صورت)
|
|
@@ -142,6 +164,7 @@
|
|
| 142 |
{ group: "مصرف منابع و Seed", id: "seed", type: "number", val: -1 },
|
| 143 |
{ group: "مصرف منابع و Seed", id: "randomize_seed", type: "checkbox", val: true },
|
| 144 |
{ group: "مصرف منابع و Seed", id: "gen_budget", type: "number", val: 0 },
|
|
|
|
| 145 |
{ group: "مصرف منابع و Seed", id: "profile_name", type: "text", val: "" },
|
| 146 |
|
| 147 |
// گروه: MSR (چند تصویره)
|
|
@@ -150,7 +173,8 @@
|
|
| 150 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_ref3", type: "file", val: null },
|
| 151 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_ref4", type: "file", val: null },
|
| 152 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_background", type: "file", val: null },
|
| 153 |
-
|
|
|
|
| 154 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_guide_strength", type: "number", val: 1.0, step: 0.05 },
|
| 155 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_lora_strength", type: "number", val: 0.7, step: 0.05 },
|
| 156 |
|
|
@@ -240,7 +264,61 @@
|
|
| 240 |
index++;
|
| 241 |
}
|
| 242 |
|
| 243 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
document.getElementById("generateBtn").addEventListener("click", async () => {
|
| 245 |
const hfToken = document.getElementById("hf_token").value.trim();
|
| 246 |
const btn = document.getElementById("generateBtn");
|
|
@@ -249,19 +327,21 @@
|
|
| 249 |
const videoRes = document.getElementById("videoResult");
|
| 250 |
const seedRes = document.getElementById("seedResult");
|
| 251 |
|
| 252 |
-
// اعتبارسنجی
|
| 253 |
const imgInput = document.getElementById("image_path");
|
| 254 |
const promptInput = document.getElementById("prompt").value;
|
|
|
|
| 255 |
if (!imgInput.files.length) return alert("لطفاً تصویر اصلی را آپلود کنید.");
|
| 256 |
if (!promptInput) return alert("لطفاً پرامپت را وارد کنید.");
|
| 257 |
|
| 258 |
btn.disabled = true;
|
| 259 |
loader.style.display = "block";
|
| 260 |
videoRes.style.display = "none";
|
| 261 |
-
|
|
|
|
|
|
|
| 262 |
|
| 263 |
try {
|
| 264 |
-
//
|
| 265 |
const params = {
|
| 266 |
image_path: imgInput.files[0],
|
| 267 |
prompt: promptInput,
|
|
@@ -270,7 +350,6 @@
|
|
| 270 |
seconds: parseFloat(document.getElementById("seconds").value),
|
| 271 |
};
|
| 272 |
|
| 273 |
-
// خواندن فیلدهای اتوماتیک
|
| 274 |
formSchema.forEach(field => {
|
| 275 |
const el = document.getElementById(field.id);
|
| 276 |
if (field.type === "checkbox") {
|
|
@@ -281,37 +360,79 @@
|
|
| 281 |
if (el.files.length > 0) {
|
| 282 |
params[field.id] = el.files[0];
|
| 283 |
}
|
| 284 |
-
|
|
|
|
|
|
|
| 285 |
} else {
|
| 286 |
params[field.id] = el.value;
|
| 287 |
}
|
| 288 |
});
|
| 289 |
|
| 290 |
-
|
| 291 |
const client = await Client.connect("Fighterdan/LTX-2.3-10Eros_I2V", { hf_token: hfToken });
|
| 292 |
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
// درخواست تولید
|
| 296 |
-
const result = await client.predict("/generate", params);
|
| 297 |
|
| 298 |
-
//
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
|
| 309 |
} catch (error) {
|
| 310 |
console.error(error);
|
| 311 |
-
statusText.innerText = "خطا در
|
|
|
|
| 312 |
} finally {
|
| 313 |
-
|
| 314 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
}
|
| 316 |
});
|
| 317 |
</script>
|
|
|
|
| 11 |
.card { margin-bottom: 20px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
|
| 12 |
.loader { border: 4px solid #f3f3f3; border-top: 4px solid #0d6efd; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; display: none; margin-bottom: 10px; }
|
| 13 |
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
|
| 14 |
+
#videoResult { width: 100%; max-width: 100%; border-radius: 8px; margin-top: 15px; display: none; }
|
| 15 |
.form-label { font-weight: bold; font-size: 0.9em; margin-top: 10px; }
|
| 16 |
+
|
| 17 |
+
/* استایل ترمینال برای لاگهای زنده */
|
| 18 |
+
#liveLogs {
|
| 19 |
+
background-color: #1e1e1e;
|
| 20 |
+
color: #00ff00;
|
| 21 |
+
font-family: Consolas, monospace;
|
| 22 |
+
font-size: 0.8em;
|
| 23 |
+
padding: 10px;
|
| 24 |
+
border-radius: 5px;
|
| 25 |
+
height: 250px;
|
| 26 |
+
overflow-y: auto;
|
| 27 |
+
text-align: left;
|
| 28 |
+
direction: ltr;
|
| 29 |
+
margin-top: 15px;
|
| 30 |
+
display: none; /* تا وقتی پردازش شروع نشده مخفی بماند */
|
| 31 |
+
}
|
| 32 |
</style>
|
| 33 |
</head>
|
| 34 |
<body>
|
| 35 |
|
| 36 |
+
<div class="container-fluid">
|
| 37 |
<h2 class="text-center mb-4 text-primary">LTX 2.3 10Eros - تبدیل تصویر به ویدیو</h2>
|
| 38 |
+
<p class="text-center text-muted">اتصال مستقیم به API با امکان مانیتورینگ زنده (Live Logs)</p>
|
| 39 |
|
| 40 |
<div class="row">
|
| 41 |
<!-- ستون تنظیمات -->
|
| 42 |
+
<div class="col-lg-7">
|
| 43 |
<div class="card p-4">
|
| 44 |
<h5 class="mb-3">تنظیمات اصلی و API</h5>
|
| 45 |
|
| 46 |
<label class="form-label">Hugging Face Token (الزامی برای جلوگیری از خطا)</label>
|
| 47 |
<input type="text" id="hf_token" class="form-control" placeholder="hf_...">
|
| 48 |
|
| 49 |
+
<label class="form-label mt-3">تصویر اصلی (الزامی) [image_path]</label>
|
| 50 |
<input type="file" id="image_path" class="form-control" accept="image/*">
|
| 51 |
|
| 52 |
+
<label class="form-label mt-3">پرامپت اصلی (الزامی) [prompt]</label>
|
| 53 |
+
<textarea id="prompt" class="form-control" rows="3" placeholder="مفهوم و توضیح ویدیو..."></textarea>
|
| 54 |
+
|
| 55 |
+
<button id="enhanceBtn" class="btn btn-outline-primary btn-sm mt-2">✨ بهینهسازی خودکار پرامپت (Enhance)</button>
|
| 56 |
|
| 57 |
+
<label class="form-label mt-3">پرامپت منفی [negative_prompt]</label>
|
| 58 |
<textarea id="negative_prompt" class="form-control" rows="2">captions, music, transition, VR, bad quality, subtitles, text, watermark, overlay effects, cartoon, childish, ugly, text, blur, logo, static, low quality, noise, mutant, horror, film grain</textarea>
|
| 59 |
|
| 60 |
<div class="row mt-3">
|
|
|
|
| 79 |
</div>
|
| 80 |
</div>
|
| 81 |
|
| 82 |
+
<!-- ستون خروجی و لاگ -->
|
| 83 |
+
<div class="col-lg-5">
|
| 84 |
<div class="card p-4 text-center sticky-top" style="top: 20px;">
|
| 85 |
<h5 class="mb-3">تولید ویدیو</h5>
|
| 86 |
<button id="generateBtn" class="btn btn-success w-100 py-3 mb-3 text-white fw-bold">شروع تولید (Generate)</button>
|
| 87 |
|
| 88 |
<div class="d-flex justify-content-center"><div id="loader" class="loader"></div></div>
|
| 89 |
+
<div id="statusText" class="text-secondary small fw-bold">آماده دریافت فرمان...</div>
|
| 90 |
|
| 91 |
+
<!-- ویدیوی خروجی -->
|
| 92 |
<video id="videoResult" controls></video>
|
|
|
|
| 93 |
<div id="seedResult" class="mt-3 text-info small"></div>
|
| 94 |
+
|
| 95 |
+
<!-- ترمینال لاگهای زنده -->
|
| 96 |
+
<pre id="liveLogs"></pre>
|
| 97 |
</div>
|
| 98 |
</div>
|
| 99 |
</div>
|
|
|
|
| 104 |
<script type="module">
|
| 105 |
import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
|
| 106 |
|
| 107 |
+
// فرمتبندی تمامی پارامترها به همراه castTo برای تبدیل نوع دادهها هنگام ارسال
|
| 108 |
const formSchema = [
|
| 109 |
// گروه: Resolution
|
| 110 |
{ group: "رزولوشن و ابعاد", id: "max_width", type: "number", val: 1120 },
|
| 111 |
{ group: "رزولوشن و ابعاد", id: "max_height", type: "number", val: 1344 },
|
| 112 |
{ group: "رزولوشن و ابعاد", id: "target_mp", type: "number", val: 1.15, step: 0.05 },
|
| 113 |
+
// توجه: castTo="number" اضافه شد تا "64" به عدد صحیح 64 تبدیل شود
|
| 114 |
+
{ group: "رزولوشن و ابعاد", id: "snap_multiple", type: "select", options: ["32", "64"], val: "64", castTo: "number" },
|
| 115 |
{ group: "رزولوشن و ابعاد", id: "custom_res_enabled", type: "checkbox", val: false },
|
| 116 |
|
| 117 |
// گروه: Targeting (شخصیت و صورت)
|
|
|
|
| 164 |
{ group: "مصرف منابع و Seed", id: "seed", type: "number", val: -1 },
|
| 165 |
{ group: "مصرف منابع و Seed", id: "randomize_seed", type: "checkbox", val: true },
|
| 166 |
{ group: "مصرف منابع و Seed", id: "gen_budget", type: "number", val: 0 },
|
| 167 |
+
{ group: "مصرف منابع و Seed", id: "enhance_budget", type: "number", val: 80 },
|
| 168 |
{ group: "مصرف منابع و Seed", id: "profile_name", type: "text", val: "" },
|
| 169 |
|
| 170 |
// گروه: MSR (چند تصویره)
|
|
|
|
| 173 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_ref3", type: "file", val: null },
|
| 174 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_ref4", type: "file", val: null },
|
| 175 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_background", type: "file", val: null },
|
| 176 |
+
// توجه: castTo="number" اضافه شد
|
| 177 |
+
{ group: "حالت چند مرجعی (MSR)", id: "msr_frame_count", type: "select", options: ["17", "25", "33", "41"], val: "41", castTo: "number" },
|
| 178 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_guide_strength", type: "number", val: 1.0, step: 0.05 },
|
| 179 |
{ group: "حالت چند مرجعی (MSR)", id: "msr_lora_strength", type: "number", val: 0.7, step: 0.05 },
|
| 180 |
|
|
|
|
| 264 |
index++;
|
| 265 |
}
|
| 266 |
|
| 267 |
+
// لاگر سفارشی برای ثبت گزارشات زنده
|
| 268 |
+
const liveLogs = document.getElementById("liveLogs");
|
| 269 |
+
const appendLog = (msg) => {
|
| 270 |
+
liveLogs.style.display = "block";
|
| 271 |
+
const time = new Date().toLocaleTimeString();
|
| 272 |
+
liveLogs.innerHTML += `[${time}] ${msg}\n`;
|
| 273 |
+
liveLogs.scrollTop = liveLogs.scrollHeight; // اسکرول به پایین
|
| 274 |
+
};
|
| 275 |
+
|
| 276 |
+
// --- تابع بهینهسازی پرامپت (Enhance Prompt) ---
|
| 277 |
+
document.getElementById("enhanceBtn").addEventListener("click", async () => {
|
| 278 |
+
const hfToken = document.getElementById("hf_token").value.trim();
|
| 279 |
+
const imgInput = document.getElementById("image_path");
|
| 280 |
+
const promptInput = document.getElementById("prompt");
|
| 281 |
+
const enhanceBtn = document.getElementById("enhanceBtn");
|
| 282 |
+
|
| 283 |
+
if (!imgInput.files.length) return alert("ابتدا باید یک تصویر اصلی انتخاب کنید!");
|
| 284 |
+
if (!promptInput.value.trim()) return alert("ابتدا یک پرامپت کوتاه برای ایده اولیه بنویسید!");
|
| 285 |
+
|
| 286 |
+
enhanceBtn.innerText = "⏳ در حال بهینهسازی...";
|
| 287 |
+
enhanceBtn.disabled = true;
|
| 288 |
+
|
| 289 |
+
try {
|
| 290 |
+
const client = await Client.connect("Fighterdan/LTX-2.3-10Eros_I2V", { hf_token: hfToken });
|
| 291 |
+
|
| 292 |
+
// گرفتن فایلهای MSR در صورت وجود، یا رد کردن مقدار null
|
| 293 |
+
const getFile = (id) => document.getElementById(id) && document.getElementById(id).files.length ? document.getElementById(id).files[0] : null;
|
| 294 |
+
|
| 295 |
+
const enhanceParams = {
|
| 296 |
+
image_path: imgInput.files[0],
|
| 297 |
+
prompt: promptInput.value,
|
| 298 |
+
enhance_budget: Number(document.getElementById("enhance_budget")?.value || 80),
|
| 299 |
+
msr_ref2_path: getFile("msr_ref2"),
|
| 300 |
+
msr_ref3_path: getFile("msr_ref3"),
|
| 301 |
+
msr_ref4_path: getFile("msr_ref4"),
|
| 302 |
+
msr_bg_path: getFile("msr_background")
|
| 303 |
+
};
|
| 304 |
+
|
| 305 |
+
const result = await client.predict("/enhance_prompt", enhanceParams);
|
| 306 |
+
|
| 307 |
+
if (result.data && result.data[0]) {
|
| 308 |
+
promptInput.value = result.data[0];
|
| 309 |
+
alert("پرامپت با موفقیت بهینهسازی شد!");
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
} catch (error) {
|
| 313 |
+
console.error(error);
|
| 314 |
+
alert("خطا در بهینهسازی پرامپت: " + error.message);
|
| 315 |
+
} finally {
|
| 316 |
+
enhanceBtn.innerText = "✨ بهینهسازی خودکار پرامپت (Enhance)";
|
| 317 |
+
enhanceBtn.disabled = false;
|
| 318 |
+
}
|
| 319 |
+
});
|
| 320 |
+
|
| 321 |
+
// --- منطق تولید اصلی (Generate) ---
|
| 322 |
document.getElementById("generateBtn").addEventListener("click", async () => {
|
| 323 |
const hfToken = document.getElementById("hf_token").value.trim();
|
| 324 |
const btn = document.getElementById("generateBtn");
|
|
|
|
| 327 |
const videoRes = document.getElementById("videoResult");
|
| 328 |
const seedRes = document.getElementById("seedResult");
|
| 329 |
|
|
|
|
| 330 |
const imgInput = document.getElementById("image_path");
|
| 331 |
const promptInput = document.getElementById("prompt").value;
|
| 332 |
+
|
| 333 |
if (!imgInput.files.length) return alert("لطفاً تصویر اصلی را آپلود کنید.");
|
| 334 |
if (!promptInput) return alert("لطفاً پرامپت را وارد کنید.");
|
| 335 |
|
| 336 |
btn.disabled = true;
|
| 337 |
loader.style.display = "block";
|
| 338 |
videoRes.style.display = "none";
|
| 339 |
+
liveLogs.innerHTML = ""; // پاک کردن لاگهای قبلی
|
| 340 |
+
statusText.innerText = "در حال اتصال...";
|
| 341 |
+
appendLog("شروع فرآیند اتصال به سرور...");
|
| 342 |
|
| 343 |
try {
|
| 344 |
+
// خواندن پارامترها و کست کردن مقادیر رشتهای به عددی (در صورت نیاز)
|
| 345 |
const params = {
|
| 346 |
image_path: imgInput.files[0],
|
| 347 |
prompt: promptInput,
|
|
|
|
| 350 |
seconds: parseFloat(document.getElementById("seconds").value),
|
| 351 |
};
|
| 352 |
|
|
|
|
| 353 |
formSchema.forEach(field => {
|
| 354 |
const el = document.getElementById(field.id);
|
| 355 |
if (field.type === "checkbox") {
|
|
|
|
| 360 |
if (el.files.length > 0) {
|
| 361 |
params[field.id] = el.files[0];
|
| 362 |
}
|
| 363 |
+
} else if (field.type === "select") {
|
| 364 |
+
// تبدیل نوع دراپداونهایی که نیاز به عدد دارند
|
| 365 |
+
params[field.id] = field.castTo === "number" ? Number(el.value) : el.value;
|
| 366 |
} else {
|
| 367 |
params[field.id] = el.value;
|
| 368 |
}
|
| 369 |
});
|
| 370 |
|
| 371 |
+
appendLog("پارامترها آماده شد. اتصال به کلاینت Gradio...");
|
| 372 |
const client = await Client.connect("Fighterdan/LTX-2.3-10Eros_I2V", { hf_token: hfToken });
|
| 373 |
|
| 374 |
+
appendLog("متصل شد! ارسال درخواست تولید ویدیو (submit)...");
|
|
|
|
|
|
|
|
|
|
| 375 |
|
| 376 |
+
// استفاده از Submit به جای Predict برای دریافت رویدادهای زنده (لاگ و وضعیت)
|
| 377 |
+
const job = client.submit("/generate", params);
|
| 378 |
+
|
| 379 |
+
// گرفتن رویدادهای وضعیت (در صف، در حال اجرا و غیره)
|
| 380 |
+
job.on("status", (status) => {
|
| 381 |
+
if (status.stage === "pending") {
|
| 382 |
+
const queueInfo = status.queue_position !== undefined ? ` (جایگاه در صف: ${status.queue_position})` : "";
|
| 383 |
+
statusText.innerText = "در صف انتظار..." + queueInfo;
|
| 384 |
+
appendLog("وضعیت: در صف انتظار... " + queueInfo);
|
| 385 |
+
} else if (status.stage === "generating") {
|
| 386 |
+
statusText.innerText = "در حال پردازش در GPU (لطفا شکیبا باشید)...";
|
| 387 |
+
appendLog("وضعیت: تولید ویدیو در حال انجام است...");
|
| 388 |
+
} else if (status.stage === "complete") {
|
| 389 |
+
statusText.innerText = "پردازش تکمیل شد.";
|
| 390 |
+
appendLog("وضعیت: پایان موفقیتآمیز.");
|
| 391 |
+
} else if (status.stage === "error") {
|
| 392 |
+
statusText.innerText = "خطا در پردازش!";
|
| 393 |
+
appendLog("خطا (Error): " + (status.message || "نامشخص"));
|
| 394 |
+
}
|
| 395 |
+
});
|
| 396 |
+
|
| 397 |
+
// گرفتن لاگهای زنده که توسط سرور چاپ میشود (مثل خطاهای ComfyUI)
|
| 398 |
+
job.on("log", (logData) => {
|
| 399 |
+
appendLog("[سرور]: " + logData.log);
|
| 400 |
+
});
|
| 401 |
+
|
| 402 |
+
// گرفتن خروجی نهایی
|
| 403 |
+
job.on("data", (result) => {
|
| 404 |
+
appendLog("پاسخ نهایی دریافت شد.");
|
| 405 |
+
const data = result.data;
|
| 406 |
+
if (data && data[0] && data[0].url) {
|
| 407 |
+
videoRes.src = data[0].url;
|
| 408 |
+
videoRes.style.display = "block";
|
| 409 |
+
statusText.innerText = data[1] || "تولید با موفقیت به پایان رسید!";
|
| 410 |
+
seedRes.innerText = "Seed استفاده شده: " + data[2];
|
| 411 |
+
appendLog("ویدیو با موفقیت بارگذاری شد.");
|
| 412 |
+
} else {
|
| 413 |
+
statusText.innerText = "خطا: ویدیو در پاسخ یافت نشد.";
|
| 414 |
+
appendLog("خطای منطقی: فایل ویدیو در خروجی Gradio قرار نگرفت.");
|
| 415 |
+
}
|
| 416 |
+
});
|
| 417 |
+
|
| 418 |
+
// در صورت بروز خطا در ارسال درخواست
|
| 419 |
+
job.on("error", (error) => {
|
| 420 |
+
console.error(error);
|
| 421 |
+
statusText.innerText = "خطای کلاینت: " + error.message;
|
| 422 |
+
appendLog("استثنا/خطا: " + error.message);
|
| 423 |
+
});
|
| 424 |
|
| 425 |
} catch (error) {
|
| 426 |
console.error(error);
|
| 427 |
+
statusText.innerText = "خطا در برقراری ارتباط اولیه: " + error.message;
|
| 428 |
+
appendLog("استثنای اتصال: " + error.message);
|
| 429 |
} finally {
|
| 430 |
+
// از آنجایی که job ناهمگام (Event-based) است، دکمه را در زمان پایان (داخل status) یا همینجا با تایمر موقت آزاد میکنیم.
|
| 431 |
+
// به صورت اصولی دکمه باید وقتی stage === complete شد فعال شود، اما برای اطمینان این تنظیمات را اینجا میگذاریم.
|
| 432 |
+
setTimeout(() => {
|
| 433 |
+
btn.disabled = false;
|
| 434 |
+
loader.style.display = "none";
|
| 435 |
+
}, 3000); // فقط برای بازگرداندن وضعیت دکمه
|
| 436 |
}
|
| 437 |
});
|
| 438 |
</script>
|