@jaak.ai/stamps 2.0.0-dev.29 → 2.0.0-dev.31
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.
- package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
- package/dist/cjs/jaak-stamps.cjs.entry.js +1317 -1241
- package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
- package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/my-component/my-component.css +132 -66
- package/dist/collection/components/my-component/my-component.js +453 -1357
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/collection/services/CameraService.js +292 -0
- package/dist/collection/services/CameraService.js.map +1 -0
- package/dist/collection/services/DetectionService.js +363 -0
- package/dist/collection/services/DetectionService.js.map +1 -0
- package/dist/collection/services/EventBusService.js +42 -0
- package/dist/collection/services/EventBusService.js.map +1 -0
- package/dist/collection/services/LoggerService.js +40 -0
- package/dist/collection/services/LoggerService.js.map +1 -0
- package/dist/collection/services/ServiceContainer.js +66 -0
- package/dist/collection/services/ServiceContainer.js.map +1 -0
- package/dist/collection/services/StateManagerService.js +109 -0
- package/dist/collection/services/StateManagerService.js.map +1 -0
- package/dist/collection/services/factories/DeviceStrategyFactory.js +16 -0
- package/dist/collection/services/factories/DeviceStrategyFactory.js.map +1 -0
- package/dist/collection/services/interfaces/ICameraService.js +2 -0
- package/dist/collection/services/interfaces/ICameraService.js.map +1 -0
- package/dist/collection/services/interfaces/IDetectionService.js +2 -0
- package/dist/collection/services/interfaces/IDetectionService.js.map +1 -0
- package/dist/collection/services/interfaces/IEventBus.js +2 -0
- package/dist/collection/services/interfaces/IEventBus.js.map +1 -0
- package/dist/collection/services/interfaces/ILogger.js +2 -0
- package/dist/collection/services/interfaces/ILogger.js.map +1 -0
- package/dist/collection/services/interfaces/IStateManager.js +2 -0
- package/dist/collection/services/interfaces/IStateManager.js.map +1 -0
- package/dist/collection/services/strategies/HighPerformanceDeviceStrategy.js +30 -0
- package/dist/collection/services/strategies/HighPerformanceDeviceStrategy.js.map +1 -0
- package/dist/collection/services/strategies/IDeviceStrategy.js +2 -0
- package/dist/collection/services/strategies/IDeviceStrategy.js.map +1 -0
- package/dist/collection/services/strategies/LowMemoryDeviceStrategy.js +30 -0
- package/dist/collection/services/strategies/LowMemoryDeviceStrategy.js.map +1 -0
- package/dist/components/jaak-stamps.js +1318 -1258
- package/dist/components/jaak-stamps.js.map +1 -1
- package/dist/esm/jaak-stamps-webcomponent.js +1 -1
- package/dist/esm/jaak-stamps.entry.js +1317 -1241
- package/dist/esm/jaak-stamps.entry.js.map +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/p-5051b84e.entry.js +2 -0
- package/dist/jaak-stamps-webcomponent/p-5051b84e.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +46 -99
- package/dist/types/components.d.ts +3 -3
- package/dist/types/services/CameraService.d.ts +41 -0
- package/dist/types/services/DetectionService.d.ts +35 -0
- package/dist/types/services/EventBusService.d.ts +9 -0
- package/dist/types/services/LoggerService.d.ts +12 -0
- package/dist/types/services/ServiceContainer.d.ts +26 -0
- package/dist/types/services/StateManagerService.d.ts +15 -0
- package/dist/types/services/factories/DeviceStrategyFactory.d.ts +4 -0
- package/dist/types/services/interfaces/ICameraService.d.ts +32 -0
- package/dist/types/services/interfaces/IDetectionService.d.ts +31 -0
- package/dist/types/services/interfaces/IEventBus.d.ts +16 -0
- package/dist/types/services/interfaces/ILogger.d.ts +8 -0
- package/dist/types/services/interfaces/IStateManager.d.ts +35 -0
- package/dist/types/services/strategies/HighPerformanceDeviceStrategy.d.ts +6 -0
- package/dist/types/services/strategies/IDeviceStrategy.d.ts +21 -0
- package/dist/types/services/strategies/LowMemoryDeviceStrategy.d.ts +6 -0
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-28adb830.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-28adb830.entry.js.map +0 -1
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { DeviceStrategyFactory } from "./factories/DeviceStrategyFactory";
|
|
2
|
+
export class DetectionService {
|
|
3
|
+
logger;
|
|
4
|
+
debug;
|
|
5
|
+
useDocumentClassification;
|
|
6
|
+
session;
|
|
7
|
+
mobileNetSession;
|
|
8
|
+
mobileNetClassMap;
|
|
9
|
+
modelLoaded = false;
|
|
10
|
+
deviceStrategy;
|
|
11
|
+
MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx";
|
|
12
|
+
MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.onnx";
|
|
13
|
+
MOBILENET_CLASSES_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json";
|
|
14
|
+
INPUT_SIZE = 320;
|
|
15
|
+
CONFIDENCE_THRESHOLD = 0.6;
|
|
16
|
+
// Canvas pool for optimization
|
|
17
|
+
preprocessCanvas;
|
|
18
|
+
preprocessCtx;
|
|
19
|
+
captureCanvas;
|
|
20
|
+
constructor(logger, debug = false, useDocumentClassification = false) {
|
|
21
|
+
this.logger = logger;
|
|
22
|
+
this.debug = debug;
|
|
23
|
+
this.useDocumentClassification = useDocumentClassification;
|
|
24
|
+
this.deviceStrategy = DeviceStrategyFactory.createStrategy();
|
|
25
|
+
this.initializeCanvasPool();
|
|
26
|
+
}
|
|
27
|
+
async loadModel() {
|
|
28
|
+
if (this.modelLoaded || this.session) {
|
|
29
|
+
this.logger.state('MODELO_YA_PRECARGADO', {
|
|
30
|
+
sessionExists: !!this.session,
|
|
31
|
+
modelPreloaded: this.modelLoaded
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath: this.MODEL_PATH });
|
|
37
|
+
const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
|
|
38
|
+
try {
|
|
39
|
+
this.session = await window.ort.InferenceSession.create(this.MODEL_PATH, sessionOptions);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error.message.includes('failed to allocate a buffer')) {
|
|
43
|
+
this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');
|
|
44
|
+
const fallbackOptions = {
|
|
45
|
+
executionProviders: ['wasm'],
|
|
46
|
+
graphOptimizationLevel: 'disabled',
|
|
47
|
+
logSeverityLevel: 4,
|
|
48
|
+
enableCpuMemArena: false,
|
|
49
|
+
enableMemPattern: false,
|
|
50
|
+
executionMode: 'sequential',
|
|
51
|
+
interOpNumThreads: 1,
|
|
52
|
+
intraOpNumThreads: 1,
|
|
53
|
+
};
|
|
54
|
+
this.session = await window.ort.InferenceSession.create(this.MODEL_PATH, fallbackOptions);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
this.modelLoaded = true;
|
|
61
|
+
this.logger.state('MODELO_DETECCION_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.session });
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
this.logger.error('Error al precargar modelo de detección:', error);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async loadClassificationModel() {
|
|
69
|
+
if (!this.useDocumentClassification) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });
|
|
74
|
+
// Load class map
|
|
75
|
+
const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
|
|
76
|
+
if (!classResponse.ok) {
|
|
77
|
+
throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);
|
|
78
|
+
}
|
|
79
|
+
this.mobileNetClassMap = await classResponse.json();
|
|
80
|
+
this.logger.state('CLASES_MOBILENET_CARGADAS', {
|
|
81
|
+
classCount: Object.keys(this.mobileNetClassMap).length
|
|
82
|
+
});
|
|
83
|
+
// Load model
|
|
84
|
+
const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
|
|
85
|
+
try {
|
|
86
|
+
this.mobileNetSession = await window.ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, sessionOptions);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error.message.includes('failed to allocate a buffer')) {
|
|
90
|
+
this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');
|
|
91
|
+
const fallbackOptions = {
|
|
92
|
+
executionProviders: ['wasm'],
|
|
93
|
+
graphOptimizationLevel: 'disabled',
|
|
94
|
+
logSeverityLevel: 4,
|
|
95
|
+
enableCpuMemArena: false,
|
|
96
|
+
enableMemPattern: false,
|
|
97
|
+
executionMode: 'sequential',
|
|
98
|
+
interOpNumThreads: 1,
|
|
99
|
+
intraOpNumThreads: 1,
|
|
100
|
+
};
|
|
101
|
+
this.mobileNetSession = await window.ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, fallbackOptions);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', {
|
|
108
|
+
sessionCreated: !!this.mobileNetSession
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
this.logger.error('Error al cargar modelo MobileNet:', error);
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
isModelLoaded() {
|
|
117
|
+
return this.modelLoaded && !!this.session;
|
|
118
|
+
}
|
|
119
|
+
preprocess(video) {
|
|
120
|
+
if (!this.preprocessCanvas || !this.preprocessCtx) {
|
|
121
|
+
this.initializeCanvasPool();
|
|
122
|
+
}
|
|
123
|
+
this.preprocessCtx.clearRect(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);
|
|
124
|
+
this.preprocessCtx.drawImage(video, 0, 0, this.INPUT_SIZE, this.INPUT_SIZE);
|
|
125
|
+
const imageData = this.preprocessCtx.getImageData(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);
|
|
126
|
+
const [R, G, B] = [[], [], []];
|
|
127
|
+
const { data } = imageData;
|
|
128
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
129
|
+
R.push(data[i] / 255);
|
|
130
|
+
G.push(data[i + 1] / 255);
|
|
131
|
+
B.push(data[i + 2] / 255);
|
|
132
|
+
}
|
|
133
|
+
const transposedData = new Float32Array(R.concat(G, B));
|
|
134
|
+
const float16Data = new Uint16Array(transposedData.length);
|
|
135
|
+
for (let i = 0; i < transposedData.length; i++) {
|
|
136
|
+
float16Data[i] = this.float32ToFloat16(transposedData[i]);
|
|
137
|
+
}
|
|
138
|
+
return new window.ort.Tensor("float16", float16Data, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);
|
|
139
|
+
}
|
|
140
|
+
async runInference(inputTensor) {
|
|
141
|
+
if (!this.session) {
|
|
142
|
+
throw new Error('Detection model not loaded');
|
|
143
|
+
}
|
|
144
|
+
const feeds = { [this.session.inputNames[0]]: inputTensor };
|
|
145
|
+
const results = await this.session.run(feeds);
|
|
146
|
+
const output = results[this.session.outputNames[0]].data;
|
|
147
|
+
const detections = [];
|
|
148
|
+
for (let i = 0; i < output.length; i += 6) {
|
|
149
|
+
const [x1, y1, x2, y2, score, classId] = output.slice(i, i + 6);
|
|
150
|
+
if (score > this.CONFIDENCE_THRESHOLD) {
|
|
151
|
+
detections.push({
|
|
152
|
+
x: x1,
|
|
153
|
+
y: y1,
|
|
154
|
+
w: x2 - x1,
|
|
155
|
+
h: y2 - y1,
|
|
156
|
+
score,
|
|
157
|
+
classId
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return detections;
|
|
162
|
+
}
|
|
163
|
+
async classifyDocument(canvas) {
|
|
164
|
+
if (!this.mobileNetSession || !this.mobileNetClassMap) {
|
|
165
|
+
this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });
|
|
170
|
+
const inputTensor = this.preprocessMobileNet(canvas);
|
|
171
|
+
const feeds = { input: inputTensor };
|
|
172
|
+
const results = await this.mobileNetSession.run(feeds);
|
|
173
|
+
const output = results[Object.keys(results)[0]].data;
|
|
174
|
+
const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
|
|
175
|
+
const confidence = output[maxIdx];
|
|
176
|
+
const className = this.mobileNetClassMap[maxIdx.toString()] || "unknown";
|
|
177
|
+
this.logger.state('DOCUMENTO_CLASIFICADO', {
|
|
178
|
+
class: className,
|
|
179
|
+
confidence: confidence.toFixed(3),
|
|
180
|
+
classIndex: maxIdx,
|
|
181
|
+
timestamp: Date.now()
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
class: className,
|
|
185
|
+
confidence: confidence,
|
|
186
|
+
classIndex: maxIdx
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
this.logger.error('Error al clasificar documento:', error);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
checkSideAlignment(box, maskConfig) {
|
|
195
|
+
const { INPUT_SIZE, ID1_ASPECT_RATIO, shouldMirrorVideo, alignmentTolerance, maskSize, videoRef } = maskConfig;
|
|
196
|
+
if (!videoRef) {
|
|
197
|
+
return { top: false, right: false, bottom: false, left: false };
|
|
198
|
+
}
|
|
199
|
+
// Get video dimensions to calculate actual mask boundaries in model space
|
|
200
|
+
const videoWidth = videoRef.videoWidth;
|
|
201
|
+
const videoHeight = videoRef.videoHeight;
|
|
202
|
+
if (videoWidth === 0 || videoHeight === 0) {
|
|
203
|
+
return { top: false, right: false, bottom: false, left: false };
|
|
204
|
+
}
|
|
205
|
+
// Calculate video aspect ratio
|
|
206
|
+
const videoAspectRatio = videoWidth / videoHeight;
|
|
207
|
+
// The model sees video stretched to 320x320, but we need to calculate where
|
|
208
|
+
// the mask should be in this distorted space to match the visual mask
|
|
209
|
+
// In the visual display, we calculate mask size based on the limiting dimension
|
|
210
|
+
// We need to replicate this logic but account for the distortion in model space
|
|
211
|
+
// Calculate the "display" dimensions (what the visual mask calculations use)
|
|
212
|
+
const containerAspectRatio = 1; // Assume square container for simplicity
|
|
213
|
+
let displayedVideoWidth, displayedVideoHeight;
|
|
214
|
+
if (videoAspectRatio > containerAspectRatio) {
|
|
215
|
+
// Video is wider - letterboxed in display
|
|
216
|
+
displayedVideoWidth = INPUT_SIZE;
|
|
217
|
+
displayedVideoHeight = INPUT_SIZE / videoAspectRatio;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
// Video is taller - pillarboxed in display
|
|
221
|
+
displayedVideoHeight = INPUT_SIZE;
|
|
222
|
+
displayedVideoWidth = INPUT_SIZE * videoAspectRatio;
|
|
223
|
+
}
|
|
224
|
+
// Calculate mask dimensions using the same logic as updateMaskDimensions
|
|
225
|
+
const maxWidthByHeight = displayedVideoHeight * ID1_ASPECT_RATIO;
|
|
226
|
+
let visualMaskWidth, visualMaskHeight;
|
|
227
|
+
const sizeRatio = maskSize / 100;
|
|
228
|
+
if (maxWidthByHeight <= displayedVideoWidth) {
|
|
229
|
+
// Video height is the limiting factor
|
|
230
|
+
visualMaskHeight = displayedVideoHeight * sizeRatio;
|
|
231
|
+
visualMaskWidth = visualMaskHeight * ID1_ASPECT_RATIO;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// Video width is the limiting factor
|
|
235
|
+
visualMaskWidth = displayedVideoWidth * sizeRatio;
|
|
236
|
+
visualMaskHeight = visualMaskWidth / ID1_ASPECT_RATIO;
|
|
237
|
+
}
|
|
238
|
+
// Now map these visual mask dimensions to the distorted model space
|
|
239
|
+
// The model stretches video to 320x320, so we need to apply the inverse transformation
|
|
240
|
+
const modelMaskWidth = visualMaskWidth * (INPUT_SIZE / displayedVideoWidth);
|
|
241
|
+
const modelMaskHeight = visualMaskHeight * (INPUT_SIZE / displayedVideoHeight);
|
|
242
|
+
// Calculate mask boundaries in model coordinate system (always centered in 320x320)
|
|
243
|
+
const maskCenterX = INPUT_SIZE / 2;
|
|
244
|
+
const maskCenterY = INPUT_SIZE / 2;
|
|
245
|
+
const maskLeft = maskCenterX - (modelMaskWidth / 2);
|
|
246
|
+
const maskRight = maskCenterX + (modelMaskWidth / 2);
|
|
247
|
+
const maskTop = maskCenterY - (modelMaskHeight / 2);
|
|
248
|
+
const maskBottom = maskCenterY + (modelMaskHeight / 2);
|
|
249
|
+
// Obtener las coordenadas del documento detectado
|
|
250
|
+
let docLeft = box.x;
|
|
251
|
+
let docRight = box.x + box.w;
|
|
252
|
+
const docTop = box.y;
|
|
253
|
+
const docBottom = box.y + box.h;
|
|
254
|
+
// Si el video está en modo mirror, invertir las coordenadas horizontales
|
|
255
|
+
if (shouldMirrorVideo) {
|
|
256
|
+
const originalDocLeft = docLeft;
|
|
257
|
+
const originalDocRight = docRight;
|
|
258
|
+
docLeft = INPUT_SIZE - originalDocRight;
|
|
259
|
+
docRight = INPUT_SIZE - originalDocLeft;
|
|
260
|
+
}
|
|
261
|
+
// Tolerancia para considerar que un lado está alineado (en píxeles)
|
|
262
|
+
const tolerance = alignmentTolerance;
|
|
263
|
+
return {
|
|
264
|
+
top: Math.abs(docTop - maskTop) <= tolerance,
|
|
265
|
+
right: Math.abs(docRight - maskRight) <= tolerance,
|
|
266
|
+
bottom: Math.abs(docBottom - maskBottom) <= tolerance,
|
|
267
|
+
left: Math.abs(docLeft - maskLeft) <= tolerance
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
isCardInFrame(box) {
|
|
271
|
+
const cardCenterX = box.x + box.w / 2;
|
|
272
|
+
const cardCenterY = box.y + box.h / 2;
|
|
273
|
+
const frameCenterX = this.INPUT_SIZE / 2;
|
|
274
|
+
const frameCenterY = this.INPUT_SIZE / 2;
|
|
275
|
+
const toleranceX = 40;
|
|
276
|
+
const toleranceY = 30;
|
|
277
|
+
const isCentered = Math.abs(cardCenterX - frameCenterX) < toleranceX &&
|
|
278
|
+
Math.abs(cardCenterY - frameCenterY) < toleranceY;
|
|
279
|
+
const isGoodSize = box.w > 150 && box.w < 300 && box.h > 90 && box.h < 200;
|
|
280
|
+
return isCentered && isGoodSize;
|
|
281
|
+
}
|
|
282
|
+
areAllSidesAligned(alignment) {
|
|
283
|
+
return alignment.top && alignment.right && alignment.bottom && alignment.left;
|
|
284
|
+
}
|
|
285
|
+
cleanup() {
|
|
286
|
+
this.cleanupCanvasPool();
|
|
287
|
+
if (this.session) {
|
|
288
|
+
this.session.release?.();
|
|
289
|
+
this.session = undefined;
|
|
290
|
+
}
|
|
291
|
+
if (this.mobileNetSession) {
|
|
292
|
+
this.mobileNetSession.release?.();
|
|
293
|
+
this.mobileNetSession = undefined;
|
|
294
|
+
}
|
|
295
|
+
this.mobileNetClassMap = undefined;
|
|
296
|
+
this.modelLoaded = false;
|
|
297
|
+
this.logger.state('DETECCION_SERVICE_LIMPIADO', { timestamp: Date.now() });
|
|
298
|
+
}
|
|
299
|
+
initializeCanvasPool() {
|
|
300
|
+
this.preprocessCanvas = document.createElement('canvas');
|
|
301
|
+
this.preprocessCanvas.width = this.INPUT_SIZE;
|
|
302
|
+
this.preprocessCanvas.height = this.INPUT_SIZE;
|
|
303
|
+
this.preprocessCtx = this.preprocessCanvas.getContext('2d', {
|
|
304
|
+
alpha: false,
|
|
305
|
+
willReadFrequently: true
|
|
306
|
+
});
|
|
307
|
+
this.captureCanvas = document.createElement('canvas');
|
|
308
|
+
this.logger.state('CANVAS_POOL_INICIALIZADO', {
|
|
309
|
+
preprocessCanvasSize: this.INPUT_SIZE
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
cleanupCanvasPool() {
|
|
313
|
+
if (this.preprocessCanvas) {
|
|
314
|
+
this.preprocessCtx = undefined;
|
|
315
|
+
this.preprocessCanvas = undefined;
|
|
316
|
+
}
|
|
317
|
+
if (this.captureCanvas) {
|
|
318
|
+
this.captureCanvas = undefined;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
float32ToFloat16(value) {
|
|
322
|
+
const buffer = new ArrayBuffer(4);
|
|
323
|
+
const view = new DataView(buffer);
|
|
324
|
+
view.setFloat32(0, value, true);
|
|
325
|
+
const f = view.getUint32(0, true);
|
|
326
|
+
const sign = (f >> 31) & 0x1;
|
|
327
|
+
const exp = (f >> 23) & 0xFF;
|
|
328
|
+
const frac = f & 0x7FFFFF;
|
|
329
|
+
let newExp = exp - 127 + 15;
|
|
330
|
+
if (exp === 0) {
|
|
331
|
+
newExp = 0;
|
|
332
|
+
}
|
|
333
|
+
else if (exp === 0xFF) {
|
|
334
|
+
newExp = 0x1F;
|
|
335
|
+
}
|
|
336
|
+
else if (newExp >= 0x1F) {
|
|
337
|
+
newExp = 0x1F;
|
|
338
|
+
return (sign << 15) | (newExp << 10);
|
|
339
|
+
}
|
|
340
|
+
else if (newExp <= 0) {
|
|
341
|
+
return (sign << 15);
|
|
342
|
+
}
|
|
343
|
+
return (sign << 15) | (newExp << 10) | (frac >> 13);
|
|
344
|
+
}
|
|
345
|
+
preprocessMobileNet(canvas) {
|
|
346
|
+
const tempCanvas = document.createElement('canvas');
|
|
347
|
+
tempCanvas.width = 224;
|
|
348
|
+
tempCanvas.height = 224;
|
|
349
|
+
const tempCtx = tempCanvas.getContext('2d');
|
|
350
|
+
tempCtx.drawImage(canvas, 0, 0, 224, 224);
|
|
351
|
+
const imageData = tempCtx.getImageData(0, 0, 224, 224);
|
|
352
|
+
const data = imageData.data;
|
|
353
|
+
const hw = 224 * 224;
|
|
354
|
+
const arr = new Float32Array(3 * hw);
|
|
355
|
+
for (let i = 0; i < hw; i++) {
|
|
356
|
+
arr[i] = (data[i * 4 + 0] / 255 - 0.5) / 0.5;
|
|
357
|
+
arr[hw + i] = (data[i * 4 + 1] / 255 - 0.5) / 0.5;
|
|
358
|
+
arr[2 * hw + i] = (data[i * 4 + 2] / 255 - 0.5) / 0.5;
|
|
359
|
+
}
|
|
360
|
+
return new window.ort.Tensor('float32', arr, [1, 3, 224, 224]);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=DetectionService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DetectionService.js","sourceRoot":"","sources":["../../src/services/DetectionService.ts"],"names":[],"mappings":"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","sourcesContent":["import { IDetectionService, DetectionBox, SideAlignment, ClassificationResult } from './interfaces/IDetectionService';\nimport { ILogger } from './interfaces/ILogger';\nimport { IDeviceStrategy } from './strategies/IDeviceStrategy';\nimport { DeviceStrategyFactory } from './factories/DeviceStrategyFactory';\n\nexport class DetectionService implements IDetectionService {\n private session?: any;\n private mobileNetSession?: any;\n private mobileNetClassMap?: any;\n private modelLoaded: boolean = false;\n private deviceStrategy: IDeviceStrategy;\n \n private readonly MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx\";\n private readonly MOBILENET_MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.onnx\";\n private readonly MOBILENET_CLASSES_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json\";\n private readonly INPUT_SIZE = 320;\n private readonly CONFIDENCE_THRESHOLD = 0.6;\n\n // Canvas pool for optimization\n private preprocessCanvas?: HTMLCanvasElement;\n private preprocessCtx?: CanvasRenderingContext2D;\n private captureCanvas?: HTMLCanvasElement;\n\n constructor(\n private logger: ILogger,\n private debug: boolean = false,\n private useDocumentClassification: boolean = false\n ) {\n this.deviceStrategy = DeviceStrategyFactory.createStrategy();\n this.initializeCanvasPool();\n }\n\n async loadModel(): Promise<void> {\n if (this.modelLoaded || this.session) {\n this.logger.state('MODELO_YA_PRECARGADO', { \n sessionExists: !!this.session, \n modelPreloaded: this.modelLoaded \n });\n return;\n }\n\n try {\n this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath: this.MODEL_PATH });\n \n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n \n try {\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, sessionOptions);\n } catch (error) {\n if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n };\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n \n this.modelLoaded = true;\n this.logger.state('MODELO_DETECCION_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.session });\n } catch (error) {\n this.logger.error('Error al precargar modelo de detección:', error);\n throw error;\n }\n }\n\n async loadClassificationModel(): Promise<void> {\n if (!this.useDocumentClassification) {\n return;\n }\n\n try {\n this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });\n \n // Load class map\n const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);\n if (!classResponse.ok) {\n throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);\n }\n this.mobileNetClassMap = await classResponse.json();\n this.logger.state('CLASES_MOBILENET_CARGADAS', { \n classCount: Object.keys(this.mobileNetClassMap).length \n });\n \n // Load model\n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n try {\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, sessionOptions);\n } catch (error) {\n if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n };\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', { \n sessionCreated: !!this.mobileNetSession \n });\n \n } catch (error) {\n this.logger.error('Error al cargar modelo MobileNet:', error);\n throw error;\n }\n }\n\n isModelLoaded(): boolean {\n return this.modelLoaded && !!this.session;\n }\n\n preprocess(video: HTMLVideoElement): any {\n if (!this.preprocessCanvas || !this.preprocessCtx) {\n this.initializeCanvasPool();\n }\n \n this.preprocessCtx!.clearRect(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n this.preprocessCtx!.drawImage(video, 0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n \n const imageData = this.preprocessCtx!.getImageData(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n const [R, G, B] = [[], [], []] as number[][];\n const { data } = imageData;\n\n for (let i = 0; i < data.length; i += 4) {\n R.push(data[i] / 255);\n G.push(data[i + 1] / 255);\n B.push(data[i + 2] / 255);\n }\n\n const transposedData = new Float32Array(R.concat(G, B));\n const float16Data = new Uint16Array(transposedData.length);\n for (let i = 0; i < transposedData.length; i++) {\n float16Data[i] = this.float32ToFloat16(transposedData[i]);\n }\n return new (window as any).ort.Tensor(\"float16\", float16Data, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);\n }\n\n async runInference(inputTensor: any): Promise<DetectionBox[]> {\n if (!this.session) {\n throw new Error('Detection model not loaded');\n }\n\n const feeds = { [this.session.inputNames[0]]: inputTensor };\n const results = await this.session.run(feeds);\n const output = results[this.session.outputNames[0]].data;\n\n const detections: DetectionBox[] = [];\n for (let i = 0; i < output.length; i += 6) {\n const [x1, y1, x2, y2, score, classId] = output.slice(i, i + 6);\n if (score > this.CONFIDENCE_THRESHOLD) {\n detections.push({ \n x: x1, \n y: y1, \n w: x2 - x1, \n h: y2 - y1, \n score, \n classId \n });\n }\n }\n\n return detections;\n }\n\n async classifyDocument(canvas: HTMLCanvasElement): Promise<ClassificationResult | null> {\n if (!this.mobileNetSession || !this.mobileNetClassMap) {\n this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');\n return null;\n }\n\n try {\n this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });\n \n const inputTensor = this.preprocessMobileNet(canvas);\n const feeds = { input: inputTensor };\n const results = await this.mobileNetSession.run(feeds);\n const output = results[Object.keys(results)[0]].data;\n \n const maxIdx = output.reduce((bestIdx: number, val: number, idx: number, arr: number[]) => \n val > arr[bestIdx] ? idx : bestIdx, 0);\n const confidence = output[maxIdx];\n \n const className = this.mobileNetClassMap[maxIdx.toString()] || \"unknown\";\n \n this.logger.state('DOCUMENTO_CLASIFICADO', {\n class: className,\n confidence: confidence.toFixed(3),\n classIndex: maxIdx,\n timestamp: Date.now()\n });\n \n return {\n class: className,\n confidence: confidence,\n classIndex: maxIdx\n };\n \n } catch (error) {\n this.logger.error('Error al clasificar documento:', error);\n return null;\n }\n }\n\n checkSideAlignment(box: DetectionBox, maskConfig: any): SideAlignment {\n const { INPUT_SIZE, ID1_ASPECT_RATIO, shouldMirrorVideo, alignmentTolerance, maskSize, videoRef } = maskConfig;\n \n if (!videoRef) {\n return { top: false, right: false, bottom: false, left: false };\n }\n \n // Get video dimensions to calculate actual mask boundaries in model space\n const videoWidth = videoRef.videoWidth;\n const videoHeight = videoRef.videoHeight;\n \n if (videoWidth === 0 || videoHeight === 0) {\n return { top: false, right: false, bottom: false, left: false };\n }\n \n // Calculate video aspect ratio\n const videoAspectRatio = videoWidth / videoHeight;\n \n // The model sees video stretched to 320x320, but we need to calculate where\n // the mask should be in this distorted space to match the visual mask\n \n // In the visual display, we calculate mask size based on the limiting dimension\n // We need to replicate this logic but account for the distortion in model space\n \n // Calculate the \"display\" dimensions (what the visual mask calculations use)\n const containerAspectRatio = 1; // Assume square container for simplicity\n let displayedVideoWidth, displayedVideoHeight;\n \n if (videoAspectRatio > containerAspectRatio) {\n // Video is wider - letterboxed in display\n displayedVideoWidth = INPUT_SIZE;\n displayedVideoHeight = INPUT_SIZE / videoAspectRatio;\n } else {\n // Video is taller - pillarboxed in display \n displayedVideoHeight = INPUT_SIZE;\n displayedVideoWidth = INPUT_SIZE * videoAspectRatio;\n }\n \n // Calculate mask dimensions using the same logic as updateMaskDimensions\n const maxWidthByHeight = displayedVideoHeight * ID1_ASPECT_RATIO;\n \n let visualMaskWidth, visualMaskHeight;\n const sizeRatio = maskSize / 100;\n \n if (maxWidthByHeight <= displayedVideoWidth) {\n // Video height is the limiting factor\n visualMaskHeight = displayedVideoHeight * sizeRatio;\n visualMaskWidth = visualMaskHeight * ID1_ASPECT_RATIO;\n } else {\n // Video width is the limiting factor\n visualMaskWidth = displayedVideoWidth * sizeRatio;\n visualMaskHeight = visualMaskWidth / ID1_ASPECT_RATIO;\n }\n \n // Now map these visual mask dimensions to the distorted model space\n // The model stretches video to 320x320, so we need to apply the inverse transformation\n const modelMaskWidth = visualMaskWidth * (INPUT_SIZE / displayedVideoWidth);\n const modelMaskHeight = visualMaskHeight * (INPUT_SIZE / displayedVideoHeight);\n \n // Calculate mask boundaries in model coordinate system (always centered in 320x320)\n const maskCenterX = INPUT_SIZE / 2;\n const maskCenterY = INPUT_SIZE / 2;\n const maskLeft = maskCenterX - (modelMaskWidth / 2);\n const maskRight = maskCenterX + (modelMaskWidth / 2);\n const maskTop = maskCenterY - (modelMaskHeight / 2);\n const maskBottom = maskCenterY + (modelMaskHeight / 2);\n \n // Obtener las coordenadas del documento detectado\n let docLeft = box.x;\n let docRight = box.x + box.w;\n const docTop = box.y;\n const docBottom = box.y + box.h;\n \n // Si el video está en modo mirror, invertir las coordenadas horizontales\n if (shouldMirrorVideo) {\n const originalDocLeft = docLeft;\n const originalDocRight = docRight;\n docLeft = INPUT_SIZE - originalDocRight;\n docRight = INPUT_SIZE - originalDocLeft;\n }\n \n // Tolerancia para considerar que un lado está alineado (en píxeles)\n const tolerance = alignmentTolerance;\n \n return {\n top: Math.abs(docTop - maskTop) <= tolerance,\n right: Math.abs(docRight - maskRight) <= tolerance,\n bottom: Math.abs(docBottom - maskBottom) <= tolerance,\n left: Math.abs(docLeft - maskLeft) <= tolerance\n };\n }\n\n isCardInFrame(box: DetectionBox): boolean {\n const cardCenterX = box.x + box.w / 2;\n const cardCenterY = box.y + box.h / 2;\n const frameCenterX = this.INPUT_SIZE / 2;\n const frameCenterY = this.INPUT_SIZE / 2;\n const toleranceX = 40;\n const toleranceY = 30;\n \n const isCentered = Math.abs(cardCenterX - frameCenterX) < toleranceX && \n Math.abs(cardCenterY - frameCenterY) < toleranceY;\n const isGoodSize = box.w > 150 && box.w < 300 && box.h > 90 && box.h < 200;\n \n return isCentered && isGoodSize;\n }\n\n areAllSidesAligned(alignment: SideAlignment): boolean {\n return alignment.top && alignment.right && alignment.bottom && alignment.left;\n }\n\n cleanup(): void {\n this.cleanupCanvasPool();\n \n if (this.session) {\n this.session.release?.();\n this.session = undefined;\n }\n if (this.mobileNetSession) {\n this.mobileNetSession.release?.();\n this.mobileNetSession = undefined;\n }\n this.mobileNetClassMap = undefined;\n this.modelLoaded = false;\n \n this.logger.state('DETECCION_SERVICE_LIMPIADO', { timestamp: Date.now() });\n }\n\n private initializeCanvasPool(): void {\n this.preprocessCanvas = document.createElement('canvas');\n this.preprocessCanvas.width = this.INPUT_SIZE;\n this.preprocessCanvas.height = this.INPUT_SIZE;\n this.preprocessCtx = this.preprocessCanvas.getContext('2d', {\n alpha: false,\n willReadFrequently: true\n })!;\n \n this.captureCanvas = document.createElement('canvas');\n \n this.logger.state('CANVAS_POOL_INICIALIZADO', { \n preprocessCanvasSize: this.INPUT_SIZE \n });\n }\n\n private cleanupCanvasPool(): void {\n if (this.preprocessCanvas) {\n this.preprocessCtx = undefined;\n this.preprocessCanvas = undefined;\n }\n if (this.captureCanvas) {\n this.captureCanvas = undefined;\n }\n }\n\n private float32ToFloat16(value: number): number {\n const buffer = new ArrayBuffer(4);\n const view = new DataView(buffer);\n view.setFloat32(0, value, true);\n \n const f = view.getUint32(0, true);\n const sign = (f >> 31) & 0x1;\n const exp = (f >> 23) & 0xFF;\n const frac = f & 0x7FFFFF;\n \n let newExp = exp - 127 + 15;\n \n if (exp === 0) {\n newExp = 0;\n } else if (exp === 0xFF) {\n newExp = 0x1F;\n } else if (newExp >= 0x1F) {\n newExp = 0x1F;\n return (sign << 15) | (newExp << 10);\n } else if (newExp <= 0) {\n return (sign << 15);\n }\n \n return (sign << 15) | (newExp << 10) | (frac >> 13);\n }\n\n private preprocessMobileNet(canvas: HTMLCanvasElement): any {\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = 224;\n tempCanvas.height = 224;\n const tempCtx = tempCanvas.getContext('2d')!;\n \n tempCtx.drawImage(canvas, 0, 0, 224, 224);\n \n const imageData = tempCtx.getImageData(0, 0, 224, 224);\n const data = imageData.data;\n const hw = 224 * 224;\n const arr = new Float32Array(3 * hw);\n \n for (let i = 0; i < hw; i++) {\n arr[i] = (data[i * 4 + 0] / 255 - 0.5) / 0.5;\n arr[hw + i] = (data[i * 4 + 1] / 255 - 0.5) / 0.5;\n arr[2 * hw + i] = (data[i * 4 + 2] / 255 - 0.5) / 0.5;\n }\n \n return new (window as any).ort.Tensor('float32', arr, [1, 3, 224, 224]);\n }\n}"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export class EventBusService {
|
|
2
|
+
events = new Map();
|
|
3
|
+
on(event, callback) {
|
|
4
|
+
if (!this.events.has(event)) {
|
|
5
|
+
this.events.set(event, []);
|
|
6
|
+
}
|
|
7
|
+
this.events.get(event).push(callback);
|
|
8
|
+
}
|
|
9
|
+
off(event, callback) {
|
|
10
|
+
const callbacks = this.events.get(event);
|
|
11
|
+
if (callbacks) {
|
|
12
|
+
const index = callbacks.indexOf(callback);
|
|
13
|
+
if (index > -1) {
|
|
14
|
+
callbacks.splice(index, 1);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
emit(event, data) {
|
|
19
|
+
const callbacks = this.events.get(event);
|
|
20
|
+
if (callbacks) {
|
|
21
|
+
callbacks.forEach(callback => {
|
|
22
|
+
try {
|
|
23
|
+
callback(data);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.error(`Error in event callback for ${event}:`, error);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
once(event, callback) {
|
|
32
|
+
const onceCallback = (data) => {
|
|
33
|
+
callback(data);
|
|
34
|
+
this.off(event, onceCallback);
|
|
35
|
+
};
|
|
36
|
+
this.on(event, onceCallback);
|
|
37
|
+
}
|
|
38
|
+
clear() {
|
|
39
|
+
this.events.clear();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=EventBusService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventBusService.js","sourceRoot":"","sources":["../../src/services/EventBusService.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,eAAe;IAClB,MAAM,GAAiC,IAAI,GAAG,EAAE,CAAC;IAEzD,EAAE,CAAU,KAAa,EAAE,QAA0B;QACnD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,IAAI,CAAC,QAAyB,CAAC,CAAC;IAC1D,CAAC;IAED,GAAG,CAAC,KAAa,EAAE,QAAuB;QACxC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC1C,IAAI,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;gBACf,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAU,KAAa,EAAE,IAAQ;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,SAAS,EAAE,CAAC;YACd,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAC3B,IAAI,CAAC;oBACH,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACjB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,KAAK,GAAG,EAAE,KAAK,CAAC,CAAC;gBAChE,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,CAAU,KAAa,EAAE,QAA0B;QACrD,MAAM,YAAY,GAAG,CAAC,IAAO,EAAE,EAAE;YAC/B,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,YAA6B,CAAC,CAAC;QACjD,CAAC,CAAC;QACF,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF","sourcesContent":["import { IEventBus, EventCallback } from './interfaces/IEventBus';\n\nexport class EventBusService implements IEventBus {\n private events: Map<string, EventCallback[]> = new Map();\n\n on<T = any>(event: string, callback: EventCallback<T>): void {\n if (!this.events.has(event)) {\n this.events.set(event, []);\n }\n this.events.get(event)!.push(callback as EventCallback);\n }\n\n off(event: string, callback: EventCallback): void {\n const callbacks = this.events.get(event);\n if (callbacks) {\n const index = callbacks.indexOf(callback);\n if (index > -1) {\n callbacks.splice(index, 1);\n }\n }\n }\n\n emit<T = any>(event: string, data?: T): void {\n const callbacks = this.events.get(event);\n if (callbacks) {\n callbacks.forEach(callback => {\n try {\n callback(data);\n } catch (error) {\n console.error(`Error in event callback for ${event}:`, error);\n }\n });\n }\n }\n\n once<T = any>(event: string, callback: EventCallback<T>): void {\n const onceCallback = (data: T) => {\n callback(data);\n this.off(event, onceCallback as EventCallback);\n };\n this.on(event, onceCallback);\n }\n\n clear(): void {\n this.events.clear();\n }\n}"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export class LoggerService {
|
|
2
|
+
debugMode;
|
|
3
|
+
constructor(debug = false) {
|
|
4
|
+
this.debugMode = debug;
|
|
5
|
+
}
|
|
6
|
+
setDebugMode(debug) {
|
|
7
|
+
this.debugMode = debug;
|
|
8
|
+
}
|
|
9
|
+
info(...args) {
|
|
10
|
+
if (this.debugMode) {
|
|
11
|
+
console.log(`[JAAK-STAMPS] [INFO] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
warn(...args) {
|
|
15
|
+
if (this.debugMode) {
|
|
16
|
+
console.warn(`[JAAK-STAMPS] [WARN] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
error(...args) {
|
|
20
|
+
if (this.debugMode) {
|
|
21
|
+
console.error(`[JAAK-STAMPS] [ERROR] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
debug(...args) {
|
|
25
|
+
if (this.debugMode) {
|
|
26
|
+
console.debug(`[JAAK-STAMPS] [DEBUG] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
state(state, data) {
|
|
30
|
+
if (this.debugMode) {
|
|
31
|
+
console.log(`[JAAK-STAMPS] [STATE] [${new Date().toLocaleTimeString()}] ${state}`, data || '');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
performance(operation, duration) {
|
|
35
|
+
if (this.debugMode) {
|
|
36
|
+
console.log(`[JAAK-STAMPS] [PERF] [${new Date().toLocaleTimeString()}] ${operation}: ${duration}ms`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=LoggerService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoggerService.js","sourceRoot":"","sources":["../../src/services/LoggerService.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,aAAa;IAChB,SAAS,CAAU;IAE3B,YAAY,QAAiB,KAAK;QAChC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,YAAY,CAAC,KAAc;QACzB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,GAAG,IAAW;QACjB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAED,IAAI,CAAC,GAAG,IAAW;QACjB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,yBAAyB,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,IAAW;QAClB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,CAAC,KAAK,CAAC,0BAA0B,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,IAAW;QAClB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,CAAC,KAAK,CAAC,0BAA0B,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAa,EAAE,IAAU;QAC7B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,KAAK,KAAK,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;IAED,WAAW,CAAC,SAAiB,EAAE,QAAgB;QAC7C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,KAAK,SAAS,KAAK,QAAQ,IAAI,CAAC,CAAC;QACvG,CAAC;IACH,CAAC;CACF","sourcesContent":["import { ILogger } from './interfaces/ILogger';\n\nexport class LoggerService implements ILogger {\n private debugMode: boolean;\n \n constructor(debug: boolean = false) {\n this.debugMode = debug;\n }\n\n setDebugMode(debug: boolean): void {\n this.debugMode = debug;\n }\n\n info(...args: any[]): void {\n if (this.debugMode) {\n console.log(`[JAAK-STAMPS] [INFO] [${new Date().toLocaleTimeString()}]`, ...args);\n }\n }\n\n warn(...args: any[]): void {\n if (this.debugMode) {\n console.warn(`[JAAK-STAMPS] [WARN] [${new Date().toLocaleTimeString()}]`, ...args);\n }\n }\n\n error(...args: any[]): void {\n if (this.debugMode) {\n console.error(`[JAAK-STAMPS] [ERROR] [${new Date().toLocaleTimeString()}]`, ...args);\n }\n }\n\n debug(...args: any[]): void {\n if (this.debugMode) {\n console.debug(`[JAAK-STAMPS] [DEBUG] [${new Date().toLocaleTimeString()}]`, ...args);\n }\n }\n\n state(state: string, data?: any): void {\n if (this.debugMode) {\n console.log(`[JAAK-STAMPS] [STATE] [${new Date().toLocaleTimeString()}] ${state}`, data || '');\n }\n }\n\n performance(operation: string, duration: number): void {\n if (this.debugMode) {\n console.log(`[JAAK-STAMPS] [PERF] [${new Date().toLocaleTimeString()}] ${operation}: ${duration}ms`);\n }\n }\n}"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { LoggerService } from "./LoggerService";
|
|
2
|
+
import { EventBusService } from "./EventBusService";
|
|
3
|
+
import { StateManagerService } from "./StateManagerService";
|
|
4
|
+
import { CameraService } from "./CameraService";
|
|
5
|
+
import { DetectionService } from "./DetectionService";
|
|
6
|
+
export class ServiceContainer {
|
|
7
|
+
services = new Map();
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.initializeServices(config);
|
|
10
|
+
}
|
|
11
|
+
initializeServices(config) {
|
|
12
|
+
// Initialize services in dependency order
|
|
13
|
+
const eventBus = new EventBusService();
|
|
14
|
+
const logger = new LoggerService(config.debug);
|
|
15
|
+
const stateManager = new StateManagerService(eventBus);
|
|
16
|
+
const cameraService = new CameraService(logger, eventBus, config.preferredCamera);
|
|
17
|
+
const detectionService = new DetectionService(logger, config.debug, config.useDocumentClassification);
|
|
18
|
+
// Register services
|
|
19
|
+
this.services.set('eventBus', eventBus);
|
|
20
|
+
this.services.set('logger', logger);
|
|
21
|
+
this.services.set('stateManager', stateManager);
|
|
22
|
+
this.services.set('cameraService', cameraService);
|
|
23
|
+
this.services.set('detectionService', detectionService);
|
|
24
|
+
}
|
|
25
|
+
get(serviceName) {
|
|
26
|
+
const service = this.services.get(serviceName);
|
|
27
|
+
if (!service) {
|
|
28
|
+
throw new Error(`Service ${serviceName} not found`);
|
|
29
|
+
}
|
|
30
|
+
return service;
|
|
31
|
+
}
|
|
32
|
+
getLogger() {
|
|
33
|
+
return this.get('logger');
|
|
34
|
+
}
|
|
35
|
+
getEventBus() {
|
|
36
|
+
return this.get('eventBus');
|
|
37
|
+
}
|
|
38
|
+
getStateManager() {
|
|
39
|
+
return this.get('stateManager');
|
|
40
|
+
}
|
|
41
|
+
getCameraService() {
|
|
42
|
+
return this.get('cameraService');
|
|
43
|
+
}
|
|
44
|
+
getDetectionService() {
|
|
45
|
+
return this.get('detectionService');
|
|
46
|
+
}
|
|
47
|
+
updateConfig(config) {
|
|
48
|
+
if (config.debug !== undefined) {
|
|
49
|
+
const logger = this.services.get('logger');
|
|
50
|
+
logger.setDebugMode(config.debug);
|
|
51
|
+
}
|
|
52
|
+
// Reinitialize services that depend on configuration changes
|
|
53
|
+
if (config.preferredCamera !== undefined ||
|
|
54
|
+
config.useDocumentClassification !== undefined) {
|
|
55
|
+
// Would need to reinitialize specific services
|
|
56
|
+
// For simplicity, this is omitted in this example
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
cleanup() {
|
|
60
|
+
// Cleanup services in reverse order
|
|
61
|
+
this.getDetectionService().cleanup();
|
|
62
|
+
this.getEventBus().clear();
|
|
63
|
+
this.services.clear();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=ServiceContainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServiceContainer.js","sourceRoot":"","sources":["../../src/services/ServiceContainer.ts"],"names":[],"mappings":"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","sourcesContent":["import { ILogger } from './interfaces/ILogger';\nimport { ICameraService } from './interfaces/ICameraService';\nimport { IDetectionService } from './interfaces/IDetectionService';\nimport { IStateManager } from './interfaces/IStateManager';\nimport { IEventBus } from './interfaces/IEventBus';\n\nimport { LoggerService } from './LoggerService';\nimport { EventBusService } from './EventBusService';\nimport { StateManagerService } from './StateManagerService';\nimport { CameraService } from './CameraService';\nimport { DetectionService } from './DetectionService';\n\nexport interface ComponentConfig {\n debug: boolean;\n alignmentTolerance: number;\n maskSize: number;\n cropMargin: number;\n useDocumentClassification: boolean;\n preferredCamera: 'auto' | 'front' | 'back';\n}\n\nexport class ServiceContainer {\n private services = new Map<string, any>();\n\n constructor(config: ComponentConfig) {\n this.initializeServices(config);\n }\n\n private initializeServices(config: ComponentConfig): void {\n // Initialize services in dependency order\n const eventBus = new EventBusService();\n const logger = new LoggerService(config.debug);\n const stateManager = new StateManagerService(eventBus);\n const cameraService = new CameraService(logger as any, eventBus, config.preferredCamera);\n const detectionService = new DetectionService(\n logger as any, \n config.debug, \n config.useDocumentClassification\n );\n\n // Register services\n this.services.set('eventBus', eventBus);\n this.services.set('logger', logger);\n this.services.set('stateManager', stateManager);\n this.services.set('cameraService', cameraService);\n this.services.set('detectionService', detectionService);\n }\n\n get<T>(serviceName: string): T {\n const service = this.services.get(serviceName);\n if (!service) {\n throw new Error(`Service ${serviceName} not found`);\n }\n return service as T;\n }\n\n getLogger(): ILogger {\n return this.get<ILogger>('logger');\n }\n\n getEventBus(): IEventBus {\n return this.get<IEventBus>('eventBus');\n }\n\n getStateManager(): IStateManager {\n return this.get<IStateManager>('stateManager');\n }\n\n getCameraService(): ICameraService {\n return this.get<ICameraService>('cameraService');\n }\n\n getDetectionService(): IDetectionService {\n return this.get<IDetectionService>('detectionService');\n }\n\n updateConfig(config: Partial<ComponentConfig>): void {\n if (config.debug !== undefined) {\n const logger = this.services.get('logger') as LoggerService;\n logger.setDebugMode(config.debug);\n }\n\n // Reinitialize services that depend on configuration changes\n if (config.preferredCamera !== undefined || \n config.useDocumentClassification !== undefined) {\n // Would need to reinitialize specific services\n // For simplicity, this is omitted in this example\n }\n }\n\n cleanup(): void {\n // Cleanup services in reverse order\n this.getDetectionService().cleanup();\n this.getEventBus().clear();\n this.services.clear();\n }\n}"]}
|