JKrishnanandhaa commited on
Commit
36c9274
·
verified ·
1 Parent(s): 613765e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +32 -68
app.py CHANGED
@@ -34,7 +34,7 @@ CLASS_COLORS = {
34
  2: (65, 105, 225) # #4169E1 - Royal blue
35
  }
36
 
37
- # Actual model performance metrics (trained model)
38
  MODEL_METRICS = {
39
  'segmentation': {
40
  'dice': 0.6212,
@@ -53,22 +53,13 @@ MODEL_METRICS = {
53
  }
54
 
55
 
56
- def create_detection_gauges(num_detections: int, avg_confidence: float) -> go.Figure:
57
- """Create radial gauge charts for detection results"""
58
- from plotly.subplots import make_subplots
59
-
60
- fig = make_subplots(
61
- rows=1, cols=2,
62
- specs=[[{'type': 'indicator'}, {'type': 'indicator'}]],
63
- horizontal_spacing=0.15
64
- )
65
-
66
- # Confidence gauge
67
- fig.add_trace(go.Indicator(
68
  mode="gauge+number",
69
- value=avg_confidence * 100,
70
  domain={'x': [0, 1], 'y': [0, 1]},
71
- title={'text': 'Avg Confidence', 'font': {'size': 14}},
72
  number={'suffix': '%', 'font': {'size': 24}},
73
  gauge={
74
  'axis': {'range': [0, 100], 'tickwidth': 1},
@@ -76,36 +67,17 @@ def create_detection_gauges(num_detections: int, avg_confidence: float) -> go.Fi
76
  'bgcolor': 'rgba(0,0,0,0)',
77
  'borderwidth': 0,
78
  'steps': [
79
- {'range': [0, 60], 'color': 'rgba(217, 83, 79, 0.1)'},
80
- {'range': [60, 80], 'color': 'rgba(240, 173, 78, 0.1)'},
81
- {'range': [80, 100], 'color': 'rgba(92, 184, 92, 0.1)'}
82
- ]
83
- }
84
- ), row=1, col=1)
85
-
86
- # Detections count gauge
87
- fig.add_trace(go.Indicator(
88
- mode="gauge+number",
89
- value=num_detections,
90
- domain={'x': [0, 1], 'y': [0, 1]},
91
- title={'text': 'Regions Detected', 'font': {'size': 14}},
92
- number={'font': {'size': 24}},
93
- gauge={
94
- 'axis': {'range': [0, 10], 'tickwidth': 1},
95
- 'bar': {'color': '#d9534f' if num_detections > 0 else '#5cb85c', 'thickness': 0.7},
96
- 'bgcolor': 'rgba(0,0,0,0)',
97
- 'borderwidth': 0,
98
- 'steps': [
99
- {'range': [0, 1], 'color': 'rgba(92, 184, 92, 0.1)'},
100
- {'range': [1, 10], 'color': 'rgba(217, 83, 79, 0.1)'}
101
  ]
102
  }
103
- ), row=1, col=2)
104
 
105
  fig.update_layout(
106
  paper_bgcolor='rgba(0,0,0,0)',
107
  plot_bgcolor='rgba(0,0,0,0)',
108
- height=250,
109
  margin=dict(l=20, r=20, t=40, b=20)
110
  )
111
 
@@ -148,7 +120,8 @@ class ForgeryDetector:
148
  Returns:
149
  original_image: Original uploaded image
150
  overlay_image: Image with detection overlay
151
- detection_gauges: Plotly figure with detection metrics
 
152
  results_html: Detection results as HTML
153
  """
154
  # Handle PDF files
@@ -232,17 +205,14 @@ class ForgeryDetector:
232
  # Create visualization
233
  overlay = self._create_overlay(original_image, results)
234
 
235
- # Calculate metrics for gauges
236
- num_detections = len(results)
237
- avg_confidence = sum(r['confidence'] for r in results) / num_detections if num_detections > 0 else 0
238
-
239
- # Create detection gauge charts
240
- detection_gauges = create_detection_gauges(num_detections, avg_confidence)
241
 
242
  # Create HTML response
243
  results_html = self._create_html_report(results)
244
 
245
- return original_image, overlay, detection_gauges, results_html
246
 
247
  def _create_overlay(self, image, results):
248
  """Create overlay visualization"""
@@ -336,19 +306,19 @@ def detect_forgery(file):
336
  try:
337
  if file is None:
338
  empty_html = "<div style='padding:12px; border:1px solid #d9534f; border-radius:8px;'>❌ <b>No file uploaded.</b></div>"
339
- return None, None, None, empty_html
340
 
341
  # Get file path
342
  file_path = file.name if hasattr(file, 'name') else file
343
 
344
  # Check if PDF
345
  if file_path.lower().endswith('.pdf'):
346
- original, overlay, gauges, results_html = detector.detect(file_path)
347
  else:
348
  image = Image.open(file_path)
349
- original, overlay, gauges, results_html = detector.detect(image)
350
 
351
- return original, overlay, gauges, results_html
352
 
353
  except Exception as e:
354
  import traceback
@@ -359,7 +329,7 @@ def detect_forgery(file):
359
  ❌ <b>Error:</b> {str(e)}
360
  </div>
361
  """
362
- return None, None, None, error_html
363
 
364
 
365
  # Custom CSS - subtle styling
@@ -385,7 +355,6 @@ with gr.Blocks(css=custom_css) as demo:
385
  )
386
 
387
  with gr.Row():
388
- # Left column: Upload
389
  with gr.Column(scale=1):
390
  gr.Markdown("### Upload Document")
391
  input_file = gr.File(
@@ -411,18 +380,17 @@ with gr.Blocks(css=custom_css) as demo:
411
  """
412
  )
413
 
414
- # Right column: Results (Original and Overlay side-by-side)
415
  with gr.Column(scale=2):
416
  gr.Markdown("### Detection Results")
417
  with gr.Row():
418
  original_image = gr.Image(label="Original Document", type="numpy")
419
  output_image = gr.Image(label="Detected Forgeries", type="numpy")
420
 
421
- # Bottom section: Gauges and Report
422
  with gr.Row():
423
  with gr.Column(scale=1):
424
- gr.Markdown("### Detection Metrics")
425
- detection_gauges = gr.Plot(label="Detection Results")
 
426
 
427
  with gr.Column(scale=1):
428
  gr.Markdown("### Analysis Report")
@@ -431,16 +399,12 @@ with gr.Blocks(css=custom_css) as demo:
431
  )
432
 
433
  gr.Markdown(
434
- f"""
435
  ---
436
- **Trained Model Performance:**
437
- - Segmentation Dice: {MODEL_METRICS['segmentation']['dice']*100:.1f}% | IoU: {MODEL_METRICS['segmentation']['iou']*100:.1f}%
438
- - Classification Accuracy: {MODEL_METRICS['classification']['overall_accuracy']*100:.1f}%
439
-
440
  **Model Architecture:**
441
- - Localization: MobileNetV3-Small + UNet
442
- - Classification: LightGBM with 526 hybrid features
443
- - Training: 140K samples from DocTamper dataset
444
  """
445
  )
446
 
@@ -448,13 +412,13 @@ with gr.Blocks(css=custom_css) as demo:
448
  analyze_btn.click(
449
  fn=detect_forgery,
450
  inputs=[input_file],
451
- outputs=[original_image, output_image, detection_gauges, output_html]
452
  )
453
 
454
  clear_btn.click(
455
- fn=lambda: (None, None, None, None, "<i>No analysis yet. Upload a document and click Analyze.</i>"),
456
  inputs=None,
457
- outputs=[input_file, original_image, output_image, detection_gauges, output_html]
458
  )
459
 
460
 
 
34
  2: (65, 105, 225) # #4169E1 - Royal blue
35
  }
36
 
37
+ # Actual model performance metrics
38
  MODEL_METRICS = {
39
  'segmentation': {
40
  'dice': 0.6212,
 
53
  }
54
 
55
 
56
+ def create_gauge_chart(value: float, title: str, max_value: float = 1.0) -> go.Figure:
57
+ """Create a subtle radial gauge chart"""
58
+ fig = go.Figure(go.Indicator(
 
 
 
 
 
 
 
 
 
59
  mode="gauge+number",
60
+ value=value * 100,
61
  domain={'x': [0, 1], 'y': [0, 1]},
62
+ title={'text': title, 'font': {'size': 14}},
63
  number={'suffix': '%', 'font': {'size': 24}},
64
  gauge={
65
  'axis': {'range': [0, 100], 'tickwidth': 1},
 
67
  'bgcolor': 'rgba(0,0,0,0)',
68
  'borderwidth': 0,
69
  'steps': [
70
+ {'range': [0, 50], 'color': 'rgba(217, 83, 79, 0.1)'},
71
+ {'range': [50, 75], 'color': 'rgba(240, 173, 78, 0.1)'},
72
+ {'range': [75, 100], 'color': 'rgba(92, 184, 92, 0.1)'}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  ]
74
  }
75
+ ))
76
 
77
  fig.update_layout(
78
  paper_bgcolor='rgba(0,0,0,0)',
79
  plot_bgcolor='rgba(0,0,0,0)',
80
+ height=200,
81
  margin=dict(l=20, r=20, t=40, b=20)
82
  )
83
 
 
120
  Returns:
121
  original_image: Original uploaded image
122
  overlay_image: Image with detection overlay
123
+ gauge_dice: Dice score gauge
124
+ gauge_accuracy: Accuracy gauge
125
  results_html: Detection results as HTML
126
  """
127
  # Handle PDF files
 
205
  # Create visualization
206
  overlay = self._create_overlay(original_image, results)
207
 
208
+ # Create gauge charts
209
+ gauge_dice = create_gauge_chart(MODEL_METRICS['segmentation']['dice'], 'Segmentation Dice')
210
+ gauge_accuracy = create_gauge_chart(MODEL_METRICS['classification']['overall_accuracy'], 'Classification Accuracy')
 
 
 
211
 
212
  # Create HTML response
213
  results_html = self._create_html_report(results)
214
 
215
+ return original_image, overlay, gauge_dice, gauge_accuracy, results_html
216
 
217
  def _create_overlay(self, image, results):
218
  """Create overlay visualization"""
 
306
  try:
307
  if file is None:
308
  empty_html = "<div style='padding:12px; border:1px solid #d9534f; border-radius:8px;'>❌ <b>No file uploaded.</b></div>"
309
+ return None, None, None, None, empty_html
310
 
311
  # Get file path
312
  file_path = file.name if hasattr(file, 'name') else file
313
 
314
  # Check if PDF
315
  if file_path.lower().endswith('.pdf'):
316
+ original, overlay, gauge_dice, gauge_acc, results_html = detector.detect(file_path)
317
  else:
318
  image = Image.open(file_path)
319
+ original, overlay, gauge_dice, gauge_acc, results_html = detector.detect(image)
320
 
321
+ return original, overlay, gauge_dice, gauge_acc, results_html
322
 
323
  except Exception as e:
324
  import traceback
 
329
  ❌ <b>Error:</b> {str(e)}
330
  </div>
331
  """
332
+ return None, None, None, None, error_html
333
 
334
 
335
  # Custom CSS - subtle styling
 
355
  )
356
 
357
  with gr.Row():
 
358
  with gr.Column(scale=1):
359
  gr.Markdown("### Upload Document")
360
  input_file = gr.File(
 
380
  """
381
  )
382
 
 
383
  with gr.Column(scale=2):
384
  gr.Markdown("### Detection Results")
385
  with gr.Row():
386
  original_image = gr.Image(label="Original Document", type="numpy")
387
  output_image = gr.Image(label="Detected Forgeries", type="numpy")
388
 
 
389
  with gr.Row():
390
  with gr.Column(scale=1):
391
+ gr.Markdown("### Model Performance")
392
+ gauge_dice = gr.Plot(label="Segmentation Dice Score")
393
+ gauge_accuracy = gr.Plot(label="Classification Accuracy")
394
 
395
  with gr.Column(scale=1):
396
  gr.Markdown("### Analysis Report")
 
399
  )
400
 
401
  gr.Markdown(
402
+ """
403
  ---
 
 
 
 
404
  **Model Architecture:**
405
+ - **Localization:** MobileNetV3-Small + UNet (Dice: 62.1%, IoU: 45.1%)
406
+ - **Classification:** LightGBM with 526 features (Accuracy: 88.97%)
407
+ - **Training:** 140K samples (DocTamper + SCD + FCD datasets)
408
  """
409
  )
410
 
 
412
  analyze_btn.click(
413
  fn=detect_forgery,
414
  inputs=[input_file],
415
+ outputs=[original_image, output_image, gauge_dice, gauge_accuracy, output_html]
416
  )
417
 
418
  clear_btn.click(
419
+ fn=lambda: (None, None, None, None, None, "<i>No analysis yet. Upload a document and click Analyze.</i>"),
420
  inputs=None,
421
+ outputs=[input_file, original_image, output_image, gauge_dice, gauge_accuracy, output_html]
422
  )
423
 
424