JKrishnanandhaa commited on
Commit
613765e
·
verified ·
1 Parent(s): 93ae4b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -32
app.py CHANGED
@@ -34,7 +34,7 @@ CLASS_COLORS = {
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,13 +53,22 @@ MODEL_METRICS = {
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,17 +76,36 @@ def create_gauge_chart(value: float, title: str, max_value: float = 1.0) -> go.F
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,8 +148,7 @@ class ForgeryDetector:
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,14 +232,17 @@ class ForgeryDetector:
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,19 +336,19 @@ def detect_forgery(file):
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,7 +359,7 @@ def detect_forgery(file):
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,6 +385,7 @@ with gr.Blocks(css=custom_css) as demo:
355
  )
356
 
357
  with gr.Row():
 
358
  with gr.Column(scale=1):
359
  gr.Markdown("### Upload Document")
360
  input_file = gr.File(
@@ -380,17 +411,18 @@ with gr.Blocks(css=custom_css) as demo:
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,12 +431,16 @@ with gr.Blocks(css=custom_css) as demo:
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,13 +448,13 @@ with gr.Blocks(css=custom_css) as demo:
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
 
 
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
  }
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
  '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
  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
  # 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
  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
  ❌ <b>Error:</b> {str(e)}
360
  </div>
361
  """
362
+ return None, None, None, error_html
363
 
364
 
365
  # Custom CSS - subtle styling
 
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
  """
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
  )
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
  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