/** * analysis.js — AI 深度分析 REST 路由 * * GET /api/analysis/communities → detectCommunities() * GET /api/analysis/followups?days=30 → getFollowUpCandidates() * POST /api/analysis/activate body: { personId } → activate + return summary */ const express = require('express'); const router = express.Router(); const { getGraphStore } = require('../db/GraphStore'); // ── GET /api/analysis/communities ─────────────────────────────────── router.get('/communities', (req, res) => { try { const maxIter = parseInt(req.query.maxIter, 10) || 10; const g = getGraphStore(); const result = g.detectCommunities(maxIter); res.json({ success: true, ...result }); } catch (err) { res.status(500).json({ error: err.message }); } }); // ── GET /api/analysis/followups ────────────────────────────────────── router.get('/followups', (req, res) => { try { const days = parseInt(req.query.days, 10) || 30; const limit = parseInt(req.query.limit, 10) || 20; const g = getGraphStore(); const candidates = g.getFollowUpCandidates(days, limit); res.json({ success: true, total: candidates.length, count: candidates.length, candidates }); } catch (err) { res.status(500).json({ error: err.message }); } }); // ── POST /api/analysis/activate ────────────────────────────────────── router.post('/activate', (req, res) => { try { const { personId } = req.body; if (!personId) { return res.status(400).json({ error: 'personId 为必填字段' }); } const g = getGraphStore(); // 解析联系人 let person = g.getNode(personId); if (!person || person._type !== 'Person') { const results = g.findByName(personId, 'Person'); person = results[0] || null; } if (!person) { return res.status(404).json({ error: `未找到联系人:${personId}` }); } // 聚合分析 const { outgoing, incoming } = g.getEdges(person.id); const allEdges = [...outgoing, ...incoming]; let interactionCount = 0; const relatedOrgs = new Set(); const recentEvents = []; const now = Date.now(); let latestEventDate = null; for (const edge of allEdges) { const neighborId = edge.from_id === person.id ? edge.to_id : edge.from_id; const neighbor = g.getNode(neighborId); if (!neighbor) continue; if (neighbor._type === 'Event') { interactionCount++; const dateStr = neighbor.date || neighbor.createdAt || null; if (dateStr) { recentEvents.push({ title: neighbor.title || neighbor.summary, date: dateStr }); if (!latestEventDate || dateStr > latestEventDate) { latestEventDate = dateStr; } } } else if (neighbor._type === 'Organization') { relatedOrgs.add(neighbor.name || neighborId); } } recentEvents.sort((a, b) => (b.date > a.date ? 1 : -1)); const daysSinceLast = latestEventDate ? Math.floor((now - new Date(latestEventDate).getTime()) / (1000 * 60 * 60 * 24)) : null; // 更新状态 g.setAnalysisStatus(person.id, 'complete'); res.json({ success: true, personId: person.id, personName: person.name, analysisStatus: 'complete', summary: { interactionCount, relatedOrganizations: [...relatedOrgs], latestInteraction: latestEventDate, daysSinceLastInteraction: daysSinceLast, recentEvents: recentEvents.slice(0, 5), }, }); } catch (err) { res.status(500).json({ error: err.message }); } }); module.exports = router;