@neuroequality/neuroadapt-core
Version:
Core sensory, cognitive, and preference management for NeuroAdapt SDK
228 lines (226 loc) • 7.95 kB
JavaScript
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