malavikapradeep2001 commited on
Commit
bccd6ac
Β·
1 Parent(s): 789e997
Files changed (1) hide show
  1. backend/app.py +75 -15
backend/app.py CHANGED
@@ -643,6 +643,10 @@ def create_designed_pdf(pdf_path, report_data, analysis_summary_json, annotated_
643
  if 'YOLO' in model_used or 'yolo' in str(analysis.get('id', '')).lower():
644
  report_type = "CYTOLOGY"
645
  report_title = "Cytology Report"
 
 
 
 
646
  elif 'CIN' in model_used or 'cin' in str(analysis.get('id', '')).lower() or 'colpo' in str(analysis.get('id', '')).lower():
647
  report_type = "COLPOSCOPY"
648
  report_title = "Colposcopy Report"
@@ -694,11 +698,17 @@ def create_designed_pdf(pdf_path, report_data, analysis_summary_json, annotated_
694
  story.append(Paragraph(f"<b>Benign Confidence:</b> {benign_conf:.2f}%", styles['NormalSmall']))
695
  story.append(Paragraph(f"<b>Malignant Confidence:</b> {malignant_conf:.2f}%", styles['NormalSmall']))
696
  elif report_type == "CYTOLOGY":
697
- # For cytology (YOLO), show abnormal/normal cells
698
- if 'abnormal_cells' in ai_summary:
699
- story.append(Paragraph(f"<b>Abnormal Cells:</b> {ai_summary.get('abnormal_cells', 'N/A')}", styles['NormalSmall']))
700
- if 'normal_cells' in ai_summary:
701
- story.append(Paragraph(f"<b>Normal Cells:</b> {ai_summary.get('normal_cells', 'N/A')}", styles['NormalSmall']))
 
 
 
 
 
 
702
  else:
703
  # For CIN/Colposcopy, show class confidences
704
  confidence_dict = ai_summary.get('confidence', {})
@@ -717,8 +727,19 @@ def create_designed_pdf(pdf_path, report_data, analysis_summary_json, annotated_
717
  try:
718
  if os.path.isfile(annotated_image_path):
719
  story.append(Spacer(1, 0.1*inch))
720
- # Use a reasonable width for the embedded image
721
- img = ReportLabImage(annotated_image_path, width=5*inch, kind='proportional')
 
 
 
 
 
 
 
 
 
 
 
722
  story.append(img)
723
  story.append(Spacer(1, 0.2*inch))
724
  except Exception as e:
@@ -812,6 +833,7 @@ async def generate_report(
812
  annotated_img = ai_summary.get('annotated_image_url') or report_data.get("analysis", {}).get("annotated_image_url") or ""
813
  annotated_img_full = ""
814
  annotated_img_local = None
 
815
 
816
  if annotated_img:
817
  # If it's an outputs path served by StaticFiles, map to local file
@@ -836,6 +858,26 @@ async def generate_report(
836
  except Exception as e:
837
  print(f"⚠️ Failed to save uploaded input image for report: {e}")
838
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
839
  # Ensure annotated_img_full has a leading slash if it's a relative path
840
  if annotated_img_full and not annotated_img_full.startswith(('http://', 'https://')):
841
  annotated_img_full = annotated_img_full if annotated_img_full.startswith('/') else '/' + annotated_img_full
@@ -857,6 +899,10 @@ async def generate_report(
857
  if 'YOLO' in model_used or 'yolo' in str(analysis_id).lower():
858
  report_type = "Cytology"
859
  report_title = "Cytology Report"
 
 
 
 
860
  elif 'CIN' in model_used or 'cin' in str(analysis_id).lower() or 'colpo' in str(analysis_id).lower():
861
  report_type = "Colposcopy"
862
  report_title = "Colposcopy Report"
@@ -881,12 +927,23 @@ async def generate_report(
881
  <tr><th>Malignant Confidence</th><td>{malignant_conf:.2f}%</td></tr>
882
  """
883
  elif report_type == "Cytology":
884
- # For cytology (YOLO), show abnormal/normal cells
885
- analysis_metrics_html = f"""
886
- <tr><th>System</th><td>Manalife AI System β€” Automated Analysis</td></tr>
887
- <tr><th>Abnormal Cells</th><td>{ai_summary.get('abnormal_cells', 'N/A')}</td></tr>
888
- <tr><th>Normal Cells</th><td>{ai_summary.get('normal_cells', 'N/A')}</td></tr>
889
- """
 
 
 
 
 
 
 
 
 
 
 
890
  else:
891
  # For CIN/Colposcopy or other models, show generic confidence
892
  confidence_dict = ai_summary.get('confidence', {})
@@ -912,6 +969,9 @@ async def generate_report(
912
  annotated_img_full = ''
913
  annotated_img = annotated_img_full
914
 
 
 
 
915
  download_pdf_btn = f'<a href="{pdf_url}" download style="text-decoration:none"><button class="btn-secondary">Download PDF</button></a>' if pdf_url else ''
916
 
917
  # Format generated time
@@ -922,7 +982,7 @@ async def generate_report(
922
  <head>
923
  <meta charset="utf-8" />
924
  <meta name="viewport" content="width=device-width,initial-scale=1" />
925
- <title>Medical Analysis Report β€” Manalife AI</title>
926
  <style>
927
  :root{{--bg:#f8fafc;--card:#ffffff;--muted:#6b7280;--accent:#0f172a}}
928
  body{{font-family:Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial;margin:0;background:var(--bg);color:var(--accent);line-height:1.45}}
@@ -1009,7 +1069,7 @@ async def generate_report(
1009
  </div>
1010
  </div>
1011
 
1012
- {'<div class="full"><div class="section-title">Annotated Analysis Image</div><img src="' + annotated_img_full + '" class="annotated-image" alt="Annotated Analysis Result" /></div>' if annotated_img else ''}
1013
 
1014
  <div class="full">
1015
  <div class="section-title">Doctor\'s Notes</div>
 
643
  if 'YOLO' in model_used or 'yolo' in str(analysis.get('id', '')).lower():
644
  report_type = "CYTOLOGY"
645
  report_title = "Cytology Report"
646
+ elif 'MWT' in model_used or 'mwt' in str(model_used).lower():
647
+ # MWT is a cytology classifier; use a clearer report title for MWT results
648
+ report_type = "CYTOLOGY"
649
+ report_title = "Cytology Analysis Report"
650
  elif 'CIN' in model_used or 'cin' in str(analysis.get('id', '')).lower() or 'colpo' in str(analysis.get('id', '')).lower():
651
  report_type = "COLPOSCOPY"
652
  report_title = "Colposcopy Report"
 
698
  story.append(Paragraph(f"<b>Benign Confidence:</b> {benign_conf:.2f}%", styles['NormalSmall']))
699
  story.append(Paragraph(f"<b>Malignant Confidence:</b> {malignant_conf:.2f}%", styles['NormalSmall']))
700
  elif report_type == "CYTOLOGY":
701
+ # For cytology and MWT, show class confidences if available, otherwise show abnormal/normal cells
702
+ confidence_dict = ai_summary.get('confidence', {})
703
+ if isinstance(confidence_dict, dict) and confidence_dict:
704
+ for cls, val in confidence_dict.items():
705
+ conf_pct = val * 100 if isinstance(val, (int, float)) else 0
706
+ story.append(Paragraph(f"<b>{cls} Confidence:</b> {conf_pct:.2f}%", styles['NormalSmall']))
707
+ else:
708
+ if 'abnormal_cells' in ai_summary:
709
+ story.append(Paragraph(f"<b>Abnormal Cells:</b> {ai_summary.get('abnormal_cells', 'N/A')}", styles['NormalSmall']))
710
+ if 'normal_cells' in ai_summary:
711
+ story.append(Paragraph(f"<b>Normal Cells:</b> {ai_summary.get('normal_cells', 'N/A')}", styles['NormalSmall']))
712
  else:
713
  # For CIN/Colposcopy, show class confidences
714
  confidence_dict = ai_summary.get('confidence', {})
 
727
  try:
728
  if os.path.isfile(annotated_image_path):
729
  story.append(Spacer(1, 0.1*inch))
730
+ # Determine image pixel size and scale to a reasonable width for PDF
731
+ try:
732
+ from PIL import Image as PILImageLocal
733
+ with PILImageLocal.open(annotated_image_path) as im:
734
+ img_w, img_h = im.size
735
+ except Exception:
736
+ img_w, img_h = (800, 600)
737
+
738
+ # Display width in points (ReportLab uses points; 1 inch = 72 points). Assume 96 DPI for pixel->inch.
739
+ display_width_px = max(300, min(img_w, 800))
740
+ width_points = min(5 * inch, (display_width_px / 96.0) * inch)
741
+
742
+ img = ReportLabImage(annotated_image_path, width=width_points, kind='proportional')
743
  story.append(img)
744
  story.append(Spacer(1, 0.2*inch))
745
  except Exception as e:
 
833
  annotated_img = ai_summary.get('annotated_image_url') or report_data.get("analysis", {}).get("annotated_image_url") or ""
834
  annotated_img_full = ""
835
  annotated_img_local = None
836
+ annotated_img_display_width = None
837
 
838
  if annotated_img:
839
  # If it's an outputs path served by StaticFiles, map to local file
 
858
  except Exception as e:
859
  print(f"⚠️ Failed to save uploaded input image for report: {e}")
860
 
861
+ # If we have a local image file, compute a reasonable display width (px)
862
+ try:
863
+ if annotated_img_local and os.path.isfile(annotated_img_local):
864
+ from PIL import Image as PILImageLocal
865
+ with PILImageLocal.open(annotated_img_local) as im:
866
+ img_w, img_h = im.size
867
+ # Choose display width: cap at 800px, don't go below 300px for visibility
868
+ annotated_img_display_width = max(300, min(img_w, 800))
869
+ elif annotated_img_full and annotated_img_full.startswith('/outputs/'):
870
+ # Map to local and attempt to open
871
+ rel = annotated_img_full[len('/outputs/'):].lstrip('/')
872
+ candidate = os.path.join(OUTPUT_DIR, rel)
873
+ if os.path.isfile(candidate):
874
+ from PIL import Image as PILImageLocal
875
+ with PILImageLocal.open(candidate) as im:
876
+ img_w, img_h = im.size
877
+ annotated_img_display_width = max(300, min(img_w, 800))
878
+ except Exception:
879
+ annotated_img_display_width = None
880
+
881
  # Ensure annotated_img_full has a leading slash if it's a relative path
882
  if annotated_img_full and not annotated_img_full.startswith(('http://', 'https://')):
883
  annotated_img_full = annotated_img_full if annotated_img_full.startswith('/') else '/' + annotated_img_full
 
899
  if 'YOLO' in model_used or 'yolo' in str(analysis_id).lower():
900
  report_type = "Cytology"
901
  report_title = "Cytology Report"
902
+ elif 'MWT' in model_used or 'mwt' in str(model_used).lower() or 'mwt' in str(analysis_id).lower():
903
+ # MWT is a cytology classifier β€” use clearer title
904
+ report_type = "Cytology"
905
+ report_title = "Cytology Analysis Report"
906
  elif 'CIN' in model_used or 'cin' in str(analysis_id).lower() or 'colpo' in str(analysis_id).lower():
907
  report_type = "Colposcopy"
908
  report_title = "Colposcopy Report"
 
927
  <tr><th>Malignant Confidence</th><td>{malignant_conf:.2f}%</td></tr>
928
  """
929
  elif report_type == "Cytology":
930
+ # For cytology (YOLO) or MWT, show class confidences if provided, else abnormal/normal counts
931
+ confidence_dict = ai_summary.get('confidence', {})
932
+ if isinstance(confidence_dict, dict) and confidence_dict:
933
+ confidence_rows = ""
934
+ for cls, val in confidence_dict.items():
935
+ conf_pct = val * 100 if isinstance(val, (int, float)) else 0
936
+ confidence_rows += f"<tr><th>{cls} Confidence</th><td>{conf_pct:.2f}%</td></tr>\n "
937
+ analysis_metrics_html = f"""
938
+ <tr><th>System</th><td>Manalife AI System β€” Automated Analysis</td></tr>
939
+ {confidence_rows}
940
+ """
941
+ else:
942
+ analysis_metrics_html = f"""
943
+ <tr><th>System</th><td>Manalife AI System β€” Automated Analysis</td></tr>
944
+ <tr><th>Abnormal Cells</th><td>{ai_summary.get('abnormal_cells', 'N/A')}</td></tr>
945
+ <tr><th>Normal Cells</th><td>{ai_summary.get('normal_cells', 'N/A')}</td></tr>
946
+ """
947
  else:
948
  # For CIN/Colposcopy or other models, show generic confidence
949
  confidence_dict = ai_summary.get('confidence', {})
 
969
  annotated_img_full = ''
970
  annotated_img = annotated_img_full
971
 
972
+ # Prepare width attribute for the HTML img tag if available
973
+ annotated_img_width_attr = f' width="{annotated_img_display_width}"' if annotated_img_display_width else ''
974
+
975
  download_pdf_btn = f'<a href="{pdf_url}" download style="text-decoration:none"><button class="btn-secondary">Download PDF</button></a>' if pdf_url else ''
976
 
977
  # Format generated time
 
982
  <head>
983
  <meta charset="utf-8" />
984
  <meta name="viewport" content="width=device-width,initial-scale=1" />
985
+ <title>{report_title} β€” Manalife AI</title>
986
  <style>
987
  :root{{--bg:#f8fafc;--card:#ffffff;--muted:#6b7280;--accent:#0f172a}}
988
  body{{font-family:Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial;margin:0;background:var(--bg);color:var(--accent);line-height:1.45}}
 
1069
  </div>
1070
  </div>
1071
 
1072
+ {'<div class="full"><div class="section-title">Annotated Analysis Image</div><img src="' + annotated_img_full + '" class="annotated-image" alt="Annotated Analysis Result"' + annotated_img_width_attr + ' /></div>' if annotated_img else ''}
1073
 
1074
  <div class="full">
1075
  <div class="section-title">Doctor\'s Notes</div>