lcccluck's picture
Add QuickDraw diffusion model and app code
9894238 verified
Raw
History Blame Contribute Delete
5.68 kB
const classSelect = document.querySelector("#class-select");
const form = document.querySelector("#generate-form");
const guidance = document.querySelector("#guidance");
const guidanceValue = document.querySelector("#guidance-value");
const statusEl = document.querySelector("#status");
const imageStage = document.querySelector("#image-stage");
const resultTitle = document.querySelector("#result-title");
const message = document.querySelector("#message");
const button = document.querySelector("#generate-button");
const downloadLink = document.querySelector("#download-link");
const recognizeButton = document.querySelector("#recognize-button");
const recognitionList = document.querySelector("#recognition-list");
const cnnStatus = document.querySelector("#cnn-status");
let currentImage = null;
function setMessage(text, isError = false) {
message.textContent = text;
message.classList.toggle("error", isError);
}
function setLoading(isLoading) {
button.disabled = isLoading;
button.querySelector("span:last-child").textContent = isLoading ? "生成中" : "生成";
}
async function loadStatus() {
const response = await fetch("/api/status");
const status = await response.json();
statusEl.textContent = status.checkpoint_exists
? `${status.device} · ${status.image_size}x${status.image_size} · step ${status.step ?? "not loaded"}`
: "checkpoint missing";
}
async function loadCnnStatus() {
try {
const response = await fetch("/api/cnn/classes");
const data = await response.json();
if (!response.ok) {
throw new Error(data.detail || "CNN offline");
}
const classes = Array.isArray(data) ? data : data.classes;
cnnStatus.textContent = `CNN: ${classes.length} classes`;
cnnStatus.title = classes.join(", ");
} catch (error) {
cnnStatus.textContent = "CNN: offline";
cnnStatus.title = error.message;
}
}
async function loadClasses() {
const response = await fetch("/api/classes");
const data = await response.json();
classSelect.innerHTML = "";
for (const name of data.classes) {
const option = document.createElement("option");
option.value = name;
option.textContent = name;
classSelect.append(option);
}
classSelect.value = data.classes.includes("cat") ? "cat" : data.classes[0];
}
guidance.addEventListener("input", () => {
guidanceValue.value = Number(guidance.value).toFixed(2);
});
form.addEventListener("submit", async (event) => {
event.preventDefault();
const formData = new FormData(form);
const seedValue = formData.get("seed");
const payload = {
class_name: formData.get("class_name"),
count: Number(formData.get("count")),
guidance_scale: Number(formData.get("guidance_scale")),
seed: seedValue ? Number(seedValue) : null,
};
setLoading(true);
setMessage("模型采样大约需要几十秒,MPS/CPU 会更慢。");
try {
const response = await fetch("/api/generate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.detail || "生成失败");
}
imageStage.innerHTML = "";
const image = document.createElement("img");
image.src = data.image;
image.alt = `${data.class_name} generated sketch samples`;
imageStage.append(image);
currentImage = data.image;
resultTitle.textContent = data.class_name;
downloadLink.href = data.image;
downloadLink.setAttribute("aria-disabled", "false");
recognizeButton.disabled = false;
recognitionList.innerHTML = "";
setMessage(`完成 · ${data.device} · step ${data.step} · CFG ${data.guidance_scale}`);
await loadStatus();
} catch (error) {
setMessage(error.message, true);
} finally {
setLoading(false);
}
});
recognizeButton.addEventListener("click", async () => {
if (!currentImage) {
return;
}
recognizeButton.disabled = true;
recognizeButton.textContent = "识别中";
setMessage("正在请求 CNN 图片识别服务。");
try {
const response = await fetch("/api/recognize", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ image: currentImage, top_k: 5, predictor: "quickdraw100" }),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.detail || "识别失败");
}
recognitionList.innerHTML = "";
for (const item of data.top || []) {
const row = document.createElement("div");
row.className = "recognition-item";
const label = document.createElement("strong");
label.textContent = item.label;
const track = document.createElement("div");
track.className = "confidence-track";
const fill = document.createElement("div");
fill.className = "confidence-fill";
fill.style.width = `${Math.max(0, Math.min(1, item.confidence)) * 100}%`;
track.append(fill);
const value = document.createElement("span");
value.className = "confidence-value";
value.textContent = `${Math.round(item.confidence * 100)}%`;
row.append(label, track, value);
recognitionList.append(row);
}
const top = data.prediction;
setMessage(top ? `CNN top-1: ${top.label} · ${(top.confidence * 100).toFixed(1)}%` : "CNN 返回为空");
} catch (error) {
setMessage(error.message, true);
} finally {
recognizeButton.disabled = false;
recognizeButton.textContent = "识别当前图片";
}
});
Promise.all([loadStatus(), loadClasses(), loadCnnStatus()]).catch((error) => {
setMessage(error.message, true);
});