@hazeljs/ml 0.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +300 -0
  3. package/dist/decorators/index.d.ts +4 -0
  4. package/dist/decorators/index.d.ts.map +1 -0
  5. package/dist/decorators/index.js +15 -0
  6. package/dist/decorators/model.decorator.d.ts +26 -0
  7. package/dist/decorators/model.decorator.d.ts.map +1 -0
  8. package/dist/decorators/model.decorator.js +48 -0
  9. package/dist/decorators/model.decorator.test.d.ts +2 -0
  10. package/dist/decorators/model.decorator.test.d.ts.map +1 -0
  11. package/dist/decorators/model.decorator.test.js +128 -0
  12. package/dist/decorators/predict.decorator.d.ts +20 -0
  13. package/dist/decorators/predict.decorator.d.ts.map +1 -0
  14. package/dist/decorators/predict.decorator.js +40 -0
  15. package/dist/decorators/train.decorator.d.ts +21 -0
  16. package/dist/decorators/train.decorator.d.ts.map +1 -0
  17. package/dist/decorators/train.decorator.js +41 -0
  18. package/dist/evaluation/metrics.service.d.ts +54 -0
  19. package/dist/evaluation/metrics.service.d.ts.map +1 -0
  20. package/dist/evaluation/metrics.service.js +163 -0
  21. package/dist/evaluation/metrics.service.test.d.ts +2 -0
  22. package/dist/evaluation/metrics.service.test.d.ts.map +1 -0
  23. package/dist/evaluation/metrics.service.test.js +253 -0
  24. package/dist/index.d.ts +16 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +42 -0
  27. package/dist/inference/batch.service.d.ts +16 -0
  28. package/dist/inference/batch.service.d.ts.map +1 -0
  29. package/dist/inference/batch.service.js +52 -0
  30. package/dist/inference/batch.service.test.d.ts +2 -0
  31. package/dist/inference/batch.service.test.d.ts.map +1 -0
  32. package/dist/inference/batch.service.test.js +86 -0
  33. package/dist/inference/predictor.service.d.ts +13 -0
  34. package/dist/inference/predictor.service.d.ts.map +1 -0
  35. package/dist/inference/predictor.service.js +65 -0
  36. package/dist/inference/predictor.service.test.d.ts +2 -0
  37. package/dist/inference/predictor.service.test.d.ts.map +1 -0
  38. package/dist/inference/predictor.service.test.js +115 -0
  39. package/dist/ml-model.base.d.ts +20 -0
  40. package/dist/ml-model.base.d.ts.map +1 -0
  41. package/dist/ml-model.base.js +33 -0
  42. package/dist/ml-model.base.test.d.ts +2 -0
  43. package/dist/ml-model.base.test.d.ts.map +1 -0
  44. package/dist/ml-model.base.test.js +57 -0
  45. package/dist/ml.module.d.ts +27 -0
  46. package/dist/ml.module.d.ts.map +1 -0
  47. package/dist/ml.module.js +126 -0
  48. package/dist/ml.module.test.d.ts +2 -0
  49. package/dist/ml.module.test.d.ts.map +1 -0
  50. package/dist/ml.module.test.js +60 -0
  51. package/dist/ml.types.d.ts +30 -0
  52. package/dist/ml.types.d.ts.map +1 -0
  53. package/dist/ml.types.js +5 -0
  54. package/dist/registry/model.registry.d.ts +21 -0
  55. package/dist/registry/model.registry.d.ts.map +1 -0
  56. package/dist/registry/model.registry.js +64 -0
  57. package/dist/registry/model.registry.test.d.ts +2 -0
  58. package/dist/registry/model.registry.test.d.ts.map +1 -0
  59. package/dist/registry/model.registry.test.js +93 -0
  60. package/dist/training/pipeline.service.d.ts +25 -0
  61. package/dist/training/pipeline.service.d.ts.map +1 -0
  62. package/dist/training/pipeline.service.js +65 -0
  63. package/dist/training/pipeline.service.test.d.ts +2 -0
  64. package/dist/training/pipeline.service.test.d.ts.map +1 -0
  65. package/dist/training/pipeline.service.test.js +52 -0
  66. package/dist/training/trainer.service.d.ts +13 -0
  67. package/dist/training/trainer.service.d.ts.map +1 -0
  68. package/dist/training/trainer.service.js +69 -0
  69. package/dist/training/trainer.service.test.d.ts +2 -0
  70. package/dist/training/trainer.service.test.d.ts.map +1 -0
  71. package/dist/training/trainer.service.test.js +99 -0
  72. package/package.json +52 -0
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const model_registry_1 = require("../registry/model.registry");
13
+ const predictor_service_1 = require("../inference/predictor.service");
14
+ const metrics_service_1 = require("./metrics.service");
15
+ const decorators_1 = require("../decorators");
16
+ describe('MetricsService', () => {
17
+ let service;
18
+ beforeEach(() => {
19
+ service = new metrics_service_1.MetricsService();
20
+ });
21
+ it('records and retrieves evaluation', () => {
22
+ service.recordEvaluation({
23
+ modelName: 'model',
24
+ version: '1.0.0',
25
+ metrics: { accuracy: 0.95, loss: 0.05 },
26
+ evaluatedAt: new Date(),
27
+ });
28
+ const metrics = service.getMetrics('model', '1.0.0');
29
+ expect(metrics?.metrics.accuracy).toBe(0.95);
30
+ });
31
+ it('getMetrics returns latest when no version', () => {
32
+ service.recordEvaluation({
33
+ modelName: 'm',
34
+ version: '1',
35
+ metrics: { accuracy: 0.9 },
36
+ evaluatedAt: new Date(),
37
+ });
38
+ service.recordEvaluation({
39
+ modelName: 'm',
40
+ version: '2',
41
+ metrics: { accuracy: 0.95 },
42
+ evaluatedAt: new Date(),
43
+ });
44
+ const latest = service.getMetrics('m');
45
+ expect(latest?.version).toBe('2');
46
+ expect(latest?.metrics.accuracy).toBe(0.95);
47
+ });
48
+ it('getHistory returns all evaluations', () => {
49
+ service.recordEvaluation({
50
+ modelName: 'm',
51
+ version: '1',
52
+ metrics: {},
53
+ evaluatedAt: new Date(),
54
+ });
55
+ service.recordEvaluation({
56
+ modelName: 'm',
57
+ version: '2',
58
+ metrics: {},
59
+ evaluatedAt: new Date(),
60
+ });
61
+ expect(service.getHistory('m')).toHaveLength(2);
62
+ });
63
+ it('compareVersions returns winner by accuracy', () => {
64
+ service.recordEvaluation({
65
+ modelName: 'm',
66
+ version: 'a',
67
+ metrics: { accuracy: 0.9 },
68
+ evaluatedAt: new Date(),
69
+ });
70
+ service.recordEvaluation({
71
+ modelName: 'm',
72
+ version: 'b',
73
+ metrics: { accuracy: 0.95 },
74
+ evaluatedAt: new Date(),
75
+ });
76
+ const { a, b, winner } = service.compareVersions('m', 'a', 'b');
77
+ expect(a?.metrics.accuracy).toBe(0.9);
78
+ expect(b?.metrics.accuracy).toBe(0.95);
79
+ expect(winner).toBe('b');
80
+ });
81
+ it('compareVersions when no accuracy', () => {
82
+ service.recordEvaluation({
83
+ modelName: 'm',
84
+ version: 'a',
85
+ metrics: {},
86
+ evaluatedAt: new Date(),
87
+ });
88
+ const { winner } = service.compareVersions('m', 'a', 'b');
89
+ expect(winner).toBeUndefined();
90
+ });
91
+ describe('evaluate', () => {
92
+ let EvalModel = class EvalModel {
93
+ train() { }
94
+ async predict(input) {
95
+ const sentiment = input.text.includes('good') ? 'positive' : 'negative';
96
+ return { sentiment };
97
+ }
98
+ };
99
+ __decorate([
100
+ (0, decorators_1.Train)(),
101
+ __metadata("design:type", Function),
102
+ __metadata("design:paramtypes", []),
103
+ __metadata("design:returntype", void 0)
104
+ ], EvalModel.prototype, "train", null);
105
+ __decorate([
106
+ (0, decorators_1.Predict)(),
107
+ __metadata("design:type", Function),
108
+ __metadata("design:paramtypes", [Object]),
109
+ __metadata("design:returntype", Promise)
110
+ ], EvalModel.prototype, "predict", null);
111
+ EvalModel = __decorate([
112
+ (0, decorators_1.Model)({ name: 'eval-model', version: '1.0.0', framework: 'custom' })
113
+ ], EvalModel);
114
+ it('throws when PredictorService not injected', async () => {
115
+ const svc = new metrics_service_1.MetricsService();
116
+ await expect(svc.evaluate('any', [{ text: 'hello', label: 'neutral' }])).rejects.toThrow('MetricsService.evaluate() requires PredictorService');
117
+ });
118
+ it('throws when testData is empty', async () => {
119
+ const registry = new model_registry_1.ModelRegistry();
120
+ registry.register({
121
+ metadata: { name: 'eval-model', version: '1.0.0', framework: 'custom' },
122
+ instance: new EvalModel(),
123
+ predictMethod: 'predict',
124
+ });
125
+ const predictor = new predictor_service_1.PredictorService(registry);
126
+ const svc = new metrics_service_1.MetricsService(registry, predictor);
127
+ await expect(svc.evaluate('eval-model', [])).rejects.toThrow('testData cannot be empty');
128
+ });
129
+ it('computes accuracy, precision, recall, f1 from test data', async () => {
130
+ const registry = new model_registry_1.ModelRegistry();
131
+ registry.register({
132
+ metadata: { name: 'eval-model', version: '1.0.0', framework: 'custom' },
133
+ instance: new EvalModel(),
134
+ predictMethod: 'predict',
135
+ });
136
+ const predictor = new predictor_service_1.PredictorService(registry);
137
+ const svc = new metrics_service_1.MetricsService(registry, predictor);
138
+ const testData = [
139
+ { text: 'good day', label: 'positive' },
140
+ { text: 'bad day', label: 'negative' },
141
+ { text: 'good weather', label: 'positive' },
142
+ { text: 'bad weather', label: 'negative' },
143
+ ];
144
+ const result = await svc.evaluate('eval-model', testData);
145
+ expect(result.modelName).toBe('eval-model');
146
+ expect(result.version).toBe('1.0.0');
147
+ expect(result.metrics.accuracy).toBe(1);
148
+ expect(result.metrics.precision).toBe(1);
149
+ expect(result.metrics.recall).toBe(1);
150
+ expect(result.metrics.f1Score).toBe(1);
151
+ });
152
+ it('supports custom labelKey and predictionKey', async () => {
153
+ let CustomModel = class CustomModel {
154
+ train() { }
155
+ async predict(input) {
156
+ return { outcome: input.x === 'a' ? 'yes' : 'no' };
157
+ }
158
+ };
159
+ __decorate([
160
+ (0, decorators_1.Train)(),
161
+ __metadata("design:type", Function),
162
+ __metadata("design:paramtypes", []),
163
+ __metadata("design:returntype", void 0)
164
+ ], CustomModel.prototype, "train", null);
165
+ __decorate([
166
+ (0, decorators_1.Predict)(),
167
+ __metadata("design:type", Function),
168
+ __metadata("design:paramtypes", [Object]),
169
+ __metadata("design:returntype", Promise)
170
+ ], CustomModel.prototype, "predict", null);
171
+ CustomModel = __decorate([
172
+ (0, decorators_1.Model)({ name: 'custom-model', version: '1.0.0', framework: 'custom' })
173
+ ], CustomModel);
174
+ const registry = new model_registry_1.ModelRegistry();
175
+ registry.register({
176
+ metadata: { name: 'custom-model', version: '1.0.0', framework: 'custom' },
177
+ instance: new CustomModel(),
178
+ predictMethod: 'predict',
179
+ });
180
+ const predictor = new predictor_service_1.PredictorService(registry);
181
+ const svc = new metrics_service_1.MetricsService(registry, predictor);
182
+ const result = await svc.evaluate('custom-model', [
183
+ { x: 'a', outcome: 'yes' },
184
+ { x: 'b', outcome: 'no' },
185
+ ], { labelKey: 'outcome', predictionKey: 'outcome' });
186
+ expect(result.metrics.accuracy).toBe(1);
187
+ });
188
+ it('extractPredictedLabel uses first value when no known key', async () => {
189
+ let FallbackModel = class FallbackModel {
190
+ train() { }
191
+ async predict() {
192
+ return { customKey: 'positive' };
193
+ }
194
+ };
195
+ __decorate([
196
+ (0, decorators_1.Train)(),
197
+ __metadata("design:type", Function),
198
+ __metadata("design:paramtypes", []),
199
+ __metadata("design:returntype", void 0)
200
+ ], FallbackModel.prototype, "train", null);
201
+ __decorate([
202
+ (0, decorators_1.Predict)(),
203
+ __metadata("design:type", Function),
204
+ __metadata("design:paramtypes", []),
205
+ __metadata("design:returntype", Promise)
206
+ ], FallbackModel.prototype, "predict", null);
207
+ FallbackModel = __decorate([
208
+ (0, decorators_1.Model)({ name: 'fallback-model', version: '1.0.0', framework: 'custom' })
209
+ ], FallbackModel);
210
+ const registry = new model_registry_1.ModelRegistry();
211
+ registry.register({
212
+ metadata: { name: 'fallback-model', version: '1.0.0', framework: 'custom' },
213
+ instance: new FallbackModel(),
214
+ predictMethod: 'predict',
215
+ });
216
+ const predictor = new predictor_service_1.PredictorService(registry);
217
+ const svc = new metrics_service_1.MetricsService(registry, predictor);
218
+ const result = await svc.evaluate('fallback-model', [{ text: 'x', label: 'positive' }], {
219
+ metrics: ['accuracy'],
220
+ });
221
+ expect(result.metrics.accuracy).toBe(1);
222
+ });
223
+ it('evaluate with only accuracy metric skips precision/recall/f1', async () => {
224
+ const registry = new model_registry_1.ModelRegistry();
225
+ registry.register({
226
+ metadata: { name: 'eval-model', version: '1.0.0', framework: 'custom' },
227
+ instance: new EvalModel(),
228
+ predictMethod: 'predict',
229
+ });
230
+ const predictor = new predictor_service_1.PredictorService(registry);
231
+ const svc = new metrics_service_1.MetricsService(registry, predictor);
232
+ const result = await svc.evaluate('eval-model', [{ text: 'good', label: 'positive' }], {
233
+ metrics: ['accuracy'],
234
+ });
235
+ expect(result.metrics.accuracy).toBeDefined();
236
+ expect(result.metrics.precision).toBeUndefined();
237
+ expect(result.metrics.recall).toBeUndefined();
238
+ expect(result.metrics.f1Score).toBeUndefined();
239
+ });
240
+ it('evaluate when modelRegistry is undefined uses version unknown', async () => {
241
+ const registry = new model_registry_1.ModelRegistry();
242
+ registry.register({
243
+ metadata: { name: 'eval-model', version: '1.0.0', framework: 'custom' },
244
+ instance: new EvalModel(),
245
+ predictMethod: 'predict',
246
+ });
247
+ const predictor = new predictor_service_1.PredictorService(registry);
248
+ const svc = new metrics_service_1.MetricsService(undefined, predictor);
249
+ const result = await svc.evaluate('eval-model', [{ text: 'good', label: 'positive' }]);
250
+ expect(result.version).toBeDefined();
251
+ });
252
+ });
253
+ });
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @hazeljs/ml - Machine Learning & Model Management for HazelJS
3
+ */
4
+ import 'reflect-metadata';
5
+ export { MLModule, ML_MODELS, type MLModuleOptions } from './ml.module';
6
+ export { Model, Train, Predict, getModelMetadata, hasModelMetadata, getTrainMetadata, hasTrainMetadata, getPredictMetadata, hasPredictMetadata, type TrainOptions, type PredictOptions, } from './decorators';
7
+ export { ModelRegistry, type RegisteredModel } from './registry/model.registry';
8
+ export { TrainerService } from './training/trainer.service';
9
+ export { PipelineService, type PipelineStep } from './training/pipeline.service';
10
+ export { PredictorService } from './inference/predictor.service';
11
+ export { BatchService, type BatchPredictionOptions } from './inference/batch.service';
12
+ export { MetricsService, type ModelMetrics, type EvaluationResult, type EvaluateOptions, type EvaluateMetric, } from './evaluation/metrics.service';
13
+ export { registerMLModel } from './ml-model.base';
14
+ export { Injectable } from '@hazeljs/core';
15
+ export type { MLFramework, ModelMetadata, TrainingData, TrainingResult, PredictionResult, ModelVersion, } from './ml.types';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAGxE,OAAO,EACL,KAAK,EACL,KAAK,EACL,OAAO,EACP,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGhF,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACtF,OAAO,EACL,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,YAAY,EACV,WAAW,EACX,aAAa,EACb,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,YAAY,GACb,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /**
3
+ * @hazeljs/ml - Machine Learning & Model Management for HazelJS
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Injectable = exports.registerMLModel = exports.MetricsService = exports.BatchService = exports.PredictorService = exports.PipelineService = exports.TrainerService = exports.ModelRegistry = exports.hasPredictMetadata = exports.getPredictMetadata = exports.hasTrainMetadata = exports.getTrainMetadata = exports.hasModelMetadata = exports.getModelMetadata = exports.Predict = exports.Train = exports.Model = exports.ML_MODELS = exports.MLModule = void 0;
7
+ require("reflect-metadata");
8
+ // Module
9
+ var ml_module_1 = require("./ml.module");
10
+ Object.defineProperty(exports, "MLModule", { enumerable: true, get: function () { return ml_module_1.MLModule; } });
11
+ Object.defineProperty(exports, "ML_MODELS", { enumerable: true, get: function () { return ml_module_1.ML_MODELS; } });
12
+ // Decorators
13
+ var decorators_1 = require("./decorators");
14
+ Object.defineProperty(exports, "Model", { enumerable: true, get: function () { return decorators_1.Model; } });
15
+ Object.defineProperty(exports, "Train", { enumerable: true, get: function () { return decorators_1.Train; } });
16
+ Object.defineProperty(exports, "Predict", { enumerable: true, get: function () { return decorators_1.Predict; } });
17
+ Object.defineProperty(exports, "getModelMetadata", { enumerable: true, get: function () { return decorators_1.getModelMetadata; } });
18
+ Object.defineProperty(exports, "hasModelMetadata", { enumerable: true, get: function () { return decorators_1.hasModelMetadata; } });
19
+ Object.defineProperty(exports, "getTrainMetadata", { enumerable: true, get: function () { return decorators_1.getTrainMetadata; } });
20
+ Object.defineProperty(exports, "hasTrainMetadata", { enumerable: true, get: function () { return decorators_1.hasTrainMetadata; } });
21
+ Object.defineProperty(exports, "getPredictMetadata", { enumerable: true, get: function () { return decorators_1.getPredictMetadata; } });
22
+ Object.defineProperty(exports, "hasPredictMetadata", { enumerable: true, get: function () { return decorators_1.hasPredictMetadata; } });
23
+ // Registry
24
+ var model_registry_1 = require("./registry/model.registry");
25
+ Object.defineProperty(exports, "ModelRegistry", { enumerable: true, get: function () { return model_registry_1.ModelRegistry; } });
26
+ // Services
27
+ var trainer_service_1 = require("./training/trainer.service");
28
+ Object.defineProperty(exports, "TrainerService", { enumerable: true, get: function () { return trainer_service_1.TrainerService; } });
29
+ var pipeline_service_1 = require("./training/pipeline.service");
30
+ Object.defineProperty(exports, "PipelineService", { enumerable: true, get: function () { return pipeline_service_1.PipelineService; } });
31
+ var predictor_service_1 = require("./inference/predictor.service");
32
+ Object.defineProperty(exports, "PredictorService", { enumerable: true, get: function () { return predictor_service_1.PredictorService; } });
33
+ var batch_service_1 = require("./inference/batch.service");
34
+ Object.defineProperty(exports, "BatchService", { enumerable: true, get: function () { return batch_service_1.BatchService; } });
35
+ var metrics_service_1 = require("./evaluation/metrics.service");
36
+ Object.defineProperty(exports, "MetricsService", { enumerable: true, get: function () { return metrics_service_1.MetricsService; } });
37
+ // Model registration helper
38
+ var ml_model_base_1 = require("./ml-model.base");
39
+ Object.defineProperty(exports, "registerMLModel", { enumerable: true, get: function () { return ml_model_base_1.registerMLModel; } });
40
+ // Re-export Injectable from core for convenience
41
+ var core_1 = require("@hazeljs/core");
42
+ Object.defineProperty(exports, "Injectable", { enumerable: true, get: function () { return core_1.Injectable; } });
@@ -0,0 +1,16 @@
1
+ import { PredictorService } from './predictor.service';
2
+ import { PredictionResult } from '../ml.types';
3
+ export interface BatchPredictionOptions {
4
+ batchSize?: number;
5
+ concurrency?: number;
6
+ }
7
+ /**
8
+ * Batch Service - Batch processing for inference
9
+ * Handles bulk prediction requests efficiently
10
+ */
11
+ export declare class BatchService {
12
+ private readonly predictorService;
13
+ constructor(predictorService: PredictorService);
14
+ predictBatch<T = unknown>(modelName: string, inputs: unknown[], options?: BatchPredictionOptions, version?: string): Promise<PredictionResult<T>[]>;
15
+ }
16
+ //# sourceMappingURL=batch.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.service.d.ts","sourceRoot":"","sources":["../../src/inference/batch.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,qBACa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAAhB,gBAAgB,EAAE,gBAAgB;IAEzD,YAAY,CAAC,CAAC,GAAG,OAAO,EAC5B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,EAAE,EACjB,OAAO,GAAE,sBAA2B,EACpC,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC;CA+BlC"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.BatchService = void 0;
16
+ const core_1 = require("@hazeljs/core");
17
+ const predictor_service_1 = require("./predictor.service");
18
+ const core_2 = __importDefault(require("@hazeljs/core"));
19
+ /**
20
+ * Batch Service - Batch processing for inference
21
+ * Handles bulk prediction requests efficiently
22
+ */
23
+ let BatchService = class BatchService {
24
+ constructor(predictorService) {
25
+ this.predictorService = predictorService;
26
+ }
27
+ async predictBatch(modelName, inputs, options = {}, version) {
28
+ const { batchSize = 32, concurrency = 4 } = options;
29
+ core_2.default.debug(`Batch prediction: ${inputs.length} inputs, batchSize=${batchSize}`);
30
+ const results = new Array(inputs.length);
31
+ const batches = [];
32
+ for (let i = 0; i < inputs.length; i += batchSize) {
33
+ const batch = inputs.slice(i, i + batchSize).map((input, j) => ({ input, idx: i + j }));
34
+ batches.push(batch);
35
+ }
36
+ for (let i = 0; i < batches.length; i += concurrency) {
37
+ const batchGroup = batches.slice(i, i + concurrency);
38
+ const batchResults = await Promise.all(batchGroup.flatMap((batch) => batch.map(({ input, idx }) => this.predictorService
39
+ .predict(modelName, input, version)
40
+ .then((r) => ({ idx, r })))));
41
+ for (const { idx, r } of batchResults) {
42
+ results[idx] = r;
43
+ }
44
+ }
45
+ return results;
46
+ }
47
+ };
48
+ exports.BatchService = BatchService;
49
+ exports.BatchService = BatchService = __decorate([
50
+ (0, core_1.Service)(),
51
+ __metadata("design:paramtypes", [predictor_service_1.PredictorService])
52
+ ], BatchService);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=batch.service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.service.test.d.ts","sourceRoot":"","sources":["../../src/inference/batch.service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const model_registry_1 = require("../registry/model.registry");
13
+ const predictor_service_1 = require("./predictor.service");
14
+ const batch_service_1 = require("./batch.service");
15
+ const decorators_1 = require("../decorators");
16
+ describe('BatchService', () => {
17
+ let batchService;
18
+ let BatchModel = class BatchModel {
19
+ train() { }
20
+ async predict(input) {
21
+ return { value: input * 2 };
22
+ }
23
+ };
24
+ __decorate([
25
+ (0, decorators_1.Train)(),
26
+ __metadata("design:type", Function),
27
+ __metadata("design:paramtypes", []),
28
+ __metadata("design:returntype", void 0)
29
+ ], BatchModel.prototype, "train", null);
30
+ __decorate([
31
+ (0, decorators_1.Predict)(),
32
+ __metadata("design:type", Function),
33
+ __metadata("design:paramtypes", [Object]),
34
+ __metadata("design:returntype", Promise)
35
+ ], BatchModel.prototype, "predict", null);
36
+ BatchModel = __decorate([
37
+ (0, decorators_1.Model)({ name: 'batch-model', version: '1.0.0', framework: 'tensorflow' })
38
+ ], BatchModel);
39
+ beforeEach(() => {
40
+ const registry = new model_registry_1.ModelRegistry();
41
+ registry.register({
42
+ metadata: { name: 'batch-model', version: '1.0.0', framework: 'tensorflow' },
43
+ instance: new BatchModel(),
44
+ predictMethod: 'predict',
45
+ });
46
+ batchService = new batch_service_1.BatchService(new predictor_service_1.PredictorService(registry));
47
+ });
48
+ it('processes batch of inputs', async () => {
49
+ const results = await batchService.predictBatch('batch-model', [1, 2, 3]);
50
+ expect(results).toEqual([{ value: 2 }, { value: 4 }, { value: 6 }]);
51
+ });
52
+ it('respects batchSize option', async () => {
53
+ const results = await batchService.predictBatch('batch-model', [1, 2, 3, 4, 5], {
54
+ batchSize: 2,
55
+ });
56
+ expect(results).toHaveLength(5);
57
+ });
58
+ it('preserves result order matching input order', async () => {
59
+ const inputs = [10, 20, 30, 40, 50];
60
+ const results = await batchService.predictBatch('batch-model', inputs, {
61
+ batchSize: 2,
62
+ concurrency: 2,
63
+ });
64
+ expect(results).toEqual([
65
+ { value: 20 },
66
+ { value: 40 },
67
+ { value: 60 },
68
+ { value: 80 },
69
+ { value: 100 },
70
+ ]);
71
+ });
72
+ it('throws when model not found', async () => {
73
+ await expect(batchService.predictBatch('unknown', [1])).rejects.toThrow('Model not found: unknown');
74
+ });
75
+ it('uses default batchSize and concurrency when options empty', async () => {
76
+ const results = await batchService.predictBatch('batch-model', [1, 2], {});
77
+ expect(results).toHaveLength(2);
78
+ expect(results).toEqual([{ value: 2 }, { value: 4 }]);
79
+ });
80
+ it('uses custom concurrency with default batchSize', async () => {
81
+ const results = await batchService.predictBatch('batch-model', [1, 2, 3], {
82
+ concurrency: 1,
83
+ });
84
+ expect(results).toEqual([{ value: 2 }, { value: 4 }, { value: 6 }]);
85
+ });
86
+ });
@@ -0,0 +1,13 @@
1
+ import { ModelRegistry } from '../registry/model.registry';
2
+ import { PredictionResult } from '../ml.types';
3
+ /**
4
+ * Predictor Service - Real-time prediction/inference
5
+ * Routes prediction requests to registered models
6
+ */
7
+ export declare class PredictorService {
8
+ private readonly modelRegistry;
9
+ constructor(modelRegistry: ModelRegistry);
10
+ predict<T = unknown>(modelName: string, input: unknown, version?: string): Promise<PredictionResult<T>>;
11
+ discoverPredictMethod(instance: object): string | undefined;
12
+ }
13
+ //# sourceMappingURL=predictor.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predictor.service.d.ts","sourceRoot":"","sources":["../../src/inference/predictor.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C;;;GAGG;AACH,qBACa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAEnD,OAAO,CAAC,CAAC,GAAG,OAAO,EACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAyB/B,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAa5D"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.PredictorService = void 0;
16
+ const core_1 = require("@hazeljs/core");
17
+ const model_registry_1 = require("../registry/model.registry");
18
+ const decorators_1 = require("../decorators");
19
+ const core_2 = __importDefault(require("@hazeljs/core"));
20
+ /**
21
+ * Predictor Service - Real-time prediction/inference
22
+ * Routes prediction requests to registered models
23
+ */
24
+ let PredictorService = class PredictorService {
25
+ constructor(modelRegistry) {
26
+ this.modelRegistry = modelRegistry;
27
+ }
28
+ async predict(modelName, input, version) {
29
+ const model = this.modelRegistry.get(modelName, version);
30
+ if (!model) {
31
+ throw new Error(`Model not found: ${modelName}`);
32
+ }
33
+ const predictMethod = model.predictMethod;
34
+ if (!predictMethod) {
35
+ throw new Error(`Model ${modelName} has no prediction method`);
36
+ }
37
+ const instance = model.instance;
38
+ const predictFn = instance[predictMethod];
39
+ if (typeof predictFn !== 'function') {
40
+ throw new Error(`Prediction method ${predictMethod} not found on model`);
41
+ }
42
+ core_2.default.debug(`Running prediction for model: ${modelName}`);
43
+ const result = await predictFn.call(instance, input);
44
+ return result;
45
+ }
46
+ discoverPredictMethod(instance) {
47
+ const proto = Object.getPrototypeOf(instance);
48
+ for (const key of Object.getOwnPropertyNames(proto)) {
49
+ if (key === 'constructor')
50
+ continue;
51
+ const descriptor = Object.getOwnPropertyDescriptor(proto, key);
52
+ if (descriptor?.value && typeof descriptor.value === 'function') {
53
+ if ((0, decorators_1.getPredictMetadata)(proto, key)) {
54
+ return key;
55
+ }
56
+ }
57
+ }
58
+ return undefined;
59
+ }
60
+ };
61
+ exports.PredictorService = PredictorService;
62
+ exports.PredictorService = PredictorService = __decorate([
63
+ (0, core_1.Service)(),
64
+ __metadata("design:paramtypes", [model_registry_1.ModelRegistry])
65
+ ], PredictorService);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=predictor.service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predictor.service.test.d.ts","sourceRoot":"","sources":["../../src/inference/predictor.service.test.ts"],"names":[],"mappings":""}