/** * 铸渊封面工作室 · Web 服务 · v2.1 * 公开页面 + 模板列表 API + 生成 API + 意图链 + 下载端点 */ import express from 'express' import cors from 'cors' import { generate, listTemplates } from './generate.js' import { join, dirname } from 'path' import { fileURLToPath } from 'url' 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(cors()) app.use(express.json({ limit: '1mb' })) app.use('/output', express.static(OUTPUT_DIR)) app.use(express.static(PUBLIC_DIR)) app.get('/api/templates', (req, res) => { try { res.json(listTemplates()) } catch (err) { res.status(500).json({ error: '无法加载模板列表' }) } }) app.post('/api/generate', async (req, res) => { try { 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 }) const filename = result.files[0].split('/').pop() const url = `/output/${filename}` res.json({ success: true, url, filename, templateId: result.templateId, templateName: result.templateName, presetId: result.presetId, layout: result.layout, intent_chain: result.intent_chain, }) } catch (err) { console.error('生成失败:', err.message) res.status(500).json({ error: err.message || '生成失败' }) } }) app.get('/api/health', (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString() }) }) app.get('*', (req, res) => { res.sendFile(join(PUBLIC_DIR, 'index.html')) }) app.listen(PORT, () => { console.log(`🎨 铸渊封面工作室 v2.1 运行在 http://localhost:${PORT}`) })