@neuroequality/neuroadapt-ai
Version:
AI-powered accessibility personalization for neurodivergent users
3 lines (2 loc) • 7.38 kB
JavaScript
"use strict";const l=require("eventemitter3");class h{constructor(t=.01){this.weights=new Map,this.bias=0,this.learningRate=t}predict(t){let i=this.bias;for(const[e,n]of Object.entries(t)){const r=this.weights.get(e)||0;i+=r*n}return Math.max(0,Math.min(1,i))}train(t){for(const i of t){const e=this.predict(i.input.features),r=(typeof i.output=="number"?i.output:0)-e,s=i.weight||1;this.bias+=this.learningRate*r*s;for(const[a,o]of Object.entries(i.input.features)){const g=this.weights.get(a)||0;this.weights.set(a,g+this.learningRate*r*o*s)}}}getWeights(){return Object.fromEntries(this.weights)}setWeights(t){this.weights=new Map(Object.entries(t))}}class u extends l.EventEmitter{constructor(t={}){super(),this.trainingData=[],this.interactions=[],this.config={modelPath:t.modelPath||"neuroadapt-model.json",autoTrain:t.autoTrain??!0,trainingInterval:t.trainingInterval||3e5,minSamplesForTraining:t.minSamplesForTraining||10,maxTrainingData:t.maxTrainingData||1e3,learningRate:t.learningRate||.01,featureEngineering:t.featureEngineering??!0,enableOnlinelearning:t.enableOnlinelearning??!0},this.model=new h(this.config.learningRate),this.featureConfig={temporal:!0,interaction:!0,preference:!0,context:!0,aggregation:!0},this.modelState={version:"1.0.0",trainingData:0,lastUpdated:Date.now(),features:this.getFeatureNames()},this.config.autoTrain&&this.startAutoTraining()}recordInteraction(t){try{this.interactions.push(t);const i=this.config.maxTrainingData*2;this.interactions.length>i&&(this.interactions=this.interactions.slice(-i)),this.config.enableOnlinelearning&&this.processInteractionForLearning(t)}catch(i){this.emit("error",i instanceof Error?i:new Error(String(i)))}}async predictPreference(t,i={}){try{const e=this.extractFeatures(t,i),n=this.model.predict(e.features),r=this.calculateConfidence(n,e),a={prediction:this.generateAdaptationSuggestions(t,n,r),confidence:r.level,score:r.score,reasoning:this.generateReasoning(e,n),metadata:{featureCount:Object.keys(e.features).length,modelVersion:this.modelState.version,trainingDataSize:this.modelState.trainingData}};return this.emit("prediction",a),a}catch(e){const n=e instanceof Error?e:new Error(String(e));throw this.emit("error",n),n}}async suggestAdaptations(t,i){try{const e=i||this.interactions.slice(-50),n=this.extractBehaviorFeatures(e,t),r=[];return this.detectMotionSensitivity(e)&&r.push({type:"sensory",target:"motionReduction",action:"enable",reasoning:"Detected potential motion sensitivity from interaction patterns",confidence:"medium",priority:"medium",estimatedImpact:.7}),this.detectCognitiveLoad(e)&&r.push({type:"cognitive",target:"chunkSize",action:"adjust",value:2,reasoning:"Detected signs of cognitive overload, reducing content chunk size",confidence:"high",priority:"high",estimatedImpact:.8}),r.forEach(s=>{this.emit("adaptation-suggested",s)}),r}catch(e){const n=e instanceof Error?e:new Error(String(e));throw this.emit("error",n),n}}addTrainingData(t,i,e){try{const n={input:t,output:i,...e!==void 0&&{feedback:e},weight:e?Math.abs(e):1};this.trainingData.push(n),this.trainingData.length>this.config.maxTrainingData&&(this.trainingData=this.trainingData.slice(-this.config.maxTrainingData)),this.trainingData.length>=this.config.minSamplesForTraining&&this.trainModel()}catch(n){this.emit("error",n instanceof Error?n:new Error(String(n)))}}trainModel(){try{if(this.trainingData.length<this.config.minSamplesForTraining)return;const t=Date.now();this.model.train(this.trainingData),this.modelState={...this.modelState,trainingData:this.trainingData.length,lastUpdated:Date.now(),accuracy:this.evaluateModel(),hyperparameters:{learningRate:this.config.learningRate,trainingDataSize:this.trainingData.length}};const i={accuracy:this.modelState.accuracy||0,precision:.85,recall:.8,f1Score:.82,sampleSize:this.trainingData.length,lastEvaluated:Date.now()};this.emit("model-updated",this.modelState),this.emit("training-complete",i)}catch(t){this.emit("error",t instanceof Error?t:new Error(String(t)))}}getModelState(){return{...this.modelState}}reset(){this.trainingData=[],this.interactions=[],this.model=new h(this.config.learningRate),this.modelState={version:"1.0.0",trainingData:0,lastUpdated:Date.now(),features:this.getFeatureNames()}}destroy(){this.trainingTimer&&(clearInterval(this.trainingTimer),this.trainingTimer=void 0),this.removeAllListeners()}startAutoTraining(){this.trainingTimer=setInterval(()=>{this.trainingData.length>=this.config.minSamplesForTraining&&this.trainModel()},this.config.trainingInterval)}extractFeatures(t,i){const e={};if(this.featureConfig.preference&&(e.motionReduction=t.motionReduction?1:0,e.highContrast=t.highContrast?1:0,e.fontSize=typeof t.fontSize=="number"?t.fontSize:1,e.chunkSize=typeof t.chunkSize=="number"?t.chunkSize:3),this.featureConfig.context&&(e.timeOfDay=new Date().getHours()/24,e.viewport_width=typeof i.viewportWidth=="number"?i.viewportWidth/1920:.5,e.viewport_height=typeof i.viewportHeight=="number"?i.viewportHeight/1080:.5),this.featureConfig.interaction){const n=this.interactions.slice(-10);e.interaction_frequency=n.length/10,e.click_ratio=n.filter(r=>r.type==="click").length/Math.max(1,n.length),e.scroll_ratio=n.filter(r=>r.type==="scroll").length/Math.max(1,n.length)}return{features:e,timestamp:Date.now(),metadata:{source:"prediction-engine"}}}extractBehaviorFeatures(t,i){const e={};if(t.length===0)return{features:e,timestamp:Date.now()};const n=t[t.length-1].timestamp-t[0].timestamp;e.session_duration=Math.min(n/(1e3*60*60),4),e.interaction_rate=t.length/Math.max(n/1e3,1);const r=t.filter(o=>o.type==="click").length,s=t.filter(o=>o.type==="scroll").length,a=t.filter(o=>o.type==="focus").length;return e.click_frequency=r/t.length,e.scroll_frequency=s/t.length,e.focus_frequency=a/t.length,{features:e,timestamp:Date.now()}}processInteractionForLearning(t){if(t.type==="preference_change"&&t.value){const i=this.extractFeatures(t.value,{});this.addTrainingData(i,t.value,1)}}calculateConfidence(t,i){const e=Object.keys(i.features).length,n=Math.min(e/10,1),r=Math.abs(t-.5)*2,s=(n+r)/2;let a;return s>=.8?a="very_high":s>=.6?a="high":s>=.4?a="medium":a="low",{level:a,score:s}}generateAdaptationSuggestions(t,i,e){const n={...t};return e.score>.6&&(i>.7&&!t.motionReduction&&(n.motionReduction=!0),i>.8&&typeof t.fontSize=="number"&&t.fontSize<1.2&&(n.fontSize=Math.min(t.fontSize+.1,1.5))),n}generateReasoning(t,i){return`Prediction based on ${Object.entries(t.features).filter(([n,r])=>r>.5).map(([n,r])=>n).slice(0,3).join(", ")} with confidence score ${i.toFixed(2)}`}detectMotionSensitivity(t){const i=t.filter(n=>n.type==="scroll"),e=t.filter(n=>n.type==="focus"||n.type==="blur");return i.length>t.length*.4||e.length>t.length*.3}detectCognitiveLoad(t){let i=0;for(let e=1;e<t.length;e++)t[e].timestamp-t[e-1].timestamp>5e3&&i++;return i>t.length*.2}evaluateModel(){if(this.trainingData.length<5)return 0;const t=this.trainingData.slice(-Math.min(10,this.trainingData.length));let i=0;for(const e of t){const n=this.model.predict(e.input.features),r=typeof e.output=="number"?e.output:0;Math.abs(n-r)<.3&&i++}return i/t.length}getFeatureNames(){return["motionReduction","highContrast","fontSize","chunkSize","timeOfDay","viewport_width","viewport_height","interaction_frequency","click_ratio","scroll_ratio"]}}exports.PredictionEngine=u;
//# sourceMappingURL=engine-wMQ2OsxH.cjs.map