@neuroequality/neuroadapt-ai
Version:
AI-powered accessibility personalization for neurodivergent users
276 lines (275 loc) • 10.2 kB
JavaScript
import { EventEmitter as l } from "eventemitter3";
class h {
constructor(t = 0.01) {
this.weights = /* @__PURE__ */ new Map(), this.bias = 0, this.learningRate = t;
}
predict(t) {
let i = this.bias;
for (const [e, n] of Object.entries(t)) {
const a = this.weights.get(e) || 0;
i += a * n;
}
return Math.max(0, Math.min(1, i));
}
train(t) {
for (const i of t) {
const e = this.predict(i.input.features), a = (typeof i.output == "number" ? i.output : 0) - e, s = i.weight || 1;
this.bias += this.learningRate * a * s;
for (const [r, o] of Object.entries(i.input.features)) {
const g = this.weights.get(r) || 0;
this.weights.set(r, g + this.learningRate * a * o * s);
}
}
}
getWeights() {
return Object.fromEntries(this.weights);
}
setWeights(t) {
this.weights = new Map(Object.entries(t));
}
}
class m extends l {
constructor(t = {}) {
super(), this.trainingData = [], this.interactions = [], this.config = {
modelPath: t.modelPath || "neuroadapt-model.json",
autoTrain: t.autoTrain ?? !0,
trainingInterval: t.trainingInterval || 3e5,
// 5 minutes
minSamplesForTraining: t.minSamplesForTraining || 10,
maxTrainingData: t.maxTrainingData || 1e3,
learningRate: t.learningRate || 0.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();
}
/**
* Record user interaction for learning
*/
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)));
}
}
/**
* Predict preference adjustment based on current context
*/
async predictPreference(t, i = {}) {
try {
const e = this.extractFeatures(t, i), n = this.model.predict(e.features), a = this.calculateConfidence(n, e), r = {
prediction: this.generateAdaptationSuggestions(t, n, a),
confidence: a.level,
score: a.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", r), r;
} catch (e) {
const n = e instanceof Error ? e : new Error(String(e));
throw this.emit("error", n), n;
}
}
/**
* Suggest adaptations based on current behavior
*/
async suggestAdaptations(t, i) {
try {
const e = i || this.interactions.slice(-50), n = this.extractBehaviorFeatures(e, t), a = [];
return this.detectMotionSensitivity(e) && a.push({
type: "sensory",
target: "motionReduction",
action: "enable",
reasoning: "Detected potential motion sensitivity from interaction patterns",
confidence: "medium",
priority: "medium",
estimatedImpact: 0.7
}), this.detectCognitiveLoad(e) && a.push({
type: "cognitive",
target: "chunkSize",
action: "adjust",
value: 2,
reasoning: "Detected signs of cognitive overload, reducing content chunk size",
confidence: "high",
priority: "high",
estimatedImpact: 0.8
}), a.forEach((s) => {
this.emit("adaptation-suggested", s);
}), a;
} catch (e) {
const n = e instanceof Error ? e : new Error(String(e));
throw this.emit("error", n), n;
}
}
/**
* Add training data with feedback
*/
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)));
}
}
/**
* Train the model with current data
*/
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: 0.85,
// Placeholder - would be calculated in real implementation
recall: 0.8,
f1Score: 0.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)));
}
}
/**
* Get current model state
*/
getModelState() {
return { ...this.modelState };
}
/**
* Clear training data and reset model
*/
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()
};
}
/**
* Stop auto-training
*/
destroy() {
this.trainingTimer && (clearInterval(this.trainingTimer), this.trainingTimer = void 0), this.removeAllListeners();
}
// Private methods
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 = (/* @__PURE__ */ new Date()).getHours() / 24, e.viewport_width = typeof i.viewportWidth == "number" ? i.viewportWidth / 1920 : 0.5, e.viewport_height = typeof i.viewportHeight == "number" ? i.viewportHeight / 1080 : 0.5), this.featureConfig.interaction) {
const n = this.interactions.slice(-10);
e.interaction_frequency = n.length / 10, e.click_ratio = n.filter((a) => a.type === "click").length / Math.max(1, n.length), e.scroll_ratio = n.filter((a) => a.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 a = t.filter((o) => o.type === "click").length, s = t.filter((o) => o.type === "scroll").length, r = t.filter((o) => o.type === "focus").length;
return e.click_frequency = a / t.length, e.scroll_frequency = s / t.length, e.focus_frequency = r / 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), a = Math.abs(t - 0.5) * 2, s = (n + a) / 2;
let r;
return s >= 0.8 ? r = "very_high" : s >= 0.6 ? r = "high" : s >= 0.4 ? r = "medium" : r = "low", { level: r, score: s };
}
generateAdaptationSuggestions(t, i, e) {
const n = { ...t };
return e.score > 0.6 && (i > 0.7 && !t.motionReduction && (n.motionReduction = !0), i > 0.8 && typeof t.fontSize == "number" && t.fontSize < 1.2 && (n.fontSize = Math.min(t.fontSize + 0.1, 1.5))), n;
}
generateReasoning(t, i) {
return `Prediction based on ${Object.entries(t.features).filter(([n, a]) => a > 0.5).map(([n, a]) => 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 * 0.4 || e.length > t.length * 0.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 * 0.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), a = typeof e.output == "number" ? e.output : 0;
Math.abs(n - a) < 0.3 && i++;
}
return i / t.length;
}
getFeatureNames() {
return [
"motionReduction",
"highContrast",
"fontSize",
"chunkSize",
"timeOfDay",
"viewport_width",
"viewport_height",
"interaction_frequency",
"click_ratio",
"scroll_ratio"
];
}
}
export {
m as P
};
//# sourceMappingURL=engine-BGE0wXCL.js.map