shukdevdatta123 commited on
Commit
5143597
·
verified ·
1 Parent(s): d55ebbb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -126
app.py CHANGED
@@ -33,15 +33,15 @@ def generate_prisma_flow_chart(records_db, records_other, duplicates, excluded_s
33
 
34
  records_after_duplicates = records_db + records_other - duplicates
35
 
36
- # Create SVG content for PRISMA flow chart with centered layout and larger boxes
37
  meta_analysis_section = ''
38
  if included_meta is not None:
39
  meta_analysis_section = f'''
40
- <line x1="400" y1="490" x2="400" y2="530" class="arrow" />
41
- <rect x="250" y="530" width="300" height="80" class="box" />
42
- <text x="400" y="570" class="box-title">Meta-Analysis</text>
43
- <text x="400" y="595">Studies included in quantitative synthesis</text>
44
- <text x="400" y="610">(n = {included_meta})</text>
45
  '''
46
 
47
  svg_content = f'''
@@ -61,9 +61,11 @@ def generate_prisma_flow_chart(records_db, records_other, duplicates, excluded_s
61
  font-family: Arial, sans-serif;
62
  font-size: 14px;
63
  text-anchor: middle;
 
64
  }}
65
  .box-title {{
66
  font-weight: bold;
 
67
  }}
68
  </style>
69
 
@@ -73,67 +75,67 @@ def generate_prisma_flow_chart(records_db, records_other, duplicates, excluded_s
73
  </marker>
74
  </defs>
75
 
 
 
 
76
  <!-- Identification Section -->
77
- <rect x="200" y="30" width="400" height="80" class="box" />
78
- <text x="400" y="70" class="box-title">Identification</text>
79
- <text x="400" y="95">Records identified through database searching</text>
80
- <text x="400" y="110">(n = {records_db})</text>
81
 
82
- <rect x="600" y="30" width="200" height="80" class="box" />
83
- <text x="700" y="70" class="box-title">Additional</text>
84
- <text x="700" y="95">Other sources</text>
85
- <text x="700" y="110">(n = {records_other})</text>
86
 
87
  <!-- Arrows -->
88
- <line x1="400" y1="110" x2="400" y2="150" class="arrow" />
89
- <line x1="700" y1="110" x2="700" y2="130" class="arrow" />
90
- <line x1="700" y1="130" x2="400" y2="130" class="arrow" />
91
 
92
  <!-- Screening Section -->
93
- <rect x="200" y="150" width="400" height="80" class="box" />
94
- <text x="400" y="190" class="box-title">Screening</text>
95
- <text x="400" y="215">Records after duplicates removed</text>
96
- <text x="400" y="230">(n = {records_after_duplicates})</text>
97
 
98
- <line x1="400" y1="230" x2="400" y2="270" class="arrow" />
99
 
100
- <rect x="200" y="270" width="400" height="80" class="box" />
101
- <text x="400" y="310" class="box-title">Title/Abstract Screening</text>
102
- <text x="400" y="335">Records screened</text>
103
- <text x="400" y="350">(n = {records_after_duplicates})</text>
 
104
 
105
- <rect x="600" y="270" width="200" height="80" class="box" />
106
- <text x="700" y="310">Records excluded</text>
107
- <text x="700" y="325">(n = {excluded_screening})</text>
108
 
109
- <line x1="400" y1="350" x2="400" y2="390" class="arrow" />
110
- <line x1="500" y1="310" x2="600" y2="310" class="arrow" />
111
 
112
  <!-- Eligibility Section -->
113
- <rect x="200" y="390" width="400" height="80" class="box" />
114
- <text x="400" y="430" class="box-title">Eligibility</text>
115
- <text x="400" y="455">Full-text articles assessed for eligibility</text>
116
- <text x="400" y="470">(n = {fulltext_assessed})</text>
117
 
118
- <rect x="600" y="390" width="200" height="80" class="box" />
119
- <text x="700" y="430">Full-text articles</text>
120
- <text x="700" y="445">excluded, with reasons</text>
121
- <text x="700" y="460">(n = {excluded_fulltext})</text>
122
 
123
- <line x1="400" y1="470" x2="400" y2="510" class="arrow" />
124
- <line x1="500" y1="430" x2="600" y2="430" class="arrow" />
125
 
126
  <!-- Included Section -->
127
- <rect x="200" y="510" width="400" height="80" class="box" />
128
- <text x="400" y="550" class="box-title">Included</text>
129
- <text x="400" y="575">Studies included in qualitative synthesis</text>
130
- <text x="400" y="590">(n = {included_studies})</text>
131
 
132
  <!-- Optional Meta-Analysis Box -->
133
  {meta_analysis_section}
134
-
135
- <!-- PRISMA Title -->
136
- <text x="400" y="10" style="font-size: 18px; font-weight: bold; text-anchor: middle;">PRISMA Flow Diagram</text>
137
  </svg>
138
  '''
139
 
@@ -263,7 +265,6 @@ def generate_systematic_review(pdf_files, review_question, prisma_numbers, inclu
263
  )
264
 
265
  # Find a suitable place to insert the PRISMA flow chart
266
- # Look for the methodology section or PRISMA mentions
267
  prisma_html = f'''
268
  <div class="prisma-flow-chart">
269
  <h3>Figure 1: PRISMA Flow Diagram</h3>
@@ -271,22 +272,18 @@ def generate_systematic_review(pdf_files, review_question, prisma_numbers, inclu
271
  </div>
272
  '''
273
 
274
- # Try to insert PRISMA diagram after methodology section or before results
275
  if "<h2>3. Methodology" in review_content:
276
  parts = review_content.split("<h2>3. Methodology", 1)
277
  if len(parts) > 1:
278
- # Find the next h2 section after methodology
279
  next_section = parts[1].find("<h2>")
280
  if next_section > -1:
281
  review_content = parts[0] + "<h2>3. Methodology" + parts[1][:next_section] + prisma_html + parts[1][next_section:]
282
  else:
283
  review_content = parts[0] + "<h2>3. Methodology" + parts[1] + prisma_html
284
  else:
285
- # If methodology section not found, insert before results or at the end
286
  insert_pos = review_content.find("<h2>4.") if "<h2>4." in review_content else len(review_content) - 100
287
  review_content = review_content[:insert_pos] + prisma_html + review_content[insert_pos:]
288
 
289
- # Apply professional academic paper styling
290
  styled_html = f"""
291
  <!DOCTYPE html>
292
  <html lang="en">
@@ -295,7 +292,6 @@ def generate_systematic_review(pdf_files, review_question, prisma_numbers, inclu
295
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
296
  <title>Systematic Review</title>
297
  <style>
298
- /* Academic Paper Styling */
299
  body {{
300
  font-family: 'Times New Roman', Times, serif;
301
  line-height: 1.6;
@@ -453,9 +449,7 @@ def save_uploaded_files(files):
453
  saved_paths = []
454
  for file in files:
455
  if file is not None:
456
- # Create a temporary file
457
  with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
458
- # Read the content from the file path provided by Gradio
459
  with open(file, "rb") as src_file:
460
  tmp_file.write(src_file.read())
461
  saved_paths.append(tmp_file.name)
@@ -467,11 +461,9 @@ def create_html_download_link(html_content):
467
  if not html_content or "<div style=\"color: red; padding: 20px;" in html_content or "Please upload at least one PDF file" in html_content:
468
  return None
469
 
470
- # Create timestamp for the filename
471
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
472
  filename = f"systematic_review_{timestamp}.html"
473
 
474
- # Encode the HTML content for download
475
  b64_html = base64.b64encode(html_content.encode()).decode()
476
  download_link = f'<a href="data:text/html;base64,{b64_html}" download="{filename}" class="download-button">Download HTML</a>'
477
 
@@ -480,39 +472,32 @@ def create_html_download_link(html_content):
480
  # Add CSS styling for the Gradio interface
481
  custom_css = """
482
  <style>
483
- /* Main UI */
484
- .gradio-container {
485
  font-family: 'Arial', sans-serif;
486
  background-color: #f9f9f9;
487
- }
488
-
489
- /* Header */
490
- h1 {
491
  font-size: 28px;
492
  color: #333;
493
  margin-bottom: 20px;
494
  text-align: center;
495
  padding-bottom: 10px;
496
  border-bottom: 2px solid #4a00e0;
497
- }
498
-
499
- /* Primary Button */
500
- #generate_button {
501
  background: linear-gradient(135deg, #4a00e0 0%, #8e2de2 100%);
502
  color: white;
503
  font-weight: bold;
504
  padding: 10px 20px;
505
  border-radius: 5px;
506
  transition: all 0.3s ease;
507
- }
508
- #generate_button:hover {
509
  background: linear-gradient(135deg, #5b10f1 0%, #9f3ef3 100%);
510
  transform: translateY(-2px);
511
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
512
- }
513
-
514
- /* API Key Button */
515
- #api_key_button {
516
  background: linear-gradient(135deg, #68d391 0%, #48bb78 100%);
517
  color: white;
518
  font-weight: bold;
@@ -520,56 +505,44 @@ custom_css = """
520
  padding: 10px 20px;
521
  border-radius: 5px;
522
  transition: all 0.3s ease;
523
- }
524
- #api_key_button:hover {
525
  background: linear-gradient(135deg, #38a169 0%, #68d391 100%);
526
  transform: translateY(-2px);
527
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
528
- }
529
-
530
- /* Form Elements */
531
- .input-container {
532
  background-color: white;
533
  padding: 20px;
534
  border-radius: 8px;
535
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
536
  margin-bottom: 20px;
537
- }
538
-
539
- /* Labels */
540
- label {
541
  font-weight: 600;
542
  color: #555;
543
  margin-bottom: 8px;
544
- }
545
-
546
- /* Instructions Accordion */
547
- .accordion {
548
  background-color: white;
549
  border: 1px solid #e0e0e0;
550
  border-radius: 8px;
551
  margin-bottom: 20px;
552
- }
553
-
554
- /* Output Container */
555
- .output-container {
556
  background-color: white;
557
  padding: 15px;
558
  border-radius: 8px;
559
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
560
- }
561
-
562
- /* File Upload Area */
563
- .file-upload {
564
  border: 2px dashed #ccc;
565
  border-radius: 5px;
566
  padding: 20px;
567
  text-align: center;
568
  margin-bottom: 20px;
569
- }
570
-
571
- /* Download Button */
572
- .download-button {
573
  display: inline-block;
574
  background: linear-gradient(135deg, #4a00e0 0%, #8e2de2 100%);
575
  color: white;
@@ -579,47 +552,40 @@ custom_css = """
579
  text-decoration: none;
580
  margin-bottom: 10px;
581
  transition: all 0.3s ease;
582
- }
583
- .download-button:hover {
584
  background: linear-gradient(135deg, #5b10f1 0%, #9f3ef3 100%);
585
  transform: translateY(-2px);
586
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
587
- }
588
-
589
- /* Download Container */
590
- #download-container {
591
  display: flex;
592
  justify-content: center;
593
  margin: 20px 0;
594
  padding: 15px;
595
  background-color: #f5f5f5;
596
  border-radius: 8px;
597
- }
598
-
599
- /* PRISMA Flow Chart Container */
600
- .prisma-section {
601
  background-color: white;
602
  padding: 20px;
603
  border-radius: 8px;
604
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
605
  margin-bottom: 20px;
606
- }
607
-
608
- .prisma-form {
609
  display: grid;
610
  grid-template-columns: 1fr 1fr;
611
  gap: 15px;
612
- }
613
-
614
- /* Responsive adjustments */
615
- @media screen and (max-width: 768px) {
616
- .gradio-container {
617
  padding: 10px;
618
- }
619
- .prisma-form {
620
  grid-template-columns: 1fr;
621
- }
622
- }
623
  </style>
624
  """
625
 
@@ -723,10 +689,10 @@ with gr.Blocks(css=custom_css) as demo:
723
  <div style="width: 30%; height: 100%; background: linear-gradient(90deg, #4a00e0, #8e2de2); animation: progress 2s infinite linear;"></div>
724
  </div>
725
  <style>
726
- @keyframes progress {
727
- 0% { margin-left: -30%; }
728
- 100% { margin-left: 100%; }
729
- }
730
  </style>
731
  </div>
732
  """
 
33
 
34
  records_after_duplicates = records_db + records_other - duplicates
35
 
36
+ # Create SVG content for PRISMA flow chart with clean and centered layout
37
  meta_analysis_section = ''
38
  if included_meta is not None:
39
  meta_analysis_section = f'''
40
+ <line x1="400" y1="580" x2="400" y2="620" class="arrow" />
41
+ <rect x="300" y="620" width="200" height="80" class="box" />
42
+ <text x="400" y="650" class="box-title">Meta-Analysis</text>
43
+ <text x="400" y="670">Studies included in quantitative</text>
44
+ <text x="400" y="685">synthesis (n = {included_meta})</text>
45
  '''
46
 
47
  svg_content = f'''
 
61
  font-family: Arial, sans-serif;
62
  font-size: 14px;
63
  text-anchor: middle;
64
+ dominant-baseline: middle;
65
  }}
66
  .box-title {{
67
  font-weight: bold;
68
+ font-size: 16px;
69
  }}
70
  </style>
71
 
 
75
  </marker>
76
  </defs>
77
 
78
+ <!-- PRISMA Title -->
79
+ <text x="400" y="20" style="font-size: 18px; font-weight: bold; text-anchor: middle;">PRISMA Flow Diagram</text>
80
+
81
  <!-- Identification Section -->
82
+ <rect x="250" y="60" width="300" height="80" class="box" />
83
+ <text x="400" y="100" class="box-title">Identification</text>
84
+ <text x="400" y="120">Records identified through</text>
85
+ <text x="400" y="135">database searching (n = {records_db})</text>
86
 
87
+ <rect x="550" y="60" width="200" height="80" class="box" />
88
+ <text x="650" y="100" class="box-title">Additional</text>
89
+ <text x="650" y="120">Other sources</text>
90
+ <text x="650" y="135">(n = {records_other})</text>
91
 
92
  <!-- Arrows -->
93
+ <line x1="400" y1="140" x2="400" y2="180" class="arrow" />
94
+ <line x1="650" y1="140" x2="650" y2="160" class="arrow" />
95
+ <line x1="650" y1="160" x2="400" y2="160" class="arrow" />
96
 
97
  <!-- Screening Section -->
98
+ <rect x="250" y="180" width="300" height="80" class="box" />
99
+ <text x="400" y="220" class="box-title">Screening</text>
100
+ <text x="400" y="240">Records after duplicates removed</text>
101
+ <text x="400" y="255">(n = {records_after_duplicates})</text>
102
 
103
+ <line x1="400" y1="260" x2="400" y2="300" class="arrow" />
104
 
105
+ <!-- Title/Abstract Screening Section -->
106
+ <rect x="250" y="300" width="300" height="80" class="box" />
107
+ <text x="400" y="340" class="box-title">Title/Abstract Screening</text>
108
+ <text x="400" y="360">Records screened</text>
109
+ <text x="400" y="375">(n = {records_after_duplicates})</text>
110
 
111
+ <rect x="550" y="300" width="200" height="80" class="box" />
112
+ <text x="650" y="340">Records excluded</text>
113
+ <text x="650" y="355">(n = {excluded_screening})</text>
114
 
115
+ <line x1="400" y1="380" x2="400" y2="420" class="arrow" />
116
+ <line x1="500" y1="340" x2="550" y2="340" class="arrow" />
117
 
118
  <!-- Eligibility Section -->
119
+ <rect x="250" y="420" width="300" height="80" class="box" />
120
+ <text x="400" y="460" class="box-title">Eligibility</text>
121
+ <text x="400" y="480">Full-text articles assessed for</text>
122
+ <text x="400" y="495">eligibility (n = {fulltext_assessed})</text>
123
 
124
+ <rect x="550" y="420" width="200" height="80" class="box" />
125
+ <text x="650" y="460">Full-text articles excluded,</text>
126
+ <text x="650" y="475">with reasons (n = {excluded_fulltext})</text>
 
127
 
128
+ <line x1="400" y1="500" x2="400" y2="540" class="arrow" />
129
+ <line x1="500" y1="460" x2="550" y2="460" class="arrow" />
130
 
131
  <!-- Included Section -->
132
+ <rect x="250" y="540" width="300" height="80" class="box" />
133
+ <text x="400" y="580" class="box-title">Included</text>
134
+ <text x="400" y="600">Studies included in qualitative</text>
135
+ <text x="400" y="615">synthesis (n = {included_studies})</text>
136
 
137
  <!-- Optional Meta-Analysis Box -->
138
  {meta_analysis_section}
 
 
 
139
  </svg>
140
  '''
141
 
 
265
  )
266
 
267
  # Find a suitable place to insert the PRISMA flow chart
 
268
  prisma_html = f'''
269
  <div class="prisma-flow-chart">
270
  <h3>Figure 1: PRISMA Flow Diagram</h3>
 
272
  </div>
273
  '''
274
 
 
275
  if "<h2>3. Methodology" in review_content:
276
  parts = review_content.split("<h2>3. Methodology", 1)
277
  if len(parts) > 1:
 
278
  next_section = parts[1].find("<h2>")
279
  if next_section > -1:
280
  review_content = parts[0] + "<h2>3. Methodology" + parts[1][:next_section] + prisma_html + parts[1][next_section:]
281
  else:
282
  review_content = parts[0] + "<h2>3. Methodology" + parts[1] + prisma_html
283
  else:
 
284
  insert_pos = review_content.find("<h2>4.") if "<h2>4." in review_content else len(review_content) - 100
285
  review_content = review_content[:insert_pos] + prisma_html + review_content[insert_pos:]
286
 
 
287
  styled_html = f"""
288
  <!DOCTYPE html>
289
  <html lang="en">
 
292
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
293
  <title>Systematic Review</title>
294
  <style>
 
295
  body {{
296
  font-family: 'Times New Roman', Times, serif;
297
  line-height: 1.6;
 
449
  saved_paths = []
450
  for file in files:
451
  if file is not None:
 
452
  with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
 
453
  with open(file, "rb") as src_file:
454
  tmp_file.write(src_file.read())
455
  saved_paths.append(tmp_file.name)
 
461
  if not html_content or "<div style=\"color: red; padding: 20px;" in html_content or "Please upload at least one PDF file" in html_content:
462
  return None
463
 
 
464
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
465
  filename = f"systematic_review_{timestamp}.html"
466
 
 
467
  b64_html = base64.b64encode(html_content.encode()).decode()
468
  download_link = f'<a href="data:text/html;base64,{b64_html}" download="{filename}" class="download-button">Download HTML</a>'
469
 
 
472
  # Add CSS styling for the Gradio interface
473
  custom_css = """
474
  <style>
475
+ .gradio-container {{
 
476
  font-family: 'Arial', sans-serif;
477
  background-color: #f9f9f9;
478
+ }}
479
+ h1 {{
 
 
480
  font-size: 28px;
481
  color: #333;
482
  margin-bottom: 20px;
483
  text-align: center;
484
  padding-bottom: 10px;
485
  border-bottom: 2px solid #4a00e0;
486
+ }}
487
+ #generate_button {{
 
 
488
  background: linear-gradient(135deg, #4a00e0 0%, #8e2de2 100%);
489
  color: white;
490
  font-weight: bold;
491
  padding: 10px 20px;
492
  border-radius: 5px;
493
  transition: all 0.3s ease;
494
+ }}
495
+ #generate_button:hover {{
496
  background: linear-gradient(135deg, #5b10f1 0%, #9f3ef3 100%);
497
  transform: translateY(-2px);
498
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
499
+ }}
500
+ #api_key_button {{
 
 
501
  background: linear-gradient(135deg, #68d391 0%, #48bb78 100%);
502
  color: white;
503
  font-weight: bold;
 
505
  padding: 10px 20px;
506
  border-radius: 5px;
507
  transition: all 0.3s ease;
508
+ }}
509
+ #api_key_button:hover {{
510
  background: linear-gradient(135deg, #38a169 0%, #68d391 100%);
511
  transform: translateY(-2px);
512
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
513
+ }}
514
+ .input-container {{
 
 
515
  background-color: white;
516
  padding: 20px;
517
  border-radius: 8px;
518
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
519
  margin-bottom: 20px;
520
+ }}
521
+ label {{
 
 
522
  font-weight: 600;
523
  color: #555;
524
  margin-bottom: 8px;
525
+ }}
526
+ .accordion {{
 
 
527
  background-color: white;
528
  border: 1px solid #e0e0e0;
529
  border-radius: 8px;
530
  margin-bottom: 20px;
531
+ }}
532
+ .output-container {{
 
 
533
  background-color: white;
534
  padding: 15px;
535
  border-radius: 8px;
536
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
537
+ }}
538
+ .file-upload {{
 
 
539
  border: 2px dashed #ccc;
540
  border-radius: 5px;
541
  padding: 20px;
542
  text-align: center;
543
  margin-bottom: 20px;
544
+ }}
545
+ .download-button {{
 
 
546
  display: inline-block;
547
  background: linear-gradient(135deg, #4a00e0 0%, #8e2de2 100%);
548
  color: white;
 
552
  text-decoration: none;
553
  margin-bottom: 10px;
554
  transition: all 0.3s ease;
555
+ }}
556
+ .download-button:hover {{
557
  background: linear-gradient(135deg, #5b10f1 0%, #9f3ef3 100%);
558
  transform: translateY(-2px);
559
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
560
+ }}
561
+ #download-container {{
 
 
562
  display: flex;
563
  justify-content: center;
564
  margin: 20px 0;
565
  padding: 15px;
566
  background-color: #f5f5f5;
567
  border-radius: 8px;
568
+ }}
569
+ .prisma-section {{
 
 
570
  background-color: white;
571
  padding: 20px;
572
  border-radius: 8px;
573
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
574
  margin-bottom: 20px;
575
+ }}
576
+ .prisma-form {{
 
577
  display: grid;
578
  grid-template-columns: 1fr 1fr;
579
  gap: 15px;
580
+ }}
581
+ @media screen and (max-width: 768px) {{
582
+ .gradio-container {{
 
 
583
  padding: 10px;
584
+ }}
585
+ .prisma-form {{
586
  grid-template-columns: 1fr;
587
+ }}
588
+ }}
589
  </style>
590
  """
591
 
 
689
  <div style="width: 30%; height: 100%; background: linear-gradient(90deg, #4a00e0, #8e2de2); animation: progress 2s infinite linear;"></div>
690
  </div>
691
  <style>
692
+ @keyframes progress {{
693
+ 0% {{ margin-left: -30%; }}
694
+ 100% {{ margin-left: 100%; }}
695
+ }}
696
  </style>
697
  </div>
698
  """