File size: 7,648 Bytes
2feea59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
"""
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,
    )