Spaces:
Sleeping
Sleeping
Kesheratmex
commited on
Commit
·
5d8f144
1
Parent(s):
1fe3c0d
**Add GPT image analysis and Markdown output for AI insights**
Browse files
app.py
CHANGED
|
@@ -240,6 +240,95 @@ def _extract_video(d):
|
|
| 240 |
def _extract_path(d):
|
| 241 |
return (d.get("path") if isinstance(d, dict) else d)
|
| 242 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 243 |
|
| 244 |
|
| 245 |
def _check_token(token: str):
|
|
@@ -899,6 +988,9 @@ with gr.Blocks(
|
|
| 899 |
output_video = gr.Video(label="Vídeo anotado", visible=False)
|
| 900 |
output_image = gr.Image(label="Imagen anotada", visible=False)
|
| 901 |
|
|
|
|
|
|
|
|
|
|
| 902 |
# Hidden JSON components for API chaining
|
| 903 |
json_video = gr.JSON(visible=False)
|
| 904 |
json_image = gr.JSON(visible=False)
|
|
@@ -906,19 +998,33 @@ with gr.Blocks(
|
|
| 906 |
# Functions to show/hide outputs based on active tab and update content
|
| 907 |
def _update_video_output(json_result):
|
| 908 |
if json_result and json_result.get("video"):
|
| 909 |
-
return gr.Video(value=json_result["video"], visible=True), gr.Image(visible=False)
|
| 910 |
-
return gr.Video(visible=False), gr.Image(visible=False)
|
| 911 |
|
| 912 |
def _update_image_output(json_result):
|
| 913 |
if json_result and json_result.get("path"):
|
| 914 |
-
|
| 915 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 916 |
|
| 917 |
# Wire up the detection events with proper output visibility
|
| 918 |
ev_video = btn_detect.click(fn=infer_media, inputs=video_input, outputs=json_video, api_name="infer_media")
|
| 919 |
-
ev_video.then(_update_video_output, inputs=json_video, outputs=[output_video, output_image])
|
| 920 |
ev_image = btn_detect.click(fn=infer_media, inputs=image_input, outputs=json_image, api_name="infer_media_1")
|
| 921 |
-
ev_image.then(_update_image_output, inputs=json_image, outputs=[output_video, output_image])
|
| 922 |
|
| 923 |
# Wire the gate
|
| 924 |
btn_enter.click(fn=_check_token, inputs=[gate_token], outputs=[gate_group, app_group, gate_status])
|
|
|
|
| 240 |
def _extract_path(d):
|
| 241 |
return (d.get("path") if isinstance(d, dict) else d)
|
| 242 |
|
| 243 |
+
def analyze_image_with_gpt(image_path, detections_summary=""):
|
| 244 |
+
"""
|
| 245 |
+
Analiza una imagen directamente con GPT para obtener observaciones adicionales
|
| 246 |
+
que el modelo YOLO podría haber perdido.
|
| 247 |
+
"""
|
| 248 |
+
try:
|
| 249 |
+
GPTClass = _load_gptoss_wrapper()
|
| 250 |
+
if not GPTClass:
|
| 251 |
+
return "Análisis de IA no disponible (GPT wrapper no configurado)"
|
| 252 |
+
|
| 253 |
+
# Obtener características visuales básicas de la imagen
|
| 254 |
+
visual_features = compute_visual_features(image_path, [])
|
| 255 |
+
|
| 256 |
+
# Construir descripción visual básica
|
| 257 |
+
visual_desc = ""
|
| 258 |
+
if visual_features:
|
| 259 |
+
brightness = visual_features.get("brightness", 0)
|
| 260 |
+
contrast = visual_features.get("contrast", 0)
|
| 261 |
+
blur = visual_features.get("blur", 0)
|
| 262 |
+
dominant_rgb = visual_features.get("dominant_rgb", [])
|
| 263 |
+
|
| 264 |
+
bright_desc = "brillante" if brightness > 130 else ("tenue" if brightness < 80 else "moderadamente iluminada")
|
| 265 |
+
contrast_desc = "alto contraste" if contrast > 60 else ("bajo contraste" if contrast < 30 else "contraste moderado")
|
| 266 |
+
blur_desc = "borrosa" if blur < 100 else "nítida"
|
| 267 |
+
|
| 268 |
+
visual_desc = f"La imagen aparece {bright_desc}, con {contrast_desc}, y está {blur_desc}."
|
| 269 |
+
if dominant_rgb:
|
| 270 |
+
visual_desc += f" Color dominante aproximado: RGB{dominant_rgb}."
|
| 271 |
+
|
| 272 |
+
# Construir prompt en español para análisis visual directo
|
| 273 |
+
prompt = f"""Eres un experto en inspección de palas de aerogeneradores. Analiza esta imagen de una pala de aerogenerador y proporciona un análisis detallado en español.
|
| 274 |
+
|
| 275 |
+
INFORMACIÓN TÉCNICA DE LA IMAGEN:
|
| 276 |
+
{visual_desc}
|
| 277 |
+
|
| 278 |
+
DETECCIONES AUTOMÁTICAS DEL MODELO YOLO:
|
| 279 |
+
{detections_summary if detections_summary else "No se detectaron defectos automáticamente"}
|
| 280 |
+
|
| 281 |
+
INSTRUCCIONES PARA TU ANÁLISIS:
|
| 282 |
+
1. Describe lo que observas en la superficie de la pala (color, textura, condiciones generales)
|
| 283 |
+
2. Identifica cualquier anomalía, defecto o área de preocupación que puedas ver visualmente
|
| 284 |
+
3. Menciona específicamente si observas algo que el modelo automático YOLO podría haber perdido
|
| 285 |
+
4. Evalúa el estado general de la pala (excelente, bueno, regular, malo, crítico)
|
| 286 |
+
5. Proporciona recomendaciones específicas de mantenimiento
|
| 287 |
+
|
| 288 |
+
ÁREAS ESPECÍFICAS A REVISAR:
|
| 289 |
+
- Borde de ataque (leading edge)
|
| 290 |
+
- Borde de salida (trailing edge)
|
| 291 |
+
- Superficie de la pala
|
| 292 |
+
- Uniones y conexiones
|
| 293 |
+
- Grietas, erosión, decoloración
|
| 294 |
+
- Daños por rayos, impactos de aves
|
| 295 |
+
- Acumulación de suciedad o hielo
|
| 296 |
+
|
| 297 |
+
IMPORTANTE:
|
| 298 |
+
- Responde SOLO en español
|
| 299 |
+
- Sé específico sobre ubicaciones y tipos de defectos
|
| 300 |
+
- Si no ves defectos obvios, menciona las características positivas
|
| 301 |
+
- Compara tus observaciones con las detecciones automáticas
|
| 302 |
+
|
| 303 |
+
Formato de respuesta:
|
| 304 |
+
## 🔍 Análisis Visual Detallado
|
| 305 |
+
|
| 306 |
+
**Estado General:** [tu evaluación del estado]
|
| 307 |
+
|
| 308 |
+
**Observaciones Principales:**
|
| 309 |
+
[describe lo que ves en la superficie, colores, texturas]
|
| 310 |
+
|
| 311 |
+
**Defectos o Anomalías Detectadas:**
|
| 312 |
+
[cualquier problema que observes, incluso si YOLO no lo detectó]
|
| 313 |
+
|
| 314 |
+
**Comparación con Detección Automática:**
|
| 315 |
+
[comenta sobre las detecciones YOLO vs lo que tú observas]
|
| 316 |
+
|
| 317 |
+
**Recomendaciones:**
|
| 318 |
+
[acciones específicas recomendadas]
|
| 319 |
+
"""
|
| 320 |
+
|
| 321 |
+
model_id = os.getenv("MODEL_ID", "gpt-oss-120")
|
| 322 |
+
wrapper = GPTClass(model=model_id)
|
| 323 |
+
|
| 324 |
+
# Generar análisis
|
| 325 |
+
analysis = wrapper.generate(prompt, max_tokens=1000, temperature=0.2)
|
| 326 |
+
|
| 327 |
+
return analysis
|
| 328 |
+
|
| 329 |
+
except Exception as e:
|
| 330 |
+
return f"Error en el análisis de IA: {str(e)}"
|
| 331 |
+
|
| 332 |
|
| 333 |
|
| 334 |
def _check_token(token: str):
|
|
|
|
| 988 |
output_video = gr.Video(label="Vídeo anotado", visible=False)
|
| 989 |
output_image = gr.Image(label="Imagen anotada", visible=False)
|
| 990 |
|
| 991 |
+
# Analysis text below the image
|
| 992 |
+
analysis_text = gr.Markdown(label="Análisis de IA", visible=False)
|
| 993 |
+
|
| 994 |
# Hidden JSON components for API chaining
|
| 995 |
json_video = gr.JSON(visible=False)
|
| 996 |
json_image = gr.JSON(visible=False)
|
|
|
|
| 998 |
# Functions to show/hide outputs based on active tab and update content
|
| 999 |
def _update_video_output(json_result):
|
| 1000 |
if json_result and json_result.get("video"):
|
| 1001 |
+
return gr.Video(value=json_result["video"], visible=True), gr.Image(visible=False), gr.Markdown(visible=False)
|
| 1002 |
+
return gr.Video(visible=False), gr.Image(visible=False), gr.Markdown(visible=False)
|
| 1003 |
|
| 1004 |
def _update_image_output(json_result):
|
| 1005 |
if json_result and json_result.get("path"):
|
| 1006 |
+
# Generar resumen de detecciones para el análisis GPT
|
| 1007 |
+
classes = json_result.get("classes", {})
|
| 1008 |
+
if classes:
|
| 1009 |
+
detections_summary = "Detecciones automáticas: " + ", ".join([f"{k}: {v}" for k, v in classes.items()])
|
| 1010 |
+
else:
|
| 1011 |
+
detections_summary = "No se detectaron defectos automáticamente"
|
| 1012 |
+
|
| 1013 |
+
# Obtener análisis de GPT
|
| 1014 |
+
analysis = analyze_image_with_gpt(json_result["path"], detections_summary)
|
| 1015 |
+
|
| 1016 |
+
return (
|
| 1017 |
+
gr.Video(visible=False),
|
| 1018 |
+
gr.Image(value=json_result["path"], visible=True),
|
| 1019 |
+
gr.Markdown(value=analysis, visible=True)
|
| 1020 |
+
)
|
| 1021 |
+
return gr.Video(visible=False), gr.Image(visible=False), gr.Markdown(visible=False)
|
| 1022 |
|
| 1023 |
# Wire up the detection events with proper output visibility
|
| 1024 |
ev_video = btn_detect.click(fn=infer_media, inputs=video_input, outputs=json_video, api_name="infer_media")
|
| 1025 |
+
ev_video.then(_update_video_output, inputs=json_video, outputs=[output_video, output_image, analysis_text])
|
| 1026 |
ev_image = btn_detect.click(fn=infer_media, inputs=image_input, outputs=json_image, api_name="infer_media_1")
|
| 1027 |
+
ev_image.then(_update_image_output, inputs=json_image, outputs=[output_video, output_image, analysis_text])
|
| 1028 |
|
| 1029 |
# Wire the gate
|
| 1030 |
btn_enter.click(fn=_check_token, inputs=[gate_token], outputs=[gate_group, app_group, gate_status])
|