* HarmonyOS 知识图谱 Web 可视化服务
*
* 启动: npm run web 或 node dist/web.js
* 访问: http://localhost:3456
*/
import express from 'express';
import * as path from 'path';
import { fileURLToPath } from 'url';
import { graphSearch, graphNeighbors, graphStats, } from './lib/graph.js';
import { isKnowledgeReady, getReferencesRoot, getTotalDocCount } from './lib/knowledge.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PORT = parseInt(process.env.PORT || '3456');
const app = express();
app.use(express.json());
const publicDir = path.join(__dirname, '..', 'public');
app.use(express.static(publicDir));
app.get('/api/status', (_req, res) => {
const ready = isKnowledgeReady();
res.json({
ready,
path: getReferencesRoot(),
docCount: ready ? getTotalDocCount() : 0,
});
});
app.get('/api/stats', (_req, res) => {
res.json(graphStats());
});
app.get('/api/graph', (req, res) => {
const query = req.query.q;
const type = req.query.type;
const limit = Math.min(parseInt(req.query.limit) || 300, 1000);
let nodes;
if (query) {
nodes = graphSearch(query, { type, maxResults: limit });
}
else {
nodes = [
...graphSearch('', { type: 'kit', maxResults: 50 }),
...graphSearch('', { type: 'module', maxResults: 200 }),
...graphSearch('', { type: 'component', maxResults: limit }),
];
const seen = new Set();
nodes = nodes.filter(n => {
if (seen.has(n.id))
return false;
seen.add(n.id);
return true;
}).slice(0, limit);
}
const nodeIds = new Set(nodes.map(n => n.id));
const edges = [];
for (const id of nodeIds) {
const result = graphNeighbors(id, { maxResults: 50 });
if (result) {
for (const e of result.edges) {
if (nodeIds.has(e.from) && nodeIds.has(e.to)) {
if (!edges.some(ex => ex.from === e.from && ex.to === e.to && ex.relation === e.relation)) {
edges.push(e);
}
}
}
}
}
res.json({ nodes, edges });
});
app.get('/api/graph/node/:id', (req, res) => {
const result = graphNeighbors(req.params.id, { maxResults: 100 });
if (!result) {
res.status(404).json({ error: 'Node not found' });
return;
}
res.json(result);
});
app.get('/api/graph/path', (req, res) => {
const { from, to } = req.query;
if (!from || !to) {
res.status(400).json({ error: 'from and to required' });
return;
}
const { graphPath } = require('./lib/graph.js');
res.json(graphPath(from, to, 5));
});
app.get('/', (_req, res) => {
res.sendFile(path.join(publicDir, 'index.html'));
});
app.listen(PORT, () => {
console.log('');
console.log('╔══════════════════════════════════════════════╗');
console.log('║ HarmonyOS 知识图谱可视化 ║');
console.log('╚══════════════════════════════════════════════╝');
console.log('');
console.log(` 访问: http://localhost:${PORT}`);
console.log(` 知识库: ${getReferencesRoot()}`);
console.log(` 状态: ${isKnowledgeReady() ? `✅ ${getTotalDocCount().toLocaleString()} 篇文档` : '⚠️ 未下载'}`);
console.log('');
});