Skip to main content
Glama
contentAnalysisService.js4.04 kB
/** * Content Analysis Service * Evaluates relevance, sentiment, and quality of content */ export class ContentAnalysisService { constructor() { this.stopwords = new Set([ "the", "is", "in", "at", "of", "on", "and", "a", "to", ]); // Expanded in real usage } analyze(text, query) { if (!text) return { score: 0, sentiment: "neutral", keywords: [] }; const cleanText = text.toLowerCase(); const cleanQuery = query.toLowerCase(); // 1. Relevance Score const relevanceScore = this.calculateRelevance(cleanText, cleanQuery); // 2. Keyword Extraction const keywords = this.extractKeywords(cleanText); // 3. Basic Sentiment (Placeholder for more advanced NLP) const sentiment = this.analyzeSentiment(cleanText); return { relevanceScore, keywords, sentiment, wordCount: text.split(/\s+/).length, readabilityScore: this.calculateReadability(text), }; } /** * Analyze a batch of search results * @param {string} query * @param {Array} results */ async analyzeSearchResults(query, results) { if (!results || results.length === 0) return null; const analysis = { summary: "Analysis of top results", topKeywords: {}, averageSentiment: { score: 0, label: "neutral" }, resultsAnalysis: [] }; let totalSentiment = 0; const allKeywords = {}; results.forEach(result => { const text = (result.title + " " + (result.snippet || "")).trim(); const resultAnalysis = this.analyze(text, query); analysis.resultsAnalysis.push({ url: result.url, ...resultAnalysis }); // Aggregate sentiment if (resultAnalysis.sentiment === "positive") totalSentiment++; if (resultAnalysis.sentiment === "negative") totalSentiment--; // Aggregate keywords resultAnalysis.keywords.forEach(kw => { allKeywords[kw] = (allKeywords[kw] || 0) + 1; }); }); // Finalize aggregates analysis.averageSentiment.score = totalSentiment; if (totalSentiment > 0) analysis.averageSentiment.label = "positive"; else if (totalSentiment < 0) analysis.averageSentiment.label = "negative"; analysis.topKeywords = Object.entries(allKeywords) .sort((a, b) => b[1] - a[1]) .slice(0, 10) .map(([word, count]) => ({ word, count })); return analysis; } calculateRelevance(text, query) { const queryTerms = query.split(/\s+/).filter((t) => !this.stopwords.has(t)); if (queryTerms.length === 0) return 0; let matchCount = 0; queryTerms.forEach((term) => { const regex = new RegExp(`\\b${term}\\b`, "g"); const matches = (text.match(regex) || []).length; matchCount += matches > 0 ? 1 : 0; }); return matchCount / queryTerms.length; } extractKeywords(text) { const words = text.match(/\b\w+\b/g) || []; const frequency = {}; words.forEach((word) => { if (word.length > 3 && !this.stopwords.has(word)) { frequency[word] = (frequency[word] || 0) + 1; } }); return Object.entries(frequency) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map((entry) => entry[0]); } analyzeSentiment(text) { const positiveWords = ["good", "great", "excellent", "best", "amazing"]; const negativeWords = ["bad", "worst", "terrible", "poor", "awful"]; let score = 0; const words = text.split(/\s+/); words.forEach((word) => { if (positiveWords.includes(word)) score++; if (negativeWords.includes(word)) score--; }); if (score > 0) return "positive"; if (score < 0) return "negative"; return "neutral"; } calculateReadability(text) { // Flesch-Kincaid simplified approximation const sentences = text.split(/[.!?]+/).length; const words = text.split(/\s+/).length; return words / (sentences || 1); // Avg sentence length } } export const contentAnalyzer = new ContentAnalysisService();

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/NosytLabs/presearch-search-api-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server