136 lines
4.4 KiB
JavaScript
136 lines
4.4 KiB
JavaScript
/* ==========================================================================
|
||
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");
|
||
},
|
||
};
|
||
})();
|