@souscheflabs/ml-vision 0.1.0

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 (48) hide show
  1. package/README.md +274 -0
  2. package/dist/components/DetectionOverlay.d.ts +57 -0
  3. package/dist/components/DetectionOverlay.js +133 -0
  4. package/dist/components/index.d.ts +4 -0
  5. package/dist/components/index.js +9 -0
  6. package/dist/core/CacheManager.d.ts +168 -0
  7. package/dist/core/CacheManager.js +331 -0
  8. package/dist/core/MLVisionProvider.d.ts +90 -0
  9. package/dist/core/MLVisionProvider.js +188 -0
  10. package/dist/core/ServerClient.d.ts +131 -0
  11. package/dist/core/ServerClient.js +291 -0
  12. package/dist/core/index.d.ts +6 -0
  13. package/dist/core/index.js +18 -0
  14. package/dist/hooks/classLabels.d.ts +35 -0
  15. package/dist/hooks/classLabels.js +439 -0
  16. package/dist/hooks/classLabelsCoco.d.ts +43 -0
  17. package/dist/hooks/classLabelsCoco.js +103 -0
  18. package/dist/hooks/index.d.ts +8 -0
  19. package/dist/hooks/index.js +27 -0
  20. package/dist/hooks/useMultiBarcodeScanner.d.ts +34 -0
  21. package/dist/hooks/useMultiBarcodeScanner.js +290 -0
  22. package/dist/hooks/useProductDetector.d.ts +38 -0
  23. package/dist/hooks/useProductDetector.js +679 -0
  24. package/dist/hooks/useReceiptScanner.d.ts +37 -0
  25. package/dist/hooks/useReceiptScanner.js +405 -0
  26. package/dist/hooks/useVideoScanner.d.ts +118 -0
  27. package/dist/hooks/useVideoScanner.js +383 -0
  28. package/dist/index.d.ts +58 -0
  29. package/dist/index.js +130 -0
  30. package/dist/processors/detectionProcessor.d.ts +86 -0
  31. package/dist/processors/detectionProcessor.js +124 -0
  32. package/dist/processors/index.d.ts +5 -0
  33. package/dist/processors/index.js +16 -0
  34. package/dist/processors/tfliteFrameProcessor.d.ts +90 -0
  35. package/dist/processors/tfliteFrameProcessor.js +213 -0
  36. package/dist/types/barcode.d.ts +91 -0
  37. package/dist/types/barcode.js +19 -0
  38. package/dist/types/detection.d.ts +166 -0
  39. package/dist/types/detection.js +8 -0
  40. package/dist/types/index.d.ts +126 -0
  41. package/dist/types/index.js +25 -0
  42. package/dist/types/ocr.d.ts +202 -0
  43. package/dist/types/ocr.js +8 -0
  44. package/dist/utils/imagePreprocessor.d.ts +85 -0
  45. package/dist/utils/imagePreprocessor.js +304 -0
  46. package/dist/utils/yoloProcessor.d.ts +40 -0
  47. package/dist/utils/yoloProcessor.js +154 -0
  48. package/package.json +78 -0
@@ -0,0 +1,383 @@
1
+ "use strict";
2
+ /**
3
+ * useVideoScanner Hook
4
+ *
5
+ * React hook for real-time video scanning combining product detection,
6
+ * barcode scanning, and text recognition.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { useVideoScanner } from '@souschef/ml-vision';
11
+ *
12
+ * function LiveScanner() {
13
+ * const {
14
+ * isScanning,
15
+ * products,
16
+ * barcodes,
17
+ * startScanning,
18
+ * stopScanning,
19
+ * cameraRef,
20
+ * } = useVideoScanner({
21
+ * modes: ['products', 'barcodes'],
22
+ * onDetected: (results) => console.log('Found:', results),
23
+ * });
24
+ *
25
+ * return (
26
+ * <Camera ref={cameraRef} />
27
+ * );
28
+ * }
29
+ * ```
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.useVideoScanner = useVideoScanner;
33
+ const react_1 = require("react");
34
+ const MLVisionProvider_1 = require("../core/MLVisionProvider");
35
+ const useProductDetector_1 = require("./useProductDetector");
36
+ const useMultiBarcodeScanner_1 = require("./useMultiBarcodeScanner");
37
+ const tfliteFrameProcessor_1 = require("../processors/tfliteFrameProcessor");
38
+ const classLabelsCoco_1 = require("./classLabelsCoco");
39
+ // ============================================================================
40
+ // Constants
41
+ // ============================================================================
42
+ const DEFAULT_TARGET_FPS = 10;
43
+ const DEFAULT_SMOOTHING_FRAMES = 3;
44
+ const MS_PER_SECOND = 1000;
45
+ // ============================================================================
46
+ // Hook Implementation
47
+ // ============================================================================
48
+ /**
49
+ * Hook for real-time video scanning
50
+ */
51
+ function useVideoScanner(options = {}) {
52
+ const { modes = ['products', 'barcodes'], targetFps = DEFAULT_TARGET_FPS, minProductConfidence = 0.5, productCategories, maxProducts = 10, maxBarcodes = 5, temporalSmoothing = true, smoothingFrames = DEFAULT_SMOOTHING_FRAMES, onDetected, onError, hapticFeedback = true,
53
+ // TFLite options
54
+ tfliteModel, useOnDeviceFrameProcessor = !!tfliteModel, foodOnly = true, } = options;
55
+ // Context
56
+ const { isInitialized } = (0, MLVisionProvider_1.useMLVisionContext)();
57
+ // Child hooks
58
+ const productDetector = (0, useProductDetector_1.useProductDetector)({
59
+ model: 'fast',
60
+ minConfidence: minProductConfidence,
61
+ categories: productCategories,
62
+ maxDetections: maxProducts,
63
+ hapticFeedback: false, // We'll handle haptics at video level
64
+ });
65
+ const barcodeScanner = (0, useMultiBarcodeScanner_1.useMultiBarcodeScanner)({
66
+ maxBarcodes,
67
+ hapticFeedback: false,
68
+ });
69
+ // State
70
+ const [isScanning, setIsScanning] = (0, react_1.useState)(false);
71
+ const [products, setProducts] = (0, react_1.useState)([]);
72
+ const [barcodes, setBarcodes] = (0, react_1.useState)([]);
73
+ const [frameNumber, setFrameNumber] = (0, react_1.useState)(0);
74
+ const [fps, setFps] = (0, react_1.useState)(0);
75
+ const [error, setError] = (0, react_1.useState)(null);
76
+ const [inferenceTimeMs, _setInferenceTimeMs] = (0, react_1.useState)(0);
77
+ // ============================================================================
78
+ // TFLite Frame Processor (for real-time video detection)
79
+ // ============================================================================
80
+ /**
81
+ * Convert TFLite detection to ProductDetectionResult
82
+ */
83
+ const tfliteToProductResult = (0, react_1.useCallback)((detection) => {
84
+ return {
85
+ id: `tflite_${Date.now()}_${detection.classIndex}`,
86
+ type: 'product',
87
+ confidence: detection.confidence,
88
+ boundingBox: {
89
+ x: detection.x,
90
+ y: detection.y,
91
+ width: detection.width,
92
+ height: detection.height,
93
+ },
94
+ source: 'on_device',
95
+ processingTimeMs: 0,
96
+ timestamp: Date.now(),
97
+ data: {
98
+ category: 'produce', // Map to closest ProductCategory
99
+ classLabel: detection.label,
100
+ classIndex: detection.classIndex,
101
+ name: detection.label.charAt(0).toUpperCase() + detection.label.slice(1),
102
+ },
103
+ };
104
+ }, []);
105
+ /**
106
+ * Handle TFLite detections
107
+ */
108
+ const handleTFLiteDetections = (0, react_1.useCallback)((detections) => {
109
+ const productResults = detections.map(tfliteToProductResult);
110
+ setProducts(productResults);
111
+ setFrameNumber((prev) => prev + 1);
112
+ // Callback
113
+ if (productResults.length > 0 && onDetected) {
114
+ onDetected({
115
+ products: productResults,
116
+ barcodes,
117
+ timestamp: Date.now(),
118
+ frameNumber,
119
+ });
120
+ }
121
+ }, [tfliteToProductResult, barcodes, frameNumber, onDetected]);
122
+ // TFLite frame processor hook
123
+ const tfliteFrameProcessor = (0, tfliteFrameProcessor_1.useTFLiteFrameProcessor)({
124
+ model: useOnDeviceFrameProcessor ? tfliteModel ?? null : null,
125
+ numClasses: 80, // COCO
126
+ confThreshold: minProductConfidence,
127
+ classLabels: [...classLabelsCoco_1.COCO_CLASSES], // Convert readonly to mutable array
128
+ foodOnly,
129
+ onDetections: handleTFLiteDetections,
130
+ });
131
+ // Refs
132
+ const cameraRef = (0, react_1.useRef)(null);
133
+ const lastFrameTimeRef = (0, react_1.useRef)(0);
134
+ const frameCountRef = (0, react_1.useRef)(0);
135
+ const fpsStartTimeRef = (0, react_1.useRef)(Date.now());
136
+ const productHistoryRef = (0, react_1.useRef)([]);
137
+ const mountedRef = (0, react_1.useRef)(true);
138
+ // Computed readiness
139
+ const isReady = (0, react_1.useMemo)(() => {
140
+ // For products: either TFLite frame processor is ready, or productDetector is loaded
141
+ const productReady = !modes.includes('products') ||
142
+ (useOnDeviceFrameProcessor ? tfliteFrameProcessor.isReady : productDetector.isModelLoaded);
143
+ const barcodeReady = !modes.includes('barcodes') || barcodeScanner.isReady;
144
+ return isInitialized && productReady && barcodeReady;
145
+ }, [
146
+ isInitialized,
147
+ modes,
148
+ useOnDeviceFrameProcessor,
149
+ tfliteFrameProcessor.isReady,
150
+ productDetector.isModelLoaded,
151
+ barcodeScanner.isReady,
152
+ ]);
153
+ // ============================================================================
154
+ // FPS Calculation
155
+ // ============================================================================
156
+ (0, react_1.useEffect)(() => {
157
+ if (!isScanning)
158
+ return;
159
+ const interval = setInterval(() => {
160
+ const now = Date.now();
161
+ const elapsed = (now - fpsStartTimeRef.current) / MS_PER_SECOND;
162
+ if (elapsed > 0) {
163
+ setFps(Math.round(frameCountRef.current / elapsed));
164
+ }
165
+ frameCountRef.current = 0;
166
+ fpsStartTimeRef.current = now;
167
+ }, MS_PER_SECOND);
168
+ return () => clearInterval(interval);
169
+ }, [isScanning]);
170
+ // ============================================================================
171
+ // Temporal Smoothing
172
+ // ============================================================================
173
+ /**
174
+ * Apply temporal smoothing to product detections
175
+ */
176
+ const smoothProducts = (0, react_1.useCallback)((newProducts) => {
177
+ if (!temporalSmoothing)
178
+ return newProducts;
179
+ // Add to history
180
+ productHistoryRef.current.push(newProducts);
181
+ if (productHistoryRef.current.length > smoothingFrames) {
182
+ productHistoryRef.current.shift();
183
+ }
184
+ // Count occurrences of each class
185
+ const classCounts = new Map();
186
+ const bestDetections = new Map();
187
+ for (const frameProducts of productHistoryRef.current) {
188
+ for (const product of frameProducts) {
189
+ const key = product.data.classLabel;
190
+ const count = (classCounts.get(key) || 0) + 1;
191
+ classCounts.set(key, count);
192
+ // Keep best confidence detection
193
+ const existing = bestDetections.get(key);
194
+ if (!existing || product.confidence > existing.confidence) {
195
+ bestDetections.set(key, product);
196
+ }
197
+ }
198
+ }
199
+ // Keep products that appear in at least half the frames
200
+ const threshold = Math.ceil(smoothingFrames / 2);
201
+ return Array.from(bestDetections.entries())
202
+ .filter(([key]) => (classCounts.get(key) || 0) >= threshold)
203
+ .map(([, product]) => product);
204
+ }, [temporalSmoothing, smoothingFrames]);
205
+ // ============================================================================
206
+ // Frame Processing
207
+ // ============================================================================
208
+ /**
209
+ * Process a frame (called from frame processor)
210
+ * @deprecated Use TFLite frame processor instead
211
+ */
212
+ const _processFrame = (0, react_1.useCallback)(async (frameUri) => {
213
+ const now = Date.now();
214
+ const minInterval = MS_PER_SECOND / targetFps;
215
+ // Throttle based on target FPS
216
+ if (now - lastFrameTimeRef.current < minInterval) {
217
+ return;
218
+ }
219
+ lastFrameTimeRef.current = now;
220
+ frameCountRef.current++;
221
+ try {
222
+ const results = {
223
+ products: [],
224
+ barcodes: [],
225
+ timestamp: now,
226
+ frameNumber: frameNumber,
227
+ };
228
+ // Product detection
229
+ if (modes.includes('products') && productDetector.isModelLoaded) {
230
+ const detected = await productDetector.detectProducts(frameUri);
231
+ results.products = smoothProducts(detected);
232
+ }
233
+ // Barcode detection is handled by VisionCamera's code scanner
234
+ // Results come through barcodeScanner.results
235
+ // Update state
236
+ if (mountedRef.current) {
237
+ setFrameNumber((prev) => prev + 1);
238
+ if (results.products.length > 0) {
239
+ setProducts(results.products);
240
+ }
241
+ // Combine with barcode results
242
+ results.barcodes = barcodeScanner.results;
243
+ // Callback
244
+ if (results.products.length > 0 || results.barcodes.length > 0) {
245
+ onDetected?.(results);
246
+ // Haptic feedback
247
+ if (hapticFeedback) {
248
+ // Trigger haptic
249
+ }
250
+ }
251
+ }
252
+ }
253
+ catch (err) {
254
+ const frameError = err instanceof Error ? err : new Error('Frame processing failed');
255
+ console.error('[useVideoScanner] Frame error:', frameError);
256
+ setError(frameError);
257
+ onError?.(frameError);
258
+ }
259
+ }, [
260
+ targetFps,
261
+ frameNumber,
262
+ modes,
263
+ productDetector,
264
+ barcodeScanner.results,
265
+ smoothProducts,
266
+ onDetected,
267
+ onError,
268
+ hapticFeedback,
269
+ ]);
270
+ // ============================================================================
271
+ // Actions
272
+ // ============================================================================
273
+ /**
274
+ * Start video scanning
275
+ */
276
+ const startScanning = (0, react_1.useCallback)(() => {
277
+ if (!isReady) {
278
+ console.warn('[useVideoScanner] Not ready to scan');
279
+ return;
280
+ }
281
+ setIsScanning(true);
282
+ setError(null);
283
+ frameCountRef.current = 0;
284
+ fpsStartTimeRef.current = Date.now();
285
+ productHistoryRef.current = [];
286
+ // Start barcode scanner if enabled
287
+ if (modes.includes('barcodes')) {
288
+ barcodeScanner.startScanning();
289
+ }
290
+ }, [isReady, modes, barcodeScanner]);
291
+ /**
292
+ * Stop video scanning
293
+ */
294
+ const stopScanning = (0, react_1.useCallback)(() => {
295
+ setIsScanning(false);
296
+ barcodeScanner.stopScanning();
297
+ }, [barcodeScanner]);
298
+ /**
299
+ * Toggle scanning
300
+ */
301
+ const toggleScanning = (0, react_1.useCallback)(() => {
302
+ if (isScanning) {
303
+ stopScanning();
304
+ }
305
+ else {
306
+ startScanning();
307
+ }
308
+ }, [isScanning, startScanning, stopScanning]);
309
+ /**
310
+ * Clear all detections
311
+ */
312
+ const clearDetections = (0, react_1.useCallback)(() => {
313
+ setProducts([]);
314
+ setBarcodes([]);
315
+ barcodeScanner.clearResults();
316
+ productDetector.clearDetections();
317
+ productHistoryRef.current = [];
318
+ }, [barcodeScanner, productDetector]);
319
+ /**
320
+ * Capture current frame as photo
321
+ */
322
+ const captureFrame = (0, react_1.useCallback)(async () => {
323
+ // This would use VisionCamera's takePhoto method
324
+ // Requires ref to be properly typed and connected
325
+ console.log('[useVideoScanner] Frame capture requires VisionCamera ref');
326
+ return null;
327
+ }, []);
328
+ // ============================================================================
329
+ // Frame Processor Configuration
330
+ // ============================================================================
331
+ const frameProcessorConfig = (0, react_1.useMemo)(() => {
332
+ if (!isScanning)
333
+ return null;
334
+ return {
335
+ // For VisionCamera frame processor
336
+ // This would be used with useFrameProcessor
337
+ codeScanner: modes.includes('barcodes') ? barcodeScanner.frameProcessor : undefined,
338
+ // Product detection happens through processFrame
339
+ };
340
+ }, [isScanning, modes, barcodeScanner.frameProcessor]);
341
+ // ============================================================================
342
+ // Cleanup
343
+ // ============================================================================
344
+ (0, react_1.useEffect)(() => {
345
+ mountedRef.current = true;
346
+ return () => {
347
+ mountedRef.current = false;
348
+ };
349
+ }, []);
350
+ // Sync barcode results
351
+ (0, react_1.useEffect)(() => {
352
+ if (barcodeScanner.results.length > 0) {
353
+ setBarcodes(barcodeScanner.results);
354
+ }
355
+ }, [barcodeScanner.results]);
356
+ // ============================================================================
357
+ // Return
358
+ // ============================================================================
359
+ return {
360
+ // State
361
+ isScanning,
362
+ isReady,
363
+ products,
364
+ barcodes,
365
+ frameNumber,
366
+ fps,
367
+ error,
368
+ inferenceTimeMs,
369
+ // Actions
370
+ startScanning,
371
+ stopScanning,
372
+ toggleScanning,
373
+ clearDetections,
374
+ captureFrame,
375
+ // Camera ref
376
+ cameraRef,
377
+ // Frame processor config
378
+ frameProcessorConfig,
379
+ // TFLite frame processor (use this with VisionCamera)
380
+ frameProcessor: useOnDeviceFrameProcessor ? tfliteFrameProcessor.frameProcessor : undefined,
381
+ };
382
+ }
383
+ exports.default = useVideoScanner;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @souschef/ml-vision
3
+ *
4
+ * ML-powered product detection for React Native
5
+ *
6
+ * Features:
7
+ * - Multi-barcode scanning (scan multiple barcodes at once)
8
+ * - Receipt OCR (photograph receipts to extract items)
9
+ * - Visual product recognition (recognize fridge/pantry contents)
10
+ * - Video scanning (real-time product detection)
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import {
15
+ * MLVisionProvider,
16
+ * useMultiBarcodeScanner,
17
+ * useProductDetector,
18
+ * useReceiptScanner,
19
+ * } from '@souschef/ml-vision';
20
+ *
21
+ * // Wrap your app with the provider
22
+ * function App() {
23
+ * return (
24
+ * <MLVisionProvider
25
+ * config={{ serverUrl: 'http://192.168.1.100:8000' }}
26
+ * storage={mmkvInstance}
27
+ * >
28
+ * <YourApp />
29
+ * </MLVisionProvider>
30
+ * );
31
+ * }
32
+ *
33
+ * // Use hooks in your components
34
+ * function ScannerScreen() {
35
+ * const { scanPhoto, results } = useMultiBarcodeScanner();
36
+ * const { detectProducts, detections } = useProductDetector();
37
+ *
38
+ * // ...
39
+ * }
40
+ * ```
41
+ *
42
+ * @packageDocumentation
43
+ */
44
+ export type { MLVisionConfig, BoundingBox, BaseDetectionResult, ModelInfo, ModelDownloadProgress, CacheEntry, CacheStats, ServerHealthResponse, ServerErrorResponse, BarcodeFormat, BarcodeData, BarcodeDetectionResult, UseMultiBarcodeScannerOptions, UseMultiBarcodeScannerReturn, BarcodeCacheEntry, ProductCategory, ProduceType, ProduceQuality, ProductData, ProductMatch, ProduceData, ProductDetectionResult, DetectionModel, UseProductDetectorOptions, UseProductDetectorReturn, TFLiteDetectionOutput, ClassLabelMap, TextLine, TextBlock, TextRecognitionResult, ReceiptItem, ReceiptMetadata, ReceiptScanResult, KnownStore, UseReceiptScannerOptions, UseReceiptScannerReturn, ReceiptLineType, ParsedReceiptLine, } from './types';
45
+ export { GROCERY_BARCODE_FORMATS } from './types/barcode';
46
+ export { MLVisionProvider, useMLVisionContext, useMLVisionReady, type MLVisionProviderProps, type MLVisionContextValue, CacheManager, createCacheManager, CACHE_TTL, type CachedBarcodeLookup, type CachedProductRecognition, ServerClient, createServerClient, ServerError, type ServerRequestOptions, type ImageUploadData, type DetectionRequestOptions, type OCRRequestOptions, } from './core';
47
+ export { useProductDetector } from './hooks/useProductDetector';
48
+ export { CLASS_LABELS, NUM_CLASSES, getClassInfo, getLabelsArray, CATEGORY_CLASSES, } from './hooks/classLabels';
49
+ export { useMultiBarcodeScanner } from './hooks/useMultiBarcodeScanner';
50
+ export { useReceiptScanner } from './hooks/useReceiptScanner';
51
+ export { useVideoScanner, type ScanMode, type VideoScanResult, type UseVideoScannerOptions, type UseVideoScannerReturn, } from './hooks/useVideoScanner';
52
+ export { DetectionOverlay, DetectionLoadingOverlay, type DetectionOverlayProps, } from './components';
53
+ export { createDetectionProcessor, frameDetectionToResult, getClassLabel, type FrameDetection, type DetectionProcessorOptions, } from './processors';
54
+ export { useTFLiteFrameProcessor, createTFLiteFrameProcessor, type TFLiteFrameDetection, type FrameProcessorResult, type UseTFLiteFrameProcessorOptions, } from './processors';
55
+ export { preprocessImage, isSkiaAvailable, isResizePluginAvailable, getFrameProcessorInstructions, } from './utils/imagePreprocessor';
56
+ export { processYoloOutput, scaleDetections, } from './utils/yoloProcessor';
57
+ export { COCO_CLASSES, CLASS_LABELS_COCO, NUM_CLASSES_COCO, FOOD_CLASS_INDICES, getCocoClassInfo, isFoodClass, } from './hooks/classLabelsCoco';
58
+ export declare const VERSION = "0.1.0";
package/dist/index.js ADDED
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ /**
3
+ * @souschef/ml-vision
4
+ *
5
+ * ML-powered product detection for React Native
6
+ *
7
+ * Features:
8
+ * - Multi-barcode scanning (scan multiple barcodes at once)
9
+ * - Receipt OCR (photograph receipts to extract items)
10
+ * - Visual product recognition (recognize fridge/pantry contents)
11
+ * - Video scanning (real-time product detection)
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import {
16
+ * MLVisionProvider,
17
+ * useMultiBarcodeScanner,
18
+ * useProductDetector,
19
+ * useReceiptScanner,
20
+ * } from '@souschef/ml-vision';
21
+ *
22
+ * // Wrap your app with the provider
23
+ * function App() {
24
+ * return (
25
+ * <MLVisionProvider
26
+ * config={{ serverUrl: 'http://192.168.1.100:8000' }}
27
+ * storage={mmkvInstance}
28
+ * >
29
+ * <YourApp />
30
+ * </MLVisionProvider>
31
+ * );
32
+ * }
33
+ *
34
+ * // Use hooks in your components
35
+ * function ScannerScreen() {
36
+ * const { scanPhoto, results } = useMultiBarcodeScanner();
37
+ * const { detectProducts, detections } = useProductDetector();
38
+ *
39
+ * // ...
40
+ * }
41
+ * ```
42
+ *
43
+ * @packageDocumentation
44
+ */
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.VERSION = exports.isFoodClass = exports.getCocoClassInfo = exports.FOOD_CLASS_INDICES = exports.NUM_CLASSES_COCO = exports.CLASS_LABELS_COCO = exports.COCO_CLASSES = exports.scaleDetections = exports.processYoloOutput = exports.getFrameProcessorInstructions = exports.isResizePluginAvailable = exports.isSkiaAvailable = exports.preprocessImage = exports.createTFLiteFrameProcessor = exports.useTFLiteFrameProcessor = exports.getClassLabel = exports.frameDetectionToResult = exports.createDetectionProcessor = exports.DetectionLoadingOverlay = exports.DetectionOverlay = exports.useVideoScanner = exports.useReceiptScanner = exports.useMultiBarcodeScanner = exports.CATEGORY_CLASSES = exports.getLabelsArray = exports.getClassInfo = exports.NUM_CLASSES = exports.CLASS_LABELS = exports.useProductDetector = exports.ServerError = exports.createServerClient = exports.ServerClient = exports.CACHE_TTL = exports.createCacheManager = exports.CacheManager = exports.useMLVisionReady = exports.useMLVisionContext = exports.MLVisionProvider = exports.GROCERY_BARCODE_FORMATS = void 0;
47
+ // Re-export barcode format constants
48
+ var barcode_1 = require("./types/barcode");
49
+ Object.defineProperty(exports, "GROCERY_BARCODE_FORMATS", { enumerable: true, get: function () { return barcode_1.GROCERY_BARCODE_FORMATS; } });
50
+ // ============================================================================
51
+ // Core - Provider, Cache, Server Client
52
+ // ============================================================================
53
+ var core_1 = require("./core");
54
+ // Provider
55
+ Object.defineProperty(exports, "MLVisionProvider", { enumerable: true, get: function () { return core_1.MLVisionProvider; } });
56
+ Object.defineProperty(exports, "useMLVisionContext", { enumerable: true, get: function () { return core_1.useMLVisionContext; } });
57
+ Object.defineProperty(exports, "useMLVisionReady", { enumerable: true, get: function () { return core_1.useMLVisionReady; } });
58
+ // Cache
59
+ Object.defineProperty(exports, "CacheManager", { enumerable: true, get: function () { return core_1.CacheManager; } });
60
+ Object.defineProperty(exports, "createCacheManager", { enumerable: true, get: function () { return core_1.createCacheManager; } });
61
+ Object.defineProperty(exports, "CACHE_TTL", { enumerable: true, get: function () { return core_1.CACHE_TTL; } });
62
+ // Server Client
63
+ Object.defineProperty(exports, "ServerClient", { enumerable: true, get: function () { return core_1.ServerClient; } });
64
+ Object.defineProperty(exports, "createServerClient", { enumerable: true, get: function () { return core_1.createServerClient; } });
65
+ Object.defineProperty(exports, "ServerError", { enumerable: true, get: function () { return core_1.ServerError; } });
66
+ // ============================================================================
67
+ // Hooks
68
+ // ============================================================================
69
+ // Phase 3: Visual product detection
70
+ var useProductDetector_1 = require("./hooks/useProductDetector");
71
+ Object.defineProperty(exports, "useProductDetector", { enumerable: true, get: function () { return useProductDetector_1.useProductDetector; } });
72
+ var classLabels_1 = require("./hooks/classLabels");
73
+ Object.defineProperty(exports, "CLASS_LABELS", { enumerable: true, get: function () { return classLabels_1.CLASS_LABELS; } });
74
+ Object.defineProperty(exports, "NUM_CLASSES", { enumerable: true, get: function () { return classLabels_1.NUM_CLASSES; } });
75
+ Object.defineProperty(exports, "getClassInfo", { enumerable: true, get: function () { return classLabels_1.getClassInfo; } });
76
+ Object.defineProperty(exports, "getLabelsArray", { enumerable: true, get: function () { return classLabels_1.getLabelsArray; } });
77
+ Object.defineProperty(exports, "CATEGORY_CLASSES", { enumerable: true, get: function () { return classLabels_1.CATEGORY_CLASSES; } });
78
+ // Phase 5: Multi-barcode scanning
79
+ var useMultiBarcodeScanner_1 = require("./hooks/useMultiBarcodeScanner");
80
+ Object.defineProperty(exports, "useMultiBarcodeScanner", { enumerable: true, get: function () { return useMultiBarcodeScanner_1.useMultiBarcodeScanner; } });
81
+ // Phase 6: Receipt OCR
82
+ var useReceiptScanner_1 = require("./hooks/useReceiptScanner");
83
+ Object.defineProperty(exports, "useReceiptScanner", { enumerable: true, get: function () { return useReceiptScanner_1.useReceiptScanner; } });
84
+ // Phase 7: Video scanning
85
+ var useVideoScanner_1 = require("./hooks/useVideoScanner");
86
+ Object.defineProperty(exports, "useVideoScanner", { enumerable: true, get: function () { return useVideoScanner_1.useVideoScanner; } });
87
+ // ============================================================================
88
+ // Components
89
+ // ============================================================================
90
+ var components_1 = require("./components");
91
+ Object.defineProperty(exports, "DetectionOverlay", { enumerable: true, get: function () { return components_1.DetectionOverlay; } });
92
+ Object.defineProperty(exports, "DetectionLoadingOverlay", { enumerable: true, get: function () { return components_1.DetectionLoadingOverlay; } });
93
+ // ============================================================================
94
+ // Processors
95
+ // ============================================================================
96
+ var processors_1 = require("./processors");
97
+ Object.defineProperty(exports, "createDetectionProcessor", { enumerable: true, get: function () { return processors_1.createDetectionProcessor; } });
98
+ Object.defineProperty(exports, "frameDetectionToResult", { enumerable: true, get: function () { return processors_1.frameDetectionToResult; } });
99
+ Object.defineProperty(exports, "getClassLabel", { enumerable: true, get: function () { return processors_1.getClassLabel; } });
100
+ // TFLite Frame Processor for real-time video scanning
101
+ var processors_2 = require("./processors");
102
+ Object.defineProperty(exports, "useTFLiteFrameProcessor", { enumerable: true, get: function () { return processors_2.useTFLiteFrameProcessor; } });
103
+ Object.defineProperty(exports, "createTFLiteFrameProcessor", { enumerable: true, get: function () { return processors_2.createTFLiteFrameProcessor; } });
104
+ // ============================================================================
105
+ // Utilities
106
+ // ============================================================================
107
+ // export { generateImageHash } from './utils/imageUtils';
108
+ // export { parseReceiptText } from './utils/receiptParser';
109
+ // Image preprocessing for on-device TFLite inference
110
+ var imagePreprocessor_1 = require("./utils/imagePreprocessor");
111
+ Object.defineProperty(exports, "preprocessImage", { enumerable: true, get: function () { return imagePreprocessor_1.preprocessImage; } });
112
+ Object.defineProperty(exports, "isSkiaAvailable", { enumerable: true, get: function () { return imagePreprocessor_1.isSkiaAvailable; } });
113
+ Object.defineProperty(exports, "isResizePluginAvailable", { enumerable: true, get: function () { return imagePreprocessor_1.isResizePluginAvailable; } });
114
+ Object.defineProperty(exports, "getFrameProcessorInstructions", { enumerable: true, get: function () { return imagePreprocessor_1.getFrameProcessorInstructions; } });
115
+ // YOLO output processing
116
+ var yoloProcessor_1 = require("./utils/yoloProcessor");
117
+ Object.defineProperty(exports, "processYoloOutput", { enumerable: true, get: function () { return yoloProcessor_1.processYoloOutput; } });
118
+ Object.defineProperty(exports, "scaleDetections", { enumerable: true, get: function () { return yoloProcessor_1.scaleDetections; } });
119
+ // COCO class labels (80 classes for general object detection)
120
+ var classLabelsCoco_1 = require("./hooks/classLabelsCoco");
121
+ Object.defineProperty(exports, "COCO_CLASSES", { enumerable: true, get: function () { return classLabelsCoco_1.COCO_CLASSES; } });
122
+ Object.defineProperty(exports, "CLASS_LABELS_COCO", { enumerable: true, get: function () { return classLabelsCoco_1.CLASS_LABELS_COCO; } });
123
+ Object.defineProperty(exports, "NUM_CLASSES_COCO", { enumerable: true, get: function () { return classLabelsCoco_1.NUM_CLASSES_COCO; } });
124
+ Object.defineProperty(exports, "FOOD_CLASS_INDICES", { enumerable: true, get: function () { return classLabelsCoco_1.FOOD_CLASS_INDICES; } });
125
+ Object.defineProperty(exports, "getCocoClassInfo", { enumerable: true, get: function () { return classLabelsCoco_1.getCocoClassInfo; } });
126
+ Object.defineProperty(exports, "isFoodClass", { enumerable: true, get: function () { return classLabelsCoco_1.isFoodClass; } });
127
+ // ============================================================================
128
+ // Version
129
+ // ============================================================================
130
+ exports.VERSION = '0.1.0';
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Detection Frame Processor
3
+ *
4
+ * VisionCamera frame processor for real-time product detection.
5
+ * Uses react-native-fast-tflite for on-device inference.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { useFrameProcessor } from 'react-native-vision-camera';
10
+ * import { detectProducts } from '@souschef/ml-vision/processors';
11
+ *
12
+ * function CameraScreen() {
13
+ * const frameProcessor = useFrameProcessor((frame) => {
14
+ * 'worklet';
15
+ * const detections = detectProducts(frame);
16
+ * // Handle detections...
17
+ * }, []);
18
+ *
19
+ * return <Camera frameProcessor={frameProcessor} />;
20
+ * }
21
+ * ```
22
+ */
23
+ import type { ProductDetectionResult } from '../types';
24
+ import { CLASS_LABELS, NUM_CLASSES } from '../hooks/classLabels';
25
+ /**
26
+ * Frame processor detection result (simplified for worklet)
27
+ */
28
+ export interface FrameDetection {
29
+ /** Class index */
30
+ classIndex: number;
31
+ /** Class label */
32
+ label: string;
33
+ /** Confidence score 0-1 */
34
+ confidence: number;
35
+ /** Bounding box (normalized 0-1) */
36
+ box: {
37
+ x: number;
38
+ y: number;
39
+ width: number;
40
+ height: number;
41
+ };
42
+ }
43
+ /**
44
+ * Frame processor options
45
+ */
46
+ export interface DetectionProcessorOptions {
47
+ /** Minimum confidence threshold (default: 0.5) */
48
+ minConfidence?: number;
49
+ /** Maximum detections per frame (default: 10) */
50
+ maxDetections?: number;
51
+ /** Run every N frames (default: 3 for ~10fps at 30fps input) */
52
+ frameSkip?: number;
53
+ /** Class indices to detect (default: all) */
54
+ classFilter?: number[];
55
+ }
56
+ /**
57
+ * Create a detection frame processor
58
+ *
59
+ * This returns a function that can be used with VisionCamera's useFrameProcessor.
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const detectFrame = createDetectionProcessor({
64
+ * minConfidence: 0.5,
65
+ * maxDetections: 10,
66
+ * });
67
+ *
68
+ * const frameProcessor = useFrameProcessor((frame) => {
69
+ * 'worklet';
70
+ * const detections = detectFrame(frame);
71
+ * runOnJS(handleDetections)(detections);
72
+ * }, []);
73
+ * ```
74
+ */
75
+ export declare function createDetectionProcessor(options?: DetectionProcessorOptions): (_frame: unknown) => FrameDetection[];
76
+ /**
77
+ * Convert FrameDetection to ProductDetectionResult
78
+ *
79
+ * Call this on the JS thread after receiving worklet results.
80
+ */
81
+ export declare function frameDetectionToResult(detection: FrameDetection, imageWidth: number, imageHeight: number): ProductDetectionResult;
82
+ /**
83
+ * Get label for class index (can be called from worklet via shared value)
84
+ */
85
+ export declare function getClassLabel(classIndex: number): string;
86
+ export { NUM_CLASSES, CLASS_LABELS };