Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import pandas as pd | |
| import plotly.graph_objects as go | |
| from ui.multi_report_functions import ( | |
| load_multi_pdfs, | |
| run_coverage_scores, | |
| run_commitment_scores, | |
| run_positioning_chart, | |
| recalculate_from_revised_file, | |
| run_revised_positioning_chart | |
| ) | |
| def build_multi_report_page(): | |
| """ | |
| Builds the Multi-Report Comparative Analysis page. | |
| Returns back_btn so interface.py can wire the Back navigation. | |
| This page is placed inside a gr.Tab by build_interface() rather than | |
| toggled via Column visibility, to avoid Gradio's known rendering bug | |
| where complex children (Dataframe, Plot, Gallery) can break after a | |
| parent Column's visibility is toggled off and back on. | |
| """ | |
| back_btn = gr.Button("⬅ Back to Home", size="sm") | |
| gr.Markdown("# Multi-Report Comparative Analysis") | |
| gr.Markdown( | |
| "Upload multiple company sustainability reports to compare " | |
| "their ESG disclosure coverage and commitment levels." | |
| ) | |
| # ========================= | |
| # UPLOAD | |
| # ========================= | |
| gr.Markdown("## Step 1: Upload Reports") | |
| multi_file = gr.File( | |
| label="Upload PDF Reports (you can select multiple files)", | |
| file_count="multiple" | |
| ) | |
| load_multi_btn = gr.Button("Load Reports", variant="primary") | |
| upload_status = gr.Markdown() | |
| extracted_download = gr.File(label="Download Combined Extracted CSV") | |
| # ========================= | |
| # COVERAGE SCORES | |
| # ========================= | |
| gr.Markdown("## Step 2: Coverage Scores") | |
| gr.Markdown( | |
| "Measures how much of each report is sustainability-relevant: " | |
| "**Relevant ÷ (Relevant + Irrelevant) × 100**" | |
| ) | |
| coverage_btn = gr.Button("Run Coverage Scores", variant="primary") | |
| coverage_status = gr.Markdown() | |
| coverage_table = gr.Dataframe(value=pd.DataFrame(), label="Coverage Scores (ranked)", interactive=False) | |
| coverage_download = gr.File(label="Download Coverage Scores CSV (per-report summary)") | |
| coverage_detail_download = gr.File(label="Download Per-Paragraph Detail CSV") | |
| # ========================= | |
| # COMMITMENT SCORES | |
| # ========================= | |
| gr.Markdown("## Step 3: Commitment Scores") | |
| gr.Markdown( | |
| "Measures the depth of disclosure among relevant paragraphs " | |
| "(quantitative claims are weighted higher than qualitative ones). " | |
| "Requires Coverage Scores to be run first." | |
| ) | |
| commitment_btn = gr.Button("Run Commitment Scores", variant="primary") | |
| commitment_status = gr.Markdown() | |
| commitment_table = gr.Dataframe(value=pd.DataFrame(), label="Commitment Scores (ranked)", interactive=False) | |
| commitment_download = gr.File(label="Download Commitment Scores CSV (per-report summary)") | |
| commitment_detail_download = gr.File(label="Download Per-Paragraph Detail CSV (PM/FC retrieval + classification)") | |
| # ---------- Positioning Quadrant Chart ---------- | |
| gr.Markdown("### Positioning") | |
| gr.Markdown( | |
| "Plots each company by Commitment Score (x-axis) vs Coverage Score " | |
| "(y-axis), split into four quadrants at the average of each score " | |
| "across all uploaded reports." | |
| ) | |
| positioning_btn = gr.Button("Run Positioning", variant="primary") | |
| positioning_status = gr.Markdown() | |
| positioning_chart = gr.Plot(value=go.Figure(), label="Positioning") | |
| # ========================= | |
| # REVISE & RECALCULATE | |
| # ========================= | |
| gr.Markdown("## Step 4: Revise & Recalculate (Optional)") | |
| gr.Markdown( | |
| "If you reviewed the downloaded per-paragraph detail CSVs and " | |
| "corrected some predictions by hand, upload the revised file here " | |
| "to recompute Coverage Scores, Commitment Scores, and a new " | |
| "Positioning chart from it. The original results above are left " | |
| "untouched, so you can compare both side by side.\n\n" | |
| "Expected columns: `Doc_name`, `SA_label` (Relevant/Irrelevant), " | |
| "`QQ_label` (Qualitative/Quantitative), `PMFC_Label` " | |
| "(`Answer: PM` / `Answer: FC`). Rows with missing or unrecognized " | |
| "values in these columns are excluded from the relevant counts " | |
| "rather than causing an error." | |
| ) | |
| revised_file = gr.File(label="Upload Revised Per-Paragraph CSV") | |
| recalculate_btn = gr.Button("Recalculate Scores", variant="primary") | |
| recalculate_status = gr.Markdown() | |
| revised_coverage_table = gr.Dataframe(value=pd.DataFrame(), label="Revised Coverage Scores (ranked)", interactive=False) | |
| revised_commitment_table = gr.Dataframe(value=pd.DataFrame(), label="Revised Commitment Scores (ranked)", interactive=False) | |
| revised_positioning_btn = gr.Button("Run Revised Positioning", variant="primary") | |
| revised_positioning_status = gr.Markdown() | |
| revised_positioning_chart = gr.Plot(value=go.Figure(), label="Positioning (Revised)") | |
| # ========================= | |
| # CONNECTIONS | |
| # ========================= | |
| load_multi_btn.click( | |
| load_multi_pdfs, | |
| inputs=multi_file, | |
| outputs=[extracted_download, upload_status] | |
| ) | |
| coverage_btn.click( | |
| run_coverage_scores, | |
| outputs=[coverage_table, coverage_download, coverage_detail_download, coverage_status] | |
| ) | |
| commitment_btn.click( | |
| run_commitment_scores, | |
| outputs=[commitment_table, commitment_download, commitment_detail_download, commitment_status] | |
| ) | |
| positioning_btn.click( | |
| run_positioning_chart, | |
| outputs=[positioning_chart, positioning_status] | |
| ) | |
| recalculate_btn.click( | |
| recalculate_from_revised_file, | |
| inputs=revised_file, | |
| outputs=[revised_coverage_table, revised_commitment_table, recalculate_status] | |
| ) | |
| revised_positioning_btn.click( | |
| run_revised_positioning_chart, | |
| outputs=[revised_positioning_chart, revised_positioning_status] | |
| ) | |
| return back_btn | |