feat: Erkennungs-Pipeline mit Barcode-Vorrang und OCR-Rueckfall
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { emptySpec, isUsable } from './spec.js';
|
||||
import { decodePartNumber } from './pn-decoder.js';
|
||||
import { extractFields } from './ocr-extract.js';
|
||||
|
||||
async function safely(fn, fallback) {
|
||||
try {
|
||||
return await fn();
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Barcode zuerst, OCR nur als Rueckfallebene.
|
||||
* @returns {Promise<{spec: object, source: 'barcode'|'ocr'|'none', confidence: 'green'|'yellow'|'red'}>}
|
||||
*/
|
||||
export async function recognize(frame, deps) {
|
||||
const codes = await safely(() => deps.decodeBarcodes(frame), []);
|
||||
|
||||
let best = emptySpec();
|
||||
for (const code of codes) {
|
||||
const decoded = decodePartNumber(code);
|
||||
if (isUsable(decoded)) {
|
||||
return { spec: decoded, source: 'barcode', confidence: 'green' };
|
||||
}
|
||||
// Teilenummer merken, auch wenn das Schema unbekannt ist.
|
||||
if (best.partNumber === null) best = decoded;
|
||||
}
|
||||
|
||||
const text = await safely(() => deps.runOcr(frame), '');
|
||||
const fromOcr = extractFields(text);
|
||||
|
||||
// Der Barcode ist die exaktere Quelle: seine Teilenummer gewinnt.
|
||||
const merged = { ...fromOcr };
|
||||
if (best.partNumber !== null) merged.partNumber = best.partNumber;
|
||||
for (const field of ['capacityGb', 'formFactor', 'rank', 'speed']) {
|
||||
if (merged[field] === null && best[field] !== null) merged[field] = best[field];
|
||||
}
|
||||
|
||||
if (isUsable(merged)) {
|
||||
return { spec: merged, source: 'ocr', confidence: 'yellow' };
|
||||
}
|
||||
return { spec: merged, source: 'none', confidence: 'red' };
|
||||
}
|
||||
Reference in New Issue
Block a user