feat: 新增以稿写稿和文章融合功能
- 新增以稿写稿 (MimicWriter) 功能:支持分析文章风格并仿写,包含风格分析、逐段仿写等模式 - 新增文章融合 (ArticleFusion) 功能:支持智能分析两篇文章优劣并生成融合版本 - 新增后端 API 服务器 (Express + SQLite) 用于范式管理 - 更新 .gitignore 忽略运行时数据文件 (data/, *.db) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
130
server/db.js
Normal file
130
server/db.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const DATA_DIR = path.join(__dirname, '../data');
|
||||
const DB_PATH = path.join(DATA_DIR, 'paradigms.db');
|
||||
|
||||
// 确保数据目录存在
|
||||
if (!fs.existsSync(DATA_DIR)) {
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
// 创建数据库连接
|
||||
const db = new Database(DB_PATH);
|
||||
|
||||
// 初始化表结构
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS paradigms (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
icon TEXT DEFAULT 'sparkles',
|
||||
tag_class TEXT DEFAULT 'bg-purple-900/30 text-purple-300',
|
||||
tags TEXT,
|
||||
specialized_prompt TEXT,
|
||||
expert_guidelines TEXT,
|
||||
is_custom INTEGER DEFAULT 1,
|
||||
created_at TEXT,
|
||||
updated_at TEXT
|
||||
)
|
||||
`);
|
||||
|
||||
console.log('📦 SQLite 数据库初始化完成:', DB_PATH);
|
||||
|
||||
// CRUD 方法
|
||||
export function getAllParadigms() {
|
||||
const rows = db.prepare('SELECT * FROM paradigms ORDER BY created_at DESC').all();
|
||||
return rows.map(row => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
description: row.description,
|
||||
icon: row.icon,
|
||||
tagClass: row.tag_class,
|
||||
tags: row.tags ? JSON.parse(row.tags) : [],
|
||||
specializedPrompt: row.specialized_prompt,
|
||||
expertGuidelines: row.expert_guidelines ? JSON.parse(row.expert_guidelines) : [],
|
||||
isCustom: Boolean(row.is_custom),
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at
|
||||
}));
|
||||
}
|
||||
|
||||
export function getParadigmById(id) {
|
||||
const row = db.prepare('SELECT * FROM paradigms WHERE id = ?').get(id);
|
||||
if (!row) return null;
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
description: row.description,
|
||||
icon: row.icon,
|
||||
tagClass: row.tag_class,
|
||||
tags: row.tags ? JSON.parse(row.tags) : [],
|
||||
specializedPrompt: row.specialized_prompt,
|
||||
expertGuidelines: row.expert_guidelines ? JSON.parse(row.expert_guidelines) : [],
|
||||
isCustom: Boolean(row.is_custom),
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at
|
||||
};
|
||||
}
|
||||
|
||||
export function createParadigm(paradigm) {
|
||||
const stmt = db.prepare(`
|
||||
INSERT INTO paradigms (id, name, description, icon, tag_class, tags, specialized_prompt, expert_guidelines, is_custom, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`);
|
||||
|
||||
const now = new Date().toISOString();
|
||||
stmt.run(
|
||||
paradigm.id,
|
||||
paradigm.name,
|
||||
paradigm.description || '',
|
||||
paradigm.icon || 'sparkles',
|
||||
paradigm.tagClass || 'bg-purple-900/30 text-purple-300',
|
||||
JSON.stringify(paradigm.tags || []),
|
||||
paradigm.specializedPrompt || '',
|
||||
JSON.stringify(paradigm.expertGuidelines || []),
|
||||
paradigm.isCustom ? 1 : 0,
|
||||
paradigm.createdAt || now,
|
||||
now
|
||||
);
|
||||
|
||||
return getParadigmById(paradigm.id);
|
||||
}
|
||||
|
||||
export function updateParadigm(id, updates) {
|
||||
const existing = getParadigmById(id);
|
||||
if (!existing) return null;
|
||||
|
||||
const merged = { ...existing, ...updates };
|
||||
const stmt = db.prepare(`
|
||||
UPDATE paradigms
|
||||
SET name = ?, description = ?, icon = ?, tag_class = ?, tags = ?,
|
||||
specialized_prompt = ?, expert_guidelines = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
`);
|
||||
|
||||
stmt.run(
|
||||
merged.name,
|
||||
merged.description,
|
||||
merged.icon,
|
||||
merged.tagClass,
|
||||
JSON.stringify(merged.tags || []),
|
||||
merged.specializedPrompt,
|
||||
JSON.stringify(merged.expertGuidelines || []),
|
||||
new Date().toISOString(),
|
||||
id
|
||||
);
|
||||
|
||||
return getParadigmById(id);
|
||||
}
|
||||
|
||||
export function deleteParadigm(id) {
|
||||
const stmt = db.prepare('DELETE FROM paradigms WHERE id = ?');
|
||||
const result = stmt.run(id);
|
||||
return result.changes > 0;
|
||||
}
|
||||
|
||||
export default db;
|
||||
93
server/index.js
Normal file
93
server/index.js
Normal file
@@ -0,0 +1,93 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import { getAllParadigms, getParadigmById, createParadigm, updateParadigm, deleteParadigm } from './db.js';
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.API_PORT || 3001;
|
||||
|
||||
// 中间件
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// API 路由
|
||||
// 获取所有范式
|
||||
app.get('/api/paradigms', (req, res) => {
|
||||
try {
|
||||
const paradigms = getAllParadigms();
|
||||
res.json({ success: true, data: paradigms });
|
||||
} catch (error) {
|
||||
console.error('获取范式列表失败:', error);
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 获取单个范式
|
||||
app.get('/api/paradigms/:id', (req, res) => {
|
||||
try {
|
||||
const paradigm = getParadigmById(req.params.id);
|
||||
if (!paradigm) {
|
||||
return res.status(404).json({ success: false, error: '范式不存在' });
|
||||
}
|
||||
res.json({ success: true, data: paradigm });
|
||||
} catch (error) {
|
||||
console.error('获取范式失败:', error);
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 创建范式
|
||||
app.post('/api/paradigms', (req, res) => {
|
||||
try {
|
||||
const paradigm = createParadigm(req.body);
|
||||
console.log('✅ 创建范式:', paradigm.name);
|
||||
res.status(201).json({ success: true, data: paradigm });
|
||||
} catch (error) {
|
||||
console.error('创建范式失败:', error);
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 更新范式
|
||||
app.put('/api/paradigms/:id', (req, res) => {
|
||||
try {
|
||||
const paradigm = updateParadigm(req.params.id, req.body);
|
||||
if (!paradigm) {
|
||||
return res.status(404).json({ success: false, error: '范式不存在' });
|
||||
}
|
||||
console.log('✅ 更新范式:', paradigm.name);
|
||||
res.json({ success: true, data: paradigm });
|
||||
} catch (error) {
|
||||
console.error('更新范式失败:', error);
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 删除范式
|
||||
app.delete('/api/paradigms/:id', (req, res) => {
|
||||
try {
|
||||
const deleted = deleteParadigm(req.params.id);
|
||||
if (!deleted) {
|
||||
return res.status(404).json({ success: false, error: '范式不存在' });
|
||||
}
|
||||
console.log('✅ 删除范式:', req.params.id);
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('删除范式失败:', error);
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 健康检查
|
||||
app.get('/api/health', (req, res) => {
|
||||
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
||||
});
|
||||
|
||||
// 启动服务器
|
||||
app.listen(PORT, () => {
|
||||
console.log(`🚀 API 服务器已启动: http://localhost:${PORT}`);
|
||||
console.log(` - GET /api/paradigms`);
|
||||
console.log(` - GET /api/paradigms/:id`);
|
||||
console.log(` - POST /api/paradigms`);
|
||||
console.log(` - PUT /api/paradigms/:id`);
|
||||
console.log(` - DELETE /api/paradigms/:id`);
|
||||
});
|
||||
Reference in New Issue
Block a user