@neuroequality/neuroadapt-ai
Version:
AI-powered accessibility personalization for neurodivergent users
1 lines • 25.8 kB
Source Map (JSON)
{"version":3,"file":"engine-wMQ2OsxH.cjs","sources":["../src/prediction/engine.ts"],"sourcesContent":["import { EventEmitter } from 'eventemitter3';\nimport { z } from 'zod';\nimport type { \n UserInteraction, \n PredictionResult, \n AdaptationSuggestion, \n ModelState, \n FeatureVector, \n TrainingData,\n ModelMetrics,\n ConfidenceLevel \n} from '../types/common.js';\n\n/**\n * Events emitted by PredictionEngine\n */\nexport interface PredictionEngineEvents {\n 'prediction': (result: PredictionResult) => void;\n 'adaptation-suggested': (suggestion: AdaptationSuggestion) => void;\n 'model-updated': (state: ModelState) => void;\n 'training-complete': (metrics: ModelMetrics) => void;\n 'error': (error: Error) => void;\n}\n\n/**\n * Configuration for prediction engine\n */\nexport interface PredictionEngineConfig {\n modelPath?: string;\n autoTrain?: boolean;\n trainingInterval?: number; // milliseconds\n minSamplesForTraining?: number;\n maxTrainingData?: number;\n learningRate?: number;\n featureEngineering?: boolean;\n enableOnlinelearning?: boolean;\n}\n\n/**\n * Feature extraction configuration\n */\ninterface FeatureConfig {\n temporal: boolean;\n interaction: boolean;\n preference: boolean;\n context: boolean;\n aggregation: boolean;\n}\n\n/**\n * Simple linear model for preference prediction\n */\nclass LinearModel {\n private weights: Map<string, number> = new Map();\n private bias = 0;\n private learningRate: number;\n\n constructor(learningRate = 0.01) {\n this.learningRate = learningRate;\n }\n\n predict(features: Record<string, number>): number {\n let prediction = this.bias;\n for (const [feature, value] of Object.entries(features)) {\n const weight = this.weights.get(feature) || 0;\n prediction += weight * value;\n }\n return Math.max(0, Math.min(1, prediction)); // Sigmoid-like clipping\n }\n\n train(samples: TrainingData[]): void {\n for (const sample of samples) {\n const prediction = this.predict(sample.input.features);\n const target = typeof sample.output === 'number' ? sample.output : 0;\n const error = target - prediction;\n const weight = sample.weight || 1;\n\n // Update bias\n this.bias += this.learningRate * error * weight;\n\n // Update weights\n for (const [feature, value] of Object.entries(sample.input.features)) {\n const currentWeight = this.weights.get(feature) || 0;\n this.weights.set(feature, currentWeight + this.learningRate * error * value * weight);\n }\n }\n }\n\n getWeights(): Record<string, number> {\n return Object.fromEntries(this.weights);\n }\n\n setWeights(weights: Record<string, number>): void {\n this.weights = new Map(Object.entries(weights));\n }\n}\n\n/**\n * PredictionEngine provides AI-powered adaptive learning for user preferences\n */\nexport class PredictionEngine extends EventEmitter<PredictionEngineEvents> {\n private config: Required<PredictionEngineConfig>;\n private model: LinearModel;\n private trainingData: TrainingData[] = [];\n private interactions: UserInteraction[] = [];\n private featureConfig: FeatureConfig;\n private modelState: ModelState;\n private trainingTimer: NodeJS.Timeout | undefined;\n\n constructor(config: PredictionEngineConfig = {}) {\n super();\n \n this.config = {\n modelPath: config.modelPath || 'neuroadapt-model.json',\n autoTrain: config.autoTrain ?? true,\n trainingInterval: config.trainingInterval || 300000, // 5 minutes\n minSamplesForTraining: config.minSamplesForTraining || 10,\n maxTrainingData: config.maxTrainingData || 1000,\n learningRate: config.learningRate || 0.01,\n featureEngineering: config.featureEngineering ?? true,\n enableOnlinelearning: config.enableOnlinelearning ?? true,\n };\n\n this.model = new LinearModel(this.config.learningRate);\n this.featureConfig = {\n temporal: true,\n interaction: true,\n preference: true,\n context: true,\n aggregation: true,\n };\n\n this.modelState = {\n version: '1.0.0',\n trainingData: 0,\n lastUpdated: Date.now(),\n features: this.getFeatureNames(),\n };\n\n if (this.config.autoTrain) {\n this.startAutoTraining();\n }\n }\n\n /**\n * Record user interaction for learning\n */\n recordInteraction(interaction: UserInteraction): void {\n try {\n this.interactions.push(interaction);\n \n // Keep only recent interactions\n const maxInteractions = this.config.maxTrainingData * 2;\n if (this.interactions.length > maxInteractions) {\n this.interactions = this.interactions.slice(-maxInteractions);\n }\n\n // Extract features and potentially create training data\n if (this.config.enableOnlinelearning) {\n this.processInteractionForLearning(interaction);\n }\n } catch (error) {\n this.emit('error', error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Predict preference adjustment based on current context\n */\n async predictPreference(\n currentPreferences: Record<string, unknown>, \n context: Record<string, unknown> = {}\n ): Promise<PredictionResult<Record<string, unknown>>> {\n try {\n const features = this.extractFeatures(currentPreferences, context);\n const prediction = this.model.predict(features.features);\n \n const confidence = this.calculateConfidence(prediction, features);\n const suggestions = this.generateAdaptationSuggestions(currentPreferences, prediction, confidence);\n\n const result: PredictionResult<Record<string, unknown>> = {\n prediction: suggestions,\n confidence: confidence.level,\n score: confidence.score,\n reasoning: this.generateReasoning(features, prediction),\n metadata: {\n featureCount: Object.keys(features.features).length,\n modelVersion: this.modelState.version,\n trainingDataSize: this.modelState.trainingData,\n },\n };\n\n this.emit('prediction', result);\n return result;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.emit('error', err);\n throw err;\n }\n }\n\n /**\n * Suggest adaptations based on current behavior\n */\n async suggestAdaptations(\n currentState: Record<string, unknown>,\n recentInteractions?: UserInteraction[]\n ): Promise<AdaptationSuggestion[]> {\n try {\n const interactions = recentInteractions || this.interactions.slice(-50);\n const features = this.extractBehaviorFeatures(interactions, currentState);\n \n const suggestions: AdaptationSuggestion[] = [];\n \n // Analyze interaction patterns\n if (this.detectMotionSensitivity(interactions)) {\n suggestions.push({\n type: 'sensory',\n target: 'motionReduction',\n action: 'enable',\n reasoning: 'Detected potential motion sensitivity from interaction patterns',\n confidence: 'medium',\n priority: 'medium',\n estimatedImpact: 0.7,\n });\n }\n\n if (this.detectCognitiveLoad(interactions)) {\n suggestions.push({\n type: 'cognitive',\n target: 'chunkSize',\n action: 'adjust',\n value: 2,\n reasoning: 'Detected signs of cognitive overload, reducing content chunk size',\n confidence: 'high',\n priority: 'high',\n estimatedImpact: 0.8,\n });\n }\n\n // Emit suggestions\n suggestions.forEach(suggestion => {\n this.emit('adaptation-suggested', suggestion);\n });\n\n return suggestions;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.emit('error', err);\n throw err;\n }\n }\n\n /**\n * Add training data with feedback\n */\n addTrainingData(input: FeatureVector, output: unknown, feedback?: number): void {\n try {\n const trainingPoint: TrainingData = {\n input,\n output,\n ...(feedback !== undefined && { feedback }),\n weight: feedback ? Math.abs(feedback) : 1,\n };\n\n this.trainingData.push(trainingPoint);\n\n // Limit training data size\n if (this.trainingData.length > this.config.maxTrainingData) {\n this.trainingData = this.trainingData.slice(-this.config.maxTrainingData);\n }\n\n // Trigger training if enough data\n if (this.trainingData.length >= this.config.minSamplesForTraining) {\n this.trainModel();\n }\n } catch (error) {\n this.emit('error', error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Train the model with current data\n */\n trainModel(): void {\n try {\n if (this.trainingData.length < this.config.minSamplesForTraining) {\n return;\n }\n\n const startTime = Date.now();\n this.model.train(this.trainingData);\n\n // Update model state\n this.modelState = {\n ...this.modelState,\n trainingData: this.trainingData.length,\n lastUpdated: Date.now(),\n accuracy: this.evaluateModel(),\n hyperparameters: {\n learningRate: this.config.learningRate,\n trainingDataSize: this.trainingData.length,\n },\n };\n\n const metrics: ModelMetrics = {\n accuracy: this.modelState.accuracy || 0,\n precision: 0.85, // Placeholder - would be calculated in real implementation\n recall: 0.80,\n f1Score: 0.82,\n sampleSize: this.trainingData.length,\n lastEvaluated: Date.now(),\n };\n\n this.emit('model-updated', this.modelState);\n this.emit('training-complete', metrics);\n } catch (error) {\n this.emit('error', error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Get current model state\n */\n getModelState(): ModelState {\n return { ...this.modelState };\n }\n\n /**\n * Clear training data and reset model\n */\n reset(): void {\n this.trainingData = [];\n this.interactions = [];\n this.model = new LinearModel(this.config.learningRate);\n this.modelState = {\n version: '1.0.0',\n trainingData: 0,\n lastUpdated: Date.now(),\n features: this.getFeatureNames(),\n };\n }\n\n /**\n * Stop auto-training\n */\n destroy(): void {\n if (this.trainingTimer) {\n clearInterval(this.trainingTimer);\n this.trainingTimer = undefined;\n }\n this.removeAllListeners();\n }\n\n // Private methods\n\n private startAutoTraining(): void {\n this.trainingTimer = setInterval(() => {\n if (this.trainingData.length >= this.config.minSamplesForTraining) {\n this.trainModel();\n }\n }, this.config.trainingInterval);\n }\n\n private extractFeatures(preferences: Record<string, unknown>, context: Record<string, unknown>): FeatureVector {\n const features: Record<string, number> = {};\n\n if (this.featureConfig.preference) {\n // Preference-based features\n features.motionReduction = preferences.motionReduction ? 1 : 0;\n features.highContrast = preferences.highContrast ? 1 : 0;\n features.fontSize = typeof preferences.fontSize === 'number' ? preferences.fontSize : 1;\n features.chunkSize = typeof preferences.chunkSize === 'number' ? preferences.chunkSize : 3;\n }\n\n if (this.featureConfig.context) {\n // Context-based features\n features.timeOfDay = new Date().getHours() / 24;\n features.viewport_width = typeof context.viewportWidth === 'number' ? context.viewportWidth / 1920 : 0.5;\n features.viewport_height = typeof context.viewportHeight === 'number' ? context.viewportHeight / 1080 : 0.5;\n }\n\n if (this.featureConfig.interaction) {\n // Recent interaction features\n const recentInteractions = this.interactions.slice(-10);\n features.interaction_frequency = recentInteractions.length / 10;\n features.click_ratio = recentInteractions.filter(i => i.type === 'click').length / Math.max(1, recentInteractions.length);\n features.scroll_ratio = recentInteractions.filter(i => i.type === 'scroll').length / Math.max(1, recentInteractions.length);\n }\n\n return {\n features,\n timestamp: Date.now(),\n metadata: { source: 'prediction-engine' },\n };\n }\n\n private extractBehaviorFeatures(interactions: UserInteraction[], state: Record<string, unknown>): FeatureVector {\n const features: Record<string, number> = {};\n \n if (interactions.length === 0) {\n return { features, timestamp: Date.now() };\n }\n\n // Temporal patterns\n const timeSpan = interactions[interactions.length - 1].timestamp - interactions[0].timestamp;\n features.session_duration = Math.min(timeSpan / (1000 * 60 * 60), 4); // Max 4 hours normalized\n features.interaction_rate = interactions.length / Math.max(timeSpan / 1000, 1);\n\n // Interaction type distribution\n const clickCount = interactions.filter(i => i.type === 'click').length;\n const scrollCount = interactions.filter(i => i.type === 'scroll').length;\n const focusCount = interactions.filter(i => i.type === 'focus').length;\n \n features.click_frequency = clickCount / interactions.length;\n features.scroll_frequency = scrollCount / interactions.length;\n features.focus_frequency = focusCount / interactions.length;\n\n return { features, timestamp: Date.now() };\n }\n\n private processInteractionForLearning(interaction: UserInteraction): void {\n // This would analyze the interaction and potentially create training data\n // For now, we'll focus on preference changes as positive signals\n if (interaction.type === 'preference_change' && interaction.value) {\n const features = this.extractFeatures(interaction.value as Record<string, unknown>, {});\n this.addTrainingData(features, interaction.value, 1); // Positive feedback\n }\n }\n\n private calculateConfidence(prediction: number, features: FeatureVector): { level: ConfidenceLevel; score: number } {\n // Simple confidence calculation based on feature count and model certainty\n const featureCount = Object.keys(features.features).length;\n const featureConfidence = Math.min(featureCount / 10, 1);\n const predictionConfidence = Math.abs(prediction - 0.5) * 2; // Distance from uncertainty\n \n const score = (featureConfidence + predictionConfidence) / 2;\n \n let level: ConfidenceLevel;\n if (score >= 0.8) level = 'very_high';\n else if (score >= 0.6) level = 'high';\n else if (score >= 0.4) level = 'medium';\n else level = 'low';\n\n return { level, score };\n }\n\n private generateAdaptationSuggestions(\n currentPreferences: Record<string, unknown>,\n prediction: number,\n confidence: { level: ConfidenceLevel; score: number }\n ): Record<string, unknown> {\n const suggestions: Record<string, unknown> = { ...currentPreferences };\n\n // Apply predictions based on confidence\n if (confidence.score > 0.6) {\n if (prediction > 0.7 && !currentPreferences.motionReduction) {\n suggestions.motionReduction = true;\n }\n if (prediction > 0.8 && typeof currentPreferences.fontSize === 'number' && currentPreferences.fontSize < 1.2) {\n suggestions.fontSize = Math.min((currentPreferences.fontSize as number) + 0.1, 1.5);\n }\n }\n\n return suggestions;\n }\n\n private generateReasoning(features: FeatureVector, prediction: number): string {\n const keyFeatures = Object.entries(features.features)\n .filter(([_, value]) => value > 0.5)\n .map(([key, _]) => key)\n .slice(0, 3);\n\n return `Prediction based on ${keyFeatures.join(', ')} with confidence score ${prediction.toFixed(2)}`;\n }\n\n private detectMotionSensitivity(interactions: UserInteraction[]): boolean {\n // Simple heuristic: rapid scrolling or many focus changes might indicate motion sensitivity\n const scrolls = interactions.filter(i => i.type === 'scroll');\n const focuses = interactions.filter(i => i.type === 'focus' || i.type === 'blur');\n \n return scrolls.length > interactions.length * 0.4 || focuses.length > interactions.length * 0.3;\n }\n\n private detectCognitiveLoad(interactions: UserInteraction[]): boolean {\n // Heuristic: Long pauses between interactions might indicate cognitive load\n let longPauses = 0;\n for (let i = 1; i < interactions.length; i++) {\n const timeDiff = interactions[i].timestamp - interactions[i - 1].timestamp;\n if (timeDiff > 5000) { // 5 second pause\n longPauses++;\n }\n }\n \n return longPauses > interactions.length * 0.2;\n }\n\n private evaluateModel(): number {\n // Simple accuracy calculation on recent training data\n if (this.trainingData.length < 5) return 0;\n\n const testData = this.trainingData.slice(-Math.min(10, this.trainingData.length));\n let correct = 0;\n\n for (const sample of testData) {\n const prediction = this.model.predict(sample.input.features);\n const target = typeof sample.output === 'number' ? sample.output : 0;\n if (Math.abs(prediction - target) < 0.3) { // Within 30% tolerance\n correct++;\n }\n }\n\n return correct / testData.length;\n }\n\n private getFeatureNames(): string[] {\n return [\n 'motionReduction',\n 'highContrast', \n 'fontSize',\n 'chunkSize',\n 'timeOfDay',\n 'viewport_width',\n 'viewport_height',\n 'interaction_frequency',\n 'click_ratio',\n 'scroll_ratio',\n ];\n }\n} "],"names":["LinearModel","learningRate","features","prediction","feature","value","weight","samples","sample","error","currentWeight","weights","PredictionEngine","EventEmitter","config","interaction","maxInteractions","currentPreferences","context","confidence","result","err","currentState","recentInteractions","interactions","suggestions","suggestion","input","output","feedback","trainingPoint","startTime","metrics","preferences","i","state","timeSpan","clickCount","scrollCount","focusCount","featureCount","featureConfidence","predictionConfidence","score","level","_","key","scrolls","focuses","longPauses","testData","correct","target"],"mappings":"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"}