OCR-Rohtext additiv zurückgeben, je Eintrag speichern und anzeigen

recognize() (pipeline.js) liefert zusätzlich den ungefilterten OCR-Rohtext
(rawText) zurück - leer, wenn keine Texterkennung lief. Rein additiv: die
Stapelzuordnung (session.js/spec.js, unangetastet) stützt sich weiterhin
ausschließlich auf die daraus abgeleiteten, verstandenen Spec-Felder.

main.js hängt den Rohtext nach dem Buchen als zusätzliche Eigenschaft an den
Eintrag (analog zu den bereits vorhandenen Barcode-Inhalten je Eintrag).
storage.js sichert/prüft/stellt entry.rawText nach demselben optionalen
Muster wie entry.codes wieder her - ein gesicherter Stand ohne dieses Feld
wird nicht verworfen.

In Funktion "Text erkennen" bleibt die Treffer-Rückmeldung jetzt stehen, bis
der Nutzer sie wegtippt, und zeigt den vollen erkannten Text (lesbar über
dasselbe Scroll-Muster wie die übrigen Vollbild-Overlays); in den beiden
Barcode-Funktionen bleibt es beim automatischen Ausblenden. Das
zurückgegebene Versprechen von showResult löst in jedem Fall - Zeitgeber,
Wegtippen, verdrängende neue Rückmeldung - genau einmal ein, damit die
Bedienung nie dauerhaft gesperrt bleibt. Die Sitzungsliste zeigt den Rohtext
zusätzlich je Eintrag zum Nachlesen.

Tests (pipeline.test.js, storage.test.js): rawText nur bei tatsächlich
gelaufener Texterkennung, unterschiedlicher Rohtext beeinflusst die
Stapelzuordnung nachweislich nicht, Rohtext übersteht Sichern/Laden inkl.
Abwärtskompatibilität zu einem Stand ohne dieses Feld.
This commit is contained in:
2026-07-29 15:19:13 +02:00
parent 1c10c68053
commit b903b1c7aa
7 changed files with 266 additions and 22 deletions
+14 -8
View File
@@ -60,10 +60,16 @@ function allCompatible(specs) {
* Stapel bekannt ist. Ist einer der gelesenen Codes bekannt, steht die
* Zuordnung fest und die Texterkennung wird uebersprungen. Fehlt die
* Funktion, verhaelt sich die Pipeline wie ohne diese Optimierung.
* @returns {Promise<{spec: object, source: 'barcode'|'ocr'|'none', confidence: 'green'|'yellow'|'red', codes: string[]}>}
* @returns {Promise<{spec: object, source: 'barcode'|'ocr'|'none', confidence: 'green'|'yellow'|'red', codes: string[], rawText: string}>}
* codes sind die im Bild gelesenen rohen Barcode-Zeichenketten (koennen
* neben der Teilenummer z.B. auch eine Seriennummer enthalten) - zur
* Weitergabe an proposeAssignment/commitAssignment in session.js.
* rawText ist der ungefilterte Texterkennungs-Rohtext, rein additiv: er
* fliesst nirgends in die Stapelzuordnung ein (die stuetzt sich weiterhin
* ausschliesslich auf die aus ihm abgeleiteten, verstandenen Spec-Felder,
* siehe extractFields/ocr-extract.js) und dient allein der Anzeige fuer den
* Nutzer. Leer, wenn die Texterkennung in diesem Durchlauf nicht lief (z.B.
* weil ein gruener Barcode-Treffer sie ueberfluessig gemacht hat).
*/
export async function recognize(frame, deps) {
const barcodeTimeoutMs = deps.barcodeTimeoutMs ?? DEFAULT_BARCODE_TIMEOUT_MS;
@@ -99,7 +105,7 @@ export async function recognize(frame, deps) {
}
if (usable.length === 1) {
return { spec: usable[0], source: 'barcode', confidence: 'green', codes };
return { spec: usable[0], source: 'barcode', confidence: 'green', codes, rawText: '' };
}
if (usable.length > 1) {
if (allCompatible(usable)) {
@@ -109,10 +115,10 @@ export async function recognize(frame, deps) {
// da alle uebrigen Felder aus derselben Teilenummer abgeleitet werden,
// sind vertraegliche Treffer ohnehin gleich. Es gibt nichts aufzufuellen,
// der erste Treffer genuegt.
return { spec: usable[0], source: 'barcode', confidence: 'green', codes };
return { spec: usable[0], source: 'barcode', confidence: 'green', codes, rawText: '' };
}
// Mehrdeutigkeit zwischen verwertbaren Barcodes: nicht raten, Nutzer entscheidet.
return { spec: emptySpec(), source: 'none', confidence: 'red', codes };
return { spec: emptySpec(), source: 'none', confidence: 'red', codes, rawText: '' };
}
// Ist einer der gelesenen Codes bereits einem Stapel bekannt, steht die
@@ -121,7 +127,7 @@ export async function recognize(frame, deps) {
// Bei einem tatsaechlich neuen Modul (kein Code bekannt) laeuft sie wie
// bisher, denn dort liefert sie die lesbare Beschriftung des neuen Stapels.
if (typeof deps.isKnownCode === 'function' && codes.some((code) => deps.isKnownCode(code))) {
return { spec: best, source: 'barcode', confidence: 'green', codes };
return { spec: best, source: 'barcode', confidence: 'green', codes, rawText: '' };
}
const ocrResult = await safely(() => deps.runOcr(frame), '', ocrTimeoutMs);
@@ -136,7 +142,7 @@ export async function recognize(frame, deps) {
}
if (isUsable(merged)) {
return { spec: merged, source: 'ocr', confidence: 'yellow', codes };
return { spec: merged, source: 'ocr', confidence: 'yellow', codes, rawText: text };
}
// Zum Sortieren muss keine Kapazitaet bekannt sein - eine exakt gelesene
// Teilenummer genuegt, um ein Modul wiederzuerkennen. Sie ueberlebt bis
@@ -144,7 +150,7 @@ export async function recognize(frame, deps) {
// mehrere sich einig waren (siehe 'best' oben) - bei widersprechenden
// Codes bleibt merged.partNumber null und die Vorsicht damit erhalten.
if (merged.partNumber !== null) {
return { spec: merged, source: 'barcode', confidence: 'green', codes };
return { spec: merged, source: 'barcode', confidence: 'green', codes, rawText: text };
}
return { spec: merged, source: 'none', confidence: 'red', codes };
return { spec: merged, source: 'none', confidence: 'red', codes, rawText: text };
}