@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,34 @@
1
+ /**
2
+ * useMultiBarcodeScanner Hook
3
+ *
4
+ * React hook for scanning multiple barcodes in a single frame or photo.
5
+ * Uses VisionCamera's built-in MLKit barcode scanning.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { useMultiBarcodeScanner } from '@souschef/ml-vision';
10
+ *
11
+ * function GroceryScanner() {
12
+ * const {
13
+ * isScanning,
14
+ * results,
15
+ * startScanning,
16
+ * stopScanning,
17
+ * scanPhoto,
18
+ * } = useMultiBarcodeScanner({
19
+ * formats: ['ean-13', 'upc-a'],
20
+ * onDetected: (barcodes) => console.log('Found:', barcodes),
21
+ * });
22
+ *
23
+ * return (
24
+ * // Your camera UI
25
+ * );
26
+ * }
27
+ * ```
28
+ */
29
+ import type { UseMultiBarcodeScannerOptions, UseMultiBarcodeScannerReturn } from '../types';
30
+ /**
31
+ * Hook for multi-barcode scanning
32
+ */
33
+ export declare function useMultiBarcodeScanner(options?: UseMultiBarcodeScannerOptions): UseMultiBarcodeScannerReturn;
34
+ export default useMultiBarcodeScanner;
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ /**
3
+ * useMultiBarcodeScanner Hook
4
+ *
5
+ * React hook for scanning multiple barcodes in a single frame or photo.
6
+ * Uses VisionCamera's built-in MLKit barcode scanning.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { useMultiBarcodeScanner } from '@souschef/ml-vision';
11
+ *
12
+ * function GroceryScanner() {
13
+ * const {
14
+ * isScanning,
15
+ * results,
16
+ * startScanning,
17
+ * stopScanning,
18
+ * scanPhoto,
19
+ * } = useMultiBarcodeScanner({
20
+ * formats: ['ean-13', 'upc-a'],
21
+ * onDetected: (barcodes) => console.log('Found:', barcodes),
22
+ * });
23
+ *
24
+ * return (
25
+ * // Your camera UI
26
+ * );
27
+ * }
28
+ * ```
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.useMultiBarcodeScanner = useMultiBarcodeScanner;
32
+ const react_1 = require("react");
33
+ const barcode_1 = require("../types/barcode");
34
+ const MLVisionProvider_1 = require("../core/MLVisionProvider");
35
+ // ============================================================================
36
+ // Constants
37
+ // ============================================================================
38
+ /** Default scan interval in milliseconds */
39
+ const DEFAULT_SCAN_INTERVAL = 100;
40
+ /** Maximum barcodes to detect per scan */
41
+ const DEFAULT_MAX_BARCODES = 20;
42
+ // ============================================================================
43
+ // Hook Implementation
44
+ // ============================================================================
45
+ /**
46
+ * Hook for multi-barcode scanning
47
+ */
48
+ function useMultiBarcodeScanner(options = {}) {
49
+ const { formats = barcode_1.GROCERY_BARCODE_FORMATS, maxBarcodes = DEFAULT_MAX_BARCODES, scanInterval = DEFAULT_SCAN_INTERVAL, onDetected, onError, hapticFeedback = true, deduplicate = true, } = options;
50
+ // Context
51
+ const { cacheManager } = (0, MLVisionProvider_1.useMLVisionContext)();
52
+ // State
53
+ const [isReady, _setIsReady] = (0, react_1.useState)(true); // MLKit is always ready
54
+ const [isScanning, setIsScanning] = (0, react_1.useState)(false);
55
+ const [results, setResults] = (0, react_1.useState)([]);
56
+ const [error, setError] = (0, react_1.useState)(null);
57
+ // Refs
58
+ const seenBarcodesRef = (0, react_1.useRef)(new Set());
59
+ const lastScanTimeRef = (0, react_1.useRef)(0);
60
+ // ============================================================================
61
+ // Barcode Processing
62
+ // ============================================================================
63
+ /**
64
+ * Process detected barcodes from VisionCamera
65
+ */
66
+ const processDetectedBarcodes = (0, react_1.useCallback)((codes) => {
67
+ const now = Date.now();
68
+ // Throttle processing
69
+ if (now - lastScanTimeRef.current < scanInterval) {
70
+ return;
71
+ }
72
+ lastScanTimeRef.current = now;
73
+ // Convert to our format
74
+ const detections = codes
75
+ .slice(0, maxBarcodes)
76
+ .map((code) => {
77
+ const format = mapCodeType(code.type);
78
+ const barcodeData = {
79
+ format,
80
+ value: code.value,
81
+ displayValue: formatBarcodeDisplay(code.value, format),
82
+ };
83
+ return {
84
+ id: `barcode_${now}_${Math.random().toString(36).substr(2, 9)}`,
85
+ type: 'barcode',
86
+ confidence: 1.0, // MLKit doesn't provide confidence
87
+ data: barcodeData,
88
+ source: 'on_device',
89
+ processingTimeMs: 0,
90
+ timestamp: now,
91
+ };
92
+ })
93
+ .filter((det) => formats.includes(det.data.format));
94
+ // Deduplicate if enabled
95
+ let newDetections = detections;
96
+ if (deduplicate) {
97
+ newDetections = detections.filter((det) => {
98
+ const key = `${det.data.format}:${det.data.value}`;
99
+ if (seenBarcodesRef.current.has(key)) {
100
+ return false;
101
+ }
102
+ seenBarcodesRef.current.add(key);
103
+ return true;
104
+ });
105
+ }
106
+ if (newDetections.length === 0)
107
+ return;
108
+ // Update results
109
+ setResults((prev) => [...prev, ...newDetections]);
110
+ // Cache barcodes
111
+ if (cacheManager) {
112
+ for (const det of newDetections) {
113
+ cacheManager.setBarcode(det.data.value, {
114
+ barcode: det.data.value,
115
+ format: det.data.format,
116
+ found: true,
117
+ });
118
+ }
119
+ }
120
+ // Callback
121
+ onDetected?.(newDetections);
122
+ // Haptic feedback
123
+ if (hapticFeedback && newDetections.length > 0) {
124
+ // Trigger haptic - implement based on your haptic service
125
+ // HapticService.light();
126
+ }
127
+ }, [
128
+ formats,
129
+ maxBarcodes,
130
+ scanInterval,
131
+ deduplicate,
132
+ cacheManager,
133
+ onDetected,
134
+ hapticFeedback,
135
+ ]);
136
+ // ============================================================================
137
+ // Actions
138
+ // ============================================================================
139
+ /**
140
+ * Start continuous scanning
141
+ */
142
+ const startScanning = (0, react_1.useCallback)(() => {
143
+ setIsScanning(true);
144
+ setError(null);
145
+ }, []);
146
+ /**
147
+ * Stop scanning
148
+ */
149
+ const stopScanning = (0, react_1.useCallback)(() => {
150
+ setIsScanning(false);
151
+ }, []);
152
+ /**
153
+ * Scan a photo for barcodes
154
+ */
155
+ const scanPhoto = (0, react_1.useCallback)(async (_uri) => {
156
+ try {
157
+ setError(null);
158
+ // Note: Photo scanning requires native module integration
159
+ // This is a placeholder that would use MLKit's image labeling
160
+ // In practice, you'd use a native module or server endpoint
161
+ console.log('[useMultiBarcodeScanner] Photo scanning not yet implemented natively');
162
+ console.log('[useMultiBarcodeScanner] Use real-time camera scanning instead');
163
+ // Return empty for now - implement with native module
164
+ return [];
165
+ }
166
+ catch (err) {
167
+ const scanError = err instanceof Error ? err : new Error('Scan failed');
168
+ setError(scanError);
169
+ onError?.(scanError);
170
+ return [];
171
+ }
172
+ }, [onError]);
173
+ /**
174
+ * Clear all results
175
+ */
176
+ const clearResults = (0, react_1.useCallback)(() => {
177
+ setResults([]);
178
+ }, []);
179
+ /**
180
+ * Reset scanner state
181
+ */
182
+ const reset = (0, react_1.useCallback)(() => {
183
+ setResults([]);
184
+ setError(null);
185
+ seenBarcodesRef.current.clear();
186
+ setIsScanning(false);
187
+ }, []);
188
+ // ============================================================================
189
+ // Frame Processor Configuration
190
+ // ============================================================================
191
+ /**
192
+ * VisionCamera code scanner configuration
193
+ * Use this with VisionCamera's codeScanner prop
194
+ */
195
+ const codeScannerConfig = (0, react_1.useMemo)(() => ({
196
+ codeTypes: formats.map(mapFormatToCodeType),
197
+ onCodeScanned: processDetectedBarcodes,
198
+ }), [formats, processDetectedBarcodes]);
199
+ // Frame processor is the code scanner config for VisionCamera
200
+ const frameProcessor = (0, react_1.useMemo)(() => {
201
+ if (!isScanning)
202
+ return null;
203
+ return codeScannerConfig;
204
+ }, [isScanning, codeScannerConfig]);
205
+ // ============================================================================
206
+ // Return
207
+ // ============================================================================
208
+ return {
209
+ // State
210
+ isReady,
211
+ isScanning,
212
+ results,
213
+ error,
214
+ // Actions
215
+ startScanning,
216
+ stopScanning,
217
+ scanPhoto,
218
+ clearResults,
219
+ reset,
220
+ // Frame processor
221
+ frameProcessor,
222
+ };
223
+ }
224
+ // ============================================================================
225
+ // Helper Functions
226
+ // ============================================================================
227
+ /**
228
+ * Map VisionCamera code type to our BarcodeFormat
229
+ */
230
+ function mapCodeType(codeType) {
231
+ const mapping = {
232
+ 'ean-13': 'ean-13',
233
+ 'ean-8': 'ean-8',
234
+ 'upc-a': 'upc-a',
235
+ 'upc-e': 'upc-e',
236
+ 'code-128': 'code-128',
237
+ 'code-39': 'code-39',
238
+ 'code-93': 'code-93',
239
+ 'itf': 'itf',
240
+ 'codabar': 'codabar',
241
+ 'qr': 'qr',
242
+ 'data-matrix': 'data-matrix',
243
+ 'pdf-417': 'pdf-417',
244
+ 'aztec': 'aztec',
245
+ // Handle variations
246
+ EAN_13: 'ean-13',
247
+ EAN_8: 'ean-8',
248
+ UPC_A: 'upc-a',
249
+ UPC_E: 'upc-e',
250
+ CODE_128: 'code-128',
251
+ CODE_39: 'code-39',
252
+ CODE_93: 'code-93',
253
+ ITF: 'itf',
254
+ CODABAR: 'codabar',
255
+ QR_CODE: 'qr',
256
+ DATA_MATRIX: 'data-matrix',
257
+ PDF_417: 'pdf-417',
258
+ AZTEC: 'aztec',
259
+ };
260
+ return mapping[codeType] || 'code-128';
261
+ }
262
+ /**
263
+ * Map our BarcodeFormat to VisionCamera code type
264
+ */
265
+ function mapFormatToCodeType(format) {
266
+ // VisionCamera uses the same format names
267
+ return format;
268
+ }
269
+ /**
270
+ * Format barcode value for display
271
+ */
272
+ function formatBarcodeDisplay(value, format) {
273
+ switch (format) {
274
+ case 'ean-13':
275
+ // Format: X-XXXXXX-XXXXX-X
276
+ if (value.length === 13) {
277
+ return `${value[0]}-${value.slice(1, 7)}-${value.slice(7, 12)}-${value[12]}`;
278
+ }
279
+ return value;
280
+ case 'upc-a':
281
+ // Format: X-XXXXX-XXXXX-X
282
+ if (value.length === 12) {
283
+ return `${value[0]}-${value.slice(1, 6)}-${value.slice(6, 11)}-${value[11]}`;
284
+ }
285
+ return value;
286
+ default:
287
+ return value;
288
+ }
289
+ }
290
+ exports.default = useMultiBarcodeScanner;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * useProductDetector Hook
3
+ *
4
+ * React hook for visual product detection using TFLite models.
5
+ * Detects products in photos or camera frames using YOLOv8.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { useProductDetector } from '@souschef/ml-vision';
10
+ *
11
+ * function FridgeScanner() {
12
+ * const {
13
+ * isModelLoaded,
14
+ * isDetecting,
15
+ * detections,
16
+ * detectProducts,
17
+ * } = useProductDetector({
18
+ * minConfidence: 0.5,
19
+ * onDetected: (products) => console.log('Found:', products),
20
+ * });
21
+ *
22
+ * const handleCapture = async (photoUri: string) => {
23
+ * const results = await detectProducts(photoUri);
24
+ * // results contain detected products with bounding boxes
25
+ * };
26
+ *
27
+ * return (
28
+ * // Your camera UI
29
+ * );
30
+ * }
31
+ * ```
32
+ */
33
+ import type { UseProductDetectorOptions, UseProductDetectorReturn } from '../types';
34
+ /**
35
+ * Hook for visual product detection using TFLite
36
+ */
37
+ export declare function useProductDetector(options?: UseProductDetectorOptions): UseProductDetectorReturn;
38
+ export default useProductDetector;