guanghulab/server.js

199 lines
6.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require('express');
const path = require('path');
const fs = require('fs');
const { execSync } = require('child_process');
const portraitEngine = require('./portrait/portrait-engine');
const pcaCalculator = require('./pca/pca-calculator');
const loopEngine = require('./loop/loop-engine');
const app = express();
const PORT = 3000;
app.use(express.json());
app.use(express.static('public'));
// API 1: 所有开发者画像
app.get('/api/portrait/all', (req, res) => {
try {
const portraits = portraitEngine.getAllPortraits();
res.json(portraits);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// API 2: 单个开发者画像
app.get('/api/portrait/:devId', (req, res) => {
try {
const portrait = portraitEngine.getPortrait(req.params.devId);
if (!portrait) {
return res.status(404).json({ error: '开发者不存在' });
}
res.json(portrait);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// API 3: PCA评估结果
app.get('/api/pca/:devId', (req, res) => {
try {
const result = pcaCalculator.calculate(req.params.devId);
res.json(result);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// API 4: 闭环状态
app.get('/api/loop/status', (req, res) => {
try {
const status = loopEngine.getStatus();
res.json(status);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// API 5: 手动触发闭环
app.post('/api/loop/execute', (req, res) => {
try {
const syslogData = req.body;
if (!syslogData || !syslogData.session_id) {
return res.status(400).json({ error: '缺少SYSLOG数据' });
}
loopEngine.executeLoop(syslogData).then(result => {
res.json(result);
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// 获取闭环历史
app.get('/api/loop/history', (req, res) => {
try {
const history = loopEngine.getHistory();
res.json(history);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// 模拟SYSLOG接收自动触发闭环
app.post('/api/syslog', (req, res) => {
try {
const syslogData = req.body;
console.log('📨 收到SYSLOG:', syslogData.session_id);
loopEngine.executeLoop(syslogData).then(loopResult => {
console.log('✅ 闭环完成');
});
res.json({ status: 'received', session_id: syslogData.session_id });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// ============================================================
// ⚡ 铸渊大脑实时状态 API首页投影面板用
// ============================================================
const BRAIN_BASE = '/data/guanghulab/repo';
app.get('/api/brain', (req, res) => {
try {
// 读取时间核心
let temporal = { clock: { latest_cognition: '', awakening_count: 0, current_date: '', repo_age_days: 0 }, timeline: { epochs: [] } };
try {
temporal = JSON.parse(fs.readFileSync(BRAIN_BASE + '/brain/temporal-core/temporal-brain.json', 'utf8'));
} catch(e) {}
// 读取母编号
let motherReg = { mothers: [] };
try {
motherReg = JSON.parse(fs.readFileSync(BRAIN_BASE + '/brain/engineering/mother-registry.json', 'utf8'));
} catch(e) {}
// 服务器实时健康
let server = { status: 'unknown', services_online: 0, services_total: 0 };
try {
const pm2 = execSync('pm2 jlist 2>/dev/null', {timeout:3000}).toString();
const list = JSON.parse(pm2);
const online = list.filter(p => p.pm2_env.status === 'online');
const stopped = list.filter(p => p.pm2_env.status !== 'online');
const memRaw = execSync('free -h 2>/dev/null | grep Mem', {timeout:2000}).toString();
const memParts = memRaw.replace(/\s+/g,' ').trim().split(' ');
server = {
status: 'online',
services_online: online.length,
services_total: list.length,
services: online.map(p => ({ name: p.name, memory: p.pm2_env?.pm_cpu || 0 })),
stopped: stopped.map(p => p.name),
memory_total: memParts[1] || 'unknown',
memory_used: memParts[2] || 'unknown'
};
} catch(e) { server.error = e.message; }
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET');
res.json({
identity: '铸渊 · ICE-GL-ZY001',
copyright: '国作登字-2026-A-00037559',
awakening: temporal.clock?.awakening_count || 0,
age_days: temporal.clock?.repo_age_days || 0,
current_date: temporal.clock?.current_date || '',
cognition: temporal.clock?.latest_cognition || '',
recent_epochs: (temporal.timeline?.epochs || []).slice(-5).map(e => ({
epoch: e.epoch,
event: (e.event || '').substring(0, 80),
date: e.date
})),
mothers: (motherReg.mothers || []).map(m => ({
name: m.name,
status: m.status,
done: (m.sub_paths || []).filter(s => s.status === 'done').length,
total: (m.sub_paths || []).length,
paths: (m.sub_paths || []).map(s => ({ name: s.name, status: s.status }))
})),
server: server,
updated_at: new Date().toISOString()
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.get('/api/heartbeat', (req, res) => {
try {
const temporal = JSON.parse(fs.readFileSync(BRAIN_BASE + '/brain/temporal-core/temporal-brain.json', 'utf8'));
res.setHeader('Access-Control-Allow-Origin', '*');
res.json({
alive: true,
time: new Date().toISOString(),
awakening: temporal.clock?.awakening_count || 0,
age_days: temporal.clock?.repo_age_days || 0
});
} catch(e) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.json({ alive: true, fallback: true });
}
});
// 仪表盘页面
app.get('/dashboard-v2', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'dashboard-v2.html'));
});
// 启动服务器
app.listen(PORT, () => {
console.log('\n🚀 铸渊大脑状态 API 已启动!');
console.log('🧠 /api/brain - 大脑实时状态');
console.log('💓 /api/heartbeat - 快速心跳');
console.log('📊 /dashboard-v2 - 仪表盘');
console.log('');
});