202 lines
6.2 KiB
JavaScript
202 lines
6.2 KiB
JavaScript
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
const portraitEngine = require('../portrait/portrait-engine');
|
|||
|
|
const pcaCalculator = require('../pca/pca-calculator');
|
|||
|
|
|
|||
|
|
// 同步引擎(Phase3已有的,这里简单模拟)
|
|||
|
|
const syncEngine = {
|
|||
|
|
syncAfterSyslog: (syslogData) => {
|
|||
|
|
console.log(`[SYNC] 同步数据: ${syslogData.session_id}`);
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
nodes: ['node1', 'node2', 'node3'],
|
|||
|
|
timestamp: new Date().toISOString()
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const LOG_PATH = path.join(__dirname, '../data/loop-history.json');
|
|||
|
|
|
|||
|
|
// 初始化日志文件
|
|||
|
|
function initLog() {
|
|||
|
|
if (!fs.existsSync(path.join(__dirname, '../data'))) {
|
|||
|
|
fs.mkdirSync(path.join(__dirname, '../data'));
|
|||
|
|
}
|
|||
|
|
if (!fs.existsSync(LOG_PATH)) {
|
|||
|
|
fs.writeFileSync(LOG_PATH, JSON.stringify([]));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成调度建议
|
|||
|
|
function generateSuggestion(pcaResult, status) {
|
|||
|
|
const { grade, totalScore, dimensions } = pcaResult;
|
|||
|
|
const suggestions = [];
|
|||
|
|
|
|||
|
|
// 根据等级和完成状态给出建议
|
|||
|
|
if (status === 'completed') {
|
|||
|
|
if (grade === 'S' || grade === 'A') {
|
|||
|
|
suggestions.push('🎯 可进更高难度:EL-9 挑战');
|
|||
|
|
suggestions.push('📈 推荐模块:M-ADVANCED·高级算法');
|
|||
|
|
} else if (grade === 'B') {
|
|||
|
|
suggestions.push('📚 继续当前模块:巩固 Phase4 基础');
|
|||
|
|
suggestions.push('💪 建议增加代码量,提升TEC维度');
|
|||
|
|
} else {
|
|||
|
|
suggestions.push('🔄 建议降难度:回顾 Phase3 核心概念');
|
|||
|
|
suggestions.push('🧘 休息调整,保持意愿信号');
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
suggestions.push('⚠️ 任务未完成,建议:');
|
|||
|
|
if (dimensions.EXE < 60) {
|
|||
|
|
suggestions.push('- 检查执行节奏,分解小步骤');
|
|||
|
|
}
|
|||
|
|
if (dimensions.TEC < 50) {
|
|||
|
|
suggestions.push('- 补充技术文档,多看示例');
|
|||
|
|
}
|
|||
|
|
if (dimensions.INI < 70) {
|
|||
|
|
suggestions.push('- 调整心态,秋秋随时支持');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 个性化建议
|
|||
|
|
if (dimensions.TEC < dimensions.EXE) {
|
|||
|
|
suggestions.push('🔧 技术纵深是潜力点,多尝试新模块');
|
|||
|
|
}
|
|||
|
|
if (dimensions.INI > 90) {
|
|||
|
|
suggestions.push('✨ 主动性极强,可以尝试自主探索');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
primary: suggestions[0] || '继续当前节奏',
|
|||
|
|
all: suggestions.slice(0, 3)
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 记录闭环执行日志
|
|||
|
|
function recordLoop(devId, steps, pcaResult, suggestion, status) {
|
|||
|
|
initLog();
|
|||
|
|
const history = JSON.parse(fs.readFileSync(LOG_PATH));
|
|||
|
|
|
|||
|
|
const record = {
|
|||
|
|
timestamp: new Date().toISOString(),
|
|||
|
|
dev_id: devId,
|
|||
|
|
steps: {
|
|||
|
|
portrait: steps.portrait ? '✅' : '❌',
|
|||
|
|
pca: steps.pca ? '✅' : '❌',
|
|||
|
|
sync: steps.sync ? '✅' : '❌'
|
|||
|
|
},
|
|||
|
|
duration_ms: steps.duration,
|
|||
|
|
pca: {
|
|||
|
|
score: pcaResult?.totalScore,
|
|||
|
|
grade: pcaResult?.grade
|
|||
|
|
},
|
|||
|
|
suggestion: suggestion.primary,
|
|||
|
|
status: status
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
history.unshift(record);
|
|||
|
|
if (history.length > 100) history.pop();
|
|||
|
|
|
|||
|
|
fs.writeFileSync(LOG_PATH, JSON.stringify(history, null, 2));
|
|||
|
|
return record;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 主执行函数:一键串联所有步骤
|
|||
|
|
async function executeLoop(syslogData) {
|
|||
|
|
console.log(`\n🔄 开始执行完整闭环 [${syslogData.session_id}]`);
|
|||
|
|
const startTime = Date.now();
|
|||
|
|
|
|||
|
|
const steps = {
|
|||
|
|
portrait: false,
|
|||
|
|
pca: false,
|
|||
|
|
sync: false,
|
|||
|
|
duration: 0
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
let pcaResult = null;
|
|||
|
|
let suggestion = { primary: '无建议', all: [] };
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// Step 1: 画像更新
|
|||
|
|
console.log('📸 Step1: 更新画像...');
|
|||
|
|
const snapshot = portraitEngine.updatePortrait(syslogData);
|
|||
|
|
steps.portrait = true;
|
|||
|
|
console.log(` ✅ 画像更新完成: ${snapshot.rhythm}节奏 · ${snapshot.mood}情绪`);
|
|||
|
|
|
|||
|
|
// Step 2: PCA评估
|
|||
|
|
console.log('📊 Step2: 计算PCA...');
|
|||
|
|
pcaResult = pcaCalculator.calculate(syslogData.dev_id || 'DEV-004');
|
|||
|
|
steps.pca = true;
|
|||
|
|
console.log(` ✅ PCA完成: ${pcaResult.grade}级 (${pcaResult.totalScore}分)`);
|
|||
|
|
console.log(` 📈 维度: ${pcaResult.summary}`);
|
|||
|
|
|
|||
|
|
// Step 3: 同步(Phase3已有)
|
|||
|
|
console.log('🔄 Step3: 三节点同步...');
|
|||
|
|
try {
|
|||
|
|
const syncResult = syncEngine.syncAfterSyslog(syslogData);
|
|||
|
|
steps.sync = true;
|
|||
|
|
console.log(` ✅ 同步成功: ${syncResult.nodes.join(' → ')}`);
|
|||
|
|
} catch (syncError) {
|
|||
|
|
console.log(` ⚠️ 同步失败: ${syncError.message}`);
|
|||
|
|
// 错误容错:同步失败不影响整体流程
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Step 4: 生成调度建议
|
|||
|
|
console.log('💡 Step4: 生成调度建议...');
|
|||
|
|
suggestion = generateSuggestion(pcaResult, syslogData.status);
|
|||
|
|
console.log(` ✅ 建议: ${suggestion.primary}`);
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.log(`❌ 闭环执行出错: ${error.message}`);
|
|||
|
|
// 错误容错:记录错误但继续
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
steps.duration = Date.now() - startTime;
|
|||
|
|
|
|||
|
|
// 记录日志
|
|||
|
|
const record = recordLoop(
|
|||
|
|
syslogData.dev_id || 'DEV-004',
|
|||
|
|
steps,
|
|||
|
|
pcaResult,
|
|||
|
|
suggestion,
|
|||
|
|
syslogData.status
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
console.log(`\n✨ 闭环完成! 耗时 ${steps.duration}ms`);
|
|||
|
|
console.log(`📝 执行记录已保存\n`);
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
success: true,
|
|||
|
|
steps: steps,
|
|||
|
|
pca: pcaResult,
|
|||
|
|
suggestion: suggestion,
|
|||
|
|
record: record
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 查询接口
|
|||
|
|
function getHistory(limit = 20) {
|
|||
|
|
initLog();
|
|||
|
|
const history = JSON.parse(fs.readFileSync(LOG_PATH));
|
|||
|
|
return history.slice(0, limit);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getStatus() {
|
|||
|
|
initLog();
|
|||
|
|
const history = JSON.parse(fs.readFileSync(LOG_PATH));
|
|||
|
|
const lastRun = history[0] || null;
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
total_runs: history.length,
|
|||
|
|
last_run: lastRun,
|
|||
|
|
success_rate: history.length > 0
|
|||
|
|
? Math.round((history.filter(r => r.steps.portrait && r.steps.pca).length / history.length) * 100)
|
|||
|
|
: 0
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = {
|
|||
|
|
executeLoop,
|
|||
|
|
getHistory,
|
|||
|
|
getStatus
|
|||
|
|
};
|