shukdevdatta123 commited on
Commit
05d1c2e
·
verified ·
1 Parent(s): f5618d5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +79 -276
app.py CHANGED
@@ -24,125 +24,8 @@ def extract_text_from_pdf(pdf_path):
24
  except Exception as e:
25
  return f"Error extracting text from PDF: {str(e)}"
26
 
27
- # Function to generate PRISMA flow chart SVG
28
- def generate_prisma_flow_chart(records_db, records_other, duplicates, excluded_screening, excluded_fulltext, included_studies,
29
- included_meta=None, fulltext_assessed=None):
30
- # Calculate values if not provided
31
- if fulltext_assessed is None:
32
- fulltext_assessed = excluded_fulltext + included_studies
33
-
34
- records_after_duplicates = records_db + records_other - duplicates
35
-
36
- # Create SVG content for PRISMA flow chart with improved arrows, spacing, and centered text
37
- meta_analysis_section = ''
38
- if included_meta is not None:
39
- meta_analysis_section = f'''
40
- <line x1="400" y1="650" x2="400" y2="690" class="arrow" />
41
- <rect x="250" y="690" width="300" height="80" class="box" />
42
- <text x="400" y="710" class="box-title">Meta-Analysis</text>
43
- <text x="400" y="730">Studies included in quantitative</text>
44
- <text x="400" y="750">synthesis (n = {included_meta})</text>
45
- '''
46
-
47
- svg_content = f'''
48
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 900" width="700" height="800">
49
- <style>
50
- .box {{
51
- fill: #f9f9f9;
52
- stroke: #333;
53
- stroke-width: 2;
54
- }}
55
- .arrow {{
56
- stroke: #333;
57
- stroke-width: 2;
58
- marker-end: url(#arrowhead);
59
- }}
60
- text {{
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
-
72
- <defs>
73
- <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
74
- <polygon points="0 0, 10 3.5, 0 7" />
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="90" class="box-title">Identification</text>
84
- <text x="400" y="110">Records identified through</text>
85
- <text x="400" y="125">database searching (n = {records_db})</text>
86
-
87
- <rect x="550" y="60" width="200" height="80" class="box" />
88
- <text x="650" y="90" class="box-title">Additional</text>
89
- <text x="650" y="110">Other sources</text>
90
- <text x="650" y="125">(n = {records_other})</text>
91
-
92
- <!-- Arrows -->
93
- <line x1="400" y1="140" x2="400" y2="190" class="arrow" />
94
- <line x1="650" y1="140" x2="650" y2="165" class="arrow" />
95
- <line x1="650" y1="165" x2="400" y2="165" class="arrow" />
96
-
97
- <!-- Screening Section -->
98
- <rect x="250" y="210" width="300" height="80" class="box" />
99
- <text x="400" y="240" class="box-title">Screening</text>
100
- <text x="400" y="260">Records after duplicates removed</text>
101
- <text x="400" y="275">(n = {records_after_duplicates})</text>
102
-
103
- <line x1="400" y1="290" x2="400" y2="340" class="arrow" />
104
-
105
- <!-- Title/Abstract Screening Section -->
106
- <rect x="250" y="360" width="300" height="80" class="box" />
107
- <text x="400" y="390" class="box-title">Title/Abstract Screening</text>
108
- <text x="400" y="410">Records screened</text>
109
- <text x="400" y="425">(n = {records_after_duplicates})</text>
110
-
111
- <rect x="550" y="360" width="200" height="80" class="box" />
112
- <text x="650" y="390">Records excluded</text>
113
- <text x="650" y="410">(n = {excluded_screening})</text>
114
-
115
- <line x1="400" y1="440" x2="400" y2="490" class="arrow" />
116
- <line x1="550" y1="400" x2="600" y2="400" class="arrow" />
117
-
118
- <!-- Eligibility Section -->
119
- <rect x="250" y="510" width="300" height="80" class="box" />
120
- <text x="400" y="540" class="box-title">Eligibility</text>
121
- <text x="400" y="560">Full-text articles assessed for</text>
122
- <text x="400" y="575">eligibility (n = {fulltext_assessed})</text>
123
-
124
- <rect x="550" y="510" width="200" height="80" class="box" />
125
- <text x="650" y="540">Full-text articles excluded,</text>
126
- <text x="650" y="555">with reasons (n = {excluded_fulltext})</text>
127
-
128
- <line x1="400" y1="590" x2="400" y2="640" class="arrow" />
129
- <line x1="550" y1="550" x2="600" y2="550" class="arrow" />
130
-
131
- <!-- Included Section -->
132
- <rect x="250" y="660" width="300" height="80" class="box" />
133
- <text x="400" y="690" class="box-title">Included</text>
134
- <text x="400" y="710">Studies included in qualitative</text>
135
- <text x="400" y="725">synthesis (n = {included_studies})</text>
136
-
137
- <!-- Optional Meta-Analysis Box -->
138
- {meta_analysis_section}
139
- </svg>
140
- '''
141
-
142
- return svg_content
143
-
144
  # Function to interact with OpenAI API for systematic review
145
- def generate_systematic_review(pdf_files, review_question, prisma_numbers, include_tables=True):
146
  if not api_key:
147
  return "Please enter your OpenAI API key first."
148
 
@@ -195,7 +78,6 @@ def generate_systematic_review(pdf_files, review_question, prisma_numbers, inclu
195
  Include a comprehensive reference list following a specific citation style (APA, Vancouver, etc.). Provide links to source papers when available.
196
 
197
  Your response should be formatted in HTML (but avoid showing these tags ```html ```) but generate the content to look like a professional academic paper. Include proper section headers, abstracts, methodology sections, etc. Number all sections like an academic paper. Follow academic journal standards with double spacing, appropriate margins, and consistent formatting throughout.
198
- Make sure to include that you conducted a PRISMA flow diagram as part of the methodology section. Reference the PRISMA diagram in your methodology section and explain the numbers used in the diagram.
199
  """
200
 
201
  # Extract text from each PDF
@@ -218,22 +100,8 @@ def generate_systematic_review(pdf_files, review_question, prisma_numbers, inclu
218
  table_instruction = ""
219
  if include_tables:
220
  table_instruction = " Please include important new generated tables in your review."
221
-
222
- # Add PRISMA flow information
223
- prisma_info = f"""
224
- Additionally, I have conducted a PRISMA flow diagram with the following data:
225
- - Records identified through database searching: {prisma_numbers['records_db']}
226
- - Additional records identified through other sources: {prisma_numbers['records_other']}
227
- - Records after duplicates removed: {int(prisma_numbers['records_db']) + int(prisma_numbers['records_other']) - int(prisma_numbers['duplicates'])}
228
- - Records excluded during title/abstract screening: {prisma_numbers['excluded_screening']}
229
- - Full-text articles excluded with reasons: {prisma_numbers['excluded_fulltext']}
230
- - Studies included in qualitative synthesis: {prisma_numbers['included_studies']}
231
- """
232
-
233
- if prisma_numbers.get('included_meta') and prisma_numbers['included_meta'].strip():
234
- prisma_info += f"- Studies included in quantitative synthesis (meta-analysis): {prisma_numbers['included_meta']}\n"
235
 
236
- user_prompt = f"Please generate a systematic review of the following {len(pdf_files)} papers: {', '.join(pdf_names)}.{table_instruction}\n\nReview Question: {review_question}\n\n{prisma_info}"
237
 
238
  # Create the messages for the API call
239
  messages = [
@@ -253,37 +121,7 @@ def generate_systematic_review(pdf_files, review_question, prisma_numbers, inclu
253
  # Get the AI response
254
  review_content = response["choices"][0]["message"]["content"]
255
 
256
- # Generate PRISMA flow chart SVG
257
- prisma_svg = generate_prisma_flow_chart(
258
- int(prisma_numbers['records_db']),
259
- int(prisma_numbers['records_other']),
260
- int(prisma_numbers['duplicates']),
261
- int(prisma_numbers['excluded_screening']),
262
- int(prisma_numbers['excluded_fulltext']),
263
- int(prisma_numbers['included_studies']),
264
- int(prisma_numbers['included_meta']) if prisma_numbers.get('included_meta') and prisma_numbers['included_meta'].strip() else None
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>
271
- {prisma_svg}
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,6 +130,7 @@ def generate_systematic_review(pdf_files, review_question, prisma_numbers, inclu
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;
@@ -405,13 +244,6 @@ def generate_systematic_review(pdf_files, review_question, prisma_numbers, inclu
405
  font-size: 12px;
406
  color: #777;
407
  }}
408
- .prisma-flow-chart {{
409
- margin: 30px 0;
410
- text-align: center;
411
- }}
412
- .prisma-flow-chart h3 {{
413
- margin-bottom: 15px;
414
- }}
415
  @media print {{
416
  body {{
417
  background-color: white;
@@ -449,9 +281,9 @@ def save_uploaded_files(files):
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)
456
 
457
  return saved_paths
@@ -461,9 +293,11 @@ def create_html_download_link(html_content):
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,32 +306,39 @@ def create_html_download_link(html_content):
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,44 +346,56 @@ custom_css = """
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,46 +405,35 @@ custom_css = """
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
 
592
  # Gradio UI Layout with improved styling
593
  with gr.Blocks(css=custom_css) as demo:
594
- gr.Markdown("# Systematic Review Generator with PRISMA Flow Chart")
595
 
596
  with gr.Accordion("How to Use This App", open=False):
597
  gr.Markdown("""
@@ -599,15 +441,9 @@ with gr.Blocks(css=custom_css) as demo:
599
  1. Enter your OpenAI API key in the field below and click "Set API Key"
600
  2. Upload multiple PDF research papers (2 or more recommended)
601
  3. Enter your review question or topic
602
- 4. Fill in the PRISMA flow chart information (numbers at each stage of your review)
603
- 5. Check the "Include Tables" option if you want the review to include comparison tables
604
- 6. Click "Generate Systematic Review" to start the process
605
- 7. After generation, you can download the review as HTML
606
-
607
- ### PRISMA Flow Chart:
608
- - The PRISMA (Preferred Reporting Items for Systematic Reviews and Meta-Analyses) flow diagram shows the flow of information through the different phases of your systematic review
609
- - Fill in the numbers for each stage to generate an accurate diagram
610
- - The diagram will be embedded in your systematic review
611
 
612
  ### Tips for Best Results:
613
  - Upload papers that are related to the same research topic or field
@@ -629,30 +465,14 @@ with gr.Blocks(css=custom_css) as demo:
629
  with gr.Row(elem_classes="input-container"):
630
  with gr.Column():
631
  gr.Markdown("### Upload Research Papers")
632
- pdf_files = gr.File(label="Upload PDF Research Papers", file_count="multiple", file_types=[".pdf"], elem_classes="file-upload")
633
  review_question = gr.Textbox(
634
  label="Review Question or Topic",
635
  value="Please generate a systematic review of the following papers.",
636
  placeholder="e.g., What are the effects of mindfulness meditation on stress reduction?"
637
  )
638
  include_tables = gr.Checkbox(label="Include Comparison Tables", value=True)
639
-
640
- # PRISMA Flow Chart inputs
641
- with gr.Row(elem_classes="prisma-section"):
642
- with gr.Column():
643
- gr.Markdown("### PRISMA Flow Chart Information")
644
- gr.Markdown("Enter the numbers for each stage of your systematic review process:")
645
-
646
- with gr.Row(elem_classes="prisma-form"):
647
- prisma_records_db = gr.Textbox(label="Records from database searching", value="100", placeholder="e.g., 100")
648
- prisma_records_other = gr.Textbox(label="Records from other sources", value="20", placeholder="e.g., 20")
649
- prisma_duplicates = gr.Textbox(label="Duplicates removed", value="15", placeholder="e.g., 15")
650
- prisma_excluded_screening = gr.Textbox(label="Records excluded at screening", value="60", placeholder="e.g., 60")
651
- prisma_excluded_fulltext = gr.Textbox(label="Full-text articles excluded", value="30", placeholder="e.g., 30")
652
- prisma_included_studies = gr.Textbox(label="Studies included in synthesis", value="15", placeholder="e.g., 15")
653
- prisma_included_meta = gr.Textbox(label="Studies in meta-analysis (optional)", value="10", placeholder="e.g., 10")
654
-
655
- generate_button = gr.Button("Generate Systematic Review", elem_id="generate_button")
656
 
657
  # Download link container
658
  download_html_output = gr.HTML(label="Download Options")
@@ -665,10 +485,7 @@ with gr.Blocks(css=custom_css) as demo:
665
  api_key_button.click(set_api_key, inputs=[api_key_input], outputs=[api_key_output])
666
 
667
  # Generate systematic review
668
- def process_files_and_generate_review(files, question, include_tables,
669
- records_db, records_other, duplicates,
670
- excluded_screening, excluded_fulltext,
671
- included_studies, included_meta):
672
  if not files:
673
  return ("""
674
  <div style="padding: 20px; border: 1px solid #e0e0e0; border-radius: 5px; background-color: #f9f9f9;">
@@ -683,35 +500,24 @@ with gr.Blocks(css=custom_css) as demo:
683
  # Show loading message
684
  loading_message = """
685
  <div style="padding: 20px; text-align: center;">
686
- <h3>Generating Systematic Review with PRISMA Flow Chart...</h3>
687
  <p>This may take a few minutes depending on the number and size of papers.</p>
688
  <div style="width: 100%; height: 4px; background-color: #f0f0f0; margin: 20px 0; border-radius: 2px; overflow: hidden;">
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
  """
699
 
700
  yield loading_message, ""
701
 
702
- # Collect PRISMA flow chart data
703
- prisma_numbers = {
704
- 'records_db': records_db,
705
- 'records_other': records_other,
706
- 'duplicates': duplicates,
707
- 'excluded_screening': excluded_screening,
708
- 'excluded_fulltext': excluded_fulltext,
709
- 'included_studies': included_studies,
710
- 'included_meta': included_meta
711
- }
712
-
713
- # Generate review with PRISMA flow chart
714
- review = generate_systematic_review(saved_paths, question, prisma_numbers, include_tables)
715
 
716
  # Create HTML download link
717
  html_link = create_html_download_link(review)
@@ -737,13 +543,10 @@ with gr.Blocks(css=custom_css) as demo:
737
 
738
  generate_button.click(
739
  process_files_and_generate_review,
740
- inputs=[pdf_files, review_question, include_tables,
741
- prisma_records_db, prisma_records_other, prisma_duplicates,
742
- prisma_excluded_screening, prisma_excluded_fulltext,
743
- prisma_included_studies, prisma_included_meta],
744
  outputs=[review_output, download_html_output]
745
  )
746
 
747
  # Launch the app
748
  if __name__ == "__main__":
749
- demo.launch()
 
24
  except Exception as e:
25
  return f"Error extracting text from PDF: {str(e)}"
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  # Function to interact with OpenAI API for systematic review
28
+ def generate_systematic_review(pdf_files, review_question, include_tables=True):
29
  if not api_key:
30
  return "Please enter your OpenAI API key first."
31
 
 
78
  Include a comprehensive reference list following a specific citation style (APA, Vancouver, etc.). Provide links to source papers when available.
79
 
80
  Your response should be formatted in HTML (but avoid showing these tags ```html ```) but generate the content to look like a professional academic paper. Include proper section headers, abstracts, methodology sections, etc. Number all sections like an academic paper. Follow academic journal standards with double spacing, appropriate margins, and consistent formatting throughout.
 
81
  """
82
 
83
  # Extract text from each PDF
 
100
  table_instruction = ""
101
  if include_tables:
102
  table_instruction = " Please include important new generated tables in your review."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
+ user_prompt = f"Please generate a systematic review of the following {len(pdf_files)} papers: {', '.join(pdf_names)}.{table_instruction}\n\nReview Question: {review_question}"
105
 
106
  # Create the messages for the API call
107
  messages = [
 
121
  # Get the AI response
122
  review_content = response["choices"][0]["message"]["content"]
123
 
124
+ # Apply professional academic paper styling
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  styled_html = f"""
126
  <!DOCTYPE html>
127
  <html lang="en">
 
130
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
131
  <title>Systematic Review</title>
132
  <style>
133
+ /* Academic Paper Styling */
134
  body {{
135
  font-family: 'Times New Roman', Times, serif;
136
  line-height: 1.6;
 
244
  font-size: 12px;
245
  color: #777;
246
  }}
 
 
 
 
 
 
 
247
  @media print {{
248
  body {{
249
  background-color: white;
 
281
  saved_paths = []
282
  for file in files:
283
  if file is not None:
284
+ # Create a temporary file
285
  with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
286
+ tmp_file.write(file)
 
287
  saved_paths.append(tmp_file.name)
288
 
289
  return saved_paths
 
293
  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:
294
  return None
295
 
296
+ # Create timestamp for the filename
297
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
298
  filename = f"systematic_review_{timestamp}.html"
299
 
300
+ # Encode the HTML content for download
301
  b64_html = base64.b64encode(html_content.encode()).decode()
302
  download_link = f'<a href="data:text/html;base64,{b64_html}" download="{filename}" class="download-button">Download HTML</a>'
303
 
 
306
  # Add CSS styling for the Gradio interface
307
  custom_css = """
308
  <style>
309
+ /* Main UI */
310
+ .gradio-container {
311
  font-family: 'Arial', sans-serif;
312
  background-color: #f9f9f9;
313
+ }
314
+
315
+ /* Header */
316
+ h1 {
317
  font-size: 28px;
318
  color: #333;
319
  margin-bottom: 20px;
320
  text-align: center;
321
  padding-bottom: 10px;
322
  border-bottom: 2px solid #4a00e0;
323
+ }
324
+
325
+ /* Primary Button */
326
+ #generate_button {
327
  background: linear-gradient(135deg, #4a00e0 0%, #8e2de2 100%);
328
  color: white;
329
  font-weight: bold;
330
  padding: 10px 20px;
331
  border-radius: 5px;
332
  transition: all 0.3s ease;
333
+ }
334
+ #generate_button:hover {
335
  background: linear-gradient(135deg, #5b10f1 0%, #9f3ef3 100%);
336
  transform: translateY(-2px);
337
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
338
+ }
339
+
340
+ /* API Key Button */
341
+ #api_key_button {
342
  background: linear-gradient(135deg, #68d391 0%, #48bb78 100%);
343
  color: white;
344
  font-weight: bold;
 
346
  padding: 10px 20px;
347
  border-radius: 5px;
348
  transition: all 0.3s ease;
349
+ }
350
+ #api_key_button:hover {
351
  background: linear-gradient(135deg, #38a169 0%, #68d391 100%);
352
  transform: translateY(-2px);
353
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
354
+ }
355
+
356
+ /* Form Elements */
357
+ .input-container {
358
  background-color: white;
359
  padding: 20px;
360
  border-radius: 8px;
361
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
362
  margin-bottom: 20px;
363
+ }
364
+
365
+ /* Labels */
366
+ label {
367
  font-weight: 600;
368
  color: #555;
369
  margin-bottom: 8px;
370
+ }
371
+
372
+ /* Instructions Accordion */
373
+ .accordion {
374
  background-color: white;
375
  border: 1px solid #e0e0e0;
376
  border-radius: 8px;
377
  margin-bottom: 20px;
378
+ }
379
+
380
+ /* Output Container */
381
+ .output-container {
382
  background-color: white;
383
  padding: 15px;
384
  border-radius: 8px;
385
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
386
+ }
387
+
388
+ /* File Upload Area */
389
+ .file-upload {
390
  border: 2px dashed #ccc;
391
  border-radius: 5px;
392
  padding: 20px;
393
  text-align: center;
394
  margin-bottom: 20px;
395
+ }
396
+
397
+ /* Download Button */
398
+ .download-button {
399
  display: inline-block;
400
  background: linear-gradient(135deg, #4a00e0 0%, #8e2de2 100%);
401
  color: white;
 
405
  text-decoration: none;
406
  margin-bottom: 10px;
407
  transition: all 0.3s ease;
408
+ }
409
+ .download-button:hover {
410
  background: linear-gradient(135deg, #5b10f1 0%, #9f3ef3 100%);
411
  transform: translateY(-2px);
412
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
413
+ }
414
+
415
+ /* Download Container */
416
+ #download-container {
417
  display: flex;
418
  justify-content: center;
419
  margin: 20px 0;
420
  padding: 15px;
421
  background-color: #f5f5f5;
422
  border-radius: 8px;
423
+ }
424
+
425
+ /* Responsive adjustments */
426
+ @media screen and (max-width: 768px) {
427
+ .gradio-container {
 
 
 
 
 
 
 
 
 
 
428
  padding: 10px;
429
+ }
430
+ }
 
 
 
431
  </style>
432
  """
433
 
434
  # Gradio UI Layout with improved styling
435
  with gr.Blocks(css=custom_css) as demo:
436
+ gr.Markdown("# Systematic Review Generator for Research Papers")
437
 
438
  with gr.Accordion("How to Use This App", open=False):
439
  gr.Markdown("""
 
441
  1. Enter your OpenAI API key in the field below and click "Set API Key"
442
  2. Upload multiple PDF research papers (2 or more recommended)
443
  3. Enter your review question or topic
444
+ 4. Check the "Include Tables" option if you want the review to include comparison tables
445
+ 5. Click "Generate Systematic Review" to start the process
446
+ 6. After generation, you can download the review as HTML
 
 
 
 
 
 
447
 
448
  ### Tips for Best Results:
449
  - Upload papers that are related to the same research topic or field
 
465
  with gr.Row(elem_classes="input-container"):
466
  with gr.Column():
467
  gr.Markdown("### Upload Research Papers")
468
+ pdf_files = gr.File(label="Upload PDF Research Papers", file_count="multiple", type="binary", elem_classes="file-upload")
469
  review_question = gr.Textbox(
470
  label="Review Question or Topic",
471
  value="Please generate a systematic review of the following papers.",
472
  placeholder="e.g., What are the effects of mindfulness meditation on stress reduction?"
473
  )
474
  include_tables = gr.Checkbox(label="Include Comparison Tables", value=True)
475
+ generate_button = gr.Button("Generate Systematic Review", elem_id="generate_button", size="large")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
 
477
  # Download link container
478
  download_html_output = gr.HTML(label="Download Options")
 
485
  api_key_button.click(set_api_key, inputs=[api_key_input], outputs=[api_key_output])
486
 
487
  # Generate systematic review
488
+ def process_files_and_generate_review(files, question, include_tables):
 
 
 
489
  if not files:
490
  return ("""
491
  <div style="padding: 20px; border: 1px solid #e0e0e0; border-radius: 5px; background-color: #f9f9f9;">
 
500
  # Show loading message
501
  loading_message = """
502
  <div style="padding: 20px; text-align: center;">
503
+ <h3>Generating Systematic Review...</h3>
504
  <p>This may take a few minutes depending on the number and size of papers.</p>
505
  <div style="width: 100%; height: 4px; background-color: #f0f0f0; margin: 20px 0; border-radius: 2px; overflow: hidden;">
506
  <div style="width: 30%; height: 100%; background: linear-gradient(90deg, #4a00e0, #8e2de2); animation: progress 2s infinite linear;"></div>
507
  </div>
508
  <style>
509
+ @keyframes progress {
510
+ 0% { margin-left: -30%; }
511
+ 100% { margin-left: 100%; }
512
+ }
513
  </style>
514
  </div>
515
  """
516
 
517
  yield loading_message, ""
518
 
519
+ # Generate review
520
+ review = generate_systematic_review(saved_paths, question, include_tables)
 
 
 
 
 
 
 
 
 
 
 
521
 
522
  # Create HTML download link
523
  html_link = create_html_download_link(review)
 
543
 
544
  generate_button.click(
545
  process_files_and_generate_review,
546
+ inputs=[pdf_files, review_question, include_tables],
 
 
 
547
  outputs=[review_output, download_html_output]
548
  )
549
 
550
  # Launch the app
551
  if __name__ == "__main__":
552
+ demo.launch(share=True)