Files
ai-write/server/db.js

890 lines
27 KiB
JavaScript

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.pragma('journal_mode = WAL');
db.exec(`
CREATE TABLE IF NOT EXISTS materials (
id TEXT PRIMARY KEY,
type TEXT NOT NULL,
title TEXT NOT NULL,
source TEXT,
date TEXT,
tags TEXT,
related_dimension_sets TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_default INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS reference_excerpts (
id TEXT PRIMARY KEY,
reference_id TEXT NOT NULL,
topic TEXT NOT NULL,
content TEXT NOT NULL,
applicable_dimensions TEXT,
use_for TEXT,
FOREIGN KEY (reference_id) REFERENCES materials(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS paradigms (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
icon TEXT,
description TEXT,
tags TEXT,
tag_class TEXT,
system_constraints TEXT,
dimension_set_id TEXT,
custom_dimensions TEXT,
logic_paradigms TEXT,
auto_match_refs INTEGER DEFAULT 1,
selected_refs TEXT,
specialized_prompt TEXT,
expert_guidelines TEXT,
outline_template TEXT,
recommended_tags TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_custom INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS dimension_sets (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
applicable_for TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_custom INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS dimensions (
id TEXT PRIMARY KEY,
dimension_set_id TEXT NOT NULL,
name TEXT NOT NULL,
focus TEXT,
keywords TEXT,
negative_keywords TEXT,
positive_benchmark TEXT,
sort_order INTEGER DEFAULT 0,
FOREIGN KEY (dimension_set_id) REFERENCES dimension_sets(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS user_config (
key TEXT PRIMARY KEY,
value TEXT,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS analysis_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
paradigm_id TEXT,
input_text TEXT,
result TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS documents (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
paradigm_id TEXT,
dimension_set_id TEXT,
selected_refs TEXT,
status TEXT DEFAULT 'draft',
word_count INTEGER DEFAULT 0,
tags TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS document_versions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
document_id TEXT NOT NULL,
content TEXT,
version_number INTEGER,
change_note TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS outline_materials (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
content TEXT NOT NULL,
word_count INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`);
const ensureColumn = (table, column, definition) => {
const columns = db.prepare(`PRAGMA table_info(${table})`).all();
const exists = columns.some(col => col.name === column);
if (!exists) {
try {
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
} catch (error) {
console.warn(`⚠️ 字段迁移失败: ${table}.${column}`, error.message);
}
}
};
const ensureSchema = () => {
ensureColumn('paradigms', 'system_constraints', 'TEXT');
ensureColumn('paradigms', 'dimension_set_id', 'TEXT');
ensureColumn('paradigms', 'custom_dimensions', 'TEXT');
ensureColumn('paradigms', 'logic_paradigms', 'TEXT');
ensureColumn('paradigms', 'auto_match_refs', 'INTEGER DEFAULT 1');
ensureColumn('paradigms', 'selected_refs', 'TEXT');
ensureColumn('paradigms', 'outline_template', 'TEXT');
ensureColumn('paradigms', 'recommended_tags', 'TEXT');
ensureColumn('paradigms', 'tag_class', "TEXT");
ensureColumn('paradigms', 'tags', 'TEXT');
ensureColumn('paradigms', 'specialized_prompt', 'TEXT');
ensureColumn('paradigms', 'expert_guidelines', 'TEXT');
ensureColumn('paradigms', 'is_custom', 'INTEGER DEFAULT 0');
ensureColumn('paradigms', 'created_at', 'TEXT');
ensureColumn('paradigms', 'updated_at', 'TEXT');
};
ensureSchema();
const parseJson = (value, fallback) => {
if (!value) return fallback;
try {
return JSON.parse(value);
} catch {
return fallback;
}
};
const getExcerptsByReferenceId = (referenceId) => {
const rows = db.prepare('SELECT * FROM reference_excerpts WHERE reference_id = ?').all(referenceId);
return rows.map(row => ({
...row,
applicableDimensions: parseJson(row.applicable_dimensions, []),
useFor: row.use_for || null
}));
};
const seedDefaultReferences = async () => {
const count = db.prepare('SELECT COUNT(*) as count FROM materials').get().count;
if (count > 0) return;
try {
const { REFERENCES } = await import('../src/config/references.js');
const insertMaterial = db.prepare(`
INSERT INTO materials (id, type, title, source, date, tags, related_dimension_sets, is_default)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`);
const insertExcerpt = db.prepare(`
INSERT INTO reference_excerpts (id, reference_id, topic, content, applicable_dimensions, use_for)
VALUES (?, ?, ?, ?, ?, ?)
`);
const insertMany = db.transaction((items) => {
items.forEach((ref) => {
insertMaterial.run(
ref.id,
ref.type,
ref.title,
ref.source || null,
ref.date || null,
JSON.stringify(ref.tags || []),
JSON.stringify(ref.relatedDimensionSets || []),
1
);
if (ref.excerpts?.length) {
ref.excerpts.forEach((excerpt, index) => {
insertExcerpt.run(
excerpt.id || `${ref.id}-excerpt-${index}`,
ref.id,
excerpt.topic,
excerpt.content,
JSON.stringify(excerpt.applicableDimensions || []),
excerpt.useFor || null
);
});
}
});
});
insertMany(Object.values(REFERENCES));
console.log('✅ 默认素材导入完成');
} catch (error) {
console.warn('⚠️ 默认素材导入失败:', error.message);
}
};
await seedDefaultReferences();
/**
* 同步现有的提纲素材到通用素材库
*/
const syncExistingOutlineMaterials = () => {
try {
const materials = db.prepare('SELECT * FROM outline_materials').all();
if (materials.length === 0) return;
console.log(`🔍 正在同步 ${materials.length} 个存量提纲素材到通用素材库...`);
db.transaction(() => {
materials.forEach(mat => {
syncToReferences(mat.id, mat.name, mat.content);
});
})();
console.log(`✅ 存量提纲素材同步完成`);
} catch (err) {
console.error('⚠️ 同步存量素材失败:', err.message);
}
};
syncExistingOutlineMaterials();
console.log('📦 SQLite 数据库初始化完成:', DB_PATH);
export function getAllReferences() {
const refs = db.prepare('SELECT * FROM materials ORDER BY created_at DESC').all();
return refs.map(ref => ({
...ref,
tags: parseJson(ref.tags, []),
relatedDimensionSets: parseJson(ref.related_dimension_sets, []),
excerpts: getExcerptsByReferenceId(ref.id)
}));
}
export function getReferenceById(id) {
const ref = db.prepare('SELECT * FROM materials WHERE id = ?').get(id);
if (!ref) return null;
return {
...ref,
tags: parseJson(ref.tags, []),
relatedDimensionSets: parseJson(ref.related_dimension_sets, []),
excerpts: getExcerptsByReferenceId(ref.id)
};
}
export function getReferencesByType(type) {
const refs = db.prepare('SELECT * FROM materials WHERE type = ? ORDER BY created_at DESC').all(type);
return refs.map(ref => ({
...ref,
tags: parseJson(ref.tags, []),
relatedDimensionSets: parseJson(ref.related_dimension_sets, []),
excerpts: getExcerptsByReferenceId(ref.id)
}));
}
export function addReference(reference) {
const id = reference.id || `ref-${Date.now()}`;
db.prepare(`
INSERT INTO materials (id, type, title, source, date, tags, related_dimension_sets, is_default)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`).run(
id,
reference.type,
reference.title,
reference.source || null,
reference.date || null,
JSON.stringify(reference.tags || []),
JSON.stringify(reference.relatedDimensionSets || []),
reference.isDefault ? 1 : 0
);
if (reference.excerpts?.length) {
const insertExcerpt = db.prepare(`
INSERT INTO reference_excerpts (id, reference_id, topic, content, applicable_dimensions, use_for)
VALUES (?, ?, ?, ?, ?, ?)
`);
reference.excerpts.forEach((excerpt, index) => {
insertExcerpt.run(
excerpt.id || `${id}-excerpt-${index}`,
id,
excerpt.topic,
excerpt.content,
JSON.stringify(excerpt.applicableDimensions || []),
excerpt.useFor || null
);
});
}
return id;
}
export function updateReference(id, updates) {
const setClauses = [];
const params = [];
if (updates.type !== undefined) {
setClauses.push('type = ?');
params.push(updates.type);
}
if (updates.title !== undefined) {
setClauses.push('title = ?');
params.push(updates.title);
}
if (updates.source !== undefined) {
setClauses.push('source = ?');
params.push(updates.source);
}
if (updates.tags !== undefined) {
setClauses.push('tags = ?');
params.push(JSON.stringify(updates.tags));
}
if (updates.relatedDimensionSets !== undefined) {
setClauses.push('related_dimension_sets = ?');
params.push(JSON.stringify(updates.relatedDimensionSets));
}
setClauses.push('updated_at = CURRENT_TIMESTAMP');
params.push(id);
db.prepare(`UPDATE materials SET ${setClauses.join(', ')} WHERE id = ?`).run(...params);
return true;
}
export function deleteReference(id) {
db.prepare('DELETE FROM reference_excerpts WHERE reference_id = ?').run(id);
db.prepare('DELETE FROM materials WHERE id = ?').run(id);
return true;
}
export function getAllParadigms() {
const paradigms = db.prepare('SELECT * FROM paradigms ORDER BY is_custom ASC, created_at DESC').all();
return paradigms.map(p => ({
...p,
tagClass: p.tag_class || 'bg-blue-900/30 text-blue-300',
tags: parseJson(p.tags, []),
systemConstraints: parseJson(p.system_constraints, []),
customDimensions: parseJson(p.custom_dimensions, null),
logicParadigms: parseJson(p.logic_paradigms, null),
selectedRefs: parseJson(p.selected_refs, []),
specializedPrompt: p.specialized_prompt || null,
expertGuidelines: parseJson(p.expert_guidelines, null),
outlineTemplate: p.outline_template || null,
recommendedTags: parseJson(p.recommended_tags, []),
isCustom: p.is_custom === 1,
autoMatchRefs: p.auto_match_refs === 1
}));
}
export function getParadigmById(id) {
const p = db.prepare('SELECT * FROM paradigms WHERE id = ?').get(id);
if (!p) return null;
return {
...p,
tagClass: p.tag_class || 'bg-blue-900/30 text-blue-300',
tags: parseJson(p.tags, []),
systemConstraints: parseJson(p.system_constraints, []),
customDimensions: parseJson(p.custom_dimensions, null),
logicParadigms: parseJson(p.logic_paradigms, null),
selectedRefs: parseJson(p.selected_refs, []),
specializedPrompt: p.specialized_prompt || null,
expertGuidelines: parseJson(p.expert_guidelines, null),
outlineTemplate: p.outline_template || null,
recommendedTags: parseJson(p.recommended_tags, []),
isCustom: p.is_custom === 1,
autoMatchRefs: p.auto_match_refs === 1
};
}
export function addParadigm(paradigm) {
const id = paradigm.id || `paradigm-${Date.now()}`;
db.prepare(`
INSERT INTO paradigms (id, name, icon, description, tags, tag_class, system_constraints,
dimension_set_id, custom_dimensions, logic_paradigms, auto_match_refs, selected_refs,
specialized_prompt, expert_guidelines, outline_template, recommended_tags, is_custom)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
id,
paradigm.name,
paradigm.icon || '📝',
paradigm.description || null,
JSON.stringify(paradigm.tags || []),
paradigm.tagClass || 'bg-blue-900/30 text-blue-300',
JSON.stringify(paradigm.systemConstraints || []),
paradigm.dimensionSetId || null,
paradigm.customDimensions ? JSON.stringify(paradigm.customDimensions) : null,
paradigm.logicParadigms ? JSON.stringify(paradigm.logicParadigms) : null,
paradigm.autoMatchRefs !== false ? 1 : 0,
JSON.stringify(paradigm.selectedRefs || []),
paradigm.specializedPrompt || null,
paradigm.expertGuidelines ? JSON.stringify(paradigm.expertGuidelines) : null,
paradigm.outlineTemplate || null,
paradigm.recommendedTags ? JSON.stringify(paradigm.recommendedTags || []) : null,
paradigm.isCustom ? 1 : 0
);
return id;
}
export function updateParadigm(id, updates) {
const setClauses = [];
const params = [];
const fieldMap = {
name: 'name',
icon: 'icon',
description: 'description',
tagClass: 'tag_class',
dimensionSetId: 'dimension_set_id',
autoMatchRefs: 'auto_match_refs'
};
Object.entries(updates).forEach(([key, value]) => {
if (fieldMap[key]) {
setClauses.push(`${fieldMap[key]} = ?`);
params.push(key === 'autoMatchRefs' ? (value ? 1 : 0) : value);
}
});
if (updates.tags !== undefined) {
setClauses.push('tags = ?');
params.push(JSON.stringify(updates.tags));
}
if (updates.systemConstraints !== undefined) {
setClauses.push('system_constraints = ?');
params.push(JSON.stringify(updates.systemConstraints));
}
if (updates.customDimensions !== undefined) {
setClauses.push('custom_dimensions = ?');
params.push(updates.customDimensions ? JSON.stringify(updates.customDimensions) : null);
}
if (updates.logicParadigms !== undefined) {
setClauses.push('logic_paradigms = ?');
params.push(updates.logicParadigms ? JSON.stringify(updates.logicParadigms) : null);
}
if (updates.selectedRefs !== undefined) {
setClauses.push('selected_refs = ?');
params.push(JSON.stringify(updates.selectedRefs));
}
if (updates.specializedPrompt !== undefined) {
setClauses.push('specialized_prompt = ?');
params.push(updates.specializedPrompt);
}
if (updates.expertGuidelines !== undefined) {
setClauses.push('expert_guidelines = ?');
params.push(updates.expertGuidelines ? JSON.stringify(updates.expertGuidelines) : null);
}
if (updates.outlineTemplate !== undefined) {
setClauses.push('outline_template = ?');
params.push(updates.outlineTemplate);
}
if (updates.recommendedTags !== undefined) {
setClauses.push('recommended_tags = ?');
params.push(updates.recommendedTags ? JSON.stringify(updates.recommendedTags) : null);
}
setClauses.push('updated_at = CURRENT_TIMESTAMP');
params.push(id);
db.prepare(`UPDATE paradigms SET ${setClauses.join(', ')} WHERE id = ?`).run(...params);
return true;
}
export function deleteParadigm(id) {
db.prepare('DELETE FROM paradigms WHERE id = ?').run(id);
return true;
}
export function getConfig(key, defaultValue = null) {
const result = db.prepare('SELECT value FROM user_config WHERE key = ?').get(key);
if (!result) return defaultValue;
return parseJson(result.value, result.value);
}
export function setConfig(key, value) {
const valueStr = typeof value === 'string' ? value : JSON.stringify(value);
db.prepare(`
INSERT INTO user_config (key, value, updated_at)
VALUES (?, ?, CURRENT_TIMESTAMP)
ON CONFLICT(key) DO UPDATE SET value = ?, updated_at = CURRENT_TIMESTAMP
`).run(key, valueStr, valueStr);
return true;
}
export function getAllDocuments() {
const docs = db.prepare('SELECT * FROM documents ORDER BY updated_at DESC').all();
return docs.map(doc => ({
...doc,
tags: parseJson(doc.tags, []),
selectedRefs: parseJson(doc.selected_refs, [])
}));
}
export function getDocumentById(id) {
const doc = db.prepare('SELECT * FROM documents WHERE id = ?').get(id);
if (!doc) return null;
return {
...doc,
tags: parseJson(doc.tags, []),
selectedRefs: parseJson(doc.selected_refs, []),
versions: getDocumentVersions(id)
};
}
export function getDocumentVersions(documentId) {
return db.prepare('SELECT * FROM document_versions WHERE document_id = ? ORDER BY version_number DESC').all(documentId);
}
export function createDocument(document) {
const id = document.id || `doc-${Date.now()}`;
db.prepare(`
INSERT INTO documents (id, title, content, paradigm_id, dimension_set_id, selected_refs, status, word_count, tags)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
id,
document.title || '未命名文稿',
document.content || '',
document.paradigmId || null,
document.dimensionSetId || null,
JSON.stringify(document.selectedRefs || []),
document.status || 'draft',
document.wordCount || 0,
JSON.stringify(document.tags || [])
);
return id;
}
export function updateDocument(id, updates) {
const setClauses = [];
const params = [];
if (updates.title !== undefined) {
setClauses.push('title = ?');
params.push(updates.title);
}
if (updates.content !== undefined) {
setClauses.push('content = ?');
params.push(updates.content);
setClauses.push('word_count = ?');
params.push(updates.content.length);
}
if (updates.paradigmId !== undefined) {
setClauses.push('paradigm_id = ?');
params.push(updates.paradigmId);
}
if (updates.dimensionSetId !== undefined) {
setClauses.push('dimension_set_id = ?');
params.push(updates.dimensionSetId);
}
if (updates.status !== undefined) {
setClauses.push('status = ?');
params.push(updates.status);
}
if (updates.tags !== undefined) {
setClauses.push('tags = ?');
params.push(JSON.stringify(updates.tags));
}
if (updates.selectedRefs !== undefined) {
setClauses.push('selected_refs = ?');
params.push(JSON.stringify(updates.selectedRefs));
}
setClauses.push('updated_at = CURRENT_TIMESTAMP');
params.push(id);
db.prepare(`UPDATE documents SET ${setClauses.join(', ')} WHERE id = ?`).run(...params);
return true;
}
export function saveDocumentVersion(documentId, content, changeNote = '') {
const result = db.prepare('SELECT MAX(version_number) as max_version FROM document_versions WHERE document_id = ?').get(documentId);
const nextVersion = (result?.max_version || 0) + 1;
db.prepare(`
INSERT INTO document_versions (document_id, content, version_number, change_note)
VALUES (?, ?, ?, ?)
`).run(documentId, content, nextVersion, changeNote);
return nextVersion;
}
export function deleteDocument(id) {
db.prepare('DELETE FROM document_versions WHERE document_id = ?').run(id);
db.prepare('DELETE FROM documents WHERE id = ?').run(id);
return true;
}
export function clearDocuments() {
db.prepare('DELETE FROM document_versions').run();
db.prepare('DELETE FROM documents').run();
return true;
}
export function getDocumentsByStatus(status) {
const docs = db.prepare('SELECT * FROM documents WHERE status = ? ORDER BY updated_at DESC').all(status);
return docs.map(doc => ({
...doc,
tags: parseJson(doc.tags, []),
selectedRefs: parseJson(doc.selected_refs, [])
}));
}
export function getAllOutlineMaterials() {
return db.prepare('SELECT * FROM outline_materials ORDER BY created_at DESC').all();
}
/**
* 将提纲素材同步到通用素材库 (materials/excerpts)
* 提纲素材作为 'outline' 类型存储,便于在通用素材库中管理
*/
const syncToReferences = (id, name, content) => {
const refId = `ref-${id}`; // 使用固定前缀关联
// 1. 更新或插入到 materials 表
db.prepare(`
INSERT INTO materials (id, type, title, source, is_default, created_at, updated_at)
VALUES (?, 'outline', ?, '提纲写作', 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
ON CONFLICT(id) DO UPDATE SET
title = EXCLUDED.title,
updated_at = CURRENT_TIMESTAMP
`).run(refId, name);
// 2. 更新或插入到 reference_excerpts 表
const excerptId = `${refId}-content`;
db.prepare(`
INSERT INTO reference_excerpts (id, reference_id, topic, content)
VALUES (?, ?, '正文', ?)
ON CONFLICT(id) DO UPDATE SET
content = EXCLUDED.content
`).run(excerptId, refId, content);
};
export function addOutlineMaterial(material) {
const id = material.id || `omat-${Date.now()}`;
db.prepare(`
INSERT INTO outline_materials (id, name, content, word_count)
VALUES (?, ?, ?, ?)
`).run(
id,
material.name,
material.content,
material.content?.length || 0
);
// 同步到通用素材库
try {
syncToReferences(id, material.name, material.content);
} catch (err) {
console.error('同步素材到通用库失败:', err);
}
return id;
}
export function updateOutlineMaterial(id, updates) {
const setClauses = [];
const params = [];
if (updates.name !== undefined) {
setClauses.push('name = ?');
params.push(updates.name);
}
if (updates.content !== undefined) {
setClauses.push('content = ?');
params.push(updates.content);
setClauses.push('word_count = ?');
params.push(updates.content?.length || 0);
}
setClauses.push('updated_at = CURRENT_TIMESTAMP');
params.push(id);
db.prepare(`UPDATE outline_materials SET ${setClauses.join(', ')} WHERE id = ?`).run(...params);
// 如果更新了名称或内容,需要同步
try {
const current = db.prepare('SELECT * FROM outline_materials WHERE id = ?').get(id);
if (current) {
syncToReferences(id, current.name, current.content);
}
} catch (err) {
console.error('更新素材同步失败:', err);
}
return true;
}
export function deleteOutlineMaterial(id) {
db.prepare('DELETE FROM outline_materials WHERE id = ?').run(id);
// 同时从通用库删除 (如果存在)
try {
const refId = `ref-${id}`;
db.prepare('DELETE FROM reference_excerpts WHERE reference_id = ?').run(refId);
db.prepare('DELETE FROM materials WHERE id = ?').run(refId);
} catch (err) {
console.error('删除素材同步失败:', err);
}
return true;
}
export function exportDatabase() {
return fs.readFileSync(DB_PATH);
}
export function exportAsJSON() {
return {
references: getAllReferences(),
paradigms: getAllParadigms(),
documents: getAllDocuments(),
config: db.prepare('SELECT * FROM user_config').all(),
exportedAt: new Date().toISOString()
};
}
export async function resetDatabase() {
db.exec(`
DROP TABLE IF EXISTS reference_excerpts;
DROP TABLE IF EXISTS materials;
DROP TABLE IF EXISTS paradigms;
DROP TABLE IF EXISTS dimension_sets;
DROP TABLE IF EXISTS dimensions;
DROP TABLE IF EXISTS user_config;
DROP TABLE IF EXISTS analysis_history;
DROP TABLE IF EXISTS documents;
DROP TABLE IF EXISTS document_versions;
DROP TABLE IF EXISTS outline_materials;
`);
db.exec(`
CREATE TABLE IF NOT EXISTS materials (
id TEXT PRIMARY KEY,
type TEXT NOT NULL,
title TEXT NOT NULL,
source TEXT,
date TEXT,
tags TEXT,
related_dimension_sets TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_default INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS reference_excerpts (
id TEXT PRIMARY KEY,
reference_id TEXT NOT NULL,
topic TEXT NOT NULL,
content TEXT NOT NULL,
applicable_dimensions TEXT,
use_for TEXT,
FOREIGN KEY (reference_id) REFERENCES materials(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS paradigms (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
icon TEXT,
description TEXT,
tags TEXT,
tag_class TEXT,
system_constraints TEXT,
dimension_set_id TEXT,
custom_dimensions TEXT,
logic_paradigms TEXT,
auto_match_refs INTEGER DEFAULT 1,
selected_refs TEXT,
specialized_prompt TEXT,
expert_guidelines TEXT,
outline_template TEXT,
recommended_tags TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_custom INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS dimension_sets (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
applicable_for TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_custom INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS dimensions (
id TEXT PRIMARY KEY,
dimension_set_id TEXT NOT NULL,
name TEXT NOT NULL,
focus TEXT,
keywords TEXT,
negative_keywords TEXT,
positive_benchmark TEXT,
sort_order INTEGER DEFAULT 0,
FOREIGN KEY (dimension_set_id) REFERENCES dimension_sets(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS user_config (
key TEXT PRIMARY KEY,
value TEXT,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS analysis_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
paradigm_id TEXT,
input_text TEXT,
result TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS documents (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
paradigm_id TEXT,
dimension_set_id TEXT,
selected_refs TEXT,
status TEXT DEFAULT 'draft',
word_count INTEGER DEFAULT 0,
tags TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS document_versions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
document_id TEXT NOT NULL,
content TEXT,
version_number INTEGER,
change_note TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS outline_materials (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
content TEXT NOT NULL,
word_count INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`);
await seedDefaultReferences();
console.log('🔄 数据库已重置并恢复默认数据');
return true;
}
export default db;