Spaces:
Running
on
Zero
Running
on
Zero
Upload 2 files
Browse files- game_engine.py +43 -9
- image_processing_gpu.py +136 -33
game_engine.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
# ==========================================
|
2 |
-
# game_engine.py - Avec métriques OCR et dataset optimisé
|
3 |
# ==========================================
|
4 |
|
5 |
"""
|
6 |
-
Moteur de jeu avec tracking complet des performances OCR
|
7 |
"""
|
8 |
|
9 |
import random
|
@@ -22,10 +22,13 @@ from image_processing_gpu import (
|
|
22 |
create_thumbnail_fast,
|
23 |
create_white_canvas,
|
24 |
cleanup_memory,
|
25 |
-
get_ocr_model_info
|
|
|
|
|
|
|
26 |
)
|
27 |
|
28 |
-
print("✅ Game Engine: Mode GPU avec métriques OCR")
|
29 |
|
30 |
# Imports dataset
|
31 |
try:
|
@@ -47,6 +50,37 @@ DIFFICULTY_RANGES = {
|
|
47 |
"÷": {"Facile": (1, 10), "Difficile": (2, 12)}
|
48 |
}
|
49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
def create_result_row_with_metrics(i: int, image: dict | np.ndarray | Image.Image, expected: int, operation_data: tuple[int, int, str, int]) -> dict:
|
51 |
"""Traite une image avec OCR et mesure les métriques"""
|
52 |
|
@@ -104,7 +138,7 @@ def create_result_row_with_metrics(i: int, image: dict | np.ndarray | Image.Imag
|
|
104 |
|
105 |
|
106 |
class MathGame:
|
107 |
-
"""Moteur de jeu avec métriques OCR complètes"""
|
108 |
|
109 |
def __init__(self):
|
110 |
self.is_running = False
|
@@ -345,14 +379,14 @@ class MathGame:
|
|
345 |
|
346 |
print(f"🔄 Traitement OCR avec métriques de {total_questions} images...")
|
347 |
|
348 |
-
# Récupérer infos modèle OCR une seule fois
|
349 |
try:
|
350 |
ocr_model_info = get_ocr_model_info()
|
351 |
-
model_name = ocr_model_info.get("model_name", "
|
352 |
hardware = f"{ocr_model_info.get('device', 'Unknown')}-{ocr_model_info.get('gpu_name', 'Unknown')}"
|
353 |
except Exception as e:
|
354 |
print(f"❌ Erreur get_ocr_model_info: {e}")
|
355 |
-
model_name = "
|
356 |
hardware = "ZeroGPU-Unknown"
|
357 |
|
358 |
# Boucle OCR avec métriques
|
@@ -407,7 +441,7 @@ class MathGame:
|
|
407 |
"session_total_questions": total_questions,
|
408 |
|
409 |
# Métadonnées techniques
|
410 |
-
"app_version": "3.
|
411 |
"hardware": hardware
|
412 |
}
|
413 |
|
|
|
1 |
# ==========================================
|
2 |
+
# game_engine.py - Avec métriques OCR et dataset optimisé + modèles commutables
|
3 |
# ==========================================
|
4 |
|
5 |
"""
|
6 |
+
Moteur de jeu avec tracking complet des performances OCR et support modèles commutables
|
7 |
"""
|
8 |
|
9 |
import random
|
|
|
22 |
create_thumbnail_fast,
|
23 |
create_white_canvas,
|
24 |
cleanup_memory,
|
25 |
+
get_ocr_model_info,
|
26 |
+
get_available_models,
|
27 |
+
set_ocr_model,
|
28 |
+
get_current_model_info
|
29 |
)
|
30 |
|
31 |
+
print("✅ Game Engine: Mode GPU avec métriques OCR et modèles commutables")
|
32 |
|
33 |
# Imports dataset
|
34 |
try:
|
|
|
50 |
"÷": {"Facile": (1, 10), "Difficile": (2, 12)}
|
51 |
}
|
52 |
|
53 |
+
def get_ocr_models_info() -> dict:
|
54 |
+
"""Retourne les informations sur les modèles OCR disponibles"""
|
55 |
+
try:
|
56 |
+
available_models = get_available_models()
|
57 |
+
current_model = get_current_model_info()
|
58 |
+
|
59 |
+
return {
|
60 |
+
"available_models": available_models,
|
61 |
+
"current_model": current_model,
|
62 |
+
"model_names": list(available_models.keys())
|
63 |
+
}
|
64 |
+
except Exception as e:
|
65 |
+
print(f"❌ Erreur get_ocr_models_info: {e}")
|
66 |
+
return {
|
67 |
+
"available_models": {},
|
68 |
+
"current_model": {"model_name": "hoololi/trocr-base-handwritten-calctrainer"},
|
69 |
+
"model_names": []
|
70 |
+
}
|
71 |
+
|
72 |
+
def switch_ocr_model(model_name: str) -> str:
|
73 |
+
"""Change le modèle OCR et retourne un message de statut"""
|
74 |
+
try:
|
75 |
+
success = set_ocr_model(model_name)
|
76 |
+
if success:
|
77 |
+
model_info = get_current_model_info()
|
78 |
+
return f"✅ Modèle changé vers: {model_info['display_name']}\n📍 {model_info['description']}"
|
79 |
+
else:
|
80 |
+
return f"❌ Échec du changement vers: {model_name}"
|
81 |
+
except Exception as e:
|
82 |
+
return f"❌ Erreur lors du changement: {str(e)}"
|
83 |
+
|
84 |
def create_result_row_with_metrics(i: int, image: dict | np.ndarray | Image.Image, expected: int, operation_data: tuple[int, int, str, int]) -> dict:
|
85 |
"""Traite une image avec OCR et mesure les métriques"""
|
86 |
|
|
|
138 |
|
139 |
|
140 |
class MathGame:
|
141 |
+
"""Moteur de jeu avec métriques OCR complètes et modèles commutables"""
|
142 |
|
143 |
def __init__(self):
|
144 |
self.is_running = False
|
|
|
379 |
|
380 |
print(f"🔄 Traitement OCR avec métriques de {total_questions} images...")
|
381 |
|
382 |
+
# Récupérer infos modèle OCR une seule fois - MODIFIÉ pour utiliser le nouveau système
|
383 |
try:
|
384 |
ocr_model_info = get_ocr_model_info()
|
385 |
+
model_name = ocr_model_info.get("model_name", "hoololi/trocr-base-handwritten-calctrainer")
|
386 |
hardware = f"{ocr_model_info.get('device', 'Unknown')}-{ocr_model_info.get('gpu_name', 'Unknown')}"
|
387 |
except Exception as e:
|
388 |
print(f"❌ Erreur get_ocr_model_info: {e}")
|
389 |
+
model_name = "hoololi/trocr-base-handwritten-calctrainer"
|
390 |
hardware = "ZeroGPU-Unknown"
|
391 |
|
392 |
# Boucle OCR avec métriques
|
|
|
441 |
"session_total_questions": total_questions,
|
442 |
|
443 |
# Métadonnées techniques
|
444 |
+
"app_version": "3.2_with_switchable_models",
|
445 |
"hardware": hardware
|
446 |
}
|
447 |
|
image_processing_gpu.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
# ==========================================
|
2 |
-
# image_processing_gpu.py - Version ZeroGPU
|
3 |
# ==========================================
|
4 |
|
5 |
"""
|
@@ -21,23 +21,137 @@ from utils import (
|
|
21 |
validate_ocr_result
|
22 |
)
|
23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
# Variables globales pour OCR
|
25 |
processor = None
|
26 |
model = None
|
27 |
-
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
-
def
|
31 |
-
"""
|
32 |
-
global processor, model
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
try:
|
35 |
-
print("🔄 Chargement
|
|
|
36 |
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
model = VisionEncoderDecoderModel.from_pretrained('hoololi/trocr-base-handwritten-calctrainer')
|
41 |
|
42 |
# Optimisations
|
43 |
model.eval()
|
@@ -45,39 +159,26 @@ def init_ocr_model() -> bool:
|
|
45 |
if torch.cuda.is_available():
|
46 |
model = model.cuda()
|
47 |
device_info = f"GPU ({torch.cuda.get_device_name()})"
|
48 |
-
print(f"✅
|
49 |
else:
|
50 |
device_info = "CPU (ZeroGPU pas encore alloué)"
|
51 |
-
print(f"⚠️
|
52 |
|
53 |
return True
|
54 |
|
55 |
except Exception as e:
|
56 |
-
print(f"❌ Erreur lors du chargement
|
57 |
return False
|
58 |
|
|
|
59 |
def get_ocr_model_info() -> dict:
|
60 |
-
"""
|
61 |
-
|
62 |
-
device = "ZeroGPU"
|
63 |
-
gpu_name = torch.cuda.get_device_name()
|
64 |
-
else:
|
65 |
-
device = "CPU"
|
66 |
-
gpu_name = "N/A"
|
67 |
-
|
68 |
-
return {
|
69 |
-
"model_name": OCR_MODEL_NAME,
|
70 |
-
"device": device,
|
71 |
-
"gpu_name": gpu_name,
|
72 |
-
"framework": "HuggingFace-Transformers-ZeroGPU",
|
73 |
-
"optimized_for": "accuracy",
|
74 |
-
"version": "microsoft/trocr-base-handwritten"
|
75 |
-
}
|
76 |
|
77 |
@spaces.GPU
|
78 |
def recognize_number_fast_with_image(image_dict, debug: bool = False) -> tuple[str, any, dict | None]:
|
79 |
"""
|
80 |
-
OCR avec TrOCR ZeroGPU - Version simplifiée
|
81 |
"""
|
82 |
if image_dict is None:
|
83 |
if debug:
|
@@ -87,7 +188,8 @@ def recognize_number_fast_with_image(image_dict, debug: bool = False) -> tuple[s
|
|
87 |
try:
|
88 |
start_time = time.time()
|
89 |
if debug:
|
90 |
-
|
|
|
91 |
|
92 |
# Optimiser image
|
93 |
optimized_image = optimize_image_for_ocr(image_dict, max_size=384)
|
@@ -133,7 +235,8 @@ def recognize_number_fast_with_image(image_dict, debug: bool = False) -> tuple[s
|
|
133 |
if debug:
|
134 |
total_time = time.time() - start_time
|
135 |
device = "ZeroGPU" if torch.cuda.is_available() else "CPU"
|
136 |
-
|
|
|
137 |
if dataset_image_data:
|
138 |
print(f" 🖼️ Image dataset: {type(dataset_image_data.get('handwriting_image', 'None'))}")
|
139 |
|
|
|
1 |
# ==========================================
|
2 |
+
# image_processing_gpu.py - Version ZeroGPU avec modèles OCR commutables
|
3 |
# ==========================================
|
4 |
|
5 |
"""
|
|
|
21 |
validate_ocr_result
|
22 |
)
|
23 |
|
24 |
+
# ==========================================
|
25 |
+
# Configuration des modèles OCR disponibles
|
26 |
+
# ==========================================
|
27 |
+
|
28 |
+
AVAILABLE_OCR_MODELS = {
|
29 |
+
"microsoft/trocr-base-handwritten": {
|
30 |
+
"description": "Modèle de base Microsoft pour écriture manuscrite",
|
31 |
+
"display_name": "TrOCR Base Handwritten (Microsoft)",
|
32 |
+
"optimized_for": "general_handwriting"
|
33 |
+
},
|
34 |
+
"hoololi/trocr-base-handwritten-calctrainer": {
|
35 |
+
"description": "Modèle fine tuné pour les nombres entiers",
|
36 |
+
"display_name": "TrOCR CalcTrainer (Hoololi)",
|
37 |
+
"optimized_for": "mathematical_numbers"
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
# Modèle par défaut
|
42 |
+
DEFAULT_OCR_MODEL = "hoololi/trocr-base-handwritten-calctrainer"
|
43 |
+
current_ocr_model_name = DEFAULT_OCR_MODEL
|
44 |
+
|
45 |
# Variables globales pour OCR
|
46 |
processor = None
|
47 |
model = None
|
48 |
+
current_loaded_model = None
|
49 |
+
|
50 |
+
def get_available_models() -> dict:
|
51 |
+
"""Retourne la liste des modèles OCR disponibles"""
|
52 |
+
return AVAILABLE_OCR_MODELS
|
53 |
+
|
54 |
+
def get_current_model_info() -> dict:
|
55 |
+
"""Retourne les informations du modèle OCR actuellement chargé"""
|
56 |
+
global current_ocr_model_name, current_loaded_model
|
57 |
+
|
58 |
+
model_config = AVAILABLE_OCR_MODELS.get(current_ocr_model_name, AVAILABLE_OCR_MODELS[DEFAULT_OCR_MODEL])
|
59 |
+
|
60 |
+
if torch.cuda.is_available():
|
61 |
+
device = "ZeroGPU"
|
62 |
+
gpu_name = torch.cuda.get_device_name()
|
63 |
+
else:
|
64 |
+
device = "CPU"
|
65 |
+
gpu_name = "N/A"
|
66 |
+
|
67 |
+
return {
|
68 |
+
"model_name": current_ocr_model_name,
|
69 |
+
"display_name": model_config["display_name"],
|
70 |
+
"description": model_config["description"],
|
71 |
+
"current_loaded": current_loaded_model,
|
72 |
+
"device": device,
|
73 |
+
"gpu_name": gpu_name,
|
74 |
+
"framework": "HuggingFace-Transformers-ZeroGPU",
|
75 |
+
"optimized_for": model_config["optimized_for"],
|
76 |
+
"is_loaded": processor is not None and model is not None,
|
77 |
+
# Compatibilité avec l'ancien code
|
78 |
+
"version": current_ocr_model_name
|
79 |
+
}
|
80 |
+
|
81 |
+
def set_ocr_model(model_name: str) -> bool:
|
82 |
+
"""
|
83 |
+
Change le modèle OCR actif
|
84 |
+
|
85 |
+
Args:
|
86 |
+
model_name: Nom exact du modèle (ex: "microsoft/trocr-base-handwritten")
|
87 |
+
|
88 |
+
Returns:
|
89 |
+
bool: True si le changement a réussi
|
90 |
+
"""
|
91 |
+
global current_ocr_model_name
|
92 |
+
|
93 |
+
if model_name not in AVAILABLE_OCR_MODELS:
|
94 |
+
print(f"❌ Modèle '{model_name}' non disponible. Modèles disponibles: {list(AVAILABLE_OCR_MODELS.keys())}")
|
95 |
+
return False
|
96 |
+
|
97 |
+
if model_name == current_ocr_model_name and processor is not None and model is not None:
|
98 |
+
print(f"✅ Modèle '{model_name}' déjà chargé")
|
99 |
+
return True
|
100 |
+
|
101 |
+
model_config = AVAILABLE_OCR_MODELS[model_name]
|
102 |
+
print(f"🔄 Changement vers le modèle: {model_config['display_name']}")
|
103 |
+
current_ocr_model_name = model_name
|
104 |
+
|
105 |
+
# Nettoyer le modèle précédent
|
106 |
+
cleanup_current_model()
|
107 |
+
|
108 |
+
# Charger le nouveau modèle
|
109 |
+
return init_ocr_model()
|
110 |
|
111 |
+
def cleanup_current_model():
|
112 |
+
"""Nettoie le modèle actuellement chargé pour libérer la mémoire"""
|
113 |
+
global processor, model, current_loaded_model
|
114 |
+
|
115 |
+
if model is not None:
|
116 |
+
del model
|
117 |
+
model = None
|
118 |
+
|
119 |
+
if processor is not None:
|
120 |
+
del processor
|
121 |
+
processor = None
|
122 |
+
|
123 |
+
current_loaded_model = None
|
124 |
+
|
125 |
+
# Nettoyage mémoire GPU si disponible
|
126 |
+
if torch.cuda.is_available():
|
127 |
+
torch.cuda.empty_cache()
|
128 |
+
|
129 |
+
print("🧹 Modèle précédent nettoyé")
|
130 |
+
|
131 |
+
def init_ocr_model(model_name: str = None) -> bool:
|
132 |
+
"""
|
133 |
+
Initialise TrOCR pour ZeroGPU avec le modèle spécifié
|
134 |
+
|
135 |
+
Args:
|
136 |
+
model_name: Nom exact du modèle à charger (optionnel, utilise current_ocr_model_name par défaut)
|
137 |
+
"""
|
138 |
+
global processor, model, current_ocr_model_name, current_loaded_model
|
139 |
+
|
140 |
+
if model_name is not None:
|
141 |
+
if model_name not in AVAILABLE_OCR_MODELS:
|
142 |
+
print(f"❌ Modèle '{model_name}' non disponible")
|
143 |
+
return False
|
144 |
+
current_ocr_model_name = model_name
|
145 |
+
|
146 |
+
model_config = AVAILABLE_OCR_MODELS[current_ocr_model_name]
|
147 |
|
148 |
try:
|
149 |
+
print(f"🔄 Chargement {model_config['display_name']} (ZeroGPU)...")
|
150 |
+
print(f" 📍 Modèle: {current_ocr_model_name}")
|
151 |
|
152 |
+
processor = TrOCRProcessor.from_pretrained(current_ocr_model_name)
|
153 |
+
model = VisionEncoderDecoderModel.from_pretrained(current_ocr_model_name)
|
154 |
+
current_loaded_model = current_ocr_model_name
|
|
|
155 |
|
156 |
# Optimisations
|
157 |
model.eval()
|
|
|
159 |
if torch.cuda.is_available():
|
160 |
model = model.cuda()
|
161 |
device_info = f"GPU ({torch.cuda.get_device_name()})"
|
162 |
+
print(f"✅ {model_config['display_name']} prêt sur {device_info} !")
|
163 |
else:
|
164 |
device_info = "CPU (ZeroGPU pas encore alloué)"
|
165 |
+
print(f"⚠️ {model_config['display_name']} sur CPU - {device_info}")
|
166 |
|
167 |
return True
|
168 |
|
169 |
except Exception as e:
|
170 |
+
print(f"❌ Erreur lors du chargement {model_config['display_name']}: {e}")
|
171 |
return False
|
172 |
|
173 |
+
# Alias pour compatibilité avec l'ancien code
|
174 |
def get_ocr_model_info() -> dict:
|
175 |
+
"""Alias pour get_current_model_info() - compatibilité"""
|
176 |
+
return get_current_model_info()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
|
178 |
@spaces.GPU
|
179 |
def recognize_number_fast_with_image(image_dict, debug: bool = False) -> tuple[str, any, dict | None]:
|
180 |
"""
|
181 |
+
OCR avec TrOCR ZeroGPU - Version simplifiée avec modèle commutable
|
182 |
"""
|
183 |
if image_dict is None:
|
184 |
if debug:
|
|
|
188 |
try:
|
189 |
start_time = time.time()
|
190 |
if debug:
|
191 |
+
model_info = get_current_model_info()
|
192 |
+
print(f" 🔄 Début OCR {model_info['display_name']} ZeroGPU...")
|
193 |
|
194 |
# Optimiser image
|
195 |
optimized_image = optimize_image_for_ocr(image_dict, max_size=384)
|
|
|
235 |
if debug:
|
236 |
total_time = time.time() - start_time
|
237 |
device = "ZeroGPU" if torch.cuda.is_available() else "CPU"
|
238 |
+
model_name = get_current_model_info()['display_name']
|
239 |
+
print(f" ✅ {model_name} ({device}) terminé en {total_time:.1f}s → '{final_result}'")
|
240 |
if dataset_image_data:
|
241 |
print(f" 🖼️ Image dataset: {type(dataset_image_data.get('handwriting_image', 'None'))}")
|
242 |
|