JoshuaCarrera commited on
Commit
7947e09
·
1 Parent(s): c221f76

Guardar logs en el s3

Browse files
Files changed (1) hide show
  1. src/app/app.py +57 -32
src/app/app.py CHANGED
@@ -3,7 +3,8 @@ import os
3
  import boto3
4
  import gc
5
  import sys
6
- import hashlib # DEBUG: Importamos hashlib para calcular los MD5
 
7
  from PIL import Image
8
  from botocore.config import Config
9
  from ultralytics import YOLO
@@ -33,19 +34,19 @@ model_configs = {
33
  }
34
  }
35
 
36
- # DEBUG: Función auxiliar para calcular el MD5 de un archivo en disco
37
- def calculate_file_md5(filepath): # DEBUG
38
- hash_md5 = hashlib.md5() # DEBUG
39
- with open(filepath, "rb") as f: # DEBUG
40
- for chunk in iter(lambda: f.read(4096), b""): # DEBUG
41
- hash_md5.update(chunk) # DEBUG
42
- return hash_md5.hexdigest() # DEBUG
43
-
44
  # ==========================================
45
- # 2. DESCARGA CONSTRUCTORA Y DESTRUCTIVA (Ahorro de RAM)
46
  # ==========================================
47
- def download_models_from_r2():
48
- s3_client = boto3.client(
 
 
 
 
 
 
 
 
49
  service_name="s3",
50
  endpoint_url=R2_ENDPOINT_URL,
51
  aws_access_key_id=R2_ACCESS_KEY,
@@ -53,6 +54,12 @@ def download_models_from_r2():
53
  config=Config(signature_version="s3v4")
54
  )
55
 
 
 
 
 
 
 
56
  for name, config in model_configs.items():
57
  os.makedirs(os.path.dirname(config["path"]), exist_ok=True)
58
 
@@ -71,18 +78,16 @@ def download_models_from_r2():
71
  else:
72
  print(f"El modelo {name} ya existe localmente. Cargando...")
73
 
74
- # DEBUG: Calculamos e imprimimos el MD5 del modelo local para verificar integridad
75
- local_md5 = calculate_file_md5(config["path"]) # DEBUG
76
- print(f"[DEBUG] MD5 del modelo {name} en disco: {local_md5}") # DEBUG
77
 
78
  del s3_client
79
  gc.collect()
80
 
81
- # Ejecutamos la descarga antes de cargar YOLO
82
  download_models_from_r2()
83
 
84
  # ==========================================
85
- # 3. CARGA DE MODELOS
86
  # ==========================================
87
  models = {
88
  "USD": YOLO(model_configs["USD"]["path"]),
@@ -90,12 +95,6 @@ models = {
90
  "INFERENCIA": YOLO(model_configs["INFERENCIA"]["path"]),
91
  }
92
 
93
- versions = {
94
- "USD": "plus_01",
95
- "VEF": "13f",
96
- "INFERENCIA": "1",
97
- }
98
-
99
  classes = {
100
  "USD": [
101
  "fifty-back", "fifty-front",
@@ -133,21 +132,18 @@ app.add_middleware(
133
  def detection_vef(image: UploadFile):
134
  print("FOTO RECIBIDA")
135
 
136
- # Flujo exacto de lectura
137
  imageBytes = image.file.read()
138
 
139
- # DEBUG: Calcular MD5 de la foto exacta recibida por la red (bytes puros)
140
- raw_md5 = hashlib.md5(imageBytes).hexdigest() # DEBUG
141
- print(f"[DEBUG] MD5 de la foto cruda recibida: {raw_md5}") # DEBUG
142
 
143
  imageStream = io.BytesIO(imageBytes)
144
  imageFile = Image.open(imageStream).convert("RGB")
145
 
146
- # DEBUG: Calcular MD5 de la foto después de ser procesada por Pillow
147
- debug_buffer = io.BytesIO() # DEBUG
148
- imageFile.save(debug_buffer, format="JPEG") # DEBUG
149
- pillow_md5 = hashlib.md5(debug_buffer.getvalue()).hexdigest() # DEBUG
150
- print(f"[DEBUG] MD5 de la foto tras procesar con Pillow (RGB): {pillow_md5}") # DEBUG
151
 
152
  which_currency = models["INFERENCIA"].predict(imageFile, verbose=False, imgsz=640, conf=0.25)
153
 
@@ -164,6 +160,35 @@ def detection_vef(image: UploadFile):
164
  results = models[currency].predict(imageFile, verbose=False, imgsz=640, conf=0.25)
165
 
166
  if len(results[0].boxes) > 0:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  boxes = [
168
  {
169
  "label": classes[currency][int(box.cls.item())],
 
3
  import boto3
4
  import gc
5
  import sys
6
+ import hashlib
7
+ from datetime import datetime, timezone, timedelta
8
  from PIL import Image
9
  from botocore.config import Config
10
  from ultralytics import YOLO
 
34
  }
35
  }
36
 
 
 
 
 
 
 
 
 
37
  # ==========================================
38
+ # 2. FUNCIONES AUXILIARES
39
  # ==========================================
40
+ def calculate_file_md5(filepath):
41
+ hash_md5 = hashlib.md5()
42
+ with open(filepath, "rb") as f:
43
+ for chunk in iter(lambda: f.read(4096), b""):
44
+ hash_md5.update(chunk)
45
+ return hash_md5.hexdigest()
46
+
47
+ def get_s3_client():
48
+ """Retorna un cliente s3 configurado para Cloudflare R2"""
49
+ return boto3.client(
50
  service_name="s3",
51
  endpoint_url=R2_ENDPOINT_URL,
52
  aws_access_key_id=R2_ACCESS_KEY,
 
54
  config=Config(signature_version="s3v4")
55
  )
56
 
57
+ # ==========================================
58
+ # 3. DESCARGA CONSTRUCTORA Y DESTRUCTIVA
59
+ # ==========================================
60
+ def download_models_from_r2():
61
+ s3_client = get_s3_client()
62
+
63
  for name, config in model_configs.items():
64
  os.makedirs(os.path.dirname(config["path"]), exist_ok=True)
65
 
 
78
  else:
79
  print(f"El modelo {name} ya existe localmente. Cargando...")
80
 
81
+ local_md5 = calculate_file_md5(config["path"])
82
+ print(f"[DEBUG] MD5 del modelo {name} en disco: {local_md5}")
 
83
 
84
  del s3_client
85
  gc.collect()
86
 
 
87
  download_models_from_r2()
88
 
89
  # ==========================================
90
+ # 4. CARGA DE MODELOS
91
  # ==========================================
92
  models = {
93
  "USD": YOLO(model_configs["USD"]["path"]),
 
95
  "INFERENCIA": YOLO(model_configs["INFERENCIA"]["path"]),
96
  }
97
 
 
 
 
 
 
 
98
  classes = {
99
  "USD": [
100
  "fifty-back", "fifty-front",
 
132
  def detection_vef(image: UploadFile):
133
  print("FOTO RECIBIDA")
134
 
 
135
  imageBytes = image.file.read()
136
 
137
+ raw_md5 = hashlib.md5(imageBytes).hexdigest()
138
+ print(f"[DEBUG] MD5 de la foto cruda recibida: {raw_md5}")
 
139
 
140
  imageStream = io.BytesIO(imageBytes)
141
  imageFile = Image.open(imageStream).convert("RGB")
142
 
143
+ debug_buffer = io.BytesIO()
144
+ imageFile.save(debug_buffer, format="JPEG")
145
+ pillow_md5 = hashlib.md5(debug_buffer.getvalue()).hexdigest()
146
+ print(f"[DEBUG] MD5 de la foto tras procesar con Pillow (RGB): {pillow_md5}")
 
147
 
148
  which_currency = models["INFERENCIA"].predict(imageFile, verbose=False, imgsz=640, conf=0.25)
149
 
 
160
  results = models[currency].predict(imageFile, verbose=False, imgsz=640, conf=0.25)
161
 
162
  if len(results[0].boxes) > 0:
163
+ # Tomamos el label y la confianza de la primera detección (la de mayor confianza usualmente)
164
+ primary_label = classes[currency][int(results[0].boxes[0].cls.item())]
165
+ primary_conf = results[0].boxes[0].conf.item() # <--- Extraemos la confianza
166
+
167
+ # -----------------------------------------------------
168
+ # LÓGICA DE GUARDADO EN R2 (LOGS)
169
+ # -----------------------------------------------------
170
+ try:
171
+ # Zona horaria de Venezuela (UTC-4)
172
+ vzla_tz = timezone(timedelta(hours=-4))
173
+ now = datetime.now(vzla_tz)
174
+
175
+ # Formato: DD-MM-YYYY_HHMMSS_<label>_<confianza>.jpg
176
+ # Usamos :.4f para limitar la confianza a 4 decimales (ej. 0.9876)
177
+ filename = f"{now.strftime('%d-%m-%Y_%H%M%S')}_{primary_label}_{primary_conf:.4f}.jpg"
178
+ r2_key = f"logs/{filename}"
179
+
180
+ s3_client = get_s3_client()
181
+ s3_client.put_object(
182
+ Bucket=R2_BUCKET_NAME,
183
+ Key=r2_key,
184
+ Body=imageBytes, # Usamos los bytes originales para no perder calidad
185
+ ContentType="image/jpeg"
186
+ )
187
+ print(f"[LOG] Imagen respaldada en R2: {r2_key}")
188
+ except Exception as e:
189
+ print(f"❌ [ERROR] Fallo al subir la imagen a logs en R2: {e}")
190
+ # -----------------------------------------------------
191
+
192
  boxes = [
193
  {
194
  "label": classes[currency][int(box.cls.item())],