DHEIVER commited on
Commit
dce5a99
·
verified ·
1 Parent(s): a8affc3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +250 -174
app.py CHANGED
@@ -2,7 +2,7 @@ import gradio as gr
2
  import cv2
3
  import numpy as np
4
  from dataclasses import dataclass
5
- from typing import Dict, List, Tuple
6
  from datetime import datetime
7
 
8
  @dataclass
@@ -10,7 +10,7 @@ class IrisZone:
10
  name: str
11
  ratio: Tuple[float, float] # (inner, outer)
12
  color: Tuple[int, int, int]
13
- conditions: Dict[str, List[str]] # Detailed health conditions
14
  recommendations: Dict[str, List[str]]
15
 
16
  class IrisAnalyzer:
@@ -194,55 +194,92 @@ class IrisAnalyzer:
194
  ]
195
 
196
  def _assess_image_quality(self, image: np.ndarray) -> float:
197
- gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
198
- blur_score = cv2.Laplacian(gray, cv2.CV_64F).var()
199
- brightness = np.mean(gray)
200
- contrast = np.std(gray)
201
-
202
- quality_score = (
203
- min(blur_score / 500, 1) * 0.4 +
204
- min(abs(brightness - 128) / 128, 1) * 0.3 +
205
- min(contrast / 50, 1) * 0.3
206
- ) * 100
207
-
208
- return quality_score
 
 
 
 
 
209
 
210
  def _analyze_texture(self, gray: np.ndarray, mask: np.ndarray) -> float:
211
- zone_pixels = cv2.bitwise_and(gray, gray, mask=mask)
212
- if np.sum(mask) == 0:
213
- return 0
 
 
 
 
214
 
215
- mean = np.mean(zone_pixels[mask > 0])
216
- std = np.std(zone_pixels[mask > 0])
217
- entropy = np.sum(np.abs(np.diff(zone_pixels[mask > 0])))
218
-
219
- texture_score = (mean * 0.3 + std * 0.3 + min(entropy/1000, 1) * 0.4) * 100
220
- return min(texture_score, 100)
 
 
 
 
 
 
 
 
 
 
 
221
 
222
  def _analyze_contrast(self, l_channel: np.ndarray, mask: np.ndarray) -> float:
223
- if np.sum(mask) == 0:
224
- return 0
 
 
 
 
 
 
 
 
 
225
 
226
- zone_pixels = l_channel[mask > 0]
227
- p5 = np.percentile(zone_pixels, 5)
228
- p95 = np.percentile(zone_pixels, 95)
229
-
230
- contrast_score = ((p95 - p5) / 255) * 100
231
- return min(contrast_score, 100)
232
 
233
  def _detect_patterns(self, gray: np.ndarray, mask: np.ndarray) -> float:
234
- if np.sum(mask) == 0:
235
- return 0
 
 
 
 
 
 
236
 
237
- sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
238
- sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
239
- gradient = np.sqrt(sobelx**2 + sobely**2)
240
-
241
- zone_gradient = gradient[mask > 0]
242
- pattern_score = (np.mean(zone_gradient) / np.max(gradient)) * 100
243
- return min(pattern_score, 100)
 
 
244
 
245
  def _customize_conditions(self, base_conditions: List[str], metrics: Dict) -> List[str]:
 
246
  customized = []
247
  for condition in base_conditions:
248
  if metrics["intensity"] < 50:
@@ -257,6 +294,7 @@ class IrisAnalyzer:
257
  return customized
258
 
259
  def _customize_recommendations(self, base_recommendations: List[str], metrics: Dict) -> List[str]:
 
260
  customized = []
261
  for rec in base_recommendations:
262
  if metrics["texture"] < 40:
@@ -268,6 +306,7 @@ class IrisAnalyzer:
268
  return customized
269
 
270
  def _calculate_confidence(self, metrics: Dict) -> str:
 
271
  confidence_score = (
272
  metrics["intensity"] * 0.25 +
273
  metrics["contrast"] * 0.25 +
@@ -282,148 +321,185 @@ class IrisAnalyzer:
282
  else:
283
  return "baixa"
284
 
285
- def analyze_iris(self, image: np.ndarray) -> Dict:
286
- gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
287
- hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
288
- lab = cv2.cvtColor(image, cv2.COLOR_RGB2LAB)
289
-
290
- circles = cv2.HoughCircles(
291
- gray, cv2.HOUGH_GRADIENT, dp=1, minDist=100,
292
- param1=50, param2=30, minRadius=50, maxRadius=150
293
- )
294
-
295
- if circles is not None:
296
- circle = circles[0][0]
297
- center = (int(circle[0]), int(circle[1]))
298
- radius = int(circle[2])
299
- else:
300
- center = (image.shape[1]//2, image.shape[0]//2)
301
- radius = min(image.shape[:2])//4
302
-
303
- results = {
304
- "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
305
- "analysis": {},
306
- "metrics": {
307
- "iris_radius": radius,
308
- "image_quality": self._assess_image_quality(image)
309
- }
310
- }
311
-
312
- for zone in self.zones:
313
- inner_r = int(radius * zone.ratio[0])
314
- outer_r = int(radius * zone.ratio[1])
315
-
316
- mask = np.zeros(gray.shape, dtype=np.uint8)
317
- cv2.circle(mask, center, outer_r, 255, -1)
318
- cv2.circle(mask, center, inner_r, 0, -1)
319
 
320
- zone_metrics = {
321
- "intensity": cv2.mean(gray, mask=mask)[0],
322
- "saturation": cv2.mean(hsv[..., 1], mask=mask)[0],
323
- "texture": self._analyze_texture(gray, mask),
324
- "contrast": self._analyze_contrast(lab[..., 0], mask),
325
- "patterns": self._detect_patterns(gray, mask)
326
- }
327
 
328
- health_score = (
329
- zone_metrics["intensity"] * 0.3 +
330
- zone_metrics["saturation"] * 0.2 +
331
- zone_metrics["texture"] * 0.2 +
332
- zone_metrics["contrast"] * 0.15 +
333
- zone_metrics["patterns"] * 0.15
 
 
 
 
334
  )
335
 
336
- if health_score < 40:
337
- level = "baixa"
338
- elif health_score < 75:
339
- level = "media"
 
340
  else:
341
- level = "alta"
342
-
343
- results["analysis"][zone.name] = {
344
- "conditions": self._customize_conditions(zone.conditions[level], zone_metrics),
345
- "recommendations": self._customize_recommendations(zone.recommendations[level], zone_metrics),
 
 
346
  "metrics": {
347
- "intensity": float(zone_metrics["intensity"]),
348
- "saturation": float(zone_metrics["saturation"]),
349
- "texture": float(zone_metrics["texture"]),
350
- "contrast": float(zone_metrics["contrast"]),
351
- "patterns": float(zone_metrics["patterns"]),
352
- "health_score": float(health_score)
353
- },
354
- "status": level,
355
- "confianca_analise": self._calculate_confidence(zone_metrics)
356
  }
357
 
358
- cv2.circle(image, center, outer_r, zone.color, 2)
359
- cv2.putText(image, zone.name,
360
- (center[0]-outer_r, center[1]+outer_r),
361
- cv2.FONT_HERSHEY_SIMPLEX, 0.5, zone.color, 1)
362
-
363
- return image, results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
 
365
- def process_image(img):
 
366
  if img is None:
367
- return [None] * 5, gr.Warning("Por favor, carregue uma imagem.")
368
-
369
- analyzer = IrisAnalyzer()
370
- processed_img, results = analyzer.analyze_iris(img)
371
-
372
- # Relatório Geral
373
- general_report = "# 📊 Visão Geral da Análise\n\n"
374
- status_counts = {"baixa": 0, "media": 0, "alta": 0}
375
- for analysis in results["analysis"].values():
376
- status_counts[analysis["status"]] += 1
377
-
378
- health_score = ((status_counts["alta"] * 100) + (status_counts["media"] * 50)) / len(results["analysis"])
379
- general_report += f"**Índice de Saúde Geral:** {health_score:.1f}%\n\n"
380
- general_report += f"**Data da Análise:** {results['timestamp']}\n\n"
381
- general_report += "**Qualidade da Imagem:** {:.1f}%\n\n".format(results['metrics']['image_quality'])
382
 
383
- # Condições Detalhadas
384
- detailed_conditions = "# 🔍 Análise Detalhada por Zona\n\n"
385
- recommendations = "# 💡 Recomendações Personalizadas\n\n"
386
- health_alerts = "# ⚠️ Alertas e Atenção Especial\n\n"
387
-
388
- for zone_name, analysis in results["analysis"].items():
389
- # Detailed conditions
390
- detailed_conditions += f"## {zone_name}\n\n"
391
- detailed_conditions += "### Condições Identificadas:\n"
392
- for condition in analysis["conditions"]:
393
- detailed_conditions += f"- {condition}\n"
394
- detailed_conditions += f"\n**Status:** {analysis['status'].title()}\n"
395
- detailed_conditions += f"**Confiança da Análise:** {analysis['confianca_analise']}\n"
396
- detailed_conditions += "**Métricas Detalhadas:**\n"
397
- for metric, value in analysis["metrics"].items():
398
- detailed_conditions += f"- {metric.replace('_', ' ').title()}: {value:.1f}\n"
399
- detailed_conditions += "\n"
 
 
 
 
 
 
 
400
 
401
- # Recommendations
402
- recommendations += f"## {zone_name}\n\n"
403
- for rec in analysis["recommendations"]:
404
- recommendations += f"- {rec}\n"
405
- recommendations += "\n"
406
 
407
- # Health alerts
408
- if analysis["status"] == "baixa" or analysis["metrics"]["health_score"] < 50:
409
- health_alerts += f"## {zone_name}\n"
410
- health_alerts += "### Pontos de Atenção:\n"
411
  for condition in analysis["conditions"]:
412
- health_alerts += f"- ⚠️ {condition}\n"
413
- health_alerts += "\n### Ações Recomendadas:\n"
 
 
 
 
 
 
 
 
 
 
414
  for rec in analysis["recommendations"]:
415
- health_alerts += f"- {rec}\n"
416
- health_alerts += "\n"
417
-
418
- return [
419
- processed_img,
420
- general_report,
421
- detailed_conditions,
422
- recommendations,
423
- health_alerts
424
- ]
 
 
 
 
 
 
 
 
 
425
 
426
- # Interface Gradio
427
  with gr.Blocks(theme=gr.themes.Soft()) as iface:
428
  gr.Markdown("""
429
  # 🔍 Analisador Avançado de Íris
@@ -433,7 +509,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as iface:
433
  """)
434
 
435
  with gr.Tabs() as tabs:
436
- with gr.Tab("📸 Análise de Imagem", id=1):
437
  with gr.Row():
438
  with gr.Column(scale=1):
439
  input_image = gr.Image(
@@ -447,21 +523,21 @@ with gr.Blocks(theme=gr.themes.Soft()) as iface:
447
  with gr.Column(scale=1):
448
  output_image = gr.Image(label="Visualização da Análise", height=400)
449
 
450
- with gr.Tab("📊 Resultados", id=2):
451
  with gr.Tabs() as result_tabs:
452
- with gr.Tab("📈 Visão Geral", id=2.1):
453
  general_output = gr.Markdown()
454
 
455
- with gr.Tab("🔍 Condições Detalhadas", id=2.2):
456
  conditions_output = gr.Markdown()
457
 
458
- with gr.Tab("💡 Recomendações", id=2.3):
459
  recommendations_output = gr.Markdown()
460
 
461
- with gr.Tab("⚠️ Alertas", id=2.4):
462
  alerts_output = gr.Markdown()
463
 
464
- with gr.Tab("ℹ️ Informações", id=3):
465
  gr.Markdown("""
466
  ## 📚 Sobre a Análise Iridológica
467
 
@@ -493,7 +569,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as iface:
493
  - Mantenha check-ups regulares
494
  """)
495
 
496
- # Configurar eventos
497
  analyze_btn.click(
498
  fn=process_image,
499
  inputs=input_image,
 
2
  import cv2
3
  import numpy as np
4
  from dataclasses import dataclass
5
+ from typing import Dict, List, Tuple, Optional
6
  from datetime import datetime
7
 
8
  @dataclass
 
10
  name: str
11
  ratio: Tuple[float, float] # (inner, outer)
12
  color: Tuple[int, int, int]
13
+ conditions: Dict[str, List[str]]
14
  recommendations: Dict[str, List[str]]
15
 
16
  class IrisAnalyzer:
 
194
  ]
195
 
196
  def _assess_image_quality(self, image: np.ndarray) -> float:
197
+ """Assess image quality with better error handling."""
198
+ try:
199
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
200
+ blur_score = cv2.Laplacian(gray, cv2.CV_64F).var()
201
+ brightness = np.mean(gray)
202
+ contrast = np.std(gray)
203
+
204
+ quality_score = (
205
+ np.clip(blur_score / 500, 0, 1) * 0.4 +
206
+ np.clip(1 - abs(brightness - 128) / 128, 0, 1) * 0.3 +
207
+ np.clip(contrast / 50, 0, 1) * 0.3
208
+ ) * 100
209
+
210
+ return float(quality_score)
211
+ except Exception as e:
212
+ print(f"Error in image quality assessment: {str(e)}")
213
+ return 0.0
214
 
215
  def _analyze_texture(self, gray: np.ndarray, mask: np.ndarray) -> float:
216
+ """Analyze texture with improved error handling and normalization."""
217
+ try:
218
+ if mask is None or np.sum(mask) == 0:
219
+ return 0.0
220
+
221
+ zone_pixels = cv2.bitwise_and(gray, gray, mask=mask)
222
+ valid_pixels = zone_pixels[mask > 0]
223
 
224
+ if len(valid_pixels) == 0:
225
+ return 0.0
226
+
227
+ mean = np.mean(valid_pixels)
228
+ std = np.std(valid_pixels)
229
+ entropy = np.sum(np.abs(np.diff(valid_pixels)))
230
+
231
+ texture_score = (
232
+ np.clip(mean / 255, 0, 1) * 0.3 +
233
+ np.clip(std / 128, 0, 1) * 0.3 +
234
+ np.clip(entropy / 1000, 0, 1) * 0.4
235
+ ) * 100
236
+
237
+ return float(texture_score)
238
+ except Exception as e:
239
+ print(f"Error in texture analysis: {str(e)}")
240
+ return 0.0
241
 
242
  def _analyze_contrast(self, l_channel: np.ndarray, mask: np.ndarray) -> float:
243
+ """Analyze contrast with improved error handling."""
244
+ try:
245
+ if mask is None or np.sum(mask) == 0:
246
+ return 0.0
247
+
248
+ zone_pixels = l_channel[mask > 0]
249
+ if len(zone_pixels) == 0:
250
+ return 0.0
251
+
252
+ p5 = np.percentile(zone_pixels, 5)
253
+ p95 = np.percentile(zone_pixels, 95)
254
 
255
+ contrast_score = np.clip((p95 - p5) / 255, 0, 1) * 100
256
+ return float(contrast_score)
257
+ except Exception as e:
258
+ print(f"Error in contrast analysis: {str(e)}")
259
+ return 0.0
 
260
 
261
  def _detect_patterns(self, gray: np.ndarray, mask: np.ndarray) -> float:
262
+ """Detect patterns with improved error handling."""
263
+ try:
264
+ if mask is None or np.sum(mask) == 0:
265
+ return 0.0
266
+
267
+ sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
268
+ sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
269
+ gradient = np.sqrt(sobelx**2 + sobely**2)
270
 
271
+ zone_gradient = gradient[mask > 0]
272
+ if len(zone_gradient) == 0 or np.max(gradient) == 0:
273
+ return 0.0
274
+
275
+ pattern_score = np.clip((np.mean(zone_gradient) / np.max(gradient)), 0, 1) * 100
276
+ return float(pattern_score)
277
+ except Exception as e:
278
+ print(f"Error in pattern detection: {str(e)}")
279
+ return 0.0
280
 
281
  def _customize_conditions(self, base_conditions: List[str], metrics: Dict) -> List[str]:
282
+ """Customize conditions based on metrics."""
283
  customized = []
284
  for condition in base_conditions:
285
  if metrics["intensity"] < 50:
 
294
  return customized
295
 
296
  def _customize_recommendations(self, base_recommendations: List[str], metrics: Dict) -> List[str]:
297
+ """Customize recommendations based on metrics."""
298
  customized = []
299
  for rec in base_recommendations:
300
  if metrics["texture"] < 40:
 
306
  return customized
307
 
308
  def _calculate_confidence(self, metrics: Dict) -> str:
309
+ """Calculate analysis confidence level."""
310
  confidence_score = (
311
  metrics["intensity"] * 0.25 +
312
  metrics["contrast"] * 0.25 +
 
321
  else:
322
  return "baixa"
323
 
324
+ def analyze_iris(self, image: np.ndarray) -> Tuple[np.ndarray, Dict]:
325
+ """Main analysis function with improved error handling and image processing."""
326
+ try:
327
+ # Convert BGR to RGB if needed
328
+ if len(image.shape) == 2:
329
+ image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
330
+ elif image.shape[2] == 4:
331
+ image = cv2.cvtColor(image, cv2.COLOR_BGRA2BGR)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
 
333
+ # Create copies for different color spaces
334
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
335
+ hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
336
+ lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
 
 
 
337
 
338
+ # Improve circle detection
339
+ circles = cv2.HoughCircles(
340
+ gray,
341
+ cv2.HOUGH_GRADIENT,
342
+ dp=1,
343
+ minDist=max(gray.shape[0], gray.shape[1]), # Only detect one circle
344
+ param1=50,
345
+ param2=30,
346
+ minRadius=min(gray.shape) // 6,
347
+ maxRadius=min(gray.shape) // 2
348
  )
349
 
350
+ if circles is not None:
351
+ circles = np.uint16(np.around(circles))
352
+ circle = circles[0][0]
353
+ center = (int(circle[0]), int(circle[1]))
354
+ radius = int(circle[2])
355
  else:
356
+ # Fallback to image center if no circle is detected
357
+ center = (image.shape[1] // 2, image.shape[0] // 2)
358
+ radius = min(image.shape[:2]) // 4
359
+
360
+ results = {
361
+ "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
362
+ "analysis": {},
363
  "metrics": {
364
+ "iris_radius": radius,
365
+ "image_quality": self._assess_image_quality(image)
366
+ }
 
 
 
 
 
 
367
  }
368
 
369
+ # Analysis for each zone
370
+ for zone in self.zones:
371
+ inner_r = int(radius * zone.ratio[0])
372
+ outer_r = int(radius * zone.ratio[1])
373
+
374
+ # Create zone mask
375
+ mask = np.zeros(gray.shape, dtype=np.uint8)
376
+ cv2.circle(mask, center, outer_r, 255, -1)
377
+ cv2.circle(mask, center, inner_r, 0, -1)
378
+
379
+ # Calculate metrics
380
+ zone_metrics = {
381
+ "intensity": float(cv2.mean(gray, mask=mask)[0]),
382
+ "saturation": float(cv2.mean(hsv[..., 1], mask=mask)[0]),
383
+ "texture": self._analyze_texture(gray, mask),
384
+ "contrast": self._analyze_contrast(lab[..., 0], mask),
385
+ "patterns": self._detect_patterns(gray, mask)
386
+ }
387
+
388
+ # Calculate health score
389
+ health_score = (
390
+ zone_metrics["intensity"] * 0.3 +
391
+ zone_metrics["saturation"] * 0.2 +
392
+ zone_metrics["texture"] * 0.2 +
393
+ zone_metrics["contrast"] * 0.15 +
394
+ zone_metrics["patterns"] * 0.15
395
+ )
396
+
397
+ # Determine health level
398
+ level = "baixa" if health_score < 40 else ("media" if health_score < 75 else "alta")
399
+
400
+ # Store results
401
+ results["analysis"][zone.name] = {
402
+ "conditions": self._customize_conditions(zone.conditions[level], zone_metrics),
403
+ "recommendations": self._customize_recommendations(zone.recommendations[level], zone_metrics),
404
+ "metrics": {k: float(v) for k, v in zone_metrics.items()},
405
+ "health_score": float(health_score),
406
+ "status": level,
407
+ "confianca_analise": self._calculate_confidence(zone_metrics)
408
+ }
409
+
410
+ # Draw zone visualization
411
+ cv2.circle(image, center, outer_r, zone.color, 2)
412
+ cv2.putText(
413
+ image,
414
+ zone.name,
415
+ (center[0] - outer_r, center[1] + outer_r),
416
+ cv2.FONT_HERSHEY_SIMPLEX,
417
+ 0.5,
418
+ zone.color,
419
+ 1,
420
+ cv2.LINE_AA
421
+ )
422
+
423
+ return image, results
424
+
425
+ except Exception as e:
426
+ print(f"Error in iris analysis: {str(e)}")
427
+ return image, {"error": str(e)}
428
 
429
+ def process_image(img: Optional[np.ndarray]) -> Tuple[Optional[np.ndarray], str, str, str, str]:
430
+ """Process image with improved error handling and input validation."""
431
  if img is None:
432
+ return None, "⚠️ Por favor, carregue uma imagem.", "", "", ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
 
434
+ try:
435
+ analyzer = IrisAnalyzer()
436
+ processed_img, results = analyzer.analyze_iris(img)
437
+
438
+ if "error" in results:
439
+ return None, f"⚠️ Erro na análise: {results['error']}", "", "", ""
440
+
441
+ # Generate reports
442
+ general_report = "# 📊 Visão Geral da Análise\n\n"
443
+ status_counts = {"baixa": 0, "media": 0, "alta": 0}
444
+
445
+ for analysis in results["analysis"].values():
446
+ status_counts[analysis["status"]] += 1
447
+
448
+ health_score = (
449
+ (status_counts["alta"] * 100 + status_counts["media"] * 50) /
450
+ max(1, len(results["analysis"]))
451
+ )
452
+
453
+ general_report += (
454
+ f"**Índice de Saúde Geral:** {health_score:.1f}%\n\n"
455
+ f"**Data da Análise:** {results['timestamp']}\n\n"
456
+ f"**Qualidade da Imagem:** {results['metrics']['image_quality']:.1f}%\n\n"
457
+ )
458
 
459
+ # Detailed reports
460
+ detailed_conditions = "# 🔍 Análise Detalhada por Zona\n\n"
461
+ recommendations = "# 💡 Recomendações Personalizadas\n\n"
462
+ health_alerts = "# ⚠️ Alertas e Atenção Especial\n\n"
 
463
 
464
+ for zone_name, analysis in results["analysis"].items():
465
+ # Add detailed conditions
466
+ detailed_conditions += f"## {zone_name}\n\n"
467
+ detailed_conditions += "### Condições Identificadas:\n"
468
  for condition in analysis["conditions"]:
469
+ detailed_conditions += f"- {condition}\n"
470
+ detailed_conditions += (
471
+ f"\n**Status:** {analysis['status'].title()}\n"
472
+ f"**Confiança da Análise:** {analysis['confianca_analise']}\n"
473
+ "**Métricas Detalhadas:**\n"
474
+ )
475
+ for metric, value in analysis["metrics"].items():
476
+ detailed_conditions += f"- {metric.replace('_', ' ').title()}: {value:.1f}\n"
477
+ detailed_conditions += "\n"
478
+
479
+ # Add recommendations
480
+ recommendations += f"## {zone_name}\n\n"
481
  for rec in analysis["recommendations"]:
482
+ recommendations += f"- {rec}\n"
483
+ recommendations += "\n"
484
+
485
+ # Add health alerts
486
+ if analysis["status"] == "baixa" or analysis["metrics"]["health_score"] < 50:
487
+ health_alerts += f"## {zone_name}\n"
488
+ health_alerts += "### Pontos de Atenção:\n"
489
+ for condition in analysis["conditions"]:
490
+ health_alerts += f"- ⚠️ {condition}\n"
491
+ health_alerts += "\n### Ações Recomendadas:\n"
492
+ for rec in analysis["recommendations"]:
493
+ health_alerts += f"- ✅ {rec}\n"
494
+ health_alerts += "\n"
495
+
496
+ return processed_img, general_report, detailed_conditions, recommendations, health_alerts
497
+
498
+ except Exception as e:
499
+ error_message = f"⚠️ Erro no processamento: {str(e)}"
500
+ return None, error_message, "", "", ""
501
 
502
+ # Gradio Interface
503
  with gr.Blocks(theme=gr.themes.Soft()) as iface:
504
  gr.Markdown("""
505
  # 🔍 Analisador Avançado de Íris
 
509
  """)
510
 
511
  with gr.Tabs() as tabs:
512
+ with gr.Tab("📸 Análise de Imagem"):
513
  with gr.Row():
514
  with gr.Column(scale=1):
515
  input_image = gr.Image(
 
523
  with gr.Column(scale=1):
524
  output_image = gr.Image(label="Visualização da Análise", height=400)
525
 
526
+ with gr.Tab("📊 Resultados"):
527
  with gr.Tabs() as result_tabs:
528
+ with gr.Tab("📈 Visão Geral"):
529
  general_output = gr.Markdown()
530
 
531
+ with gr.Tab("🔍 Condições Detalhadas"):
532
  conditions_output = gr.Markdown()
533
 
534
+ with gr.Tab("💡 Recomendações"):
535
  recommendations_output = gr.Markdown()
536
 
537
+ with gr.Tab("⚠️ Alertas"):
538
  alerts_output = gr.Markdown()
539
 
540
+ with gr.Tab("ℹ️ Informações"):
541
  gr.Markdown("""
542
  ## 📚 Sobre a Análise Iridológica
543
 
 
569
  - Mantenha check-ups regulares
570
  """)
571
 
572
+ # Event handlers
573
  analyze_btn.click(
574
  fn=process_image,
575
  inputs=input_image,