/* ========================================================================== api.js — 数据访问层(真实 REST) 所有页面只通过 window.API 访问后端。 ========================================================================== */ (function () { async function request(path, options) { const res = await fetch(path, { headers: { "Content-Type": "application/json" }, ...options, }); const text = await res.text(); let data = null; if (text) { try { data = JSON.parse(text); } catch (e) { data = text; } } if (!res.ok) { let detail = data && typeof data === "object" ? data.detail || data.message || JSON.stringify(data) : String(data || res.statusText); if (Array.isArray(detail)) { detail = detail.map((item) => (item.loc || []).slice(1).join(".") + ": " + item.msg).join(";"); } throw new Error(detail); } return data; } const get = (path) => request(path, { method: "GET" }); const post = (path, body) => request(path, { method: "POST", body: JSON.stringify(body || {}) }); const patch = (path, body) => request(path, { method: "PATCH", body: JSON.stringify(body || {}) }); const del = (path) => request(path, { method: "DELETE" }); window.API = { /* ---------------------------------------------------------- 供应商 */ async listProviders() { return get("/api/providers"); }, async saveProvider(payload) { await post("/api/providers", payload); return get("/api/providers"); }, async deleteProvider(id) { await del("/api/providers/" + encodeURIComponent(id)); return get("/api/providers"); }, /* ------------------------------------- 上游模型发现(含 image 筛选) */ /* 按供应商 ID 拉取上游模型 */ async discoverProviderModels(providerId) { return post("/api/providers/" + encodeURIComponent(providerId) + "/discover", {}); }, /* 保存勾选的模型 */ async saveProviderModels(providerId, modelIds, enabled, note) { await post("/api/providers/" + encodeURIComponent(providerId) + "/models", { model_ids: modelIds, enabled: enabled !== false, note: note || "自动发现", }); return get("/api/models?provider_id=" + encodeURIComponent(providerId)); }, /* ---------------------------------------------------------- 模型 */ async listModels(providerId) { const q = providerId ? "?provider_id=" + encodeURIComponent(providerId) : ""; return get("/api/models" + q); }, async toggleModel(modelId, enabled) { await patch("/api/models/" + encodeURIComponent(modelId), { enabled: !!enabled }); return get("/api/models"); }, async setModelsEnabled(modelIds, enabled) { await post("/api/models/bulk", { ids: modelIds, enabled: !!enabled }); return get("/api/models"); }, /* ---------------------------------------------------------- 画廊 */ async listGalleries() { return get("/api/galleries"); }, async listGallery(profileName) { if (!profileName) return []; return get("/api/galleries/" + encodeURIComponent(profileName)); }, async deleteGalleryImage(profileName, filename) { return del("/api/galleries/" + encodeURIComponent(profileName) + "/" + encodeURIComponent(filename)); }, /* ------------------------------------------------------ 生成记录 */ async listGenerations() { return get("/api/generations"); }, /* ---------------------------------------------------- 网页端出图 */ /* 网页端固定 profile_name = "user",落到 output/user/(不存在则自动创建) */ async generateImage(payload) { const body = Object.assign({}, payload); if (!body.profile_name) body.profile_name = "user"; const res = await post("/api/generate", body); return { generation: { id: res.id, provider_id: res.provider, provider_name: res.provider_name, model: res.model, profile_name: res.profile_name, size: res.size, ratio: res.ratio, created_at: res.created_at, }, images: res.images || [], output_dir: res.output_dir, }; }, /* ---------------------------------------------------------- SKILL */ async getSkill() { return get("/api/skills"); }, }; })();