zhizhi/pca/pca-calculator.js

269 lines
7.2 KiB
JavaScript
Raw Normal View History

const fs = require('fs');
const path = require('path');
const portraitEngine = require('../portrait/portrait-engine');
// 加载规则配置
function loadRules() {
const rulesPath = path.join(__dirname, 'pca-rules.json');
return JSON.parse(fs.readFileSync(rulesPath));
}
// 维度1EXE执行力计算
function calculateEXE(portrait, rules) {
const factors = rules.dimensions.EXE.factors;
const raw = portrait.raw_stats || {};
const recent = portrait.recent_snapshots?.[0] || {};
// 连胜率 (30%)
const streakRate = Math.min(100, (raw.streak || 0) * 10);
// 完成率 (30%)
const completionRate = raw.total_items ? (raw.completed_items / raw.total_items) * 100 : 100;
// 执行节奏得分 (20%)
const rhythmScore = {
'快': 100,
'稳': 80,
'慢': 50
}[recent.rhythm] || 60;
// 摩擦恢复得分 (20%)
const frictionScore = {
'无': 100,
'低': 85,
'中': 60,
'高': 30
}[recent.friction] || 50;
const total = (
streakRate * (factors.streak_rate / 100) +
completionRate * (factors.completion_rate / 100) +
rhythmScore * (factors.rhythm_score / 100) +
frictionScore * (factors.friction_recovery / 100)
);
return {
score: Math.round(total),
details: {
streakRate,
completionRate,
rhythmScore,
frictionScore
}
};
}
// 维度2TEC技术纵深计算
function calculateTEC(portrait, rules) {
const factors = rules.dimensions.TEC.factors;
const raw = portrait.raw_stats || {};
// EL等级得分 (40%)
const elScore = raw.el_level ? parseInt(raw.el_level) * 10 : 80;
// 代码量得分 (30%)
const codeLines = raw.code_lines || 0;
const codeScore = Math.min(100, codeLines / 100);
// 技术栈广度 (30%) - 从最近快照中推断
const recentSnapshots = portrait.recent_snapshots || [];
const uniqueModules = new Set();
recentSnapshots.forEach(s => {
if (s.raw_stats?.module) uniqueModules.add(s.raw_stats.module);
});
const breadthScore = Math.min(100, uniqueModules.size * 25);
const total = (
elScore * (factors.el_level / 100) +
codeScore * (factors.code_lines / 100) +
breadthScore * (factors.tech_breadth / 100)
);
return {
score: Math.round(total),
details: {
elScore,
codeScore,
breadthScore
}
};
}
// 维度3SYS系统理解力计算
function calculateSYS(portrait, rules) {
const factors = rules.dimensions.SYS.factors;
const recent = portrait.recent_snapshots?.[0] || {};
// 跨模块能力 (35%)
const crossModuleScore = portrait.total_sessions > 3 ? 100 : 60;
// 系统级任务 (35%)
const systemTasksScore = recent.raw_stats?.completed_items > 3 ? 100 : 70;
// 工程思维 (30%)
const engineeringScore = recent.growth?.signals?.includes('自主修复报错') ? 100 : 80;
const total = (
crossModuleScore * (factors.cross_module / 100) +
systemTasksScore * (factors.system_tasks / 100) +
engineeringScore * (factors.engineering_mind / 100)
);
return {
score: Math.round(total),
details: {
crossModuleScore,
systemTasksScore,
engineeringScore
}
};
}
// 维度4COL协作力计算
function calculateCOL(portrait, rules) {
const factors = rules.dimensions.COL.factors;
const recent = portrait.recent_snapshots?.[0] || {};
// SYSLOG质量 (40%)
const syslogScore = recent.will === '强烈' ? 100 : 80;
// Git协作 (30%) - 从连胜推断
const gitScore = Math.min(100, (portrait.current_streak || 0) * 20);
// 人格体协同 (30%)
const personaScore = recent.mood === '正向' ? 100 : 70;
const total = (
syslogScore * (factors.syslog_quality / 100) +
gitScore * (factors.git_collab / 100) +
personaScore * (factors.persona_sync / 100)
);
return {
score: Math.round(total),
details: {
syslogScore,
gitScore,
personaScore
}
};
}
// 维度5INI主动性计算
function calculateINI(portrait, rules) {
const factors = rules.dimensions.INI.factors;
const recent = portrait.recent_snapshots?.[0] || {};
// 意愿信号 (40%)
const willScore = {
'强烈': 100,
'正常': 80,
'低落': 40,
'待观察': 50
}[recent.will] || 60;
// 自发行为 (30%)
const selfScore = recent.growth?.signals?.includes('自主解决问题') ? 100 : 70;
// 72h响应 (30%)
const responseScore = portrait.current_streak > 0 ? 100 : 50;
const total = (
willScore * (factors.will_signal / 100) +
selfScore * (factors.self_initiative / 100) +
responseScore * (factors.response_72h / 100)
);
return {
score: Math.round(total),
details: {
willScore,
selfScore,
responseScore
}
};
}
// 主计算函数
function calculate(devId) {
// 获取画像数据
const portrait = portraitEngine.getPortrait(devId);
if (!portrait) {
throw new Error(`开发者 ${devId} 不存在`);
}
const rules = loadRules();
// 计算各维度
const exe = calculateEXE(portrait, rules);
const tec = calculateTEC(portrait, rules);
const sys = calculateSYS(portrait, rules);
const col = calculateCOL(portrait, rules);
const ini = calculateINI(portrait, rules);
// 加权汇总
const totalScore = Math.round(
exe.score * (rules.dimensions.EXE.weight / 100) +
tec.score * (rules.dimensions.TEC.weight / 100) +
sys.score * (rules.dimensions.SYS.weight / 100) +
col.score * (rules.dimensions.COL.weight / 100) +
ini.score * (rules.dimensions.INI.weight / 100)
);
// 等级判定
let grade = 'D';
for (const [g, threshold] of Object.entries(rules.grade_thresholds)) {
if (totalScore >= threshold) {
grade = g;
break;
}
}
// 维度摘要
const summary = `EXE:${exe.score} TEC:${tec.score} SYS:${sys.score} COL:${col.score} INI:${ini.score}`;
return {
dev_id: devId,
timestamp: new Date().toISOString(),
totalScore,
grade,
dimensions: {
EXE: exe.score,
TEC: tec.score,
SYS: sys.score,
COL: col.score,
INI: ini.score
},
details: {
EXE: exe.details,
TEC: tec.details,
SYS: sys.details,
COL: col.details,
INI: ini.details
},
summary
};
}
// 便捷方法:直接计算最新画像
function calculateLatest() {
const portraits = portraitEngine.getAllPortraits();
const results = {};
for (const devId in portraits) {
results[devId] = calculate(devId);
}
return results;
}
module.exports = {
calculate,
calculateLatest,
calculateEXE,
calculateTEC,
calculateSYS,
calculateCOL,
calculateINI
};