| """ |
| app.py β Gradio Blocks UI for Research Draft. |
| |
| Provides a clean, academic interface with two roles: |
| β’ Student β upload PDF, generate abstract, view result. |
| β’ Researcher β same as Student + view history, export results. |
| |
| Launch: |
| python app.py |
| """ |
|
|
| import gradio as gr |
|
|
| from abstract_service import generate_abstract_from_pdf |
| from history_manager import ( |
| get_history_as_table, |
| clear_history, |
| export_latest_to_txt, |
| export_full_history_to_txt, |
| ) |
|
|
| |
| |
| |
|
|
| CUSTOM_CSS = """ |
| .main-title { |
| text-align: center; |
| margin-bottom: 0.2em; |
| } |
| .sub-title { |
| text-align: center; |
| color: #555; |
| font-size: 0.95em; |
| margin-top: 0; |
| } |
| """ |
|
|
| |
| |
| |
|
|
| def on_role_change(role: str): |
| """Toggle visibility of the Researcher-only section.""" |
| return gr.Column(visible=(role == "Researcher")) |
|
|
|
|
| def on_generate(pdf_file, role: str): |
| """ |
| Handle the Generate Abstract button click. |
| |
| Returns: (abstract_text, status_message) |
| """ |
| if pdf_file is None: |
| raise gr.Error("Please upload a PDF file first.") |
|
|
| |
| file_path = getattr(pdf_file, "path", None) or getattr(pdf_file, "name", None) |
| if not file_path: |
| raise gr.Error("Could not read the uploaded file path.") |
|
|
| try: |
| result = generate_abstract_from_pdf(file_path=file_path, role=role) |
| except ValueError as exc: |
| raise gr.Error(str(exc)) |
| except RuntimeError as exc: |
| raise gr.Error(str(exc)) |
| except FileNotFoundError as exc: |
| raise gr.Error(str(exc)) |
| except Exception as exc: |
| raise gr.Error(f"Unexpected error: {exc}") |
|
|
| return result["abstract"], f"β
{result['status']}" |
|
|
|
|
| def on_view_history(): |
| """Load history rows for the Dataframe.""" |
| rows = get_history_as_table() |
| if not rows: |
| gr.Info("No history entries yet.") |
| return rows |
|
|
|
|
| def on_clear_history(): |
| """Wipe the persistent history file and return an empty table.""" |
| clear_history() |
| gr.Info("History cleared.") |
| return [] |
|
|
|
|
| def on_export_latest(): |
| """Export the latest abstract to a .txt download.""" |
| path = export_latest_to_txt() |
| if path is None: |
| raise gr.Error("Nothing to export β history is empty.") |
| return path |
|
|
|
|
| def on_export_full(): |
| """Export the entire history to a .txt download.""" |
| path = export_full_history_to_txt() |
| if path is None: |
| raise gr.Error("Nothing to export β history is empty.") |
| return path |
|
|
|
|
| |
| |
| |
|
|
| with gr.Blocks(title="Research Draft") as demo: |
|
|
| |
| gr.Markdown( |
| "<h1 class='main-title'>π Research Draft</h1>", |
| ) |
| gr.Markdown( |
| "<p class='sub-title'>" |
| "AI-powered academic abstract generation Β· Local & Private" |
| "</p>", |
| ) |
|
|
| |
| with gr.Row(): |
| role_dropdown = gr.Dropdown( |
| choices=["Student", "Researcher"], |
| value="Student", |
| label="Select your role", |
| scale=1, |
| interactive=True, |
| ) |
|
|
| gr.Markdown("---") |
|
|
| |
| gr.Markdown("### Upload & Generate") |
| with gr.Row(): |
| with gr.Column(scale=2): |
| pdf_input = gr.File( |
| label="Upload Research Paper (PDF)", |
| file_types=[".pdf"], |
| file_count="single", |
| ) |
| generate_btn = gr.Button( |
| "π Generate Abstract", |
| variant="primary", |
| size="lg", |
| ) |
| status_box = gr.Textbox( |
| label="Status", |
| interactive=False, |
| lines=1, |
| placeholder="Upload a PDF and click Generateβ¦", |
| ) |
|
|
| with gr.Column(scale=3): |
| abstract_output = gr.Textbox( |
| label="Generated Abstract", |
| interactive=False, |
| lines=12, |
| buttons=["copy"], |
| placeholder="Your generated abstract will appear hereβ¦", |
| ) |
|
|
| |
| with gr.Column(visible=False) as researcher_section: |
| gr.Markdown("---") |
| gr.Markdown("### π¬ Researcher Tools") |
|
|
| with gr.Row(): |
| view_history_btn = gr.Button("π View History") |
| clear_history_btn = gr.Button("ποΈ Clear History") |
| export_latest_btn = gr.Button("π₯ Export Latest") |
| export_full_btn = gr.Button("π₯ Export Full History") |
|
|
| history_table = gr.Dataframe( |
| headers=["Timestamp", "Role", "Filename", "Abstract (preview)"], |
| datatype=["str", "str", "str", "str"], |
| interactive=False, |
| wrap=True, |
| label="Generation History", |
| ) |
|
|
| export_file = gr.File( |
| label="Download Export", |
| interactive=False, |
| ) |
|
|
| |
| gr.Markdown( |
| "<br><center style='color:#999; font-size:0.8em;'>" |
| "Research Draft Β· B.Tech Final Year Project Β· Runs 100 % locally" |
| "</center>" |
| ) |
|
|
| |
|
|
| |
| role_dropdown.change( |
| fn=on_role_change, |
| inputs=role_dropdown, |
| outputs=researcher_section, |
| ) |
|
|
| |
| generate_btn.click( |
| fn=on_generate, |
| inputs=[pdf_input, role_dropdown], |
| outputs=[abstract_output, status_box], |
| ) |
|
|
| |
| view_history_btn.click( |
| fn=on_view_history, |
| outputs=history_table, |
| ) |
| clear_history_btn.click( |
| fn=on_clear_history, |
| outputs=history_table, |
| ) |
| export_latest_btn.click( |
| fn=on_export_latest, |
| outputs=export_file, |
| ) |
| export_full_btn.click( |
| fn=on_export_full, |
| outputs=export_file, |
| ) |
|
|
|
|
| |
| |
| |
|
|
| if __name__ == "__main__": |
| demo.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| show_error=True, |
| css=CUSTOM_CSS, |
| ) |
|
|