@raven-js/cortex
Version:
Zero-dependency machine learning, AI, and data processing library for modern JavaScript
179 lines (162 loc) • 4.69 kB
JavaScript
/**
* @author Anonyfox <max@anonyfox.com>
* @license MIT
* @see {@link https://github.com/Anonyfox/ravenjs}
* @see {@link https://ravenjs.dev}
* @see {@link https://anonyfox.com}
*/
/**
* @file Base Model class providing serialization and lifecycle management for ML algorithms.
*
* Abstract foundation class that all machine learning models inherit from.
* Handles model state tracking, JSON serialization, and validation patterns.
*/
/**
* Abstract base class for machine learning models providing serialization and state management.
*
* All Cortex learning algorithms inherit from this class to ensure consistent
* serialization behavior and lifecycle validation across different environments.
*
* @abstract
* @example
* // Custom model implementation
* class CustomModel extends Model {
* constructor() {
* super();
* this.weights = [];
* }
*
* train(data) {
* // Implementation required
* this._markTrained();
* }
*
* predict(input) {
* this._validateTrained();
* // Implementation required
* }
* }
*/
export class Model {
/**
* Create a new Model instance.
* Initializes the base state tracking and validation.
*/
constructor() {
/** @type {boolean} */
this._trained = false;
/** @type {number} */
this._version = 1;
/** @type {string} */
this._modelType = this.constructor.name;
/** @type {number} */
this._createdAt = Date.now();
}
/**
* Serialize the model state to a JSON-friendly object.
* Captures all serializable properties while excluding methods and private state.
*
* @returns {Object} The serialized model state
* @example
* const serialized = model.toJSON();
* const jsonString = JSON.stringify(serialized);
*/
toJSON() {
/** @type {Record<string, any>} */
const result = {};
// Capture all enumerable own properties
for (const key of Object.getOwnPropertyNames(this)) {
/** @type {any} */
const value = /** @type {any} */ (this)[key];
// Skip functions and symbols, capture serializable data
if (typeof value !== "function" && typeof value !== "symbol") {
result[key] = value;
}
}
// Ensure metadata is always included
result._trained = this._trained;
result._version = this._version;
result._modelType = this._modelType;
result._createdAt = this._createdAt;
result._serializedAt = Date.now();
return result;
}
/**
* Create a new model instance from serialized state.
* Validates the serialized data and reconstructs the model.
*
* @param {Record<string, any>} json - The serialized model state
* @param {new () => Model} ModelClass - The model class constructor to instantiate
* @returns {Model} A new model instance
* @throws {Error} If the serialized data is invalid or incompatible
*
* @example
* const modelData = JSON.parse(jsonString);
* const model = Model.fromJSON(modelData, LinearRegression);
*/
static fromJSON(json, ModelClass) {
if (!json || typeof json !== "object") {
throw new Error("Invalid JSON: expected object");
}
if (!ModelClass || typeof ModelClass !== "function") {
throw new Error("Invalid ModelClass: expected constructor function");
}
// Validate model type compatibility
/** @type {any} */
const jsonAny = json;
if (jsonAny._modelType && jsonAny._modelType !== ModelClass.name) {
throw new Error(
`Model type mismatch: expected ${ModelClass.name}, got ${jsonAny._modelType}`,
);
}
// Create new instance and restore state
const model = new ModelClass();
// Restore all serialized properties
for (const [key, value] of Object.entries(json)) {
if (key !== "_serializedAt") {
// Skip serialization timestamp
/** @type {any} */ (model)[key] = value;
}
}
return model;
}
/**
* Validate that the model has been trained before making predictions.
* Prevents usage of untrained models.
*
* @throws {Error} If the model has not been trained
* @protected
*/
_validateTrained() {
if (!this._trained) {
throw new Error(
`${this._modelType} model must be trained before making predictions`,
);
}
}
/**
* Mark the model as trained and update metadata.
* Called by subclasses after successful training.
*
* @protected
*/
_markTrained() {
this._trained = true;
}
/**
* Get model metadata for introspection and debugging.
*
* @returns {Object} Model metadata
* @example
* const info = model.getModelInfo();
* console.log(`Model: ${info.type}, trained: ${info.trained}`);
*/
getModelInfo() {
return {
type: this._modelType,
trained: this._trained,
version: this._version,
createdAt: new Date(this._createdAt),
};
}
}