diff --git a/image-studio/server.js b/image-studio/server.js index 1f0d44b..a29906d 100644 --- a/image-studio/server.js +++ b/image-studio/server.js @@ -1,104 +1,134 @@ /** * ═══════════════════════════════════════════════════ - * 铸渊图片工作室 · Web 服务 + * 铸渊封面工作室 · Web 服务 · v2.0 * ═══════════════════════════════════════════════════ * - * 部署到服务器,冰朔可以在浏览器预览已生成的图片。 - * 我在对话里生成图片后,冰朔可以直接访问链接下载。 + * 公开页面 + 模板列表 API + 生成 API + 下载端点 */ import express from 'express' -import { generate } from './generate.js' +import cors from 'cors' +import { generate, listTemplates } from './generate.js' import { join, dirname } from 'path' import { fileURLToPath } from 'url' -import { readdirSync, existsSync } from 'fs' +import { existsSync, mkdirSync } from 'fs' const __dirname = dirname(fileURLToPath(import.meta.url)) const OUTPUT_DIR = join(__dirname, 'output') +const PUBLIC_DIR = join(__dirname, 'public') const PORT = process.env.PORT || 3912 +// 确保输出目录存在 +if (!existsSync(OUTPUT_DIR)) mkdirSync(OUTPUT_DIR, { recursive: true }) + const app = express() -app.use(express.json()) -/* ── 静态文件服务 ── */ +// ── 中间件 ── +app.use(cors()) +app.use(express.json({ limit: '1mb' })) + +// 静态文件:输出图片 app.use('/output', express.static(OUTPUT_DIR)) +// 静态文件:前端页面(默认首页) +app.use(express.static(PUBLIC_DIR)) -/* ── 首页 · 预览画廊 ── */ -app.get('/', (req, res) => { - let files = [] + +/* ═══════════════════════════════════════════════════ + * API + * ═══════════════════════════════════════════════════ */ + +/** + * GET /api/templates + * 获取所有可用模板列表 + */ +app.get('/api/templates', (req, res) => { try { - if (existsSync(OUTPUT_DIR)) { - files = readdirSync(OUTPUT_DIR) - .filter(f => /\.(png|webp|jpg)$/i.test(f)) - .sort() - .reverse() - } - } catch {} - - const galleryHtml = files.length > 0 - ? files.map(f => - `` - ).join('\n') - : '
还没有生成的图片
在对话里告诉铸渊你想做什么图
' - - res.send(` - - - - -铸渊图片工作室 - - - -

🎨 铸渊图片工作室

-

冰朔 · 你的配图我包了 · 在对话里告诉我内容就行

- - -`) }) -/* ── 生成 API ── */ + +/** + * POST /api/generate + * 生成封面图片 + * + * Body: + * templateId - 模板ID(默认第一个) + * presetId - 预设风格ID + * title - 标题 + * body - 正文 + * subtitle - 副标题(可选) + * tag - 标签(可选) + * layout - 布局(default/hero/quote) + */ app.post('/api/generate', async (req, res) => { try { - const result = await generate(req.body) + const { + templateId, + presetId = '', + title = '', + body = '', + subtitle = '', + tag = '', + layout = 'default', + } = req.body + + if (!title && !body) { + return res.status(400).json({ error: '请至少提供标题或正文内容' }) + } + + const result = await generate({ + templateId, + presetId, + title, + body, + subtitle, + tag, + layout, + }) + + // 构造可访问的 URL + const filename = result.files[0].split('/').pop() + const url = `/output/${filename}` + res.json({ success: true, + url, files: result.files, - urls: result.files.map(f => `/output/${f.split('/').pop()}`), + templateId: result.templateId, + templateName: result.templateName, + presetId: result.presetId, + layout: result.layout, + filename, }) } catch (err) { - res.status(400).json({ success: false, error: err.message }) + console.error('生成失败:', err.message) + res.status(500).json({ error: err.message || '生成失败' }) } }) -app.listen(PORT, () => { - console.log(`🎨 铸渊图片工作室运行在 http://localhost:${PORT}`) + +/** + * GET /api/health + * 健康检查 + */ +app.get('/api/health', (req, res) => { + res.json({ status: 'ok', timestamp: new Date().toISOString() }) +}) + + +// ── 兜底:SPA 路由 ── +app.get('*', (req, res) => { + res.sendFile(join(PUBLIC_DIR, 'index.html')) +}) + + +// ── 启动 ── +app.listen(PORT, () => { + console.log(`🎨 铸渊封面工作室 v2.0 运行在 http://localhost:${PORT}`) + console.log(` 📋 模板API: http://localhost:${PORT}/api/templates`) + console.log(` 🎯 生成API: http://localhost:${PORT}/api/generate`) })