milwright commited on
Commit
2d01495
·
1 Parent(s): 6b37887
.DS_Store CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
 
.clinerules/activeContext.md DELETED
@@ -1,31 +0,0 @@
1
- # Current Work Focus
2
-
3
- Refining image preprocessing pipelines to better balance cleaning and preservation of fine details (especially for handwritten inputs)
4
-
5
- Improving document type detection accuracy to feed better prompts to the OCR system
6
-
7
- Enhancing structured output schemas to cover additional types like travel logs and scientific diagrams
8
-
9
- Recent Changes
10
-
11
- Implemented more document-type-specific preprocessing pipelines
12
-
13
- Switched default OCR engine to Mistral for both printed and handwritten material
14
-
15
- Modularized utility functions across utils.py, ocr_utils.py, and newly proposed submodules
16
-
17
- Active Decisions and Considerations
18
-
19
- Whether to expose preprocessing options to end users (e.g., deskew threshold)
20
-
21
- Whether to allow fallback to local Tesseract OCR for offline cases
22
-
23
- Determining best practices for handling multi-page PDFs with mixed layouts
24
-
25
- Important Patterns and Learnings
26
-
27
- Document type detection greatly improves OCR quality when tuned per-class
28
-
29
- Over-aggressive preprocessing can erase faint handwriting; thresholds must be conservative for historical artifacts
30
-
31
- Keeping preprocessing modular enables rapid experimentation and tuning.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.clinerules/apiDocumentation.md DELETED
@@ -1,29 +0,0 @@
1
- apiDocumentation.md
2
- API Interaction Documentation
3
- Mistral OCR API
4
-
5
- Endpoint: /v1/ocr
6
-
7
- Payload:
8
-
9
- image (binary)
10
-
11
- prompt (optional contextual instructions)
12
-
13
- Response:
14
-
15
- structured_data: Hierarchical text + metadata output
16
-
17
- raw_text: Plain extracted text
18
-
19
- Error Handling:
20
-
21
- Timeout retries (up to 3 attempts)
22
-
23
- Local fallback to Tesseract if Mistral service unavailable
24
-
25
- Tesseract Fallback
26
-
27
- Only invoked if Mistral API fails after retries.
28
-
29
- No structured output; raw text only.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.clinerules/complexFeature.md DELETED
@@ -1,29 +0,0 @@
1
- # Complex Feature Documentation
2
-
3
- Document Type Detection
4
-
5
- Utilizes lightweight statistical heuristics combined with visual features.
6
-
7
- Preprocessing-driven (thresholding, aspect ratios, contour analysis).
8
-
9
- Outputs labels such as "handwritten letter", "scientific report", "recipe".
10
-
11
- Preprocessing Pipelines
12
-
13
- Customizable per document type.
14
-
15
- Adaptive thresholding for delicate handwriting.
16
-
17
- Morphological operations for removing bleed-through or artifacts.
18
-
19
- Multilingual Handling
20
-
21
- Language detection on OCR snippets using language_detection.py.
22
-
23
- Allows contextual OCR prompting based on dominant language.
24
-
25
- Structured Output Generation
26
-
27
- Parsing OCR results into structured categories: titles, subtitles, body, marginalia, dates.
28
-
29
- Supports output in raw text, JSON, and annotated Markdown.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.clinerules/hocr-basics-api.md DELETED
@@ -1,106 +0,0 @@
1
- # HOCR Basics: API Integrations (Streamlit and Mistral OCR)
2
-
3
- This rule defines the essential development standards for integrating the Mistral OCR API and using Streamlit components in the `milwright/historical-ocr` application.
4
-
5
- ## 📌 Rule 1: Mistral OCR API Usage
6
-
7
- * **Endpoint:**
8
- `POST https://api.mistral.ai/v1/ocr`
9
-
10
- * **Headers:**
11
-
12
- ```http
13
- Authorization: Bearer YOUR_API_KEY
14
- Content-Type: application/json
15
- ```
16
-
17
- * **Required JSON Body Fields:**
18
-
19
- ```json
20
- {
21
- "file_url": "https://example.com/your.pdf"
22
- }
23
- ```
24
-
25
- * **Expected Response Fields:**
26
-
27
- * `text`: Raw OCR output
28
- * `metadata`: Document structure, language, layout information
29
-
30
- > **Note:** Always validate presence of required fields and handle error codes gracefully.
31
-
32
- ---
33
-
34
- ### 🖼️ Rule 2: Streamlit Usage Standards
35
-
36
- * Use these core components:
37
-
38
- * `st.file_uploader()`
39
- * `st.selectbox()`
40
- * `st.image()`
41
- * `st.markdown()`
42
- * `st.download_button()`
43
-
44
- * Always set:
45
- `use_container_width=True` for responsive display where supported
46
-
47
- * Avoid global state; prefer `st.session_state` for interactivity and stateful inputs
48
-
49
- ## Mistral OCR Examples
50
-
51
- ``` json
52
- {
53
- "id": "string",
54
- "object": "model",
55
- "created": 0,{
56
- "model": "string",
57
- "id": "string",
58
- "document": {
59
- "document_url": "string",
60
- "document_name": "string",
61
- "type": "document_url"
62
- },
63
- "pages": [
64
- 0
65
- ],
66
- "include_image_base64": true,
67
- "image_limit": 0,
68
- "image_min_size": 0
69
- }
70
- ```
71
-
72
- ``` json
73
- {
74
- "pages": [
75
- {
76
- "index": 0,
77
- "markdown": "string",
78
- "images": [
79
- {
80
- "id": "string",
81
- "top_left_x": 0,
82
- "top_left_y": 0,
83
- "bottom_right_x": 0,
84
- "bottom_right_y": 0,
85
- "image_base64": "string"
86
- }
87
- ],
88
- "dimensions": {
89
- "dpi": 0,
90
- "height": 0,
91
- "width": 0
92
- }
93
- }
94
- ],
95
- "model": "string",
96
- "usage_info": {
97
- "pages_processed": 0,
98
- "doc_size_bytes": 0
99
- }
100
- }
101
- ```
102
-
103
- ### Links and Resources to Understand
104
-
105
- * [URL to Mistral OCR APi doc](https://docs.mistral.ai/api/#tag/batch/operation/jobs_api_routes_batch_cancel_batch_job)
106
- * [URL to Streamlit API documentation](https://docs.streamlit.io/develop/api-reference)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.clinerules/integrationSpecs.md DELETED
@@ -1,27 +0,0 @@
1
- # Integration Specifications
2
-
3
- External Services
4
-
5
- Mistral OCR API: Primary service for document transcription and structured extraction.
6
-
7
- Tesseract OCR (Local Fallback): Optional backup when API unavailable.
8
-
9
- Internal Module Communication
10
-
11
- app.py triggers ocr_processing.py orchestration based on user input.
12
-
13
- ocr_processing.py dynamically calls preprocessing and OCR modules based on document type.
14
-
15
- Preprocessed images passed through structured_ocr.py for API interaction and postprocessing.
16
-
17
- Session State
18
-
19
- Streamlit session stores:
20
-
21
- Uploaded file metadata
22
-
23
- Preprocessing parameters
24
-
25
- Detected document type
26
-
27
- OCR structured output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.clinerules/principle-of-simplicity.md DELETED
@@ -1,55 +0,0 @@
1
- # Project Rule: Maintain Clean Separation Between Data and Presentation
2
- The Principle of Content Purity
3
- Core rule: Data that needs to be processed or stored should never contain presentation markup that's only meant for display.
4
-
5
- What This Means in Practice
6
- Avoid HTML in data structures
7
-
8
- ✅ DO: Keep raw text as pure text content
9
- ❌ DON'T: Embed HTML, CSS, or other presentation-specific markup in data fields
10
- Design clear boundaries between data and presentation layers
11
-
12
- ✅ DO: Add presentation elements at the final rendering stage only
13
- ❌ DON'T: Add and strip presentation elements repeatedly throughout the processing pipeline
14
- Fix problems at their source, not their symptoms
15
-
16
- ✅ DO: Prevent markup injection at the origin rather than adding complex stripping logic later
17
- ❌ DON'T: Create complex sanitization functions to clean data that shouldn't be contaminated in the first place
18
- The OCR Text Formatter Example
19
- Before (problematic):
20
-
21
- def format_ocr_text(text, for_display=True):
22
- # Text processing...
23
-
24
- if for_display:
25
- html = f"""
26
- <div class="ocr-text-container">
27
- {formatted_text}
28
- </div>
29
- """
30
- return html
31
- else:
32
- return formatted_text
33
- After (better):
34
-
35
- def format_ocr_text(text, for_display=False):
36
- # Text processing...
37
-
38
- if for_display:
39
- html = f"""
40
- {formatted_text}
41
- """
42
- return html
43
- else:
44
- return formatted_text
45
- What changed:
46
-
47
- Default parameter changed to avoid accidental HTML addition
48
- HTML wrapper div completely removed to eliminate the source of pollution
49
- The simplest solution (removing the container) was better than any complex stripping logic
50
- Benefits
51
- Cleaner data: Raw content remains genuinely raw and easier to work with
52
- More predictable processing: No need to account for unexpected HTML in processing pipelines
53
- Easier debugging: Problems are visible at their source rather than as mysterious artifacts later
54
- Reduced complexity: Eliminates the need for complex HTML stripping and sanitization logic
55
- Remember: Simplicity is not just an ideal—it's a practical strategy that prevents entire classes of bugs.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.clinerules/productContext.md DELETED
@@ -1,25 +0,0 @@
1
- # Why the Project Exists
2
-
3
- Historians, archivists, and researchers often struggle to extract reliable text from scanned archival materials. Many OCR tools fail when dealing with handwritten letters, historical scientific documents, and poorly digitized photographs.
4
-
5
- Problems Being Solved
6
-
7
- Low OCR accuracy on handwritten or degraded historical documents
8
-
9
- Lack of structured metadata extraction for archival research
10
-
11
- Inability to easily apply context-specific AI prompting for nuanced historical material
12
-
13
- How the Product Should Work
14
-
15
- Users upload images or PDFs
16
-
17
- Preprocessing automatically improves OCR readiness
18
-
19
- Document type detection informs customized AI prompting
20
-
21
- Mistral OCR processes the document to output structured data (titles, authors, dates, body text, marginalia, etc.)
22
-
23
- Users can download raw text, structured JSON, or annotated markdown
24
-
25
- Example: "The OCR system must intelligently handle multilingual documents, support marginal notes and irregular layouts, and allow historians to guide the extraction process."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.clinerules/progress.md DELETED
@@ -1,27 +0,0 @@
1
- # Current Status of Features
2
-
3
- ✅ Upload and preprocess historical documents
4
-
5
- ⚙️ Document type detection (estimated 80% accuracy)
6
-
7
- ✅ OCR extraction with structured outputs (titles, body, marginalia)
8
-
9
- ✅ Multiple output formats (Raw text, JSON, Markdown)
10
-
11
- Known Issues and Limitations
12
-
13
- Inconsistent marginalia capture in low-quality scans
14
-
15
- Difficulties with heavily degraded non-Latin handwritten scripts
16
-
17
- Layout detection errors on highly irregular, mixed-content PDFs
18
-
19
- Evolution of Project Decisions
20
-
21
- Migrated from Tesseract-only OCR to Mistral-first hybrid approach
22
-
23
- Modularized preprocessing steps to allow flexible experimentation
24
-
25
- Added support for marginalia and footnotes where feasible
26
-
27
- Enhanced session state management to preserve intermediate results.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.clinerules/systemPatterns.md DELETED
@@ -1,31 +0,0 @@
1
- # System Architecture
2
-
3
- Frontend: Streamlit app (app.py) for user interface and interactions.
4
-
5
- Core Processing: ocr_processing.py orchestrates preprocessing, document type detection, and OCR operations.
6
-
7
- Image Preprocessing: preprocessing.py, image_segmentation.py handle deskewing, thresholding, and cleaning.
8
-
9
- OCR and Structuring: structured_ocr.py and ocr_utils.py manage API communication and formatting structured outputs.
10
-
11
- Utilities and Detection: language_detection.py, utils.py, and constants.py provide language detection, helpers, and prompt templates.
12
-
13
- Key Technical Decisions
14
-
15
- Streamlit cache management for upload processing efficiency.
16
-
17
- Modular design of preprocessing paths based on document type.
18
-
19
- Mistral AI as the primary OCR processor, with Tesseract fallback for redundancy.
20
-
21
- Design Patterns in Use
22
-
23
- Delegation: Frontend delegates all processing to backend orchestrators.
24
-
25
- Modularity: Preprocessing and OCR tasks divided into clean, testable modules.
26
-
27
- State-driven Processing: Output dynamically reflects session state and user input.
28
-
29
- Component Relationships
30
-
31
- app.py ⇨ ocr_processing.py ⇨ preprocessing.py, structured_ocr.py, language_detection.py, etc.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.clinerules/techContext.md DELETED
@@ -1,40 +0,0 @@
1
- techContext.md
2
- Technologies and Frameworks Used
3
-
4
- Frontend Framework: Streamlit 1.44.1
5
-
6
- OCR Engine: Mistralai Python SDK (≥ 0.1.0)
7
-
8
- Image Processing: OpenCV, Pillow
9
-
10
- PDF Parsing: pdf2image
11
-
12
- Fallback OCR: Pytesseract
13
-
14
- Utilities: NumPy, Requests, pycountry
15
-
16
- Development Setup
17
-
18
- Python 3.11+ virtual environment
19
-
20
- Requirements managed through requirements.txt
21
-
22
- .env file setup for API keys and environment configs
23
-
24
- Type checking with mypy, linting with ruff
25
-
26
- Technical Constraints
27
-
28
- API rate limits and payload size restrictions from Mistral
29
-
30
- Streamlit's session state limitations for very large files
31
-
32
- Processing timeouts for oversized or complex PDFs
33
-
34
- Dependencies and Tool Configurations
35
-
36
- Mistralai pinned version (≥ 0.1.0)
37
-
38
- OpenCV configured for headless environments
39
-
40
- Pillow used for post-processing and visualization checks
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore CHANGED
@@ -18,6 +18,13 @@ output/preview/
18
  logs/
19
  *.backup
20
  *.json
 
 
 
 
 
 
 
21
 
22
  # Test files
23
  test_*.py
@@ -33,3 +40,5 @@ input/*.pdf
33
  # Temporary documents
34
  Tmplf6xnkgr*
35
  .env
 
 
 
18
  logs/
19
  *.backup
20
  *.json
21
+ *.jpg
22
+ *.png
23
+ *.txt
24
+ *.csv
25
+ *.log
26
+ *.zip
27
+ *.tar
28
 
29
  # Test files
30
  test_*.py
 
40
  # Temporary documents
41
  Tmplf6xnkgr*
42
  .env
43
+ output/pipeline_test/americae-retectio/americae-retectio_comparison.jpg
44
+ docs/environment_variables.md
docs/config_refactoring.md ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Configuration Refactoring
2
+
3
+ ## Overview
4
+ This document outlines the changes made to centralize configuration parameters and reduce technical debt in the OCR processing system.
5
+
6
+ ## Key Changes
7
+
8
+ ### Centralized Configuration
9
+ All previously hard-coded parameters have been moved to `config.py` and organized by functional category:
10
+
11
+ - **PDF_SETTINGS**: Parameters for PDF processing
12
+ - **SEGMENTATION_SETTINGS**: Image segmentation configuration
13
+ - **CACHE_SETTINGS**: Cache TTL and capacity settings
14
+ - **TEXT_REPAIR_SETTINGS**: Duplication detection and repair thresholds
15
+
16
+ ### Environment Variable Support
17
+ All configuration parameters can now be overridden via environment variables:
18
+
19
+ ```bash
20
+ # Example: Override PDF DPI
21
+ export PDF_DEFAULT_DPI=200
22
+
23
+ # Example: Increase cache size
24
+ export CACHE_MAX_ENTRIES=50
25
+ ```
26
+
27
+ ### Import Strategy
28
+ To prevent circular dependencies, configuration is imported at function level where needed:
29
+
30
+ ```python
31
+ def process_image():
32
+ from config import SEGMENTATION_SETTINGS
33
+ # Function implementation using settings
34
+ ```
35
+
36
+ ## Benefits
37
+
38
+ - **Maintainability**: Settings are centralized and documented
39
+ - **Flexibility**: Configuration can be adjusted without code changes
40
+ - **Consistency**: Standardized approach to configuration across modules
41
+ - **Traceability**: Clear overview of all configurable parameters
42
+
43
+ ## Future Improvements
44
+
45
+ - Add configuration schema validation
46
+ - Support for configuration profiles (dev/test/prod)
47
+ - Add detailed documentation for each parameter
improvements.md ADDED
@@ -0,0 +1,587 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Historical OCR Application Improvements
2
+
3
+ Based on a thorough code review of the Historical OCR application, I've identified several areas for improvement to reduce technical debt and enhance the application's functionality, maintainability, and performance.
4
+
5
+ ## 1. Code Organization and Structure
6
+
7
+ ### 1.1 Modularize Large Functions
8
+ Several functions in the codebase are excessively long and handle multiple responsibilities:
9
+
10
+ - **Issue**: `process_file()` in ocr_processing.py is over 400 lines and handles file validation, preprocessing, OCR processing, and result formatting.
11
+ - **Solution**: Break down into smaller, focused functions:
12
+ ```python
13
+ def process_file(uploaded_file, options):
14
+ # Validate and prepare file
15
+ file_info = validate_and_prepare_file(uploaded_file)
16
+
17
+ # Apply preprocessing based on document type
18
+ preprocessed_file = preprocess_document(file_info, options)
19
+
20
+ # Perform OCR processing
21
+ ocr_result = perform_ocr(preprocessed_file, options)
22
+
23
+ # Format and enhance results
24
+ return format_and_enhance_results(ocr_result, file_info)
25
+ ```
26
+
27
+ ### 1.2 Consistent Error Handling
28
+ Error handling approaches vary across modules:
29
+
30
+ - **Issue**: Some functions use try/except blocks with detailed logging, while others return error dictionaries or raise exceptions.
31
+ - **Solution**: Implement a consistent error handling strategy:
32
+ ```python
33
+ class OCRError(Exception):
34
+ def __init__(self, message, error_code=None, details=None):
35
+ self.message = message
36
+ self.error_code = error_code
37
+ self.details = details
38
+ super().__init__(self.message)
39
+
40
+ def handle_error(func):
41
+ @functools.wraps(func)
42
+ def wrapper(*args, **kwargs):
43
+ try:
44
+ return func(*args, **kwargs)
45
+ except OCRError as e:
46
+ logger.error(f"OCR Error: {e.message} (Code: {e.error_code})")
47
+ return {"error": e.message, "error_code": e.error_code, "details": e.details}
48
+ except Exception as e:
49
+ logger.error(f"Unexpected error: {str(e)}")
50
+ return {"error": "An unexpected error occurred", "details": str(e)}
51
+ return wrapper
52
+ ```
53
+
54
+ ## 2. API Integration and Performance
55
+
56
+ ### 2.1 API Client Optimization
57
+ The Mistral API client initialization and usage can be improved:
58
+
59
+ - **Issue**: The client is initialized for each request and error handling is duplicated.
60
+ - **Solution**: Create a singleton API client with centralized error handling:
61
+ ```python
62
+ class MistralClient:
63
+ _instance = None
64
+
65
+ @classmethod
66
+ def get_instance(cls, api_key=None):
67
+ if cls._instance is None:
68
+ cls._instance = cls(api_key)
69
+ return cls._instance
70
+
71
+ def __init__(self, api_key=None):
72
+ self.api_key = api_key or os.environ.get("MISTRAL_API_KEY", "")
73
+ self.client = Mistral(api_key=self.api_key)
74
+
75
+ def process_ocr(self, document, **kwargs):
76
+ try:
77
+ return self.client.ocr.process(document=document, **kwargs)
78
+ except Exception as e:
79
+ # Centralized error handling
80
+ return self._handle_api_error(e)
81
+ ```
82
+
83
+ ### 2.2 Caching Strategy
84
+ The current caching approach can be improved:
85
+
86
+ - **Issue**: Cache keys don't always account for all relevant parameters, and TTL is fixed at 24 hours.
87
+ - **Solution**: Implement a more sophisticated caching strategy:
88
+ ```python
89
+ def generate_cache_key(file_content, options):
90
+ # Create a comprehensive hash of all relevant parameters
91
+ options_str = json.dumps(options, sort_keys=True)
92
+ content_hash = hashlib.md5(file_content).hexdigest()
93
+ return f"{content_hash}_{hashlib.md5(options_str.encode()).hexdigest()}"
94
+
95
+ # Adaptive TTL based on document type
96
+ def get_cache_ttl(document_type):
97
+ ttl_map = {
98
+ "handwritten": 48 * 3600, # 48 hours for handwritten docs
99
+ "newspaper": 24 * 3600, # 24 hours for newspapers
100
+ "standard": 12 * 3600 # 12 hours for standard docs
101
+ }
102
+ return ttl_map.get(document_type, 24 * 3600)
103
+ ```
104
+
105
+ ## 3. State Management
106
+
107
+ ### 3.1 Streamlit Session State
108
+ The application uses a complex state management approach:
109
+
110
+ - **Issue**: Many session state variables with unclear relationships and reset logic.
111
+ - **Solution**: Implement a more structured state management approach:
112
+ ```python
113
+ class DocumentState:
114
+ def __init__(self):
115
+ self.document = None
116
+ self.original_bytes = None
117
+ self.name = None
118
+ self.mime_type = None
119
+ self.is_sample = False
120
+ self.processed = False
121
+ self.temp_files = []
122
+
123
+ def reset(self):
124
+ # Clean up temp files
125
+ for temp_file in self.temp_files:
126
+ if os.path.exists(temp_file):
127
+ os.unlink(temp_file)
128
+
129
+ # Reset state
130
+ self.__init__()
131
+
132
+ # Initialize in session state
133
+ if 'document_state' not in st.session_state:
134
+ st.session_state.document_state = DocumentState()
135
+ ```
136
+
137
+ ### 3.2 Result History Management
138
+ The current approach to managing result history can be improved:
139
+
140
+ - **Issue**: Results are stored directly in session state with limited management.
141
+ - **Solution**: Create a dedicated class for result history:
142
+ ```python
143
+ class ResultHistory:
144
+ def __init__(self, max_results=20):
145
+ self.results = []
146
+ self.max_results = max_results
147
+
148
+ def add_result(self, result):
149
+ # Add timestamp and ensure result is serializable
150
+ result = self._prepare_result(result)
151
+ self.results.insert(0, result)
152
+
153
+ # Trim to max size
154
+ if len(self.results) > self.max_results:
155
+ self.results = self.results[:self.max_results]
156
+
157
+ def _prepare_result(self, result):
158
+ # Add timestamp and ensure result is serializable
159
+ result = result.copy()
160
+ result['timestamp'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
161
+
162
+ # Ensure result is serializable
163
+ return json.loads(json.dumps(result, default=str))
164
+ ```
165
+
166
+ ## 4. Image Processing Pipeline
167
+
168
+ ### 4.1 Preprocessing Configuration
169
+ The preprocessing configuration can be improved:
170
+
171
+ - **Issue**: Preprocessing options are scattered across different parts of the code.
172
+ - **Solution**: Create a centralized preprocessing configuration:
173
+ ```python
174
+ PREPROCESSING_CONFIGS = {
175
+ "standard": {
176
+ "grayscale": True,
177
+ "denoise": True,
178
+ "contrast": 5,
179
+ "deskew": True
180
+ },
181
+ "handwritten": {
182
+ "grayscale": True,
183
+ "denoise": True,
184
+ "contrast": 10,
185
+ "deskew": True,
186
+ "adaptive_threshold": {
187
+ "block_size": 21,
188
+ "constant": 5
189
+ }
190
+ },
191
+ "newspaper": {
192
+ "grayscale": True,
193
+ "denoise": True,
194
+ "contrast": 5,
195
+ "deskew": True,
196
+ "column_detection": True
197
+ }
198
+ }
199
+ ```
200
+
201
+ ### 4.2 Image Segmentation
202
+ The image segmentation approach can be improved:
203
+
204
+ - **Issue**: Segmentation is optional and not well-integrated with the preprocessing pipeline.
205
+ - **Solution**: Make segmentation a standard part of the preprocessing pipeline for certain document types:
206
+ ```python
207
+ def preprocess_document(file_info, options):
208
+ # Apply basic preprocessing
209
+ preprocessed_file = apply_basic_preprocessing(file_info, options)
210
+
211
+ # Apply segmentation for specific document types
212
+ if options["document_type"] in ["newspaper", "book", "multi_column"]:
213
+ return apply_segmentation(preprocessed_file, options)
214
+
215
+ return preprocessed_file
216
+ ```
217
+
218
+ ## 5. User Experience Enhancements
219
+
220
+ ### 5.1 Progressive Loading
221
+ Improve the user experience during processing:
222
+
223
+ - **Issue**: The UI can appear frozen during long-running operations.
224
+ - **Solution**: Implement progressive loading and feedback:
225
+ ```python
226
+ def process_with_feedback(file, options, progress_callback):
227
+ # Update progress at each step
228
+ progress_callback(10, "Validating document...")
229
+ file_info = validate_and_prepare_file(file)
230
+
231
+ progress_callback(30, "Preprocessing document...")
232
+ preprocessed_file = preprocess_document(file_info, options)
233
+
234
+ progress_callback(50, "Performing OCR...")
235
+ ocr_result = perform_ocr(preprocessed_file, options)
236
+
237
+ progress_callback(80, "Enhancing results...")
238
+ final_result = format_and_enhance_results(ocr_result, file_info)
239
+
240
+ progress_callback(100, "Complete!")
241
+ return final_result
242
+ ```
243
+
244
+ ### 5.2 Result Visualization
245
+ Enhance the visualization of OCR results:
246
+
247
+ - **Issue**: Results are displayed in a basic format with limited visualization.
248
+ - **Solution**: Implement enhanced visualization options:
249
+ ```python
250
+ def display_enhanced_results(result):
251
+ # Create tabs for different views
252
+ tabs = st.tabs(["Text", "Annotated", "Side-by-Side", "JSON"])
253
+
254
+ with tabs[0]:
255
+ # Display formatted text
256
+ st.markdown(format_ocr_text(result["ocr_contents"]["raw_text"]))
257
+
258
+ with tabs[1]:
259
+ # Display annotated image with bounding boxes
260
+ display_annotated_image(result)
261
+
262
+ with tabs[2]:
263
+ # Display side-by-side comparison
264
+ col1, col2 = st.columns(2)
265
+ with col1:
266
+ st.image(result["original_image"])
267
+ with col2:
268
+ st.markdown(format_ocr_text(result["ocr_contents"]["raw_text"]))
269
+
270
+ with tabs[3]:
271
+ # Display raw JSON
272
+ st.json(result)
273
+ ```
274
+
275
+ ## 6. Testing and Reliability
276
+
277
+ ### 6.1 Automated Testing
278
+ Implement comprehensive testing:
279
+
280
+ - **Issue**: Limited or no automated testing.
281
+ - **Solution**: Implement unit and integration tests:
282
+ ```python
283
+ # Unit test for preprocessing
284
+ def test_preprocess_image():
285
+ # Test with various document types
286
+ for doc_type in ["standard", "handwritten", "newspaper"]:
287
+ # Load test image
288
+ with open(f"test_data/{doc_type}_sample.jpg", "rb") as f:
289
+ image_bytes = f.read()
290
+
291
+ # Apply preprocessing
292
+ options = {"document_type": doc_type, "grayscale": True, "denoise": True}
293
+ result = preprocess_image(image_bytes, options)
294
+
295
+ # Assert result is not None and different from original
296
+ assert result is not None
297
+ assert result != image_bytes
298
+ ```
299
+
300
+ ### 6.2 Error Recovery
301
+ Implement better error recovery mechanisms:
302
+
303
+ - **Issue**: Errors in one part of the pipeline can cause the entire process to fail.
304
+ - **Solution**: Implement graceful degradation:
305
+ ```python
306
+ def process_with_fallbacks(file, options):
307
+ try:
308
+ # Try full processing pipeline
309
+ return full_processing_pipeline(file, options)
310
+ except OCRError as e:
311
+ logger.warning(f"Full pipeline failed: {e.message}. Trying simplified pipeline.")
312
+ try:
313
+ # Try simplified pipeline
314
+ return simplified_processing_pipeline(file, options)
315
+ except Exception as e2:
316
+ logger.error(f"Simplified pipeline failed: {str(e2)}. Falling back to basic OCR.")
317
+ # Fall back to basic OCR
318
+ return basic_ocr_only(file)
319
+ ```
320
+
321
+ ## 7. Documentation and Maintainability
322
+
323
+ ### 7.1 Code Documentation
324
+ Improve code documentation:
325
+
326
+ - **Issue**: Inconsistent documentation across modules.
327
+ - **Solution**: Implement consistent docstring format and add module-level documentation:
328
+ ```python
329
+ """
330
+ OCR Processing Module
331
+
332
+ This module handles the core OCR processing functionality, including:
333
+ - File validation and preparation
334
+ - Image preprocessing
335
+ - OCR processing with Mistral AI
336
+ - Result formatting and enhancement
337
+
338
+ The main entry point is the `process_file` function.
339
+ """
340
+
341
+ def process_file(file, options):
342
+ """
343
+ Process a file with OCR.
344
+
345
+ Args:
346
+ file: The file to process (UploadedFile or bytes)
347
+ options: Dictionary of processing options
348
+ - document_type: Type of document (standard, handwritten, etc.)
349
+ - preprocessing: Dictionary of preprocessing options
350
+ - use_vision: Whether to use vision model
351
+
352
+ Returns:
353
+ Dictionary containing OCR results and metadata
354
+
355
+ Raises:
356
+ OCRError: If OCR processing fails
357
+ """
358
+ # Implementation
359
+ ```
360
+
361
+ ### 7.2 Configuration Management
362
+ Improve configuration management:
363
+
364
+ - **Issue**: Configuration is scattered across multiple files.
365
+ - **Solution**: Implement a centralized configuration system:
366
+ ```python
367
+ """
368
+ Configuration Module
369
+
370
+ This module provides a centralized configuration system for the application.
371
+ """
372
+
373
+ import os
374
+ import yaml
375
+ from pathlib import Path
376
+
377
+ class Config:
378
+ _instance = None
379
+
380
+ @classmethod
381
+ def get_instance(cls):
382
+ if cls._instance is None:
383
+ cls._instance = cls()
384
+ return cls._instance
385
+
386
+ def __init__(self):
387
+ self.config = {}
388
+ self.load_config()
389
+
390
+ def load_config(self):
391
+ # Load from config file
392
+ config_path = Path(__file__).parent / "config.yaml"
393
+ if config_path.exists():
394
+ with open(config_path, "r") as f:
395
+ self.config = yaml.safe_load(f)
396
+
397
+ # Override with environment variables
398
+ for key, value in os.environ.items():
399
+ if key.startswith("OCR_"):
400
+ config_key = key[4:].lower()
401
+ self.config[config_key] = value
402
+
403
+ def get(self, key, default=None):
404
+ return self.config.get(key, default)
405
+ ```
406
+
407
+ ## 8. Security Enhancements
408
+
409
+ ### 8.1 API Key Management
410
+ Improve API key management:
411
+
412
+ - **Issue**: API keys are stored in environment variables with limited validation.
413
+ - **Solution**: Implement secure API key management:
414
+ ```python
415
+ def get_api_key():
416
+ # Try to get from secure storage first
417
+ api_key = get_from_secure_storage("mistral_api_key")
418
+
419
+ # Fall back to environment variable
420
+ if not api_key:
421
+ api_key = os.environ.get("MISTRAL_API_KEY", "")
422
+
423
+ # Validate key format
424
+ if api_key and not re.match(r'^[A-Za-z0-9_-]{30,}$', api_key):
425
+ logger.warning("API key format appears invalid")
426
+
427
+ return api_key
428
+ ```
429
+
430
+ ### 8.2 Input Validation
431
+ Improve input validation:
432
+
433
+ - **Issue**: Limited validation of user inputs.
434
+ - **Solution**: Implement comprehensive input validation:
435
+ ```python
436
+ def validate_file(file):
437
+ # Check file size
438
+ if len(file.getvalue()) > MAX_FILE_SIZE:
439
+ raise OCRError("File too large", "FILE_TOO_LARGE")
440
+
441
+ # Check file type
442
+ file_type = get_file_type(file)
443
+ if file_type not in ALLOWED_FILE_TYPES:
444
+ raise OCRError(f"Unsupported file type: {file_type}", "UNSUPPORTED_FILE_TYPE")
445
+
446
+ # Check for malicious content
447
+ if is_potentially_malicious(file):
448
+ raise OCRError("File appears to be malicious", "SECURITY_RISK")
449
+
450
+ return file_type
451
+ ```
452
+
453
+ ## 9. Performance Optimizations
454
+
455
+ ### 9.1 Parallel Processing
456
+ Implement parallel processing for multi-page documents:
457
+
458
+ - **Issue**: Pages are processed sequentially, which can be slow for large documents.
459
+ - **Solution**: Implement parallel processing:
460
+ ```python
461
+ def process_pdf_pages(pdf_path, options):
462
+ # Extract pages
463
+ pages = extract_pdf_pages(pdf_path)
464
+
465
+ # Process pages in parallel
466
+ with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
467
+ future_to_page = {executor.submit(process_page, page, options): i
468
+ for i, page in enumerate(pages)}
469
+
470
+ results = []
471
+ for future in concurrent.futures.as_completed(future_to_page):
472
+ page_idx = future_to_page[future]
473
+ try:
474
+ result = future.result()
475
+ results.append((page_idx, result))
476
+ except Exception as e:
477
+ logger.error(f"Error processing page {page_idx}: {str(e)}")
478
+
479
+ # Sort results by page index
480
+ results.sort(key=lambda x: x[0])
481
+
482
+ # Combine results
483
+ return combine_page_results([r[1] for r in results])
484
+ ```
485
+
486
+ ### 9.2 Resource Management
487
+ Improve resource management:
488
+
489
+ - **Issue**: Temporary files are not always cleaned up properly.
490
+ - **Solution**: Implement better resource management:
491
+ ```python
492
+ class TempFileManager:
493
+ def __init__(self):
494
+ self.temp_files = []
495
+
496
+ def create_temp_file(self, content, suffix=".tmp"):
497
+ with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
498
+ tmp.write(content)
499
+ self.temp_files.append(tmp.name)
500
+ return tmp.name
501
+
502
+ def cleanup(self):
503
+ for temp_file in self.temp_files:
504
+ try:
505
+ if os.path.exists(temp_file):
506
+ os.unlink(temp_file)
507
+ except Exception as e:
508
+ logger.warning(f"Failed to remove temp file {temp_file}: {str(e)}")
509
+ self.temp_files = []
510
+
511
+ def __enter__(self):
512
+ return self
513
+
514
+ def __exit__(self, exc_type, exc_val, exc_tb):
515
+ self.cleanup()
516
+ ```
517
+
518
+ ## 10. Extensibility
519
+
520
+ ### 10.1 Plugin System
521
+ Implement a plugin system for extensibility:
522
+
523
+ - **Issue**: Adding new document types or processing methods requires code changes.
524
+ - **Solution**: Implement a plugin system:
525
+ ```python
526
+ class OCRPlugin:
527
+ def __init__(self, name, description):
528
+ self.name = name
529
+ self.description = description
530
+
531
+ def can_handle(self, file_info):
532
+ """Return True if this plugin can handle the file"""
533
+ raise NotImplementedError
534
+
535
+ def process(self, file_info, options):
536
+ """Process the file and return results"""
537
+ raise NotImplementedError
538
+
539
+ # Example plugin
540
+ class HandwrittenDocumentPlugin(OCRPlugin):
541
+ def __init__(self):
542
+ super().__init__("handwritten", "Handwritten document processor")
543
+
544
+ def can_handle(self, file_info):
545
+ # Check if this is a handwritten document
546
+ return file_info.get("document_type") == "handwritten"
547
+
548
+ def process(self, file_info, options):
549
+ # Specialized processing for handwritten documents
550
+ # ...
551
+ ```
552
+
553
+ ### 10.2 API Abstraction
554
+ Create an abstraction layer for the OCR API:
555
+
556
+ - **Issue**: The application is tightly coupled to the Mistral AI API.
557
+ - **Solution**: Implement an abstraction layer:
558
+ ```python
559
+ class OCRProvider:
560
+ def process_image(self, image_path, options):
561
+ """Process an image and return OCR results"""
562
+ raise NotImplementedError
563
+
564
+ def process_pdf(self, pdf_path, options):
565
+ """Process a PDF and return OCR results"""
566
+ raise NotImplementedError
567
+
568
+ class MistralOCRProvider(OCRProvider):
569
+ def __init__(self, api_key=None):
570
+ self.client = MistralClient.get_instance(api_key)
571
+
572
+ def process_image(self, image_path, options):
573
+ # Implementation using Mistral API
574
+
575
+ def process_pdf(self, pdf_path, options):
576
+ # Implementation using Mistral API
577
+
578
+ # Factory function to get the appropriate provider
579
+ def get_ocr_provider(provider_name="mistral"):
580
+ if provider_name == "mistral":
581
+ return MistralOCRProvider()
582
+ # Add more providers as needed
583
+ raise ValueError(f"Unknown OCR provider: {provider_name}")
584
+ ```
585
+
586
+ ## Implementation Priority
587
+
memory-bank/activeContext.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Active Context
2
+
3
+ ## Current Work Focus
4
+
5
+ * Initializing the core Memory Bank files (`projectbrief.md`, `productContext.md`, `systemPatterns.md`, `techContext.md`, `activeContext.md`, `progress.md`) based on the existing project structure, defined `.clinerules`, and the global `memory-bank.md` specification.
6
+
7
+ ## Recent Changes
8
+
9
+ * This is the initial population of the Memory Bank. No prior changes within this system.
10
+
11
+ ## Next Steps
12
+
13
+ * Complete the creation of the initial Memory Bank files (specifically `progress.md`).
14
+ * Await further instructions from the user regarding the next development task for the `historical-ocr` project.
15
+
16
+ ## Active Decisions, Patterns, and Preferences
17
+
18
+ * **Memory Bank Structure:** Adopting the 6-core-file structure defined in the global `memory-bank.md`.
19
+ * **Content Derivation:** Populating initial Memory Bank content by analyzing the existing file structure and `.clinerules`.
20
+ * **Iterative Improvement Workflow:** Implementing a post-task review step after completing tasks in Act Mode. This involves:
21
+ 1. Completing the assigned task.
22
+ 2. Presenting the result using `attempt_completion`.
23
+ 3. Explicitly asking the user: "Are there any takeaways from this interaction that should be added to the project's `.clinerules`?"
24
+ 4. If takeaways are provided, update the relevant `.clinerules` file(s).
25
+ 5. Recursively update the Memory Bank (especially `activeContext.md` and `progress.md`) to reflect the new rule or pattern.
26
+
27
+ ## Learnings and Project Insights
28
+
29
+ * The project emphasizes clear documentation and rule definition from the start (`.clinerules`).
30
+ * Maintaining synchronization between `.clinerules` and the Memory Bank is crucial for consistent development.
31
+ * The iterative feedback loop (post-task review) is a key requirement for evolving project standards.
memory-bank/productContext.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Product Context
2
+
3
+ ## Why This Project Exists
4
+
5
+ Historical documents often contain invaluable information but are locked away in formats (scans, photos, complex PDFs) that are difficult to search, analyze, or integrate into digital research workflows. Standard OCR tools may struggle with the unique challenges presented by archival materials, such as varying print quality, handwriting, complex layouts, and archaic language.
6
+
7
+ ## Problems It Solves
8
+
9
+ This application aims to bridge the gap between physical historical archives and modern digital research by:
10
+
11
+ * Providing high-accuracy text extraction from challenging historical documents.
12
+ * Structuring the extracted text and metadata in a usable format.
13
+ * Making advanced OCR capabilities accessible to researchers without requiring deep technical expertise.
14
+ * Optimizing documents specifically for OCR to improve accuracy.
15
+
16
+ ## How It Should Work
17
+
18
+ The core workflow involves:
19
+
20
+ 1. **Upload:** Users upload historical documents (images or PDFs) via a web interface.
21
+ 2. **Preprocessing:** The application automatically applies image enhancement and optimization techniques tailored to historical materials.
22
+ 3. **OCR:** Processed documents are sent to the Mistral AI OCR API for text extraction. Document type detection may inform specific OCR prompting.
23
+ 4. **Structuring:** The raw OCR output is processed to extract structured information (e.g., paragraphs, headings, metadata) based on document type and potentially user instructions.
24
+ 5. **Output:** Users can view the extracted text and download structured transcripts and analysis.
25
+
26
+ ## User Experience Goals
27
+
28
+ * **Intuitive Interface:** A clean, straightforward Streamlit web application that is easy for researchers to use.
29
+ * **Clear Feedback:** Provide users with status updates during processing and clear presentation of results.
30
+ * **Flexibility:** Allow users some control over the process (e.g., contextual instructions) where appropriate.
31
+ * **Reliability:** Ensure consistent and accurate results.
memory-bank/progress.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Project Progress
2
+
3
+ ## Current Status
4
+
5
+ * **Overall:** Initial project setup phase. Core application structure exists, and foundational documentation (Memory Bank, `.clinerules`) is being established.
6
+ * **Memory Bank:** The six core Memory Bank files have just been created with initial content derived from the project structure and rules.
7
+
8
+ ## What Works
9
+
10
+ * The basic file and directory structure for a modular Python/Streamlit application is in place.
11
+ * Project rules (`.clinerules`) defining the brief, API usage, simplicity principle, and technical debt priorities exist.
12
+ * The Memory Bank system is now initialized.
13
+
14
+ ## What's Left to Build / Next Steps
15
+
16
+ * Implement the actual functionality described in the project brief (file upload, preprocessing, OCR integration, structuring, UI interactions).
17
+ * Address the technical debt items listed below.
18
+ * Refine and expand Memory Bank documentation as development progresses.
19
+ * Specific next development tasks are pending user direction.
20
+
21
+ ## Known Issues / Technical Debt
22
+
23
+ The following technical debt items have been identified in `.clinerules/technical-debt.md` and should be addressed during development:
24
+
25
+ 1. **Modularize large functions:** Break down functions exceeding 100 lines into smaller, focused units.
26
+ 2. **Consistent Error Handling:** Implement a uniform error handling strategy across all modules.
27
+ 3. **Preprocessing Pipeline Improvement:** Enhance the preprocessing steps to better handle diverse historical document types.
28
+ 4. **Image Segmentation Enhancement:** Improve the current approach for identifying text regions.
29
+ 5. **Documentation:** Create comprehensive documentation (docstrings, comments) for public functions and APIs.
30
+
31
+ ## Evolution of Project Decisions
32
+
33
+ * **[YYYY-MM-DD]:** Initialized Memory Bank structure based on global rules.
34
+ * **[YYYY-MM-DD]:** Adopted a post-task review workflow to iteratively update `.clinerules` and the Memory Bank.
.clinerules/projectBrief.md → memory-bank/project-brief.md RENAMED
@@ -1,21 +1,19 @@
1
- # Foundation
2
 
3
  Historical OCR is an advanced optical character recognition (OCR) application designed to support historical research. It leverages Mistral AI's OCR models alongside image preprocessing pipelines optimized for archival material.
4
 
5
- High-Level Overview
6
 
7
  Building a Streamlit-based web application to process historical documents (images or PDFs), optimize them for OCR using advanced preprocessing techniques, and extract structured text and metadata through Mistral's large language models.
8
 
9
- Core Requirements and Goals
10
 
11
- Upload and preprocess historical documents
12
 
13
- Automatically detect document types (e.g., handwritten letters, scientific papers)
14
 
15
- Apply tailored OCR prompting and structured output based on document type
16
 
17
- Support user-defined contextual instructions to refine output
18
 
19
- Provide downloadable structured transcripts and analysis
20
-
21
- Example: "Building a Streamlit web app for OCR transcription and structured extraction from historical documents using Mistral AI."
 
1
+ # Project Brief
2
 
3
  Historical OCR is an advanced optical character recognition (OCR) application designed to support historical research. It leverages Mistral AI's OCR models alongside image preprocessing pipelines optimized for archival material.
4
 
5
+ ## High-Level Overview
6
 
7
  Building a Streamlit-based web application to process historical documents (images or PDFs), optimize them for OCR using advanced preprocessing techniques, and extract structured text and metadata through Mistral's large language models.
8
 
9
+ ## Core Requirements and Goals
10
 
11
+ * Upload and preprocess historical documents
12
 
13
+ * Apply tailored OCR prompting and structured output based on document type
14
 
15
+ * Support user-defined contextual instructions to refine output
16
 
17
+ * Provide downloadable structured transcripts and analysis
18
 
19
+ * Example: "Building a Streamlit web app for OCR transcription and structured extraction from historical documents using Mistral AI."
 
 
.clinerules/project-brief.md → memory-bank/projectbrief.md RENAMED
File without changes
memory-bank/systemPatterns.md ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # System Patterns
2
+
3
+ ## Architecture Overview
4
+
5
+ The application follows a modular Python structure, orchestrated by a main Streamlit application script (`app.py`). Key architectural components include:
6
+
7
+ * **Entry Point:** `app.py` likely initializes the Streamlit application and coordinates calls to other modules.
8
+ * **UI Layer:** Managed by Streamlit. Core UI elements are defined in `ui/layout.py` and potentially reusable components in `ui/ui_components.py` (or the root `ui_components.py`). Custom styling is applied via `ui/custom.css`.
9
+ * **Processing Modules:** Functionality is separated into distinct Python modules:
10
+ * `preprocessing.py`: Handles image optimization and preparation for OCR.
11
+ * `image_segmentation.py`: Deals with identifying regions of interest within documents.
12
+ * `ocr_processing.py`: Manages the interaction with the OCR engine (Mistral API).
13
+ * `structured_ocr.py`: Focuses on interpreting raw OCR output and structuring it.
14
+ * `language_detection.py`: Detects the language of the document content.
15
+ * `letterhead_handler.py`: Specific logic for dealing with letterheads.
16
+ * `pdf_ocr.py`: Handles OCR specific to PDF inputs (likely coordinating other modules).
17
+ * `process_file.py`: A potential high-level orchestrator for the entire file processing pipeline.
18
+ * **Configuration:** `config.py` likely holds application settings, potentially including API keys or processing parameters. `constants.py` holds fixed values used across the application.
19
+ * **Utilities:** Common functions are grouped in the `utils/` directory, further categorized (e.g., `image_utils.py`, `text_utils.py`, `file_utils.py`).
20
+ * **Error Handling:** A dedicated `error_handler.py` suggests a centralized approach to managing exceptions.
21
+
22
+ ## Key Technical Decisions & Patterns
23
+
24
+ * **Modularity:** Code is organized into feature-specific modules, promoting separation of concerns.
25
+ * **External API Integration:** Relies on the Mistral AI OCR API for core text extraction (`.clinerules/hocr-basics-api.md`). API interaction logic is likely within `ocr_processing.py` or related utilities.
26
+ * **Streamlit Framework:** Leverages Streamlit for the web interface, using standard components (`.clinerules/hocr-basics-api.md`). State management likely uses `st.session_state`.
27
+ * **Content Purity:** Adheres to the principle of separating data from presentation markup (`.clinerules/principle-of-simplicity.md`). Presentation logic should reside primarily in the UI layer.
28
+ * **Configuration Management:** Centralized configuration likely managed through `config.py`.
29
+
30
+ ## Component Relationships (Conceptual)
31
+
32
+ ```mermaid
33
+ graph TD
34
+ A[User via Streamlit UI] --> B(app.py);
35
+ B --> C{process_file.py?};
36
+ C --> D[preprocessing.py];
37
+ C --> E[image_segmentation.py];
38
+ C --> F[language_detection.py];
39
+ C --> G[pdf_ocr.py / ocr_processing.py];
40
+ G -- Mistral API --> H((External Mistral OCR));
41
+ H -- OCR Result --> G;
42
+ G --> I[structured_ocr.py];
43
+ I --> J[Output Generation];
44
+ J --> A;
45
+
46
+ subgraph Modules
47
+ D; E; F; G; I; J;
48
+ end
49
+
50
+ subgraph Configuration & Utils
51
+ K[config.py];
52
+ L[constants.py];
53
+ M[utils/];
54
+ N[error_handler.py];
55
+ end
56
+
57
+ B --> K; B --> L; B --> M; B --> N;
58
+ Modules --> K; Modules --> L; Modules --> M; Modules --> N;
59
+ ```
60
+
61
+ ## Critical Implementation Paths
62
+
63
+ * The end-to-end flow from file upload (`st.file_uploader`) through preprocessing, OCR API call, structuring, and displaying results (`st.markdown`, `st.download_button`).
64
+ * Handling different input file types (Images vs. PDFs).
65
+ * Integration and error handling for the Mistral API calls.
66
+ * Implementation of specific preprocessing steps relevant to historical documents.
memory-bank/techContext.md ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Technical Context
2
+
3
+ ## Technologies Used
4
+
5
+ * **Primary Language:** Python 3.x
6
+ * **Web Framework:** Streamlit
7
+ * **Core API:** Mistral AI OCR API (via HTTPS requests)
8
+ * **Potential Libraries:**
9
+ * `requests`: For making HTTP calls to the Mistral API.
10
+ * `streamlit`: For the web UI framework.
11
+ * `Pillow` (PIL Fork): For basic image loading and manipulation.
12
+ * `OpenCV` (`cv2`): Likely used for more advanced image preprocessing tasks (e.g., thresholding, noise reduction, deskewing).
13
+ * `python-dotenv`: Potentially used for managing environment variables like API keys (especially if `config.py` loads from a `.env` file).
14
+ * `PyMuPDF` or similar: If PDF processing involves direct text/image extraction from PDF structures beyond just sending to OCR.
15
+
16
+ *(Note: Specific libraries beyond Streamlit and requests need confirmation, e.g., by inspecting `requirements.txt` or import statements in the code).*
17
+
18
+ ## Development Setup
19
+
20
+ * **Environment:** Standard Python environment (virtual environment recommended, e.g., `venv` or `conda`).
21
+ * **Dependencies:** Install required packages (likely via `pip install -r requirements.txt` if a requirements file exists).
22
+ * **API Keys:** Requires a Mistral AI API key, which needs to be configured securely (likely via environment variables loaded in `config.py`).
23
+ * **Running the App:** Typically run using `streamlit run app.py` from the project root directory.
24
+
25
+ ## Technical Constraints
26
+
27
+ * **API Limits:** Subject to Mistral AI API usage limits, rate limits, and potential costs. Error handling for API responses (e.g., 429 Too Many Requests, 401 Unauthorized, 5xx Server Errors) is crucial.
28
+ * **Processing Time:** OCR and complex image preprocessing can be time-consuming, especially for large documents or high-resolution images. Streamlit's execution model needs to be considered for long-running tasks (e.g., using background processes or providing user feedback).
29
+ * **Resource Usage:** Image processing can be memory and CPU intensive.
30
+
31
+ ## Tool Usage Patterns
32
+
33
+ * **Streamlit Components:** Primarily use core components as specified in `.clinerules/hocr-basics-api.md` (`st.file_uploader`, `st.selectbox`, `st.image`, `st.markdown`, `st.download_button`).
34
+ * **State Management:** Use `st.session_state` for managing user interactions and state across reruns.
35
+ * **API Interaction:** Follow standard practices for REST API calls (headers, JSON body, error checking) as defined in `.clinerules/hocr-basics-api.md`.
utils/README.md ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # OCR Utilities
2
+
3
+ This directory contains utility modules for the Historical OCR project.
4
+
5
+ ## PDF OCR Processing
6
+
7
+ The `pdf_ocr.py` module provides specialized functionality for processing PDF documents with OCR.
8
+
9
+ ### Features
10
+
11
+ - **Robust PDF-to-Image Conversion**: Converts PDF documents to images using optimized settings before OCR processing
12
+ - **Multi-Page Support**: Intelligently handles multi-page documents, allowing processing of specific pages or page ranges
13
+ - **Memory-Efficient Processing**: Processes PDFs in batches to prevent memory issues with large documents
14
+ - **Fallback Mechanism**: Falls back to structured_ocr's internal processing if direct conversion fails
15
+ - **Cleanup Management**: Automatically cleans up temporary files after processing
16
+
17
+ ### Key Components
18
+
19
+ - **PDFOCR**: Main class for processing PDF files with OCR
20
+ - **PDFConversionResult**: Helper class that holds PDF conversion results and manages cleanup
21
+
22
+ ### Basic Usage
23
+
24
+ ```python
25
+ from utils.pdf_ocr import PDFOCR
26
+
27
+ # Initialize the processor
28
+ processor = PDFOCR()
29
+
30
+ # Process a PDF file (all pages, with vision model)
31
+ result = processor.process_pdf('document.pdf')
32
+
33
+ # Process a PDF file (specific pages, with vision model)
34
+ result = processor.process_pdf('document.pdf', custom_pages=[1, 3, 5])
35
+
36
+ # Process a PDF file (first N pages, without vision model)
37
+ result = processor.process_pdf('document.pdf', max_pages=3, use_vision=False)
38
+
39
+ # Process a PDF file with custom prompt
40
+ result = processor.process_pdf(
41
+ 'document.pdf',
42
+ custom_prompt="This is a historical newspaper with multiple columns."
43
+ )
44
+
45
+ # Save results to JSON
46
+ output_path = processor.save_json_output('document.pdf', 'results.json')
47
+ ```
48
+
49
+ ### Command Line Usage
50
+
51
+ The module can also be used directly from the command line:
52
+
53
+ ```bash
54
+ python utils/pdf_ocr.py document.pdf --output results.json
55
+ python utils/pdf_ocr.py document.pdf --max-pages 3
56
+ python utils/pdf_ocr.py document.pdf --pages 1,3,5
57
+ python utils/pdf_ocr.py document.pdf --prompt "This is a historical newspaper with multiple columns."
58
+ python utils/pdf_ocr.py document.pdf --no-vision
59
+ ```
60
+
61
+ ### How It Works
62
+
63
+ 1. The module first attempts to convert the PDF to images using `pdf2image`
64
+ 2. It processes the first page with the vision model (if requested) for detailed analysis
65
+ 3. Additional pages are processed with the text model for efficiency
66
+ 4. All text is combined into a single result with appropriate metadata
67
+ 5. If direct conversion fails, it falls back to using `structured_ocr.py` for PDF processing
68
+
69
+ ### Parameters
70
+
71
+ - **pdf_path**: Path to the PDF file to process
72
+ - **use_vision**: Whether to use vision model for improved analysis (default: True)
73
+ - **max_pages**: Maximum number of pages to process (default: all pages)
74
+ - **custom_pages**: Specific page numbers to process, 1-based indexing (e.g., [1, 3, 5])
75
+ - **custom_prompt**: Custom instructions for OCR processing