UNPKG

@neuroequality/neuroadapt-core

Version:

Core sensory, cognitive, and preference management for NeuroAdapt SDK

228 lines (226 loc) 7.95 kB
import { EventEmitter } from "eventemitter3"; class CognitiveLoadEngine extends EventEmitter { constructor(config) { super(); this.strategies = /* @__PURE__ */ new Map(); this.preferences = config.preferences; this.memoryEnabled = config.sessionMemory ?? true; this.adaptationThreshold = config.adaptationThreshold ?? 70; this.sessionMemory = { explanations: /* @__PURE__ */ new Set(), adaptations: /* @__PURE__ */ new Map(), timestamp: Date.now() }; this.initializeStrategies(); } /** * Analyze text and calculate cognitive load score */ analyzeText(text, context) { const metrics = this.calculateTextMetrics(text); const score = this.calculateCognitiveScore(metrics); const tier = this.getCognitiveTier(score); this.emit("load-score", { score, tier, ...context && { context } }); if (score >= this.adaptationThreshold) { this.suggestAdaptation(text, score, context); } return metrics; } /** * Estimate reading time for given text based on user preferences */ readingTimeEstimate(text) { const wordCount = this.countWords(text); const baseWPM = this.getReadingSpeed(); const complexityFactor = this.getComplexityFactor(text); const adjustedWPM = baseWPM / complexityFactor; return Math.ceil(wordCount / adjustedWPM); } /** * Identify dense sections that may cause cognitive overload */ denseSections(text) { const sentences = this.splitIntoSentences(text); const denseSections = []; for (const sentence of sentences) { if (this.isDenseSentence(sentence)) { denseSections.push(sentence.trim()); } } return denseSections; } /** * Apply adaptation strategy to text */ applyStrategy(strategy, text, context) { const strategyFn = this.strategies.get(strategy); if (!strategyFn) { throw new Error(`Unknown adaptation strategy: ${strategy}`); } const memoryKey = `${strategy}:${text.substring(0, 100)}`; if (this.memoryEnabled && this.sessionMemory.adaptations.has(memoryKey)) { return this.sessionMemory.adaptations.get(memoryKey); } const result = strategyFn(text, context); if (this.memoryEnabled) { this.sessionMemory.adaptations.set(memoryKey, result); } this.emit("adaptation-applied", strategy, result); return result; } /** * Register a custom adaptation strategy */ registerStrategy(name, fn) { this.strategies.set(name, fn); } /** * Clear session memory */ clearMemory() { this.sessionMemory.explanations.clear(); this.sessionMemory.adaptations.clear(); this.sessionMemory.timestamp = Date.now(); } /** * Get current cognitive load tier based on score */ getCognitiveTier(score) { if (score < 40) return "low"; if (score < 70) return "moderate"; return "high"; } calculateTextMetrics(text) { const words = this.countWords(text); const sentences = this.splitIntoSentences(text); const complexWords = this.countComplexWords(text); const metrics = { wordCount: words, sentenceCount: sentences.length, averageWordsPerSentence: words / Math.max(sentences.length, 1), complexWords, readingTimeEstimate: this.readingTimeEstimate(text), fleschScore: this.calculateFleschScore(words, sentences.length, complexWords), denseSections: this.denseSections(text) }; return metrics; } calculateCognitiveScore(metrics) { let score = 0; if (metrics.averageWordsPerSentence > 20) score += 25; else if (metrics.averageWordsPerSentence > 15) score += 15; else if (metrics.averageWordsPerSentence > 10) score += 5; const complexWordRatio = metrics.complexWords / metrics.wordCount; if (complexWordRatio > 0.3) score += 30; else if (complexWordRatio > 0.2) score += 20; else if (complexWordRatio > 0.1) score += 10; if (metrics.fleschScore < 30) score += 25; else if (metrics.fleschScore < 50) score += 15; else if (metrics.fleschScore < 70) score += 10; score += metrics.denseSections.length * 5; score = this.adjustForPreferences(score); return Math.min(Math.max(score, 0), 100); } adjustForPreferences(baseScore) { let adjusted = baseScore; switch (this.preferences.readingSpeed) { case "slow": adjusted *= 1.3; break; case "fast": adjusted *= 0.7; break; } switch (this.preferences.processingPace) { case "relaxed": adjusted *= 1.2; break; case "quick": adjusted *= 0.8; break; } if (!this.preferences.allowInterruptions) { adjusted *= 1.1; } return adjusted; } suggestAdaptation(_text, score, context) { let strategy; if (score >= 85) { strategy = "offerBreak"; } else if (score >= 70) { strategy = "simplifyLanguage"; } else { strategy = "chunk"; } this.emit("strategy-suggested", strategy, context || "high cognitive load detected"); } initializeStrategies() { this.strategies.set("chunk", (text) => { const sentences = this.splitIntoSentences(text); const chunkSize = this.preferences.chunkSize || 3; const chunks = []; for (let i = 0; i < sentences.length; i += chunkSize) { const chunk = sentences.slice(i, i + chunkSize).join(" "); chunks.push(chunk); } return chunks.join("\n\n[Continue when ready]\n\n"); }); this.strategies.set("offerBreak", (text) => { return `[BreakSuggestion] This content is quite dense. Would you like to take a break before continuing? ${text}`; }); this.strategies.set("simplifyLanguage", (text) => { return text.replace(/\b(utilize|utilization)\b/gi, "use").replace(/\b(demonstrate|demonstrates)\b/gi, "show").replace(/\b(facilitate|facilitates)\b/gi, "help").replace(/\b(implement|implementation)\b/gi, "put in place").replace(/\b(methodology)\b/gi, "method").replace(/\b(subsequently)\b/gi, "then").replace(/\b(furthermore)\b/gi, "also").replace(/\b(nevertheless)\b/gi, "however") + "\n\n[Simplified for easier reading]"; }); } getReadingSpeed() { switch (this.preferences.readingSpeed) { case "slow": return 150; case "fast": return 300; default: return 200; } } getComplexityFactor(text) { const complexWords = this.countComplexWords(text); const totalWords = this.countWords(text); const ratio = complexWords / totalWords; return 1 + ratio * 0.5; } countWords(text) { return text.trim().split(/\s+/).filter((word) => word.length > 0).length; } splitIntoSentences(text) { return text.split(/[.!?]+/).filter((sentence) => sentence.trim().length > 0); } countComplexWords(text) { const words = text.toLowerCase().match(/\b\w+\b/g) || []; return words.filter((word) => this.isComplexWord(word)).length; } isComplexWord(word) { return this.countSyllables(word) >= 3 || /^(implementation|functionality|configuration|optimization|methodology)/.test(word) || word.length > 12; } countSyllables(word) { const vowels = word.match(/[aeiouy]+/gi); const silentE = /e$/i.test(word); const syllableCount = vowels ? vowels.length : 1; return silentE && syllableCount > 1 ? syllableCount - 1 : syllableCount; } isDenseSentence(sentence) { const words = this.countWords(sentence); const complexWords = this.countComplexWords(sentence); return words > 25 || complexWords / words > 0.3 || sentence.split(",").length > 4; } calculateFleschScore(words, sentences, complexWords) { const avgSentenceLength = words / Math.max(sentences, 1); const avgSyllablesPerWord = (words + complexWords) / Math.max(words, 1); return 206.835 - 1.015 * avgSentenceLength - 84.6 * avgSyllablesPerWord; } } export { CognitiveLoadEngine }; //# sourceMappingURL=load-engine.js.map