milwright commited on
Commit
e65ba1a
·
1 Parent(s): 341cb11

Add robust dependency handling with fallbacks for missing packages

Browse files
Files changed (1) hide show
  1. structured_ocr.py +67 -10
structured_ocr.py CHANGED
@@ -6,14 +6,29 @@ from enum import Enum
6
  from pathlib import Path
7
  import json
8
  import base64
9
- import pycountry
10
  import logging
11
  from functools import lru_cache
12
  from typing import Optional, Dict, Any, List, Union, Tuple
 
 
 
 
 
 
 
 
 
13
  from pydantic import BaseModel
14
- from mistralai import Mistral
15
- from mistralai import DocumentURLChunk, ImageURLChunk, TextChunk
16
- from mistralai.models import OCRImageObject
 
 
 
 
 
 
 
17
 
18
  # Configure logging
19
  logging.basicConfig(level=logging.INFO,
@@ -41,7 +56,17 @@ except ImportError:
41
  return "\n\n".join(markdowns)
42
 
43
  # Import config directly (now local to historical-ocr)
44
- from config import MISTRAL_API_KEY, OCR_MODEL, TEXT_MODEL, VISION_MODEL, TEST_MODE
 
 
 
 
 
 
 
 
 
 
45
 
46
  # Helper function to make OCR objects JSON serializable
47
  # Removed caching to fix unhashable type error
@@ -89,7 +114,24 @@ def serialize_ocr_response(obj):
89
  # Create language enum for structured output - cache language lookup to avoid repeated processing
90
  @lru_cache(maxsize=1)
91
  def get_language_dict():
92
- return {lang.alpha_2: lang.name for lang in pycountry.languages if hasattr(lang, 'alpha_2')}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
  class LanguageMeta(Enum.__class__):
95
  def __new__(metacls, cls, bases, classdict):
@@ -99,7 +141,12 @@ class LanguageMeta(Enum.__class__):
99
  return super().__new__(metacls, cls, bases, classdict)
100
 
101
  class Language(Enum, metaclass=LanguageMeta):
102
- pass
 
 
 
 
 
103
 
104
  class StructuredOCRModel(BaseModel):
105
  file_name: str
@@ -110,8 +157,15 @@ class StructuredOCRModel(BaseModel):
110
  class StructuredOCR:
111
  def __init__(self, api_key=None):
112
  """Initialize the OCR processor with API key"""
113
- # Check if we're running in test mode
114
- self.test_mode = TEST_MODE
 
 
 
 
 
 
 
115
 
116
  # Initialize API key - use provided key, or environment var
117
  if self.test_mode and not api_key:
@@ -140,7 +194,10 @@ class StructuredOCR:
140
  if "unauthorized" in error_msg or "401" in error_msg:
141
  raise ValueError(f"API key authentication failed. Please check your Mistral API key: {str(e)}")
142
  else:
143
- raise
 
 
 
144
 
145
  def process_file(self, file_path, file_type=None, use_vision=True, max_pages=None, file_size_mb=None, custom_pages=None, custom_prompt=None):
146
  """Process a file and return structured OCR results
 
6
  from pathlib import Path
7
  import json
8
  import base64
 
9
  import logging
10
  from functools import lru_cache
11
  from typing import Optional, Dict, Any, List, Union, Tuple
12
+
13
+ # Try to import pycountry, provide fallback if not available
14
+ try:
15
+ import pycountry
16
+ PYCOUNTRY_AVAILABLE = True
17
+ except ImportError:
18
+ PYCOUNTRY_AVAILABLE = False
19
+ logging.warning("pycountry module not available - using language code fallback")
20
+
21
  from pydantic import BaseModel
22
+
23
+ # Try to import Mistral AI, provide fallback if not available
24
+ try:
25
+ from mistralai import Mistral
26
+ from mistralai import DocumentURLChunk, ImageURLChunk, TextChunk
27
+ from mistralai.models import OCRImageObject
28
+ MISTRAL_AVAILABLE = True
29
+ except ImportError:
30
+ MISTRAL_AVAILABLE = False
31
+ logging.warning("mistralai module not available - OCR functionality will be limited")
32
 
33
  # Configure logging
34
  logging.basicConfig(level=logging.INFO,
 
56
  return "\n\n".join(markdowns)
57
 
58
  # Import config directly (now local to historical-ocr)
59
+ try:
60
+ from config import MISTRAL_API_KEY, OCR_MODEL, TEXT_MODEL, VISION_MODEL, TEST_MODE
61
+ except ImportError:
62
+ # Fallback defaults if config is not available
63
+ import os
64
+ MISTRAL_API_KEY = os.environ.get("MISTRAL_API_KEY", "")
65
+ OCR_MODEL = "mistral-ocr-latest"
66
+ TEXT_MODEL = "mistral-large-latest"
67
+ VISION_MODEL = "mistral-large-latest"
68
+ TEST_MODE = True
69
+ logging.warning("Config module not found. Using environment variables and defaults.")
70
 
71
  # Helper function to make OCR objects JSON serializable
72
  # Removed caching to fix unhashable type error
 
114
  # Create language enum for structured output - cache language lookup to avoid repeated processing
115
  @lru_cache(maxsize=1)
116
  def get_language_dict():
117
+ if PYCOUNTRY_AVAILABLE:
118
+ return {lang.alpha_2: lang.name for lang in pycountry.languages if hasattr(lang, 'alpha_2')}
119
+ else:
120
+ # Fallback with basic languages when pycountry is not available
121
+ return {
122
+ "en": "English",
123
+ "es": "Spanish",
124
+ "fr": "French",
125
+ "de": "German",
126
+ "it": "Italian",
127
+ "pt": "Portuguese",
128
+ "ru": "Russian",
129
+ "zh": "Chinese",
130
+ "ja": "Japanese",
131
+ "ar": "Arabic",
132
+ "hi": "Hindi",
133
+ "la": "Latin"
134
+ }
135
 
136
  class LanguageMeta(Enum.__class__):
137
  def __new__(metacls, cls, bases, classdict):
 
141
  return super().__new__(metacls, cls, bases, classdict)
142
 
143
  class Language(Enum, metaclass=LanguageMeta):
144
+ # Fallback languages in case enum creation fails
145
+ ENGLISH = "English"
146
+ SPANISH = "Spanish"
147
+ FRENCH = "French"
148
+ GERMAN = "German"
149
+ LATIN = "Latin"
150
 
151
  class StructuredOCRModel(BaseModel):
152
  file_name: str
 
157
  class StructuredOCR:
158
  def __init__(self, api_key=None):
159
  """Initialize the OCR processor with API key"""
160
+ # Check if we're running in test mode or if Mistral is not available
161
+ self.test_mode = TEST_MODE or not MISTRAL_AVAILABLE
162
+
163
+ if not MISTRAL_AVAILABLE:
164
+ logger = logging.getLogger("api_validator")
165
+ logger.warning("Mistral AI package not available - running in test mode")
166
+ self.api_key = "placeholder_key"
167
+ self.client = None
168
+ return
169
 
170
  # Initialize API key - use provided key, or environment var
171
  if self.test_mode and not api_key:
 
194
  if "unauthorized" in error_msg or "401" in error_msg:
195
  raise ValueError(f"API key authentication failed. Please check your Mistral API key: {str(e)}")
196
  else:
197
+ logger = logging.getLogger("api_validator")
198
+ logger.warning(f"Failed to initialize Mistral client: {str(e)}")
199
+ self.test_mode = True
200
+ self.client = None
201
 
202
  def process_file(self, file_path, file_type=None, use_vision=True, max_pages=None, file_size_mb=None, custom_pages=None, custom_prompt=None):
203
  """Process a file and return structured OCR results