UNPKG

yijing-bazi-mcp

Version:

易经八字分析 MCP 服务器 - 提供传统命理分析和易经卦象解读的AI工具

537 lines (468 loc) 14.1 kB
/** * 搜索引擎工具类 * 提供知识库搜索和匹配功能 */ const { knowledgeDatabase } = require('../data/knowledge-database.js'); class SearchEngine { constructor() { this.database = knowledgeDatabase; this.searchIndex = this.buildSearchIndex(); } /** * 构建搜索索引 */ buildSearchIndex() { const index = { hexagrams: new Map(), trigrams: new Map(), stems: new Map(), branches: new Map(), elements: new Map(), tenGods: new Map(), patterns: new Map() }; // 索引六十四卦 Object.entries(this.database.hexagrams).forEach(([key, hexagram]) => { const searchTerms = [ hexagram.name, hexagram.chinese, hexagram.meaning, hexagram.judgment, ...Object.values(hexagram.interpretation) ].join(' ').toLowerCase(); index.hexagrams.set(key, { data: hexagram, searchTerms, keywords: [hexagram.name, hexagram.chinese, hexagram.meaning] }); }); // 索引八卦 Object.entries(this.database.trigrams).forEach(([key, trigram]) => { const searchTerms = [ key, trigram.meaning, trigram.element, trigram.direction, trigram.season, ...trigram.characteristics ].join(' ').toLowerCase(); index.trigrams.set(key, { data: trigram, searchTerms, keywords: [key, trigram.meaning, trigram.element] }); }); // 索引天干 Object.entries(this.database.heavenly_stems).forEach(([key, stem]) => { const searchTerms = [ key, stem.element, stem.polarity, stem.meaning, stem.personality, ...stem.characteristics ].join(' ').toLowerCase(); index.stems.set(key, { data: stem, searchTerms, keywords: [key, stem.element, stem.meaning] }); }); // 索引地支 Object.entries(this.database.earthly_branches).forEach(([key, branch]) => { const searchTerms = [ key, branch.element, branch.animal, branch.meaning, branch.season, ...branch.characteristics ].join(' ').toLowerCase(); index.branches.set(key, { data: branch, searchTerms, keywords: [key, branch.animal, branch.meaning] }); }); // 索引十神 Object.entries(this.database.ten_gods).forEach(([key, god]) => { const searchTerms = [ key, god.relationship, god.meaning, god.career, god.personality, ...god.characteristics, ...god.positive, ...god.negative ].join(' ').toLowerCase(); index.tenGods.set(key, { data: god, searchTerms, keywords: [key, god.meaning, god.relationship] }); }); // 索引格局 Object.entries(this.database.patterns).forEach(([key, pattern]) => { const searchTerms = [ key, pattern.description, pattern.life_advice, ...pattern.characteristics, ...pattern.suitable_career, ...pattern.famous_examples ].join(' ').toLowerCase(); index.patterns.set(key, { data: pattern, searchTerms, keywords: [key, pattern.description, ...pattern.characteristics] }); }); return index; } /** * 搜索六十四卦 * @param {string} query - 搜索关键词 * @param {number} limit - 返回结果数量限制 * @returns {Array} 搜索结果 */ searchHexagrams(query, limit = 10) { return this.performSearch(this.searchIndex.hexagrams, query, limit); } /** * 搜索八卦 * @param {string} query - 搜索关键词 * @param {number} limit - 返回结果数量限制 * @returns {Array} 搜索结果 */ searchTrigrams(query, limit = 8) { return this.performSearch(this.searchIndex.trigrams, query, limit); } /** * 搜索天干 * @param {string} query - 搜索关键词 * @param {number} limit - 返回结果数量限制 * @returns {Array} 搜索结果 */ searchHeavenlyStems(query, limit = 10) { return this.performSearch(this.searchIndex.stems, query, limit); } /** * 搜索地支 * @param {string} query - 搜索关键词 * @param {number} limit - 返回结果数量限制 * @returns {Array} 搜索结果 */ searchEarthlyBranches(query, limit = 12) { return this.performSearch(this.searchIndex.branches, query, limit); } /** * 搜索十神 * @param {string} query - 搜索关键词 * @param {number} limit - 返回结果数量限制 * @returns {Array} 搜索结果 */ searchTenGods(query, limit = 10) { return this.performSearch(this.searchIndex.tenGods, query, limit); } /** * 搜索格局 * @param {string} query - 搜索关键词 * @param {number} limit - 返回结果数量限制 * @returns {Array} 搜索结果 */ searchPatterns(query, limit = 10) { return this.performSearch(this.searchIndex.patterns, query, limit); } /** * 综合搜索 * @param {string} query - 搜索关键词 * @param {Object} options - 搜索选项 * @returns {Object} 分类搜索结果 */ searchAll(query, options = {}) { const { includeHexagrams = true, includeTrigrams = true, includeStems = true, includeBranches = true, includeTenGods = true, includePatterns = true, limit = 5 } = options; const results = {}; if (includeHexagrams) { results.hexagrams = this.searchHexagrams(query, limit); } if (includeTrigrams) { results.trigrams = this.searchTrigrams(query, limit); } if (includeStems) { results.heavenly_stems = this.searchHeavenlyStems(query, limit); } if (includeBranches) { results.earthly_branches = this.searchEarthlyBranches(query, limit); } if (includeTenGods) { results.ten_gods = this.searchTenGods(query, limit); } if (includePatterns) { results.patterns = this.searchPatterns(query, limit); } return results; } /** * 执行搜索 * @param {Map} index - 搜索索引 * @param {string} query - 搜索关键词 * @param {number} limit - 结果限制 * @returns {Array} 搜索结果 */ performSearch(index, query, limit) { if (!query || typeof query !== 'string') { return []; } const searchQuery = query.toLowerCase().trim(); const results = []; for (const [key, item] of index) { const score = this.calculateRelevanceScore(item, searchQuery); if (score > 0) { results.push({ key, data: item.data, score, relevance: this.getRelevanceLevel(score) }); } } // 按相关性得分排序 results.sort((a, b) => b.score - a.score); return results.slice(0, limit); } /** * 计算相关性得分 * @param {Object} item - 索引项 * @param {string} query - 搜索查询 * @returns {number} 相关性得分 */ calculateRelevanceScore(item, query) { let score = 0; const queryTerms = query.split(/\s+/); // 关键词完全匹配得分最高 for (const keyword of item.keywords) { if (keyword.toLowerCase() === query) { score += 100; } else if (keyword.toLowerCase().includes(query)) { score += 50; } } // 搜索词在内容中的匹配 for (const term of queryTerms) { if (term.length > 0) { const termCount = (item.searchTerms.match(new RegExp(term, 'gi')) || []).length; score += termCount * 10; } } // 部分匹配 if (item.searchTerms.includes(query)) { score += 20; } return score; } /** * 获取相关性级别 * @param {number} score - 相关性得分 * @returns {string} 相关性级别 */ getRelevanceLevel(score) { if (score >= 100) return 'high'; if (score >= 50) return 'medium'; if (score >= 20) return 'low'; return 'minimal'; } /** * 根据元素查找相关内容 * @param {string} element - 五行元素 * @returns {Object} 相关内容 */ findByElement(element) { const results = { trigrams: [], stems: [], branches: [], characteristics: null }; // 查找相关八卦 for (const [key, trigram] of Object.entries(this.database.trigrams)) { if (trigram.element === element) { results.trigrams.push({ key, ...trigram }); } } // 查找相关天干 for (const [key, stem] of Object.entries(this.database.heavenly_stems)) { if (stem.element === element) { results.stems.push({ key, ...stem }); } } // 查找相关地支 for (const [key, branch] of Object.entries(this.database.earthly_branches)) { if (branch.element === element) { results.branches.push({ key, ...branch }); } } // 获取元素特性 results.characteristics = this.database.element_relations.characteristics[element]; return results; } /** * 根据十神查找相关信息 * @param {string} tenGod - 十神名称 * @returns {Object} 十神详细信息 */ findTenGodInfo(tenGod) { return this.database.ten_gods[tenGod] || null; } /** * 根据格局查找相关信息 * @param {string} pattern - 格局名称 * @returns {Object} 格局详细信息 */ findPatternInfo(pattern) { return this.database.patterns[pattern] || null; } /** * 获取五行相生相克关系 * @param {string} element1 - 第一个元素 * @param {string} element2 - 第二个元素 * @returns {Object} 关系信息 */ getElementRelation(element1, element2) { const relations = this.database.element_relations; if (relations.generating[element1] === element2) { return { type: 'generating', description: `${element1}生${element2}` }; } if (relations.destructive[element1] === element2) { return { type: 'destructive', description: `${element1}克${element2}` }; } if (relations.generating[element2] === element1) { return { type: 'being_generated', description: `${element2}生${element1}` }; } if (relations.destructive[element2] === element1) { return { type: 'being_destructed', description: `${element2}克${element1}` }; } if (element1 === element2) { return { type: 'same', description: `${element1}同类` }; } return { type: 'neutral', description: `${element1}与${element2}无直接关系` }; } /** * 获取建议和指导 * @param {string} category - 类别 * @param {string} key - 关键词 * @returns {Array} 建议列表 */ getAdvice(category, key) { const advice = []; switch (category) { case 'health': const healthData = this.database.health.constitution_types[key]; if (healthData) { advice.push(...healthData.wellness_advice); } break; case 'career': const patternData = this.database.patterns[key]; if (patternData) { advice.push(patternData.life_advice); advice.push(...patternData.suitable_career.map(career => `适合从事${career}相关工作`)); } break; case 'element': const elementData = this.database.element_relations.characteristics[key]; if (elementData) { advice.push(`发挥${key}的特质:${elementData.personality.join('、')}`); } break; } return advice; } /** * 模糊搜索 * @param {string} query - 搜索关键词 * @param {number} threshold - 相似度阈值 * @returns {Array} 搜索结果 */ fuzzySearch(query, threshold = 0.6) { const results = []; const allIndexes = [ { name: 'hexagrams', index: this.searchIndex.hexagrams }, { name: 'trigrams', index: this.searchIndex.trigrams }, { name: 'stems', index: this.searchIndex.stems }, { name: 'branches', index: this.searchIndex.branches }, { name: 'tenGods', index: this.searchIndex.tenGods }, { name: 'patterns', index: this.searchIndex.patterns } ]; for (const { name, index } of allIndexes) { for (const [key, item] of index) { for (const keyword of item.keywords) { const similarity = this.calculateSimilarity(query.toLowerCase(), keyword.toLowerCase()); if (similarity >= threshold) { results.push({ category: name, key, data: item.data, similarity, matchedKeyword: keyword }); } } } } return results.sort((a, b) => b.similarity - a.similarity); } /** * 计算字符串相似度 * @param {string} str1 - 字符串1 * @param {string} str2 - 字符串2 * @returns {number} 相似度(0-1) */ calculateSimilarity(str1, str2) { const longer = str1.length > str2.length ? str1 : str2; const shorter = str1.length > str2.length ? str2 : str1; if (longer.length === 0) { return 1.0; } const editDistance = this.levenshteinDistance(longer, shorter); return (longer.length - editDistance) / longer.length; } /** * 计算编辑距离 * @param {string} str1 - 字符串1 * @param {string} str2 - 字符串2 * @returns {number} 编辑距离 */ levenshteinDistance(str1, str2) { const matrix = []; for (let i = 0; i <= str2.length; i++) { matrix[i] = [i]; } for (let j = 0; j <= str1.length; j++) { matrix[0][j] = j; } for (let i = 1; i <= str2.length; i++) { for (let j = 1; j <= str1.length; j++) { if (str2.charAt(i - 1) === str1.charAt(j - 1)) { matrix[i][j] = matrix[i - 1][j - 1]; } else { matrix[i][j] = Math.min( matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1 ); } } } return matrix[str2.length][str1.length]; } } module.exports = SearchEngine;