Spaces:
Sleeping
Sleeping
Upload 21 files
Browse files- frontend/assets/app.js +166 -2
- frontend/index.html +0 -1
frontend/assets/app.js
CHANGED
|
@@ -8,6 +8,12 @@
|
|
| 8 |
let soundEnabled = false;
|
| 9 |
let soundUrl = "/ring/ring.mp3";
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
// ===== 移动端后台恢复处理 =====
|
| 12 |
// 修复手机切屏后回来无法输入的问题
|
| 13 |
function handlePageResume() {
|
|
@@ -385,8 +391,146 @@
|
|
| 385 |
}
|
| 386 |
}
|
| 387 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
// T2I
|
| 389 |
async function handleT2I() {
|
|
|
|
|
|
|
|
|
|
| 390 |
const payloadBase = {
|
| 391 |
prompt: byId("t2i-prompt").value || "",
|
| 392 |
negative: byId("t2i-negative").value || "",
|
|
@@ -466,6 +610,9 @@
|
|
| 466 |
|
| 467 |
// I2I
|
| 468 |
async function handleI2I() {
|
|
|
|
|
|
|
|
|
|
| 469 |
const file = byId("i2i-image").files?.[0];
|
| 470 |
if (!file) {
|
| 471 |
toast("请上传输入图片", "error");
|
|
@@ -555,6 +702,9 @@
|
|
| 555 |
|
| 556 |
// Inpaint
|
| 557 |
async function handleInpaint() {
|
|
|
|
|
|
|
|
|
|
| 558 |
const imgFile = byId("inpaint-image").files?.[0];
|
| 559 |
const maskFile = byId("inpaint-mask").files?.[0];
|
| 560 |
if (!imgFile || !maskFile) {
|
|
@@ -652,11 +802,16 @@
|
|
| 652 |
ensureCountField("tab-i2i", "i2i-count");
|
| 653 |
ensureCountField("tab-inpaint", "inpaint-count");
|
| 654 |
|
| 655 |
-
byId("btn-load-config").addEventListener("click", loadConfig);
|
| 656 |
byId("btn-save-config").addEventListener("click", saveConfig);
|
| 657 |
const selOutBtn = byId("btn-select-output-dir");
|
| 658 |
if (selOutBtn) {
|
| 659 |
selOutBtn.addEventListener("click", async () => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 660 |
try {
|
| 661 |
loading.show();
|
| 662 |
const res = await fetch("/api/select-output-dir");
|
|
@@ -690,6 +845,12 @@
|
|
| 690 |
const openOutBtn = byId("btn-open-output-dir");
|
| 691 |
if (openOutBtn) {
|
| 692 |
openOutBtn.addEventListener("click", async () => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 693 |
try {
|
| 694 |
loading.show();
|
| 695 |
const p = byId("cfg-output-dir")?.value || "";
|
|
@@ -728,6 +889,9 @@
|
|
| 728 |
// 设置图片信息展开/收起功能
|
| 729 |
setupImageInfoToggle();
|
| 730 |
|
| 731 |
-
// Init
|
| 732 |
loadConfig();
|
|
|
|
|
|
|
|
|
|
| 733 |
})();
|
|
|
|
| 8 |
let soundEnabled = false;
|
| 9 |
let soundUrl = "/ring/ring.mp3";
|
| 10 |
|
| 11 |
+
// 检测是否为移动端设备
|
| 12 |
+
function isMobileDevice() {
|
| 13 |
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
|
| 14 |
+
(window.innerWidth <= 768);
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
// ===== 移动端后台恢复处理 =====
|
| 18 |
// 修复手机切屏后回来无法输入的问题
|
| 19 |
function handlePageResume() {
|
|
|
|
| 391 |
}
|
| 392 |
}
|
| 393 |
|
| 394 |
+
// ===== localStorage 生成参数保存/恢复 =====
|
| 395 |
+
const STORAGE_KEY_T2I = 'nai_t2i_params';
|
| 396 |
+
const STORAGE_KEY_I2I = 'nai_i2i_params';
|
| 397 |
+
const STORAGE_KEY_INPAINT = 'nai_inpaint_params';
|
| 398 |
+
|
| 399 |
+
function saveT2IParams() {
|
| 400 |
+
const params = {
|
| 401 |
+
prompt: byId("t2i-prompt").value || "",
|
| 402 |
+
negative: byId("t2i-negative").value || "",
|
| 403 |
+
width: byId("t2i-width").value || "768",
|
| 404 |
+
height: byId("t2i-height").value || "768",
|
| 405 |
+
steps: byId("t2i-steps").value || "",
|
| 406 |
+
scale: byId("t2i-scale").value || "",
|
| 407 |
+
sampler: byId("t2i-sampler").value || "",
|
| 408 |
+
noise_schedule: byId("t2i-noise-schedule").value || "",
|
| 409 |
+
seed: byId("t2i-seed").value || "-1",
|
| 410 |
+
variety: byId("t2i-variety").checked,
|
| 411 |
+
decrisp: byId("t2i-decrisp").checked,
|
| 412 |
+
cfg_rescale: byId("t2i-cfg-rescale").value || "",
|
| 413 |
+
count: byId("t2i-count")?.value || "1"
|
| 414 |
+
};
|
| 415 |
+
try { localStorage.setItem(STORAGE_KEY_T2I, JSON.stringify(params)); } catch {}
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
function restoreT2IParams() {
|
| 419 |
+
try {
|
| 420 |
+
const saved = localStorage.getItem(STORAGE_KEY_T2I);
|
| 421 |
+
if (!saved) return;
|
| 422 |
+
const params = JSON.parse(saved);
|
| 423 |
+
if (params.prompt !== undefined) byId("t2i-prompt").value = params.prompt;
|
| 424 |
+
if (params.negative !== undefined) byId("t2i-negative").value = params.negative;
|
| 425 |
+
if (params.width) byId("t2i-width").value = params.width;
|
| 426 |
+
if (params.height) byId("t2i-height").value = params.height;
|
| 427 |
+
if (params.steps) byId("t2i-steps").value = params.steps;
|
| 428 |
+
if (params.scale) byId("t2i-scale").value = params.scale;
|
| 429 |
+
if (params.sampler !== undefined) byId("t2i-sampler").value = params.sampler;
|
| 430 |
+
if (params.noise_schedule !== undefined) byId("t2i-noise-schedule").value = params.noise_schedule;
|
| 431 |
+
if (params.seed !== undefined) byId("t2i-seed").value = params.seed;
|
| 432 |
+
if (params.variety !== undefined) byId("t2i-variety").checked = params.variety;
|
| 433 |
+
if (params.decrisp !== undefined) byId("t2i-decrisp").checked = params.decrisp;
|
| 434 |
+
if (params.cfg_rescale) byId("t2i-cfg-rescale").value = params.cfg_rescale;
|
| 435 |
+
if (params.count && byId("t2i-count")) byId("t2i-count").value = params.count;
|
| 436 |
+
} catch {}
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
function saveI2IParams() {
|
| 440 |
+
const params = {
|
| 441 |
+
positive: byId("i2i-positive").value || "",
|
| 442 |
+
negative: byId("i2i-negative").value || "",
|
| 443 |
+
width: byId("i2i-width").value || "",
|
| 444 |
+
height: byId("i2i-height").value || "",
|
| 445 |
+
steps: byId("i2i-steps").value || "",
|
| 446 |
+
scale: byId("i2i-scale").value || "",
|
| 447 |
+
sampler: byId("i2i-sampler").value || "",
|
| 448 |
+
noise_schedule: byId("i2i-noise-schedule").value || "",
|
| 449 |
+
seed: byId("i2i-seed").value || "-1",
|
| 450 |
+
strength: byId("i2i-strength").value || "0.5",
|
| 451 |
+
noise: byId("i2i-noise").value || "0.0",
|
| 452 |
+
variety: byId("i2i-variety").checked,
|
| 453 |
+
decrisp: byId("i2i-decrisp").checked,
|
| 454 |
+
cfg_rescale: byId("i2i-cfg-rescale").value || "",
|
| 455 |
+
count: byId("i2i-count")?.value || "1"
|
| 456 |
+
};
|
| 457 |
+
try { localStorage.setItem(STORAGE_KEY_I2I, JSON.stringify(params)); } catch {}
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
function restoreI2IParams() {
|
| 461 |
+
try {
|
| 462 |
+
const saved = localStorage.getItem(STORAGE_KEY_I2I);
|
| 463 |
+
if (!saved) return;
|
| 464 |
+
const params = JSON.parse(saved);
|
| 465 |
+
if (params.positive !== undefined) byId("i2i-positive").value = params.positive;
|
| 466 |
+
if (params.negative !== undefined) byId("i2i-negative").value = params.negative;
|
| 467 |
+
if (params.width) byId("i2i-width").value = params.width;
|
| 468 |
+
if (params.height) byId("i2i-height").value = params.height;
|
| 469 |
+
if (params.steps) byId("i2i-steps").value = params.steps;
|
| 470 |
+
if (params.scale) byId("i2i-scale").value = params.scale;
|
| 471 |
+
if (params.sampler !== undefined) byId("i2i-sampler").value = params.sampler;
|
| 472 |
+
if (params.noise_schedule !== undefined) byId("i2i-noise-schedule").value = params.noise_schedule;
|
| 473 |
+
if (params.seed !== undefined) byId("i2i-seed").value = params.seed;
|
| 474 |
+
if (params.strength !== undefined) byId("i2i-strength").value = params.strength;
|
| 475 |
+
if (params.noise !== undefined) byId("i2i-noise").value = params.noise;
|
| 476 |
+
if (params.variety !== undefined) byId("i2i-variety").checked = params.variety;
|
| 477 |
+
if (params.decrisp !== undefined) byId("i2i-decrisp").checked = params.decrisp;
|
| 478 |
+
if (params.cfg_rescale) byId("i2i-cfg-rescale").value = params.cfg_rescale;
|
| 479 |
+
if (params.count && byId("i2i-count")) byId("i2i-count").value = params.count;
|
| 480 |
+
} catch {}
|
| 481 |
+
}
|
| 482 |
+
|
| 483 |
+
function saveInpaintParams() {
|
| 484 |
+
const params = {
|
| 485 |
+
positive: byId("inpaint-positive").value || "",
|
| 486 |
+
negative: byId("inpaint-negative").value || "",
|
| 487 |
+
add_original: byId("inpaint-add-original").checked,
|
| 488 |
+
width: byId("inpaint-width").value || "",
|
| 489 |
+
height: byId("inpaint-height").value || "",
|
| 490 |
+
steps: byId("inpaint-steps").value || "",
|
| 491 |
+
scale: byId("inpaint-scale").value || "",
|
| 492 |
+
sampler: byId("inpaint-sampler").value || "",
|
| 493 |
+
noise_schedule: byId("inpaint-noise-schedule").value || "",
|
| 494 |
+
seed: byId("inpaint-seed").value || "-1",
|
| 495 |
+
strength: byId("inpaint-strength").value || "0.5",
|
| 496 |
+
noise: byId("inpaint-noise-val").value || "0.0",
|
| 497 |
+
variety: byId("inpaint-variety").checked,
|
| 498 |
+
decrisp: byId("inpaint-decrisp").checked,
|
| 499 |
+
cfg_rescale: byId("inpaint-cfg-rescale").value || "",
|
| 500 |
+
count: byId("inpaint-count")?.value || "1"
|
| 501 |
+
};
|
| 502 |
+
try { localStorage.setItem(STORAGE_KEY_INPAINT, JSON.stringify(params)); } catch {}
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
function restoreInpaintParams() {
|
| 506 |
+
try {
|
| 507 |
+
const saved = localStorage.getItem(STORAGE_KEY_INPAINT);
|
| 508 |
+
if (!saved) return;
|
| 509 |
+
const params = JSON.parse(saved);
|
| 510 |
+
if (params.positive !== undefined) byId("inpaint-positive").value = params.positive;
|
| 511 |
+
if (params.negative !== undefined) byId("inpaint-negative").value = params.negative;
|
| 512 |
+
if (params.add_original !== undefined) byId("inpaint-add-original").checked = params.add_original;
|
| 513 |
+
if (params.width) byId("inpaint-width").value = params.width;
|
| 514 |
+
if (params.height) byId("inpaint-height").value = params.height;
|
| 515 |
+
if (params.steps) byId("inpaint-steps").value = params.steps;
|
| 516 |
+
if (params.scale) byId("inpaint-scale").value = params.scale;
|
| 517 |
+
if (params.sampler !== undefined) byId("inpaint-sampler").value = params.sampler;
|
| 518 |
+
if (params.noise_schedule !== undefined) byId("inpaint-noise-schedule").value = params.noise_schedule;
|
| 519 |
+
if (params.seed !== undefined) byId("inpaint-seed").value = params.seed;
|
| 520 |
+
if (params.strength !== undefined) byId("inpaint-strength").value = params.strength;
|
| 521 |
+
if (params.noise !== undefined) byId("inpaint-noise-val").value = params.noise;
|
| 522 |
+
if (params.variety !== undefined) byId("inpaint-variety").checked = params.variety;
|
| 523 |
+
if (params.decrisp !== undefined) byId("inpaint-decrisp").checked = params.decrisp;
|
| 524 |
+
if (params.cfg_rescale) byId("inpaint-cfg-rescale").value = params.cfg_rescale;
|
| 525 |
+
if (params.count && byId("inpaint-count")) byId("inpaint-count").value = params.count;
|
| 526 |
+
} catch {}
|
| 527 |
+
}
|
| 528 |
+
|
| 529 |
// T2I
|
| 530 |
async function handleT2I() {
|
| 531 |
+
// 保存当前参数到 localStorage
|
| 532 |
+
saveT2IParams();
|
| 533 |
+
|
| 534 |
const payloadBase = {
|
| 535 |
prompt: byId("t2i-prompt").value || "",
|
| 536 |
negative: byId("t2i-negative").value || "",
|
|
|
|
| 610 |
|
| 611 |
// I2I
|
| 612 |
async function handleI2I() {
|
| 613 |
+
// 保存当前参数到 localStorage
|
| 614 |
+
saveI2IParams();
|
| 615 |
+
|
| 616 |
const file = byId("i2i-image").files?.[0];
|
| 617 |
if (!file) {
|
| 618 |
toast("请上传输入图片", "error");
|
|
|
|
| 702 |
|
| 703 |
// Inpaint
|
| 704 |
async function handleInpaint() {
|
| 705 |
+
// 保存当前参数到 localStorage
|
| 706 |
+
saveInpaintParams();
|
| 707 |
+
|
| 708 |
const imgFile = byId("inpaint-image").files?.[0];
|
| 709 |
const maskFile = byId("inpaint-mask").files?.[0];
|
| 710 |
if (!imgFile || !maskFile) {
|
|
|
|
| 802 |
ensureCountField("tab-i2i", "i2i-count");
|
| 803 |
ensureCountField("tab-inpaint", "inpaint-count");
|
| 804 |
|
|
|
|
| 805 |
byId("btn-save-config").addEventListener("click", saveConfig);
|
| 806 |
const selOutBtn = byId("btn-select-output-dir");
|
| 807 |
if (selOutBtn) {
|
| 808 |
selOutBtn.addEventListener("click", async () => {
|
| 809 |
+
// 移动端检测:手机无法弹出服务器上的目录选择器
|
| 810 |
+
if (isMobileDevice()) {
|
| 811 |
+
toast("手机端请直接在输入框中填写目录路径", "info");
|
| 812 |
+
return;
|
| 813 |
+
}
|
| 814 |
+
|
| 815 |
try {
|
| 816 |
loading.show();
|
| 817 |
const res = await fetch("/api/select-output-dir");
|
|
|
|
| 845 |
const openOutBtn = byId("btn-open-output-dir");
|
| 846 |
if (openOutBtn) {
|
| 847 |
openOutBtn.addEventListener("click", async () => {
|
| 848 |
+
// 移动端检测:手机无法打开服务器上的目录
|
| 849 |
+
if (isMobileDevice()) {
|
| 850 |
+
toast("手机端无法打开服务器目录,请在电脑上操作", "info");
|
| 851 |
+
return;
|
| 852 |
+
}
|
| 853 |
+
|
| 854 |
try {
|
| 855 |
loading.show();
|
| 856 |
const p = byId("cfg-output-dir")?.value || "";
|
|
|
|
| 889 |
// 设置图片信息展开/收起功能
|
| 890 |
setupImageInfoToggle();
|
| 891 |
|
| 892 |
+
// Init - 加载配置和恢复上次的生成参数
|
| 893 |
loadConfig();
|
| 894 |
+
restoreT2IParams();
|
| 895 |
+
restoreI2IParams();
|
| 896 |
+
restoreInpaintParams();
|
| 897 |
})();
|
frontend/index.html
CHANGED
|
@@ -122,7 +122,6 @@
|
|
| 122 |
</label>
|
| 123 |
</div>
|
| 124 |
<div class="actions">
|
| 125 |
-
<button id="btn-load-config">读取配置</button>
|
| 126 |
<button id="btn-select-output-dir">选择保存目录</button>
|
| 127 |
<button id="btn-open-output-dir">打开保存目录</button>
|
| 128 |
<button id="btn-save-config" class="primary">保存配置</button>
|
|
|
|
| 122 |
</label>
|
| 123 |
</div>
|
| 124 |
<div class="actions">
|
|
|
|
| 125 |
<button id="btn-select-output-dir">选择保存目录</button>
|
| 126 |
<button id="btn-open-output-dir">打开保存目录</button>
|
| 127 |
<button id="btn-save-config" class="primary">保存配置</button>
|