UNPKG

sensitive-lexicon-mcp

Version:

MCP server for sensitive word detection using Sensitive-lexicon library

126 lines 4.45 kB
import fetch from 'node-fetch'; export class SensitiveDetector { wordLists = new Map(); isInitialized = false; vocabularyFiles = [ 'COVID-19词库.txt', 'GFW补充词库.txt', '其他词库.txt', '反动词库.txt', '广告类型.txt', '政治类型.txt', '暴恐词库.txt', '民生词库.txt', '涉枪涉爆.txt', '色情类型.txt', '色情词库.txt', '补充词库.txt', '贪腐词库.txt', '零时-Tencent.txt', '非法网址.txt' ]; async initialize() { if (this.isInitialized) return; for (const filename of this.vocabularyFiles) { try { const category = this.getCategoryFromFilename(filename); const words = await this.fetchWordList(filename); this.wordLists.set(category, new Set(words)); } catch (error) { console.warn(`Failed to load ${filename}:`, error); } } this.isInitialized = true; } getCategoryFromFilename(filename) { const mapping = { 'COVID-19词库.txt': 'covid19', 'GFW补充词库.txt': 'gfw', '其他词库.txt': 'other', '反动词库.txt': 'subversive', '广告类型.txt': 'advertisement', '政治类型.txt': 'political', '暴恐词库.txt': 'violence', '民生词库.txt': 'livelihood', '涉枪涉爆.txt': 'weapons', '色情类型.txt': 'pornography-type', '色情词库.txt': 'pornography', '补充词库.txt': 'supplementary', '贪腐词库.txt': 'corruption', '零时-Tencent.txt': 'tencent', '非法网址.txt': 'illegal-urls' }; return mapping[filename] || 'unknown'; } async fetchWordList(filename) { const url = `https://raw.githubusercontent.com/konsheng/Sensitive-lexicon/master/Vocabulary/${encodeURIComponent(filename)}`; try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const text = await response.text(); return text .split('\n') .map(line => line.trim()) .filter(line => line.length > 0 && !line.startsWith('#')); } catch (error) { console.error(`Error fetching ${filename}:`, error); return []; } } detect(text, categories) { if (!this.isInitialized) { throw new Error('SensitiveDetector not initialized. Call initialize() first.'); } const sensitiveWords = []; const categoriesToCheck = categories || Array.from(this.wordLists.keys()); for (const category of categoriesToCheck) { const wordSet = this.wordLists.get(category); if (!wordSet) continue; for (const word of wordSet) { if (text.toLowerCase().includes(word.toLowerCase())) { sensitiveWords.push({ word, category }); } } } return { isSensitive: sensitiveWords.length > 0, sensitiveWords, originalText: text }; } filter(text, replacement = '***', categories) { const result = this.detect(text, categories); if (!result.isSensitive) { result.filteredText = text; return result; } let filteredText = text; for (const { word } of result.sensitiveWords) { const regex = new RegExp(word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi'); filteredText = filteredText.replace(regex, replacement); } result.filteredText = filteredText; return result; } getAvailableCategories() { return Array.from(this.wordLists.keys()); } getWordCount(category) { if (category) { const wordSet = this.wordLists.get(category); return wordSet ? wordSet.size : 0; } let total = 0; for (const wordSet of this.wordLists.values()) { total += wordSet.size; } return total; } } //# sourceMappingURL=sensitive-detector.js.map