HaanIlango commited on
Commit
fde0a5b
·
verified ·
1 Parent(s): 1ed4013

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -3
app.py CHANGED
@@ -8,10 +8,17 @@ from huggingface_hub import snapshot_download
8
  import pytesseract
9
  import io
10
  import math
 
 
 
11
  from collections import defaultdict
12
  import matplotlib
13
  matplotlib.use("Agg")
14
  import matplotlib.pyplot as plt
 
 
 
 
15
 
16
  _msi_model = None
17
 
@@ -240,6 +247,8 @@ def identify_hotspots(saliency_map, img_h, img_w, top_n=4):
240
  "intensity": round(avg_intensity * 100, 1), "cx": int(cx), "cy": int(cy)})
241
  zones.sort(key=lambda z: -z["intensity"])
242
  top_zones = zones[:top_n]
 
 
243
  top_zones.sort(key=lambda z: (z["cy"], z["cx"]))
244
  return top_zones
245
 
@@ -397,6 +406,76 @@ def draw_issue_markers(overlay_bgr, issue_boxes):
397
  return img
398
 
399
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  def draw_zone_labels(overlay_bgr, zones):
401
  img = overlay_bgr.copy()
402
  for i, z in enumerate(zones, 1):
@@ -429,6 +508,7 @@ def analyze(pil_image, overlay_strength):
429
  tips = generate_recommendations(saliency_map, scores, read, h, w)
430
  chart_image = create_score_chart(scores['focus_score'], scores['spread_score'], readability_score)
431
 
 
432
  overlay_bgr = draw_zone_labels(overlay_bgr, zones)
433
  overlay_bgr = draw_issue_markers(overlay_bgr, read.get("issue_boxes", []))
434
  overlay_rgb = cv2.cvtColor(overlay_bgr, cv2.COLOR_BGR2RGB)
@@ -499,9 +579,10 @@ with gr.Blocks(title="Design Analyzer") as demo:
499
  "screens, banner ads, print, packaging.\n"
500
  "- **Attention + readability in one pass**, not two separate tools.\n"
501
  "- **No inflated claims.** A cited, transparent process instead "
502
- "of a marketing number.\n\n"
503
- "Coming soon: exportable PDF reports, before/after comparisons, "
504
- "and attention scan-path visualization."
 
505
  )
506
  with gr.Row():
507
  with gr.Column():
@@ -512,6 +593,9 @@ with gr.Blocks(title="Design Analyzer") as demo:
512
  image_output = gr.Image(label="Heatmap result")
513
  chart_output = gr.Image(label="Scores at a glance")
514
  text_output = gr.Markdown()
 
 
515
  analyze_btn.click(fn=analyze, inputs=[image_input, strength_slider], outputs=[image_output, chart_output, text_output])
 
516
 
517
  demo.launch()
 
8
  import pytesseract
9
  import io
10
  import math
11
+ import os
12
+ import re
13
+ import tempfile
14
  from collections import defaultdict
15
  import matplotlib
16
  matplotlib.use("Agg")
17
  import matplotlib.pyplot as plt
18
+ from reportlab.lib.pagesizes import letter
19
+ from reportlab.lib.units import inch
20
+ from reportlab.lib.styles import getSampleStyleSheet
21
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image as RLImage
22
 
23
  _msi_model = None
24
 
 
247
  "intensity": round(avg_intensity * 100, 1), "cx": int(cx), "cy": int(cy)})
248
  zones.sort(key=lambda z: -z["intensity"])
249
  top_zones = zones[:top_n]
250
+ for idx, z in enumerate(top_zones):
251
+ z["intensity_rank"] = idx + 1
252
  top_zones.sort(key=lambda z: (z["cy"], z["cx"]))
253
  return top_zones
254
 
 
406
  return img
407
 
408
 
409
+ def markdown_to_paragraphs(md_text, styles):
410
+ story = []
411
+ for raw_line in md_text.split("\n"):
412
+ line = raw_line.strip()
413
+ if not line:
414
+ story.append(Spacer(1, 6))
415
+ continue
416
+ if line.startswith("## "):
417
+ story.append(Paragraph(line[3:], styles['Heading1']))
418
+ elif line.startswith("### "):
419
+ story.append(Paragraph(line[4:], styles['Heading2']))
420
+ elif line.startswith("---"):
421
+ story.append(Spacer(1, 10))
422
+ elif line.startswith("- ") or line.startswith("* "):
423
+ text = line[2:]
424
+ text = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', text)
425
+ text = re.sub(r'\*(.*?)\*', r'<i>\1</i>', text)
426
+ story.append(Paragraph("&bull; " + text, styles['Normal']))
427
+ elif re.match(r'^\d+\.\s', line):
428
+ num, text = line.split('.', 1)
429
+ text = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', text.strip())
430
+ story.append(Paragraph(f"{num}. {text}", styles['Normal']))
431
+ else:
432
+ text = re.sub(r'\*\*(.*?)\*\*', r'<b>\1</b>', line)
433
+ text = re.sub(r'\*(.*?)\*', r'<i>\1</i>', text)
434
+ text = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'<link href="\2"><u>\1</u></link>', text)
435
+ story.append(Paragraph(text, styles['Normal']))
436
+ return story
437
+
438
+
439
+ def export_pdf(heatmap_img, chart_img, summary_md):
440
+ if heatmap_img is None or not summary_md:
441
+ return None
442
+ styles = getSampleStyleSheet()
443
+ tmp_dir = tempfile.gettempdir()
444
+ pdf_path = os.path.join(tmp_dir, "design_analysis_report.pdf")
445
+ doc = SimpleDocTemplate(pdf_path, pagesize=letter, topMargin=0.6 * inch, bottomMargin=0.6 * inch,
446
+ leftMargin=0.7 * inch, rightMargin=0.7 * inch)
447
+ story = [Paragraph("Design Analyzer Report", styles['Title']), Spacer(1, 12)]
448
+
449
+ max_width = 6.1 * inch
450
+ heatmap_path = os.path.join(tmp_dir, "heatmap_export_temp.png")
451
+ heatmap_img.save(heatmap_path)
452
+ ratio = heatmap_img.height / heatmap_img.width
453
+ story.append(RLImage(heatmap_path, width=max_width, height=max_width * ratio))
454
+ story.append(Spacer(1, 14))
455
+
456
+ if chart_img is not None:
457
+ chart_path = os.path.join(tmp_dir, "chart_export_temp.png")
458
+ chart_img.save(chart_path)
459
+ chart_ratio = chart_img.height / chart_img.width
460
+ story.append(RLImage(chart_path, width=max_width, height=max_width * chart_ratio))
461
+ story.append(Spacer(1, 14))
462
+
463
+ story.extend(markdown_to_paragraphs(summary_md, styles))
464
+ doc.build(story)
465
+ return pdf_path
466
+
467
+
468
+ def draw_scan_path(overlay_bgr, zones):
469
+ img = overlay_bgr.copy()
470
+ ordered = sorted(zones, key=lambda z: z["intensity_rank"])
471
+ for i in range(len(ordered) - 1):
472
+ pt1 = (ordered[i]["cx"], ordered[i]["cy"])
473
+ pt2 = (ordered[i + 1]["cx"], ordered[i + 1]["cy"])
474
+ cv2.arrowedLine(img, pt1, pt2, (255, 255, 255), 4, tipLength=0.06, line_type=cv2.LINE_AA)
475
+ cv2.arrowedLine(img, pt1, pt2, (20, 20, 20), 2, tipLength=0.06, line_type=cv2.LINE_AA)
476
+ return img
477
+
478
+
479
  def draw_zone_labels(overlay_bgr, zones):
480
  img = overlay_bgr.copy()
481
  for i, z in enumerate(zones, 1):
 
508
  tips = generate_recommendations(saliency_map, scores, read, h, w)
509
  chart_image = create_score_chart(scores['focus_score'], scores['spread_score'], readability_score)
510
 
511
+ overlay_bgr = draw_scan_path(overlay_bgr, zones)
512
  overlay_bgr = draw_zone_labels(overlay_bgr, zones)
513
  overlay_bgr = draw_issue_markers(overlay_bgr, read.get("issue_boxes", []))
514
  overlay_rgb = cv2.cvtColor(overlay_bgr, cv2.COLOR_BGR2RGB)
 
579
  "screens, banner ads, print, packaging.\n"
580
  "- **Attention + readability in one pass**, not two separate tools.\n"
581
  "- **No inflated claims.** A cited, transparent process instead "
582
+ "of a marketing number.\n"
583
+ "- **Scan-path arrows** show the predicted order attention flows, "
584
+ "not just isolated hotspots.\n\n"
585
+ "Coming soon: before/after comparisons."
586
  )
587
  with gr.Row():
588
  with gr.Column():
 
593
  image_output = gr.Image(label="Heatmap result")
594
  chart_output = gr.Image(label="Scores at a glance")
595
  text_output = gr.Markdown()
596
+ pdf_btn = gr.Button("Download PDF Report")
597
+ pdf_output = gr.File(label="PDF Report")
598
  analyze_btn.click(fn=analyze, inputs=[image_input, strength_slider], outputs=[image_output, chart_output, text_output])
599
+ pdf_btn.click(fn=export_pdf, inputs=[image_output, chart_output, text_output], outputs=pdf_output)
600
 
601
  demo.launch()