research-draft / app.py
Arunvarma2565's picture
Add app.py - Gradio Blocks UI
2feea59 verified
"""
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,
)
# ---------------------------------------------------------------------------
# CSS β€” minimal overrides for a clean academic look
# ---------------------------------------------------------------------------
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;
}
"""
# ---------------------------------------------------------------------------
# Event handlers
# ---------------------------------------------------------------------------
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.")
# Gradio file path β€” handle both v5 (.name) and v6 (.path)
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
# ---------------------------------------------------------------------------
# UI layout (Gradio Blocks)
# ---------------------------------------------------------------------------
with gr.Blocks(title="Research Draft") as demo:
# ── Header ────────────────────────────────────────────────────────────
gr.Markdown(
"<h1 class='main-title'>πŸ“„ Research Draft</h1>",
)
gr.Markdown(
"<p class='sub-title'>"
"AI-powered academic abstract generation Β· Local &amp; Private"
"</p>",
)
# ── Role selector ─────────────────────────────────────────────────────
with gr.Row():
role_dropdown = gr.Dropdown(
choices=["Student", "Researcher"],
value="Student",
label="Select your role",
scale=1,
interactive=True,
)
gr.Markdown("---")
# ── Main generation section (visible to all roles) ────────────────────
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…",
)
# ── Researcher-only section ───────────────────────────────────────────
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,
)
# ── Footer ────────────────────────────────────────────────────────────
gr.Markdown(
"<br><center style='color:#999; font-size:0.8em;'>"
"Research Draft Β· B.Tech Final Year Project Β· Runs 100 % locally"
"</center>"
)
# ── Event wiring ──────────────────────────────────────────────────────
# Role switch β†’ show/hide researcher section
role_dropdown.change(
fn=on_role_change,
inputs=role_dropdown,
outputs=researcher_section,
)
# Generate abstract
generate_btn.click(
fn=on_generate,
inputs=[pdf_input, role_dropdown],
outputs=[abstract_output, status_box],
)
# Researcher tools
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,
)
# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
show_error=True,
css=CUSTOM_CSS,
)