93773f3887
Includes FastAPI backend, vendored step2urdf frontend, and A7 handtuned arm JSON for URDF generation.
115 lines
3.5 KiB
JavaScript
115 lines
3.5 KiB
JavaScript
const state = {
|
|
jobId: null,
|
|
draft: null,
|
|
};
|
|
|
|
const $ = (id) => document.getElementById(id);
|
|
|
|
function pretty(obj) {
|
|
return JSON.stringify(obj, null, 2);
|
|
}
|
|
|
|
async function refreshHealth() {
|
|
const el = $("health");
|
|
try {
|
|
const res = await fetch("/api/health");
|
|
const data = await res.json();
|
|
const z = data.zhipu_configured ? `智谱 OK (${data.zhipu_model})` : "智谱未配置";
|
|
const g = data.geometry?.available ? "几何后端可用" : "几何后端未装(占位 mesh)";
|
|
el.textContent = `${z} · ${g}`;
|
|
el.className = "pill " + (data.zhipu_configured ? "ok" : "warn");
|
|
} catch (e) {
|
|
el.textContent = "后端未连接";
|
|
el.className = "pill warn";
|
|
}
|
|
}
|
|
|
|
$("btnParse").addEventListener("click", async () => {
|
|
const file = $("file").files?.[0];
|
|
if (!file) {
|
|
$("parseOut").textContent = "请先选择 STEP 文件";
|
|
$("parseOut").classList.add("error");
|
|
return;
|
|
}
|
|
$("parseOut").classList.remove("error");
|
|
$("parseOut").textContent = "解析中…";
|
|
const fd = new FormData();
|
|
fd.append("file", file);
|
|
try {
|
|
const res = await fetch("/api/parse", { method: "POST", body: fd });
|
|
if (!res.ok) throw new Error(await res.text());
|
|
const data = await res.json();
|
|
state.jobId = data.job_id;
|
|
$("btnPropose").disabled = false;
|
|
$("parseOut").textContent = pretty({
|
|
job_id: data.job_id,
|
|
root_name: data.root_name,
|
|
product_count: data.product_names?.length,
|
|
product_names: data.product_names,
|
|
stats: data.stats,
|
|
});
|
|
} catch (e) {
|
|
$("parseOut").textContent = String(e);
|
|
$("parseOut").classList.add("error");
|
|
}
|
|
});
|
|
|
|
$("btnPropose").addEventListener("click", async () => {
|
|
if (!state.jobId) return;
|
|
$("proposeOut").classList.remove("error");
|
|
$("proposeOut").textContent = "调用智谱中(可能需要几十秒)…";
|
|
try {
|
|
const res = await fetch("/api/propose", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
job_id: state.jobId,
|
|
profile: $("profile").value,
|
|
robot_name: $("robotName").value || "A7",
|
|
extra_hint: $("hint").value || "",
|
|
}),
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
const draft = await res.json();
|
|
state.draft = draft;
|
|
$("draftEditor").value = pretty(draft);
|
|
$("btnExport").disabled = false;
|
|
$("proposeOut").textContent = `links=${draft.links?.length || 0}, joints=${draft.joints?.length || 0}\n` +
|
|
(draft.notes || []).map((n) => `- ${n}`).join("\n");
|
|
} catch (e) {
|
|
$("proposeOut").textContent = String(e);
|
|
$("proposeOut").classList.add("error");
|
|
}
|
|
});
|
|
|
|
$("btnExport").addEventListener("click", async () => {
|
|
if (!state.jobId) return;
|
|
$("exportOut").classList.remove("error");
|
|
try {
|
|
const draft = JSON.parse($("draftEditor").value);
|
|
state.draft = draft;
|
|
const res = await fetch("/api/export", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
job_id: state.jobId,
|
|
draft,
|
|
include_meshes: true,
|
|
}),
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
const meta = await res.json();
|
|
$("exportOut").textContent = pretty(meta);
|
|
const name = draft.name || "robot";
|
|
const a = $("dlLink");
|
|
a.hidden = false;
|
|
a.href = `/api/jobs/${state.jobId}/download/${encodeURIComponent(name)}`;
|
|
a.textContent = `下载 ${name}.urdf`;
|
|
} catch (e) {
|
|
$("exportOut").textContent = String(e);
|
|
$("exportOut").classList.add("error");
|
|
}
|
|
});
|
|
|
|
refreshHealth();
|