diff --git a/app.js b/app.js index 6b817c2..343bc05 100644 --- a/app.js +++ b/app.js @@ -7,13 +7,19 @@ const fs = require('fs'); const PORT = 8195; const HOST = '0.0.0.0'; +const app = express(); +app.use(express.json()); +app.use(express.static(__dirname)); + +// ── Config ────────────────────────────────────────────────────── + const CONFIG_FILE = path.join(__dirname, 'config.json'); function loadConfig() { try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch { - return { apiKey: '', baseUrl: 'https://api.minimaxi.com' }; + return { baseUrl: 'https://api.minimaxi.com' }; } } @@ -21,23 +27,17 @@ function saveConfig(cfg) { fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2)); } -const app = express(); -app.use(express.json()); -app.use(express.static(__dirname)); - -// ── Config ────────────────────────────────────────────────────── - app.get('/api/config', (req, res) => { const cfg = loadConfig(); - res.json({ hasApiKey: !!cfg.apiKey, baseUrl: cfg.baseUrl || 'https://api.minimaxi.com' }); + res.json({ baseUrl: cfg.baseUrl || 'https://api.minimaxi.com' }); }); app.post('/api/config', (req, res) => { - const { apiKey, baseUrl } = req.body; - if (typeof apiKey !== 'string' || typeof baseUrl !== 'string') { + const { baseUrl } = req.body; + if (typeof baseUrl !== 'string') { return res.status(400).json({ error: '参数格式错误' }); } - const cfg = { apiKey: apiKey.trim(), baseUrl: baseUrl.trim() || 'https://api.minimaxi.com' }; + const cfg = { baseUrl: baseUrl.trim() || 'https://api.minimaxi.com' }; saveConfig(cfg); res.json({ ok: true }); }); @@ -46,9 +46,9 @@ app.post('/api/config', (req, res) => { app.post('/api/generate', async (req, res) => { const { - model, prompt, style, aspect_ratio, + model, prompt, aspect_ratio, width, height, response_format, seed, - n, prompt_optimizer, aigc_watermark, + n, prompt_optimizer, aigc_watermark, apiKey, } = req.body; // Validation @@ -58,9 +58,7 @@ app.post('/api/generate', async (req, res) => { if (model !== 'image-01') { return res.status(400).json({ error: 'model 参数无效' }); } - - const cfg = loadConfig(); - if (!cfg.apiKey) { + if (!apiKey || typeof apiKey !== 'string') { return res.status(400).json({ error: '未配置 API Key,请先在设置中填写。' }); } @@ -78,7 +76,7 @@ app.post('/api/generate', async (req, res) => { if (prompt_optimizer) payload.prompt_optimizer = true; if (aigc_watermark) payload.aigc_watermark = true; - const baseUrl = cfg.baseUrl || 'https://api.minimaxi.com'; + const baseUrl = loadConfig().baseUrl || 'https://api.minimaxi.com'; const endpoint = `${baseUrl}/v1/image_generation`; let response; @@ -86,7 +84,7 @@ app.post('/api/generate', async (req, res) => { response = await fetch(endpoint, { method: 'POST', headers: { - 'Authorization': `Bearer ${cfg.apiKey}`, + 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, body: JSON.stringify(payload), @@ -117,14 +115,14 @@ app.post('/api/generate', async (req, res) => { // ── Task Status (future-proofing) ─────────────────────────────── app.get('/api/task/:id', async (req, res) => { - const cfg = loadConfig(); - if (!cfg.apiKey) { - return res.status(400).json({ error: '未配置 API Key。' }); + const apiKey = req.headers['x-api-key']; + if (!apiKey) { + return res.status(400).json({ error: '缺少 API Key。' }); } - const baseUrl = cfg.baseUrl || 'https://api.minimaxi.com'; + const baseUrl = loadConfig().baseUrl || 'https://api.minimaxi.com'; try { const response = await fetch(`${baseUrl}/v1/image_generation/${req.params.id}`, { - headers: { 'Authorization': `Bearer ${cfg.apiKey}` }, + headers: { 'Authorization': `Bearer ${apiKey}` }, }); const data = await response.json(); if (!response.ok) { diff --git a/index.html b/index.html index ee27660..225a79b 100644 --- a/index.html +++ b/index.html @@ -262,7 +262,7 @@ -

请从 platform.minimaxi.com 获取

+

存储在浏览器本地,不会上传服务器。获取 API Key →

diff --git a/ui.js b/ui.js index a19127b..4e8ed3d 100644 --- a/ui.js +++ b/ui.js @@ -89,11 +89,12 @@ function buildPayload() { const height = heightInput.value ? parseInt(heightInput.value) : undefined; const payload = { - model: currentModel, - prompt: promptInput.value.trim(), - aspect_ratio: aspectRatio.value, + model: currentModel, + prompt: promptInput.value.trim(), + aspect_ratio: aspectRatio.value, response_format: responseFormat.value, - n: n, + n: n, + apiKey: localStorage.getItem('imgGen-apiKey') || '', }; if (seed) payload.seed = seed; @@ -179,11 +180,11 @@ async function copySrc(src, fmt, btn) { // ── Init ──────────────────────────────────────────────────────── async function init() { - try { - const cfg = await api('/api/config'); - if (!cfg.hasApiKey) apiKeyAlert.style.display = 'flex'; - baseUrlInput.value = cfg.baseUrl || 'https://api.minimaxi.com'; - } catch { /* non-fatal */ } + const savedKey = localStorage.getItem('imgGen-apiKey') || ''; + const savedBaseUrl = localStorage.getItem('imgGen-baseUrl') || 'https://api.minimaxi.com'; + if (!savedKey) apiKeyAlert.style.display = 'flex'; + apiKeyInput.value = savedKey; + baseUrlInput.value = savedBaseUrl; } // ── Generate ──────────────────────────────────────────────────── @@ -269,17 +270,12 @@ saveSettingsBtn.addEventListener('click', async () => { clearError(); const apiKey = apiKeyInput.value.trim(); const baseUrl = baseUrlInput.value.trim() || 'https://api.minimaxi.com'; - try { - await api('/api/config', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ apiKey, baseUrl }), - }); - if (apiKey) apiKeyAlert.style.display = 'none'; - closeModal(); - } catch (err) { - showError(err.message); - } + + localStorage.setItem('imgGen-apiKey', apiKey); + localStorage.setItem('imgGen-baseUrl', baseUrl); + + if (apiKey) apiKeyAlert.style.display = 'none'; + closeModal(); }); // ── Theme switcher ─────────────────────────────────────────────