Files
skill-convertor/web/api-config.html
2026-04-15 01:17:01 +08:00

155 lines
5.1 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SGClaw Skill Converter - API 配置</title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<main class="page">
<header class="hero">
<h1>API 配置</h1>
<p>这里填写 AI 调用参数,转换页面会作为实际生效配置使用。</p>
<p class="subnav">
<a href="/">返回转换页</a>
</p>
</header>
<section class="grid">
<section class="card">
<label>
API Base URL
<input id="aiBaseUrl" type="text" placeholder="https://open.bigmodel.cn/api/paas/v4" />
</label>
<label>
API Key
<input id="aiApiKey" type="password" placeholder="sk-..." />
</label>
<label>
模型
<input id="aiModel" type="text" placeholder="glm-5.1" />
</label>
<label>
超时(秒)
<input id="aiTimeout" type="number" min="1" placeholder="30" />
</label>
<div class="actions">
<button type="button" id="saveApiConfig">保存</button>
<button type="button" id="clearApiConfig">清空</button>
</div>
<p id="apiStatus" class="muted">未保存</p>
<p id="serverCfgHint" class="muted">服务端: 读取中...</p>
<p id="effectiveCfgHint" class="muted">实际生效: 未加载</p>
</section>
</section>
</main>
<script>
const API_CONFIG_KEY = "sgclaw.converter.apiConfig";
const aiBaseUrl = document.getElementById("aiBaseUrl");
const aiApiKey = document.getElementById("aiApiKey");
const aiModel = document.getElementById("aiModel");
const aiTimeout = document.getElementById("aiTimeout");
const apiStatus = document.getElementById("apiStatus");
const serverCfgHint = document.getElementById("serverCfgHint");
const effectiveCfgHint = document.getElementById("effectiveCfgHint");
function trimText(v) {
return typeof v === "string" ? v.trim() : "";
}
function parseTimeout(v) {
const n = Number.parseInt(trimText(v), 10);
return Number.isFinite(n) && n > 0 ? n : "";
}
function formatCfgLine(cfg) {
const timeout = cfg.timeout ? `${cfg.timeout}s` : "未设置";
const keyStatus = cfg.api_key ? "已配置" : "未配置";
return `base_url=${cfg.base_url || "未设置"} | model=${cfg.model || "未设置"} | timeout=${timeout} | api_key=${keyStatus}`;
}
function loadServerCfg() {
return fetch("/api/config")
.then((resp) => (resp.ok ? resp.json() : Promise.reject(new Error("config api unavailable"))))
.then((cfg) => {
serverCfgHint.textContent = `服务端: ${formatCfgLine(cfg)}`;
return cfg;
})
.catch(() => {
serverCfgHint.textContent = "服务端: 读取失败";
return {};
});
}
function refreshEffectiveCfg(serverCfg) {
const local = loadLocalCfg();
const effective = {
base_url: trimText(local.base_url) || trimText(serverCfg.base_url),
model: trimText(local.model) || trimText(serverCfg.model),
timeout: parseTimeout(trimText(local.timeout || serverCfg.timeout)),
api_key: trimText(local.api_key),
};
effectiveCfgHint.textContent = `实际生效: ${formatCfgLine(effective)}${effective.api_key ? "本地覆盖" : "服务端兜底"}`;
}
function loadLocalCfg() {
try {
const raw = localStorage.getItem(API_CONFIG_KEY);
if (!raw) {
return {};
}
return JSON.parse(raw);
} catch {
return {};
}
}
function syncFromStorage() {
const cfg = loadLocalCfg();
aiBaseUrl.value = cfg.base_url || "";
aiApiKey.value = cfg.api_key || "";
aiModel.value = cfg.model || "";
aiTimeout.value = cfg.timeout ? String(cfg.timeout) : "";
apiStatus.textContent = cfg ? "本地配置已加载" : "未保存";
}
function saveConfig() {
const cfg = {
base_url: trimText(aiBaseUrl.value),
api_key: trimText(aiApiKey.value),
model: trimText(aiModel.value),
};
const timeout = parseTimeout(aiTimeout.value);
if (timeout) {
cfg.timeout = timeout;
}
localStorage.setItem(API_CONFIG_KEY, JSON.stringify(cfg));
apiStatus.textContent = "已保存(仅浏览器本地)";
loadServerCfg().then(refreshEffectiveCfg);
}
function clearConfig() {
localStorage.removeItem(API_CONFIG_KEY);
aiBaseUrl.value = "";
aiApiKey.value = "";
aiModel.value = "";
aiTimeout.value = "";
apiStatus.textContent = "已清空";
loadServerCfg().then(refreshEffectiveCfg);
}
document.getElementById("saveApiConfig").addEventListener("click", saveConfig);
document.getElementById("clearApiConfig").addEventListener("click", clearConfig);
(async () => {
const srv = await loadServerCfg();
syncFromStorage();
refreshEffectiveCfg(srv);
})();
</script>
</body>
</html>