Update app.py
Browse files
app.py
CHANGED
|
@@ -13,28 +13,28 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(
|
|
| 13 |
logger = logging.getLogger(__name__)
|
| 14 |
|
| 15 |
# =========================
|
| 16 |
-
# Import PARSeq modules
|
| 17 |
# =========================
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
try:
|
| 19 |
-
# Try to import from installed parseq package
|
| 20 |
from strhub.models.parseq.model import PARSeq
|
| 21 |
from strhub.data.utils import Tokenizer
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
except ImportError as e:
|
| 36 |
-
logger.error(f"Failed to import PARSeq: {e}")
|
| 37 |
-
exit()
|
| 38 |
|
| 39 |
warnings.filterwarnings('ignore')
|
| 40 |
|
|
@@ -101,7 +101,7 @@ def load_model(model_path, lang_name):
|
|
| 101 |
checkpoint = torch.load(model_path, map_location='cpu', weights_only=False)
|
| 102 |
logger.info(f"Checkpoint loaded for {lang_name}")
|
| 103 |
|
| 104 |
-
# Get charset from checkpoint
|
| 105 |
if 'charset' not in checkpoint:
|
| 106 |
logger.error(f"No charset found in checkpoint for {lang_name}")
|
| 107 |
return None, None, None
|
|
@@ -112,13 +112,7 @@ def load_model(model_path, lang_name):
|
|
| 112 |
# Create tokenizer
|
| 113 |
tokenizer = Tokenizer(charset_str)
|
| 114 |
|
| 115 |
-
#
|
| 116 |
-
model = torch.hub.load('baudm/parseq', 'parseq', pretrained=True, trust_repo=True)
|
| 117 |
-
|
| 118 |
-
# Modify the tokenizer
|
| 119 |
-
model.tokenizer = tokenizer
|
| 120 |
-
|
| 121 |
-
# Now load your fine-tuned weights
|
| 122 |
if 'model_state_dict' in checkpoint:
|
| 123 |
state_dict = checkpoint['model_state_dict']
|
| 124 |
elif 'model' in checkpoint:
|
|
@@ -137,13 +131,33 @@ def load_model(model_path, lang_name):
|
|
| 137 |
k = k[10:]
|
| 138 |
new_state_dict[k] = v
|
| 139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
# Load weights
|
| 141 |
missing, unexpected = model.load_state_dict(new_state_dict, strict=False)
|
| 142 |
if missing:
|
| 143 |
-
logger.warning(f"Missing keys: {missing[:
|
| 144 |
if unexpected:
|
| 145 |
-
logger.warning(f"Unexpected keys: {unexpected[:
|
| 146 |
|
|
|
|
| 147 |
model = model.to(device)
|
| 148 |
model.eval()
|
| 149 |
|
|
@@ -298,7 +312,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Multilingual Scene Text Recognitio
|
|
| 298 |
margin: auto !important;
|
| 299 |
}
|
| 300 |
|
| 301 |
-
/* Make tab text clearly visible */
|
| 302 |
.tab-nav button {
|
| 303 |
font-size: 18px !important;
|
| 304 |
font-weight: bold !important;
|
|
@@ -321,7 +334,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Multilingual Scene Text Recognitio
|
|
| 321 |
transform: translateY(-2px);
|
| 322 |
}
|
| 323 |
|
| 324 |
-
/* Button styling */
|
| 325 |
button {
|
| 326 |
transition: all 0.3s ease !important;
|
| 327 |
font-weight: bold !important;
|
|
@@ -335,7 +347,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Multilingual Scene Text Recognitio
|
|
| 335 |
box-shadow: 0 5px 15px rgba(0,0,0,0.2) !important;
|
| 336 |
}
|
| 337 |
|
| 338 |
-
/* Gallery styling - prevent expansion */
|
| 339 |
.gr-gallery {
|
| 340 |
border: 2px solid #e0e0e0;
|
| 341 |
border-radius: 10px;
|
|
@@ -352,13 +363,11 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Multilingual Scene Text Recognitio
|
|
| 352 |
transform: scale(1.05) !important;
|
| 353 |
}
|
| 354 |
|
| 355 |
-
/* Box styling */
|
| 356 |
.gr-box {
|
| 357 |
border-radius: 10px;
|
| 358 |
border: 1px solid #e0e0e0;
|
| 359 |
}
|
| 360 |
|
| 361 |
-
/* Primary button styling */
|
| 362 |
.gr-button-primary {
|
| 363 |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
| 364 |
color: white !important;
|
|
@@ -366,7 +375,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Multilingual Scene Text Recognitio
|
|
| 366 |
}
|
| 367 |
""") as demo:
|
| 368 |
|
| 369 |
-
# Header
|
| 370 |
gr.Markdown("""
|
| 371 |
# π Multilingual Scene Text Recognition System
|
| 372 |
### Extract text from images in Telugu, Bengali, and Oriya languages
|
|
@@ -380,7 +388,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Multilingual Scene Text Recognitio
|
|
| 380 |
with gr.TabItem(f"π€ {lang}"):
|
| 381 |
create_language_tab(lang)
|
| 382 |
|
| 383 |
-
# Footer
|
| 384 |
gr.Markdown("""
|
| 385 |
---
|
| 386 |
### π‘ How to use:
|
|
@@ -388,24 +395,17 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Multilingual Scene Text Recognitio
|
|
| 388 |
2. **Click any sample thumbnail** - it will load into the main preview above
|
| 389 |
3. **Click "Extract Text"** button below the preview
|
| 390 |
4. **View results** on the right side
|
| 391 |
-
|
| 392 |
-
### π Note:
|
| 393 |
-
- Sample thumbnails stay as thumbnails - they don't expand when clicked
|
| 394 |
-
- Only the main preview area changes when you click a sample
|
| 395 |
-
- You can also upload your own images
|
| 396 |
""")
|
| 397 |
|
| 398 |
# =========================
|
| 399 |
# Run
|
| 400 |
# =========================
|
| 401 |
if __name__ == "__main__":
|
| 402 |
-
# Check directories
|
| 403 |
for lang, config in LANGUAGES.items():
|
| 404 |
if not os.path.exists(config["model_path"]):
|
| 405 |
logger.warning(f"β οΈ Model not found: {config['model_path']} for {lang}")
|
| 406 |
if not os.path.exists(config["samples_dir"]):
|
| 407 |
os.makedirs(config["samples_dir"], exist_ok=True)
|
| 408 |
-
logger.warning(f"π Created samples directory: {config['samples_dir']}")
|
| 409 |
|
| 410 |
demo.launch(
|
| 411 |
server_name="0.0.0.0",
|
|
|
|
| 13 |
logger = logging.getLogger(__name__)
|
| 14 |
|
| 15 |
# =========================
|
| 16 |
+
# Import PARSeq modules
|
| 17 |
# =========================
|
| 18 |
+
parseq_path = os.path.join(os.path.dirname(__file__), 'parseq')
|
| 19 |
+
if os.path.exists(parseq_path):
|
| 20 |
+
sys.path.insert(0, parseq_path)
|
| 21 |
+
|
| 22 |
try:
|
|
|
|
| 23 |
from strhub.models.parseq.model import PARSeq
|
| 24 |
from strhub.data.utils import Tokenizer
|
| 25 |
+
from strhub.models.utils import create_model
|
| 26 |
+
logger.info("Successfully imported PARSeq modules")
|
| 27 |
+
except ImportError as e:
|
| 28 |
+
logger.error(f"Failed to import PARSeq: {e}")
|
| 29 |
+
# Simple tokenizer fallback
|
| 30 |
+
class Tokenizer:
|
| 31 |
+
def __init__(self, charset):
|
| 32 |
+
self.charset = charset
|
| 33 |
+
self._itos = {i: ch for i, ch in enumerate(charset)}
|
| 34 |
+
self._stoi = {ch: i for i, ch in enumerate(charset)}
|
| 35 |
+
self.pad_id = 0
|
| 36 |
+
self.bos_id = 1
|
| 37 |
+
self.eos_id = 2
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
warnings.filterwarnings('ignore')
|
| 40 |
|
|
|
|
| 101 |
checkpoint = torch.load(model_path, map_location='cpu', weights_only=False)
|
| 102 |
logger.info(f"Checkpoint loaded for {lang_name}")
|
| 103 |
|
| 104 |
+
# Get charset from checkpoint
|
| 105 |
if 'charset' not in checkpoint:
|
| 106 |
logger.error(f"No charset found in checkpoint for {lang_name}")
|
| 107 |
return None, None, None
|
|
|
|
| 112 |
# Create tokenizer
|
| 113 |
tokenizer = Tokenizer(charset_str)
|
| 114 |
|
| 115 |
+
# Get model state dict
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
if 'model_state_dict' in checkpoint:
|
| 117 |
state_dict = checkpoint['model_state_dict']
|
| 118 |
elif 'model' in checkpoint:
|
|
|
|
| 131 |
k = k[10:]
|
| 132 |
new_state_dict[k] = v
|
| 133 |
|
| 134 |
+
# Get model parameters from state dict
|
| 135 |
+
img_size = new_state_dict.get('encoder.conv1.weight').shape[-1] if 'encoder.conv1.weight' in new_state_dict else 32
|
| 136 |
+
max_label_length = 100
|
| 137 |
+
|
| 138 |
+
# Create model instance using create_model with config
|
| 139 |
+
try:
|
| 140 |
+
# Try to create model with default config
|
| 141 |
+
model = create_model('parseq', pretrained=False)
|
| 142 |
+
logger.info("Model created with create_model")
|
| 143 |
+
except:
|
| 144 |
+
# Fallback: create PARSeq instance directly
|
| 145 |
+
from strhub.models.parseq.model import PARSeq
|
| 146 |
+
model = PARSeq(
|
| 147 |
+
charset_size=len(charset_str),
|
| 148 |
+
img_size=(32, 128),
|
| 149 |
+
max_label_length=max_label_length
|
| 150 |
+
)
|
| 151 |
+
logger.info("Model created with direct PARSeq initialization")
|
| 152 |
+
|
| 153 |
# Load weights
|
| 154 |
missing, unexpected = model.load_state_dict(new_state_dict, strict=False)
|
| 155 |
if missing:
|
| 156 |
+
logger.warning(f"Missing keys ({len(missing)}): {missing[:3]}...")
|
| 157 |
if unexpected:
|
| 158 |
+
logger.warning(f"Unexpected keys ({len(unexpected)}): {unexpected[:3]}...")
|
| 159 |
|
| 160 |
+
model.tokenizer = tokenizer
|
| 161 |
model = model.to(device)
|
| 162 |
model.eval()
|
| 163 |
|
|
|
|
| 312 |
margin: auto !important;
|
| 313 |
}
|
| 314 |
|
|
|
|
| 315 |
.tab-nav button {
|
| 316 |
font-size: 18px !important;
|
| 317 |
font-weight: bold !important;
|
|
|
|
| 334 |
transform: translateY(-2px);
|
| 335 |
}
|
| 336 |
|
|
|
|
| 337 |
button {
|
| 338 |
transition: all 0.3s ease !important;
|
| 339 |
font-weight: bold !important;
|
|
|
|
| 347 |
box-shadow: 0 5px 15px rgba(0,0,0,0.2) !important;
|
| 348 |
}
|
| 349 |
|
|
|
|
| 350 |
.gr-gallery {
|
| 351 |
border: 2px solid #e0e0e0;
|
| 352 |
border-radius: 10px;
|
|
|
|
| 363 |
transform: scale(1.05) !important;
|
| 364 |
}
|
| 365 |
|
|
|
|
| 366 |
.gr-box {
|
| 367 |
border-radius: 10px;
|
| 368 |
border: 1px solid #e0e0e0;
|
| 369 |
}
|
| 370 |
|
|
|
|
| 371 |
.gr-button-primary {
|
| 372 |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
| 373 |
color: white !important;
|
|
|
|
| 375 |
}
|
| 376 |
""") as demo:
|
| 377 |
|
|
|
|
| 378 |
gr.Markdown("""
|
| 379 |
# π Multilingual Scene Text Recognition System
|
| 380 |
### Extract text from images in Telugu, Bengali, and Oriya languages
|
|
|
|
| 388 |
with gr.TabItem(f"π€ {lang}"):
|
| 389 |
create_language_tab(lang)
|
| 390 |
|
|
|
|
| 391 |
gr.Markdown("""
|
| 392 |
---
|
| 393 |
### π‘ How to use:
|
|
|
|
| 395 |
2. **Click any sample thumbnail** - it will load into the main preview above
|
| 396 |
3. **Click "Extract Text"** button below the preview
|
| 397 |
4. **View results** on the right side
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
""")
|
| 399 |
|
| 400 |
# =========================
|
| 401 |
# Run
|
| 402 |
# =========================
|
| 403 |
if __name__ == "__main__":
|
|
|
|
| 404 |
for lang, config in LANGUAGES.items():
|
| 405 |
if not os.path.exists(config["model_path"]):
|
| 406 |
logger.warning(f"β οΈ Model not found: {config['model_path']} for {lang}")
|
| 407 |
if not os.path.exists(config["samples_dir"]):
|
| 408 |
os.makedirs(config["samples_dir"], exist_ok=True)
|
|
|
|
| 409 |
|
| 410 |
demo.launch(
|
| 411 |
server_name="0.0.0.0",
|