UNPKG

@nodify_at/hailo.js

Version:

High-performance Node.js bindings for Hailo AI acceleration processors (NPU). Run neural network inference with hardware acceleration on Hailo-8 devices.

186 lines 5.88 kB
import { createRequire } from 'node:module'; /** * HailoDevice - High-level wrapper for Hailo AI inference * Provides a clean, type-safe interface with performance monitoring */ import { EventEmitter } from 'events'; import { ModelType, } from './types.js'; import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { join } from 'path'; // Create require for CommonJS modules const require = createRequire(import.meta.url); const __dirname = dirname(fileURLToPath(import.meta.url)); // Load node-gyp-build and cast it const nodeGypBuild = require('node-gyp-build'); const addon = nodeGypBuild(join(__dirname, '..')); /** * High-level Hailo device interface with enhanced functionality * * @example * ```typescript * const device = new HailoDevice(); * await device.loadModel({ * type: ModelType.YOLOV8, * path: './models/yolov8n.hef', * numClasses: 80 * }); * * const output = await device.infer(inputTensor); * ``` */ export class HailoDevice extends EventEmitter { device; modelConfig; performanceBuffer = []; options; constructor(options = {}) { super(); this.options = { debug: false, deviceIndex: 0, ...options }; // Create native device instance this.device = new addon.HailoDevice(); if (this.options.debug) { this.on('debug', msg => console.log(`[HailoDevice] ${msg}`)); } } /** * Load a model with configuration * Supports automatic model type detection from filename */ async loadModel(config) { const startTime = performance.now(); // Handle string path with auto-detection if (typeof config === 'string') { config = this.detectModelConfig(config); } this.modelConfig = config; this.emit('debug', `Loading model: ${config.path} (type: ${config.type})`); try { const success = await this.device.loadModel(config.path); if (!success) { throw new Error('Failed to load model'); } const loadTime = performance.now() - startTime; this.emit('modelLoaded', { config, loadTime, info: this.device.getModelInfo() }); this.emit('debug', `Model loaded in ${loadTime.toFixed(2)}ms`); } catch (error) { this.emit('error', error); throw error; } } /** * Run inference with performance tracking */ async infer(inputs) { if (!this.device.isActive()) { throw new Error('No model loaded'); } const metrics = { inferenceTime: 0, totalTime: 0, fps: 0 }; const startTime = performance.now(); try { // Run inference const inferStart = performance.now(); const outputs = await this.device.infer(inputs); metrics.inferenceTime = performance.now() - inferStart; metrics.totalTime = performance.now() - startTime; metrics.fps = 1000 / metrics.totalTime; // Track performance this.trackPerformance(metrics); this.emit('inference', { outputs, metrics }); return outputs; } catch (error) { this.emit('error', error); throw error; } } /** * Get model information */ getModelInfo() { return this.device.getModelInfo(); } /** * Check if device is ready for inference */ isReady() { return this.device.isActive(); } /** * Get average performance metrics */ getPerformanceStats() { if (this.performanceBuffer.length === 0) { return { avgInferenceTime: 0, avgFps: 0, minInferenceTime: 0, maxInferenceTime: 0 }; } const times = this.performanceBuffer.map(m => m.inferenceTime); const sum = times.reduce((a, b) => a + b, 0); return { avgInferenceTime: sum / times.length, avgFps: this.performanceBuffer.reduce((a, b) => a + b.fps, 0) / this.performanceBuffer.length, minInferenceTime: Math.min(...times), maxInferenceTime: Math.max(...times), }; } /** * Reset performance tracking */ resetPerformanceStats() { this.performanceBuffer = []; } /** * Get current model configuration */ getModelConfig() { return this.modelConfig; } /** * Detect model configuration from filename */ detectModelConfig(path) { const filename = path.toLowerCase(); let type = ModelType.CUSTOM; let numClasses = 80; // Default COCO classes if (filename.includes('yolov8') || filename.includes('yolo8')) { type = ModelType.YOLOV8; } else if (filename.includes('yolox')) { type = ModelType.YOLOX; } else if (filename.includes('yolo')) { type = ModelType.YOLO; } // Try to detect number of classes from filename const classMatch = filename.match(/(\d+)classes?/); if (classMatch) { numClasses = parseInt(classMatch[1], 10); } return { type, path, numClasses }; } /** * Track performance metrics with sliding window */ trackPerformance(metrics) { this.performanceBuffer.push(metrics); // Keep last 100 measurements if (this.performanceBuffer.length > 100) { this.performanceBuffer.shift(); } } /** * Static method to scan for available devices */ static async scanDevices() { return addon.scanDevices(); } /** * Get addon version */ static get version() { return addon.version; } } // Re-export types export * from './types.js'; //# sourceMappingURL=hailo-device.js.map