File size: 5,385 Bytes
8db761b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from __future__ import annotations

from .service import StudyService


def _sources_md(result) -> str:
    return ("**Sources** (open the files below to verify at the exact slide/page)\n\n" + result.sources_md) \
        if result.sources_md else ""


def build_app(service: StudyService, title: str = "StudyHub"):
    import gradio as gr

    with gr.Blocks(title=title) as demo:
        gr.Markdown(
            f"# {title}\nBrowse by topic or ask freely. Answers are grounded in the course materials, "
            "cite the exact file + slide/page, and reply in your language — even when the source is in "
            "Italian. Short snippets go to a no-training model provider to generate answers."
        )

        with gr.Tab("Topics"):
            gr.Markdown("Pick a module → a topic. Answers draw on **all** of that topic's sources "
                        "(slides, notes, transcripts), each cited.")
            module_dd = gr.Dropdown(
                choices=[(f"{m['title']} · {m['lecturer']}".strip(" ·"), m["id"]) for m in service.modules()],
                label="Module",
            )
            topic_dd = gr.Dropdown(choices=[], label="Topic")
            t_sources = gr.Markdown()
            sum_btn = gr.Button("Generate summary")
            t_summary = gr.Markdown()
            t_sum_files = gr.File(label="Summary sources — download the cited files", file_count="multiple")
            gr.Markdown("—")
            with gr.Row():
                t_q = gr.Textbox(label="Ask about this topic (any language)", lines=1, scale=4)
                t_ask = gr.Button("Ask", variant="primary", scale=1)
            t_ans = gr.Markdown()
            t_ans_src = gr.Markdown()
            t_files = gr.File(label="Cited sources", file_count="multiple")

            def _topic_src_md(tid):
                srcs = service.topic_sources(tid) if tid else []
                if not srcs:
                    return "_No sources linked to this topic yet._"
                return "**Sources:** " + " · ".join(f"`{s['type']}` {s['file'].split('/')[-1]}" for s in srcs)

            def _on_module(mid):
                choices = [(t["title"], t["id"]) for t in service.topics(mid)] if mid else []
                return gr.update(choices=choices, value=None), ""

            def _summarize(tid):
                if not tid:
                    return "Pick a topic first.", []
                r = service.topic_summary(tid)
                return (r.answer + (("\n\n" + _sources_md(r)) if r.sources_md else "")), service.cited_files(r)

            def _topic_ask(tid, q):
                if not tid:
                    return "Pick a topic first.", "", []
                r = service.topic_ask(tid, q or "")
                return r.answer, _sources_md(r), service.cited_files(r)

            module_dd.change(_on_module, inputs=module_dd, outputs=[topic_dd, t_sources])
            topic_dd.change(_topic_src_md, inputs=topic_dd, outputs=t_sources)
            sum_btn.click(_summarize, inputs=topic_dd, outputs=[t_summary, t_sum_files])
            t_ask.click(_topic_ask, inputs=[topic_dd, t_q], outputs=[t_ans, t_ans_src, t_files])

        with gr.Tab("Ask"):
            q = gr.Textbox(label="Your question (Italian or English)", lines=2)
            ask = gr.Button("Ask", variant="primary")
            a_ans = gr.Markdown()
            a_src = gr.Markdown()
            a_files = gr.File(label="Cited sources — click to open/download", file_count="multiple")

            def _ask(query):
                r = service.ask(query or "")
                return r.answer, _sources_md(r), service.cited_files(r)

            ask.click(_ask, inputs=q, outputs=[a_ans, a_src, a_files])

        with gr.Tab("Summaries"):
            doc = gr.Dropdown(choices=service.list_files(), label="Document")
            sbtn = gr.Button("Summarize", variant="primary")
            s_out = gr.Markdown()
            s_src = gr.Markdown()
            s_files = gr.File(label="Cited sources — click to open/download", file_count="multiple")

            def _sum(file):
                if not file:
                    return "Pick a document first.", "", []
                r = service.summarize(file)
                return r.answer, _sources_md(r), service.cited_files(r)

            sbtn.click(_sum, inputs=doc, outputs=[s_out, s_src, s_files])

        with gr.Tab("Quiz"):
            topic = gr.Textbox(label="Topic")
            n = gr.Slider(1, 10, value=5, step=1, label="Number of questions")
            qbtn = gr.Button("Generate quiz", variant="primary")
            q_out = gr.Markdown()
            q_src = gr.Markdown()
            q_files = gr.File(label="Cited sources — click to open/download", file_count="multiple")

            def _quiz(t, num):
                r = service.quiz(t or "", int(num))
                return r.answer, _sources_md(r), service.cited_files(r)

            qbtn.click(_quiz, inputs=[topic, n], outputs=[q_out, q_src, q_files])

        with gr.Tab("Browse & Download"):
            mat = gr.Dropdown(choices=service.list_files(), label="Material")
            dbtn = gr.Button("Get file")
            dfile = gr.File(label="Download")

            def _dl(file):
                return service.download_path(file) if file else None

            dbtn.click(_dl, inputs=mat, outputs=dfile)

    return demo