Spaces:
Running on Zero
Running on Zero
| from __future__ import annotations | |
| import json | |
| import tempfile | |
| import unittest | |
| from pathlib import Path | |
| from datasets.field_notes import FieldNote, FieldNoteStore | |
| from datasets.ocr import ( | |
| export_corrected_ocr_notes, | |
| import_uncertain_predictions, | |
| load_ocr_predictions, | |
| ocr_import_summary, | |
| uncertain_predictions, | |
| ) | |
| from ui.notes_tab import import_ocr_predictions, preview_ocr_predictions | |
| class OCRPipelineTest(unittest.TestCase): | |
| def test_loads_ocr_predictions_from_jsonl(self) -> None: | |
| with tempfile.TemporaryDirectory() as tmp: | |
| path = Path(tmp) / "ocr.jsonl" | |
| path.write_text( | |
| json.dumps( | |
| { | |
| "source_path": "receipt.png", | |
| "text": "Total 12.30", | |
| "confidence": 0.91, | |
| "page": 1, | |
| } | |
| ) | |
| + "\n", | |
| encoding="utf-8", | |
| ) | |
| predictions = load_ocr_predictions(path) | |
| self.assertEqual(len(predictions), 1) | |
| self.assertEqual(predictions[0].source_path, "receipt.png") | |
| self.assertEqual(predictions[0].confidence, 0.91) | |
| self.assertEqual(predictions[0].page, "1") | |
| def test_loads_ocr_predictions_from_csv_alias_columns(self) -> None: | |
| with tempfile.TemporaryDirectory() as tmp: | |
| path = Path(tmp) / "ocr.csv" | |
| path.write_text( | |
| "image_path,prediction,score\nlabel.png,Best before 2026,0.72\n", | |
| encoding="utf-8", | |
| ) | |
| predictions = load_ocr_predictions(path) | |
| self.assertEqual(predictions[0].source_path, "label.png") | |
| self.assertEqual(predictions[0].text, "Best before 2026") | |
| self.assertEqual(predictions[0].confidence, 0.72) | |
| def test_filters_uncertain_predictions_by_threshold_and_empty_text(self) -> None: | |
| with tempfile.TemporaryDirectory() as tmp: | |
| path = Path(tmp) / "ocr.jsonl" | |
| rows = [ | |
| {"source_path": "a.png", "text": "clear", "confidence": 0.95}, | |
| {"source_path": "b.png", "text": "maybe", "confidence": 0.7}, | |
| {"source_path": "c.png", "text": "", "confidence": 0.99}, | |
| ] | |
| path.write_text( | |
| "\n".join(json.dumps(row) for row in rows), | |
| encoding="utf-8", | |
| ) | |
| uncertain = uncertain_predictions(load_ocr_predictions(path), 0.8) | |
| self.assertEqual([item.source_path for item in uncertain], ["b.png", "c.png"]) | |
| def test_imports_uncertain_predictions_to_field_notes(self) -> None: | |
| with tempfile.TemporaryDirectory() as tmp: | |
| predictions_path = Path(tmp) / "ocr.jsonl" | |
| predictions_path.write_text( | |
| "\n".join( | |
| [ | |
| json.dumps( | |
| { | |
| "source_path": "uncertain.png", | |
| "text": "hel1o", | |
| "confidence": 0.5, | |
| } | |
| ), | |
| json.dumps( | |
| { | |
| "source_path": "confident.png", | |
| "text": "hello", | |
| "confidence": 0.99, | |
| } | |
| ), | |
| ] | |
| ), | |
| encoding="utf-8", | |
| ) | |
| store = FieldNoteStore(Path(tmp) / "field_notes.csv") | |
| imported = import_uncertain_predictions( | |
| store, | |
| load_ocr_predictions(predictions_path), | |
| "minicpm5_1b", | |
| confidence_threshold=0.8, | |
| ) | |
| notes = store.list_notes(tag="ocr") | |
| self.assertEqual(imported, 1) | |
| self.assertEqual(len(notes), 1) | |
| self.assertEqual(notes[0].response, "hel1o") | |
| self.assertEqual(notes[0].image_path, "uncertain.png") | |
| self.assertFalse(notes[0].use_for_training) | |
| def test_exports_corrected_ocr_notes(self) -> None: | |
| with tempfile.TemporaryDirectory() as tmp: | |
| store = FieldNoteStore(Path(tmp) / "field_notes.csv") | |
| store.save( | |
| FieldNote.create( | |
| model_id="minicpm5_1b", | |
| prompt="Review OCR text for receipt.png.", | |
| response="Tota1", | |
| correction="Total", | |
| tags="ocr,uncertain", | |
| image_path="receipt.png", | |
| ) | |
| ) | |
| store.save( | |
| FieldNote.create( | |
| model_id="minicpm5_1b", | |
| prompt="Other correction", | |
| response="abc", | |
| correction="abc", | |
| tags="demo", | |
| ) | |
| ) | |
| output = export_corrected_ocr_notes(store, Path(tmp) / "ocr_corrections.jsonl") | |
| rows = [json.loads(line) for line in output.read_text(encoding="utf-8").splitlines()] | |
| self.assertEqual(len(rows), 1) | |
| self.assertEqual(rows[0]["source_path"], "receipt.png") | |
| self.assertEqual(rows[0]["predicted_text"], "Tota1") | |
| self.assertEqual(rows[0]["corrected_text"], "Total") | |
| def test_ocr_import_summary_reports_uncertain_sample(self) -> None: | |
| with tempfile.TemporaryDirectory() as tmp: | |
| path = Path(tmp) / "ocr.jsonl" | |
| path.write_text( | |
| json.dumps({"source_path": "a.png", "text": "?", "confidence": 0.1}), | |
| encoding="utf-8", | |
| ) | |
| summary = ocr_import_summary(path, 0.8) | |
| self.assertEqual(summary["rows"], 1) | |
| self.assertEqual(summary["uncertain_rows"], 1) | |
| self.assertEqual(summary["confidence_threshold"], 0.8) | |
| def test_notes_tab_ocr_preview_callback_reports_missing_path(self) -> None: | |
| self.assertEqual( | |
| preview_ocr_predictions("", 0.8), | |
| {"error": "Enter a local OCR prediction file path."}, | |
| ) | |
| def test_notes_tab_ocr_import_callback_binds_store(self) -> None: | |
| with tempfile.TemporaryDirectory() as tmp: | |
| path = Path(tmp) / "ocr.jsonl" | |
| path.write_text( | |
| json.dumps({"source_path": "a.png", "text": "?", "confidence": 0.1}), | |
| encoding="utf-8", | |
| ) | |
| store = FieldNoteStore(Path(tmp) / "field_notes.csv") | |
| status = import_ocr_predictions(store, "minicpm5_1b", str(path), 0.8) | |
| self.assertIn("Imported 1 uncertain OCR predictions", status) | |
| self.assertEqual(len(store.list_notes(tag="ocr")), 1) | |
| if __name__ == "__main__": | |
| unittest.main() | |