203 lines
6.3 KiB
JavaScript
203 lines
6.3 KiB
JavaScript
/**
|
|
* persona-studio · 模式识别引擎
|
|
*
|
|
* 触发:每完成一个项目 + 每日凌晨聚合
|
|
* 功能:从已完成项目中识别高频模式,建立模式库
|
|
*/
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const BRAIN_DIR = path.join(__dirname, '..', '..', 'brain');
|
|
const PATTERN_PATH = path.join(BRAIN_DIR, 'pattern-library.json');
|
|
const MEMORY_DIR = path.join(BRAIN_DIR, 'memory');
|
|
|
|
/**
|
|
* 加载模式库
|
|
*/
|
|
function loadPatternLibrary() {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(PATTERN_PATH, 'utf-8'));
|
|
} catch {
|
|
return {
|
|
schema_version: '1.0',
|
|
description: '系统模式库 · 自动识别',
|
|
last_updated: null,
|
|
total_patterns: 0,
|
|
patterns: []
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 保存模式库
|
|
*/
|
|
function savePatternLibrary(lib) {
|
|
lib.last_updated = new Date().toISOString();
|
|
lib.total_patterns = lib.patterns.length;
|
|
fs.writeFileSync(PATTERN_PATH, JSON.stringify(lib, null, 2), 'utf-8');
|
|
}
|
|
|
|
/**
|
|
* 从项目中检测模式类型
|
|
*/
|
|
function detectPatternType(conversation, projectFiles) {
|
|
const allText = (conversation || [])
|
|
.map(function (m) { return m.content || ''; })
|
|
.join('\n')
|
|
.toLowerCase();
|
|
|
|
const patterns = [];
|
|
|
|
const patternDefs = [
|
|
{ name: '个人博客', keywords: ['博客', 'blog', '文章', '发布', '个人主页'] },
|
|
{ name: '登录注册', keywords: ['登录', '注册', 'login', 'register', '用户认证', '用户系统'] },
|
|
{ name: '管理后台', keywords: ['管理', '后台', 'dashboard', '管理面板', 'admin'] },
|
|
{ name: '电商页面', keywords: ['商城', '购物', '商品', '购买', '电商', 'shop'] },
|
|
{ name: '展示页面', keywords: ['展示', '介绍', '落地页', 'landing', '产品页'] },
|
|
{ name: '数据表格', keywords: ['表格', '数据', '列表', '筛选', 'table', '搜索'] },
|
|
{ name: '表单系统', keywords: ['表单', '提交', '验证', 'form', '输入'] },
|
|
{ name: '聊天应用', keywords: ['聊天', 'chat', '即时通讯', '消息', '对话'] },
|
|
{ name: '小工具', keywords: ['工具', '计算器', '转换器', '生成器', 'tool', 'utility'] },
|
|
{ name: 'API服务', keywords: ['api', '接口', '后端服务', 'restful', 'server'] }
|
|
];
|
|
|
|
patternDefs.forEach(function (def) {
|
|
const matchCount = def.keywords.filter(function (kw) {
|
|
return allText.includes(kw);
|
|
}).length;
|
|
|
|
if (matchCount >= 2) {
|
|
patterns.push(def.name);
|
|
}
|
|
});
|
|
|
|
return patterns.length > 0 ? patterns : ['通用项目'];
|
|
}
|
|
|
|
/**
|
|
* 检测技术栈
|
|
*/
|
|
function detectTechStack(conversation, projectFiles) {
|
|
const allText = (conversation || [])
|
|
.map(function (m) { return m.content || ''; })
|
|
.join('\n')
|
|
.toLowerCase();
|
|
|
|
const stack = [];
|
|
const techMap = {
|
|
'HTML/CSS/JS': ['html', 'css', 'javascript'],
|
|
'React': ['react', 'jsx', 'tsx'],
|
|
'Vue': ['vue', 'vuex'],
|
|
'Node.js': ['node', 'express', 'koa'],
|
|
'Python': ['python', 'flask', 'django'],
|
|
'TypeScript': ['typescript', 'ts'],
|
|
'Tailwind': ['tailwind'],
|
|
'Bootstrap': ['bootstrap']
|
|
};
|
|
|
|
for (const [tech, keywords] of Object.entries(techMap)) {
|
|
if (keywords.some(function (kw) { return allText.includes(kw); })) {
|
|
stack.push(tech);
|
|
}
|
|
}
|
|
|
|
// 从文件扩展名推断
|
|
if (projectFiles && projectFiles.length > 0) {
|
|
const exts = projectFiles.map(function (f) {
|
|
return path.extname(f).toLowerCase();
|
|
});
|
|
|
|
if (exts.includes('.html')) stack.push('HTML/CSS/JS');
|
|
if (exts.includes('.jsx') || exts.includes('.tsx')) stack.push('React');
|
|
if (exts.includes('.vue')) stack.push('Vue');
|
|
if (exts.includes('.py')) stack.push('Python');
|
|
}
|
|
|
|
return [...new Set(stack)];
|
|
}
|
|
|
|
/**
|
|
* 核心方法:分析项目并更新模式库
|
|
* @param {string} devId - 开发者编号
|
|
* @param {Array} conversation - 对话历史
|
|
* @param {Array} projectFiles - 项目文件列表
|
|
* @param {number} buildTimeMs - 构建耗时(毫秒)
|
|
* @param {boolean} success - 是否成功
|
|
*/
|
|
function analyzeAndUpdatePatterns(devId, conversation, projectFiles, buildTimeMs, success) {
|
|
const lib = loadPatternLibrary();
|
|
const patternNames = detectPatternType(conversation, projectFiles);
|
|
const techStack = detectTechStack(conversation, projectFiles);
|
|
|
|
patternNames.forEach(function (patternName) {
|
|
// 查找已有模式
|
|
const existing = lib.patterns.find(function (p) { return p.name === patternName; });
|
|
|
|
if (existing) {
|
|
// 更新已有模式
|
|
existing.frequency = (existing.frequency || 0) + 1;
|
|
existing.common_tech_stack = mergeArrays(existing.common_tech_stack, techStack);
|
|
if (buildTimeMs) {
|
|
existing.avg_build_time = existing.avg_build_time
|
|
? Math.round((existing.avg_build_time + buildTimeMs) / 2)
|
|
: buildTimeMs;
|
|
}
|
|
if (success !== undefined) {
|
|
const totalAttempts = existing.frequency;
|
|
const prevSuccesses = Math.round((existing.success_rate || 100) / 100 * (totalAttempts - 1));
|
|
existing.success_rate = Math.round((prevSuccesses + (success ? 1 : 0)) / totalAttempts * 100);
|
|
}
|
|
existing.last_seen = new Date().toISOString();
|
|
} else {
|
|
// 添加新模式
|
|
lib.patterns.push({
|
|
name: patternName,
|
|
frequency: 1,
|
|
common_features: [],
|
|
common_tech_stack: techStack,
|
|
avg_build_time: buildTimeMs || null,
|
|
success_rate: success !== false ? 100 : 0,
|
|
first_seen: new Date().toISOString(),
|
|
last_seen: new Date().toISOString()
|
|
});
|
|
}
|
|
});
|
|
|
|
savePatternLibrary(lib);
|
|
return patternNames;
|
|
}
|
|
|
|
/**
|
|
* 查询模式库(供 persona-engine 调用)
|
|
* @param {string} query - 搜索关键词
|
|
* @returns {Array} 匹配的模式
|
|
*/
|
|
function queryPatterns(query) {
|
|
const lib = loadPatternLibrary();
|
|
if (!query || lib.patterns.length === 0) return [];
|
|
|
|
const lower = query.toLowerCase();
|
|
|
|
return lib.patterns
|
|
.filter(function (p) {
|
|
return p.name.toLowerCase().includes(lower) ||
|
|
(p.common_tech_stack || []).some(function (t) { return t.toLowerCase().includes(lower); });
|
|
})
|
|
.sort(function (a, b) { return (b.frequency || 0) - (a.frequency || 0); });
|
|
}
|
|
|
|
/**
|
|
* 工具:合并去重数组
|
|
*/
|
|
function mergeArrays(arr1, arr2) {
|
|
return [...new Set((arr1 || []).concat(arr2 || []))];
|
|
}
|
|
|
|
module.exports = {
|
|
analyzeAndUpdatePatterns,
|
|
queryPatterns,
|
|
loadPatternLibrary,
|
|
detectPatternType,
|
|
detectTechStack
|
|
};
|