G-Madhuri commited on
Commit
b995d2a
Β·
verified Β·
1 Parent(s): a505446

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -72
app.py CHANGED
@@ -10,7 +10,7 @@ from PIL import Image
10
  import numpy as np
11
 
12
  # =========================
13
- # Auto-unzip parseq.zip if it exists
14
  # =========================
15
  if os.path.exists('parseq.zip'):
16
  print("Found parseq.zip, extracting...")
@@ -29,24 +29,29 @@ logger = logging.getLogger(__name__)
29
  # =========================
30
  # Setup PARSeq path
31
  # =========================
32
- current_dir = os.path.dirname(os.path.abspath(__file__))
33
- parseq_local_path = os.path.join(current_dir, 'parseq')
34
-
35
- if os.path.exists(parseq_local_path):
36
- sys.path.insert(0, parseq_local_path)
37
- logger.info(f"βœ… Using local parseq folder at {parseq_local_path}")
38
  else:
39
- logger.error(f"parseq folder not found at {parseq_local_path}")
40
- sys.exit(1)
 
41
 
42
- # Import from local parseq folder
43
  try:
44
  from strhub.data.utils import Tokenizer
45
- from strhub.models.parseq.model import PARSeq
46
- logger.info("βœ… Successfully imported Tokenizer and PARSeq from local folder")
47
  except ImportError as e:
48
- logger.error(f"Failed to import: {e}")
49
- raise
 
 
 
 
 
 
 
 
50
 
51
  warnings.filterwarnings('ignore')
52
 
@@ -80,6 +85,20 @@ transform = T.Compose([
80
  T.Normalize(mean=[0.5], std=[0.5])
81
  ])
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  # =========================
84
  # Model Cache
85
  # =========================
@@ -91,32 +110,34 @@ def load_model(model_path, lang_name):
91
  return model_cache[cache_key]
92
 
93
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
94
- logger.info(f"Loading {lang_name} model on {device}")
95
 
96
  if not os.path.exists(model_path):
97
  logger.error(f"Model not found: {model_path}")
98
  return None, None, None
99
 
100
  try:
101
- # Load checkpoint
102
  checkpoint = torch.load(model_path, map_location='cpu', weights_only=False)
103
- logger.info(f"Checkpoint loaded for {lang_name}")
104
 
105
  if 'charset' in checkpoint:
106
  charset_str = checkpoint['charset']
107
  elif lang_name == "Oriya":
108
  charset_str = ORIYA_CHARSET
109
  else:
110
- logger.warning(f"No charset found for {lang_name}")
111
  return None, None, None
112
 
113
- logger.info(f"Charset length for {lang_name}: {len(charset_str)}")
 
 
114
 
115
- # Create tokenizer
116
- tokenizer = Tokenizer(charset_str)
117
-
118
- # Get model state dict
119
- state_dict = checkpoint.get('model_state_dict', checkpoint.get('model', checkpoint))
 
 
120
 
121
  # Remove 'module.' prefix if present
122
  new_state_dict = {}
@@ -125,38 +146,13 @@ def load_model(model_path, lang_name):
125
  k = k.replace('module.', '')
126
  new_state_dict[k] = v
127
 
128
- # Create model
129
- model = PARSeq(
130
- num_tokens=len(charset_str),
131
- max_label_length=100,
132
- img_size=(32, 128),
133
- patch_size=(4, 8),
134
- embed_dim=384,
135
- enc_num_heads=6,
136
- enc_mlp_ratio=4,
137
- enc_depth=12,
138
- dec_num_heads=6,
139
- dec_mlp_ratio=4,
140
- dec_depth=4,
141
- decode_ar=True,
142
- refine_iters=1,
143
- dropout=0.1
144
- )
145
-
146
- # Load weights
147
- missing, unexpected = model.load_state_dict(new_state_dict, strict=False)
148
- if missing:
149
- logger.warning(f"Missing keys: {len(missing)}")
150
- if unexpected:
151
- logger.warning(f"Unexpected keys: {len(unexpected)}")
152
-
153
- model.tokenizer = tokenizer
154
  model = model.to(device)
155
  model.eval()
156
 
157
- model_cache[cache_key] = (model, device, tokenizer)
158
  logger.info(f"βœ… Loaded {lang_name} model successfully")
159
- return model, device, tokenizer
160
 
161
  except Exception as e:
162
  logger.error(f"Error loading {lang_name}: {e}")
@@ -165,33 +161,23 @@ def load_model(model_path, lang_name):
165
  return None, None, None
166
 
167
  # =========================
168
- # Inference - Use model's generate method
169
  # =========================
170
  def inference_image(model, image, device, tokenizer):
171
- if image is None:
172
- return "", 0.0
173
-
174
  if image.mode != 'RGB':
175
  image = image.convert('RGB')
176
 
177
  img_tensor = transform(image).unsqueeze(0).to(device)
178
 
179
  with torch.no_grad():
180
- # Use the model's generate method instead of forward
181
- # This handles the tokenization internally
182
- pred_str = model.generate(img_tensor, tokenizer)
183
-
184
- # Calculate confidence (approximate)
185
- try:
186
- # Get logits for confidence estimation
187
- logits = model(images=img_tensor, tokenizer=tokenizer)
188
- probs = torch.softmax(logits, dim=-1)
189
- max_probs = probs.max(dim=-1)[0][0]
190
- avg_conf = max_probs[:len(pred_str[0])].mean().item() if len(pred_str[0]) > 0 else 0
191
- except:
192
- avg_conf = 0.5 # Default confidence if can't calculate
193
-
194
- return pred_str[0] if isinstance(pred_str, list) else pred_str, avg_conf
195
 
196
  # =========================
197
  # Get samples for specific language
@@ -289,7 +275,7 @@ def create_language_tab(language):
289
 
290
  text, conf = inference_image(model, image, device, tokenizer)
291
 
292
- if text == "" or text is None:
293
  return "πŸ” No text detected in the image", ""
294
 
295
  return text, f"βœ… Confidence: {conf:.2%}"
 
10
  import numpy as np
11
 
12
  # =========================
13
+ # Auto-unzip parseq.zip if it exists (ONLY ADDITION)
14
  # =========================
15
  if os.path.exists('parseq.zip'):
16
  print("Found parseq.zip, extracting...")
 
29
  # =========================
30
  # Setup PARSeq path
31
  # =========================
32
+ parseq_path = os.path.join(os.path.dirname(__file__), 'parseq')
33
+ if os.path.exists(parseq_path):
34
+ sys.path.insert(0, parseq_path)
 
 
 
35
  else:
36
+ logger.error(f"PARSeq not found at {parseq_path}")
37
+ # Don't exit, try to continue
38
+ print(f"WARNING: PARSeq folder not found at {parseq_path}")
39
 
 
40
  try:
41
  from strhub.data.utils import Tokenizer
42
+ import torch.hub
43
+ print("βœ… Successfully imported Tokenizer")
44
  except ImportError as e:
45
+ print(f"Import error: {e}")
46
+ # Create a simple tokenizer as fallback
47
+ class Tokenizer:
48
+ def __init__(self, chars):
49
+ self.charset = chars
50
+ self._itos = {i: ch for i, ch in enumerate(chars)}
51
+ self._stoi = {ch: i for i, ch in enumerate(chars)}
52
+ self.pad_id = 0
53
+ self.bos_id = 1
54
+ self.eos_id = 2
55
 
56
  warnings.filterwarnings('ignore')
57
 
 
85
  T.Normalize(mean=[0.5], std=[0.5])
86
  ])
87
 
88
+ # =========================
89
+ # Decode
90
+ # =========================
91
+ def decode_prediction(logits, tokenizer):
92
+ pred_ids = logits.argmax(-1)[0]
93
+ chars = []
94
+ for t in pred_ids:
95
+ t = t.item()
96
+ if t == tokenizer.eos_id:
97
+ break
98
+ if t not in [tokenizer.pad_id, tokenizer.bos_id] and t < len(tokenizer._itos):
99
+ chars.append(tokenizer._itos[t])
100
+ return "".join(chars)
101
+
102
  # =========================
103
  # Model Cache
104
  # =========================
 
110
  return model_cache[cache_key]
111
 
112
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
113
 
114
  if not os.path.exists(model_path):
115
  logger.error(f"Model not found: {model_path}")
116
  return None, None, None
117
 
118
  try:
119
+ # Load checkpoint with weights_only=False for compatibility
120
  checkpoint = torch.load(model_path, map_location='cpu', weights_only=False)
 
121
 
122
  if 'charset' in checkpoint:
123
  charset_str = checkpoint['charset']
124
  elif lang_name == "Oriya":
125
  charset_str = ORIYA_CHARSET
126
  else:
127
+ logger.warning(f"No charset found for {lang_name}, using default")
128
  return None, None, None
129
 
130
+ # Load model from torch hub (THIS IS THE KEY - works locally)
131
+ model = torch.hub.load('baudm/parseq', 'parseq', pretrained=False, trust_repo=True)
132
+ model.tokenizer = Tokenizer(charset_str)
133
 
134
+ # Handle different checkpoint formats
135
+ if 'model_state_dict' in checkpoint:
136
+ state_dict = checkpoint['model_state_dict']
137
+ elif 'model' in checkpoint:
138
+ state_dict = checkpoint['model']
139
+ else:
140
+ state_dict = checkpoint
141
 
142
  # Remove 'module.' prefix if present
143
  new_state_dict = {}
 
146
  k = k.replace('module.', '')
147
  new_state_dict[k] = v
148
 
149
+ model.load_state_dict(new_state_dict, strict=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  model = model.to(device)
151
  model.eval()
152
 
153
+ model_cache[cache_key] = (model, device, model.tokenizer)
154
  logger.info(f"βœ… Loaded {lang_name} model successfully")
155
+ return model, device, model.tokenizer
156
 
157
  except Exception as e:
158
  logger.error(f"Error loading {lang_name}: {e}")
 
161
  return None, None, None
162
 
163
  # =========================
164
+ # Inference
165
  # =========================
166
  def inference_image(model, image, device, tokenizer):
 
 
 
167
  if image.mode != 'RGB':
168
  image = image.convert('RGB')
169
 
170
  img_tensor = transform(image).unsqueeze(0).to(device)
171
 
172
  with torch.no_grad():
173
+ logits = model(img_tensor)
174
+ predicted_text = decode_prediction(logits, tokenizer)
175
+
176
+ probs = torch.softmax(logits, dim=-1)
177
+ max_probs = probs.max(dim=-1)[0][0]
178
+ avg_conf = max_probs[:len(predicted_text)].mean().item() if len(predicted_text) > 0 else 0
179
+
180
+ return predicted_text, avg_conf
 
 
 
 
 
 
 
181
 
182
  # =========================
183
  # Get samples for specific language
 
275
 
276
  text, conf = inference_image(model, image, device, tokenizer)
277
 
278
+ if text == "":
279
  return "πŸ” No text detected in the image", ""
280
 
281
  return text, f"βœ… Confidence: {conf:.2%}"