Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

210 lines
5.0 KiB
JavaScript
Raw Permalink 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.

//知识库管理器·kb-manager.js
// HoloLake·M-DINGTALK Phase 3
// DEV-004 之之×秋秋
//
const fs = require('fs');
const path = require('path');
//知识库文档目录
const DOCS_DIR = path.join(__dirname, 'docs');
const INDEX_FILE = path.join(__dirname, 'kb-index.json');
// 知识库索引(内存缓存)
let kbIndex = [];
/**
* 扫描文档目录,建立索引
* 索引结构:[{ filename, title, sections: [{ heading, content, keywords }] }]
*/
function buildIndex() {
console.log('[KB] 开始建立知识库索引...');
kbIndex = [];
// 读取docs目录下所有.md文件
const docsDir = DOCS_DIR;
if (!fs.existsSync(docsDir)) {
console.log('[KB] 文档目录不存在,创建中...');
fs.mkdirSync(docsDir, { recursive: true });
return kbIndex;
}
const files = fs.readdirSync(docsDir).filter(f => f.endsWith('.md'));
console.log(`[KB] 发现 ${files.length} 个文档文件`);
for (const file of files) {
const filePath = path.join(docsDir, file);
const content = fs.readFileSync(filePath, 'utf-8');
// 解析文档结构
const doc = parseDocument(file, content);
kbIndex.push(doc);
}
// 保存索引到文件
fs.writeFileSync(INDEX_FILE, JSON.stringify(kbIndex, null, 2), 'utf-8');
console.log(`[KB] 索引建立完成,共 ${kbIndex.length} 个文档, ${kbIndex.reduce((sum, d) => sum + d.sections.length, 0)} 个章节`);
return kbIndex;
}
/**
* 解析单个Markdown文档
*/
function parseDocument(filename, content) {
const lines = content.split('\n');
const doc = {
filename,
title: '',
sections: []
};
let currentSection = null;
for (const line of lines) {
// 检测标题行
const headingMatch = line.match(/^(#{1,3})\s+(.+)/);
if (headingMatch) {
// 保存上一个section
if (currentSection) {
currentSection.keywords = extractKeywords(currentSection.content);
doc.sections.push(currentSection);
}
const level = headingMatch[1].length;
const heading = headingMatch[2].trim();
// 第一个h1作为文档标题
if (level === 1 && !doc.title) {
doc.title = heading;
}
currentSection = {
heading,
level,
content: ''
};
} else if (currentSection) {
currentSection.content += line + '\n';
}
}
// 保存最后一个section
if (currentSection) {
currentSection.keywords = extractKeywords(currentSection.content);
doc.sections.push(currentSection);
}
// 如果没有找到h1标题用文件名
if (!doc.title) {
doc.title = filename.replace('.md', '');
}
return doc;
}
/**
* 从文本中提取关键词(简单版:提取中英文词汇)
*/
function extractKeywords(text) {
// 移除Markdown语法
const clean = text
.replace(/```[\s\S]*?```/g, '') // 移除代码块
.replace(/[`*_#\[\]()]/g, '') // 移除Markdown符号
.replace(/\s+/g, ' ');
// 提取关键词2个字以上的词
const words = clean.match(/[a-zA-Z]{3,}|[\u4e00-\u9fa5]{2,}/g) || [];
// 去重并返回
return [...new Set(words)].slice(0, 30);
}
/**
* 搜索知识库
* @param {string} query - 搜索关键词
* @returns {Array} - 匹配结果列表
*/
function search(query) {
if (kbIndex.length === 0) {
buildIndex();
}
const queryLower = query.toLowerCase();
const queryWords = queryLower.split(/\s+/).filter(w => w.length >= 1);
const results = [];
for (const doc of kbIndex) {
for (const section of doc.sections) {
// 计算匹配分数
let score = 0;
const sectionText = (section.heading + ' ' + section.content).toLowerCase();
for (const word of queryWords) {
// 标题匹配权重更高
if (section.heading.toLowerCase().includes(word)) {
score += 10;
}
// 内容匹配
if (sectionText.includes(word)) {
score += 5;
}
// 关键词匹配
if (section.keywords && section.keywords.some(k => k.toLowerCase().includes(word))) {
score += 3;
}
}
if (score > 0) {
results.push({
doc: doc.title,
filename: doc.filename,
heading: section.heading,
content: section.content.trim().substring(0, 500),
score
});
}
}
}
// 按分数排序返回前5个
results.sort((a, b) => b.score - a.score);
return results.slice(0, 5);
}
/**
* 获取知识库统计信息
*/
function getStats() {
if (kbIndex.length === 0) {
buildIndex();
}
return {
totalDocs: kbIndex.length,
totalSections: kbIndex.reduce((sum, d) => sum + d.sections.length, 0),
docs: kbIndex.map(d => ({
filename: d.filename,
title: d.title,
sections: d.sections.length
}))
};
}
/**
* 重新加载知识库(用于热更新)
*/
function reload() {
console.log('[KB] 热更新:重新加载知识库...');
return buildIndex();
}
module.exports = {
buildIndex,
search,
getStats,
reload
};