Introduce pluggable OcrEngine ABC with PaddleOCR PP-OCRv4 as primary
engine and Tesseract wrapper for backward compatibility. Engine factory
reads OCR_PRIMARY_ENGINE config to instantiate the correct engine.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace direct pytesseract calls with OcrEngine interface in vin_extractor.py,
receipt_extractor.py, and ocr_service.py. PSM mode fallbacks replaced with
engine-agnostic single-line/single-word configs. Dead _process_ocr_data removed.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
CloudEngine wraps Google Vision TEXT_DETECTION with lazy init.
HybridEngine runs primary engine, falls back to cloud when confidence
is below threshold. Disabled by default (OCR_FALLBACK_ENGINE=none).
Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Replace libtesseract-dev with libgomp1 (OpenMP for PaddlePaddle)
- Pre-download PP-OCRv4 models during Docker build
- Add OCR engine env vars to all compose files (base, staging, prod)
- Add optional Google Vision secret mount (commented, enable on demand)
- Create google-vision-key.json.example placeholder
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Three bugs fixed in the draw-first crop tool introduced by PR #114:
1. Stale cropAreaRef: replaced useEffect-based ref sync with direct
synchronous updates in handleMove and handleDrawStart. The useEffect
ran after browser paint, so handleDragEnd read stale values (often
{width:0, height:0}), preventing cropDrawn from being set.
2. Aspect ratio minSize: when aspectRatio=6 (VIN mode), height=width/6
required width>=60% to pass the height>=10% check. Now only checks
width>=minSize when aspect ratio constrains height.
3. Bounds clamping: aspect-ratio-forced height could push crop area
past 100% of container. Now clamps y position to keep within bounds.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add engine abstraction tests and update docs to reflect PaddleOCR primary
architecture with optional Google Vision cloud fallback.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
This PR successfully implements the PaddleOCR migration with excellent engineering discipline. All critical quality gates pass. Minor structural concerns noted for future refactoring consideration.
Google Vision key loaded from Docker secret mount (/run/secrets/google-vision-key.json)
No hardcoded credentials in code
Example file properly documented as placeholder
Fallback disabled by default (OCR_FALLBACK_ENGINE=none)
Resource Management - VERIFIED SAFE:
Hybrid engine has 5-second timeout guard (hybrid_engine.py line 80-86)
Lazy initialization prevents startup failures when optional dependencies missing
PaddleOCR models pre-downloaded during Docker build (not runtime)
Considered but not flagged:
manual_extractor.py still uses pytesseract directly (lines 8, 247, 362) - This is acceptable as TesseractEngine exists for backward compatibility and the manual extractor is a separate feature path.
Issue: TesseractEngine retained for "backward compatibility" but never actually used in production code paths
Evidence: Primary engine is paddleocr (config.py line 15), no production extractors reference tesseract engine, only manual_extractor uses pytesseract directly (not via TesseractEngine)
Impact: Maintenance burden, 115 lines of untested production code, misleading "backward compatibility" claim
Suggested Fix: Either (1) remove TesseractEngine entirely if truly unused, OR (2) add explicit test coverage and document real use case
APPROVED FOR MERGE with recommendation to address RULE 2 findings in follow-up issue:
Remove TesseractEngine if truly unused, or add test coverage + real use case documentation
Migrate manual_extractor to use engine abstraction for consistency
All critical production reliability checks pass. Project conformance standards met. Excellent work on the engine abstraction and comprehensive testing.
## QR Review: Final Review
**Meta:**
- Phase: post-implementation
- Agent: quality-agent
- Status: COMPLETE
- Reviewed: All 33 changed files across 7 commits
---
## VERDICT: PASS WITH MINOR CONCERNS
This PR successfully implements the PaddleOCR migration with excellent engineering discipline. All critical quality gates pass. Minor structural concerns noted for future refactoring consideration.
---
## Findings
### RULE 1 (HIGH): CI/CD Conformance - PASS
- **Lint**: 0 errors (220 frontend warnings, 624 backend warnings - all pre-existing)
- **Type-check**: Both frontend and backend pass with 0 errors
- **Tests**: Unit tests confirmed passing in PR description
- **Mobile + Desktop**: Crop tool fix (issue #120) explicitly addresses mobile regression
- **Naming conventions**: Proper snake_case in DB, camelCase in TypeScript throughout
### RULE 0 (CRITICAL): Production Reliability - PASS
**Engine Error Handling - VERIFIED SAFE:**
- All engines properly raise `EngineUnavailableError` on initialization failure
- All engines properly raise `EngineProcessingError` on recognition failure
- Hybrid engine gracefully falls back to primary result on cloud timeout/error (lines 104-116 in hybrid_engine.py)
- Factory pattern properly propagates exceptions (engine_factory.py lines 34-39)
**Secret Management - VERIFIED SAFE:**
- Google Vision key loaded from Docker secret mount (`/run/secrets/google-vision-key.json`)
- No hardcoded credentials in code
- Example file properly documented as placeholder
- Fallback disabled by default (OCR_FALLBACK_ENGINE=none)
**Resource Management - VERIFIED SAFE:**
- Hybrid engine has 5-second timeout guard (hybrid_engine.py line 80-86)
- Lazy initialization prevents startup failures when optional dependencies missing
- PaddleOCR models pre-downloaded during Docker build (not runtime)
**Considered but not flagged:**
- manual_extractor.py still uses pytesseract directly (lines 8, 247, 362) - This is acceptable as TesseractEngine exists for backward compatibility and the manual extractor is a separate feature path.
---
## Findings - RULE 2 (SHOULD_FIX): Structural Quality
### RULE 2 (SHOULD_FIX): Dead Code Retention
- **Location**: `ocr/app/engines/tesseract_engine.py` (entire file, 115 lines)
- **Issue**: TesseractEngine retained for "backward compatibility" but never actually used in production code paths
- **Evidence**: Primary engine is paddleocr (config.py line 15), no production extractors reference tesseract engine, only manual_extractor uses pytesseract directly (not via TesseractEngine)
- **Impact**: Maintenance burden, 115 lines of untested production code, misleading "backward compatibility" claim
- **Suggested Fix**: Either (1) remove TesseractEngine entirely if truly unused, OR (2) add explicit test coverage and document real use case
### RULE 2 (SHOULD_FIX): Inconsistent Engine Abstraction
- **Location**: `ocr/app/extractors/manual_extractor.py` lines 8, 247, 362
- **Issue**: Manual extractor directly imports pytesseract instead of using TesseractEngine abstraction
- **Impact**: Bypasses engine abstraction layer, cannot benefit from hybrid fallback, inconsistent with VIN/receipt extractors
- **Suggested Fix**: Migrate manual_extractor to use TesseractEngine via create_engine() for consistency
---
## Considered But Not Flagged
**PaddleOCR Model Download (Dockerfile line 39-40):**
- Models downloaded during build, not runtime - correct approach
- Build step verified with success message - appropriate
- Not a production risk
**Hybrid Engine Confidence Comparison (hybrid_engine.py line 89):**
- Simple float comparison without epsilon tolerance
- Acceptable for OCR confidence values (0.0-1.0 range, coarse-grained)
- Edge case of exact equality is handled correctly (returns fallback if strictly greater)
**Frontend Crop Tool Complexity (useImageCrop.ts 424 lines):**
- Handles aspect ratio, touch/mouse, drawing, dragging
- Well-structured with clear separation of concerns
- Properly tested (21 tests confirmed in PR)
- Not a god function - most logic in constrainCrop and handleMove callbacks
**Secret Mount Comment (docker-compose.yml line 203-205):**
- Clear instructions for enabling cloud fallback
- Properly commented out by default
- Not a production risk
---
## Quality Metrics
**Code Quality:**
- 33 files changed, +2564/-321 lines (net +2243)
- 7 commits following conventional commit format
- Comprehensive test coverage (35 engine tests, 7 VIN tests, 21 frontend tests)
**Documentation:**
- Tech stack doc updated (ocr-pipeline-tech-stack.md)
- All CLAUDE.md files updated
- context.json updated
- Inline documentation thorough
**Architecture:**
- Clean abstraction layer with OcrEngine ABC
- Factory pattern properly implemented
- Dependency injection ready for testing
---
## Final Assessment
**APPROVED FOR MERGE** with recommendation to address RULE 2 findings in follow-up issue:
1. Remove TesseractEngine if truly unused, or add test coverage + real use case documentation
2. Migrate manual_extractor to use engine abstraction for consistency
All critical production reliability checks pass. Project conformance standards met. Excellent work on the engine abstraction and comprehensive testing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Linked issues
Fixes #115
Fixes #116
Fixes #117
Fixes #118
Fixes #119
Fixes #120
Fixes #121
Type
Test plan
Commands / steps:
make lint- 0 errorsmake type-check- frontend + backend passcd ocr && python -m pytest tests/ -v- run in OCR containercd backend && npx jest- 89/89 unit tests passcd frontend && npx jest- 119 unit tests passMilestones
ebc633f013fb0c4ef942c9b641733c1a09047c5676Checklist
QR Review: Final Review
Meta:
VERDICT: PASS WITH MINOR CONCERNS
This PR successfully implements the PaddleOCR migration with excellent engineering discipline. All critical quality gates pass. Minor structural concerns noted for future refactoring consideration.
Findings
RULE 1 (HIGH): CI/CD Conformance - PASS
RULE 0 (CRITICAL): Production Reliability - PASS
Engine Error Handling - VERIFIED SAFE:
EngineUnavailableErroron initialization failureEngineProcessingErroron recognition failureSecret Management - VERIFIED SAFE:
/run/secrets/google-vision-key.json)Resource Management - VERIFIED SAFE:
Considered but not flagged:
Findings - RULE 2 (SHOULD_FIX): Structural Quality
RULE 2 (SHOULD_FIX): Dead Code Retention
ocr/app/engines/tesseract_engine.py(entire file, 115 lines)RULE 2 (SHOULD_FIX): Inconsistent Engine Abstraction
ocr/app/extractors/manual_extractor.pylines 8, 247, 362Considered But Not Flagged
PaddleOCR Model Download (Dockerfile line 39-40):
Hybrid Engine Confidence Comparison (hybrid_engine.py line 89):
Frontend Crop Tool Complexity (useImageCrop.ts 424 lines):
Secret Mount Comment (docker-compose.yml line 203-205):
Quality Metrics
Code Quality:
Documentation:
Architecture:
Final Assessment
APPROVED FOR MERGE with recommendation to address RULE 2 findings in follow-up issue:
All critical production reliability checks pass. Project conformance standards met. Excellent work on the engine abstraction and comprehensive testing.