summary refs log tree commit diff
path: root/src/components/smart_summary.rs
blob: b360d77c14f343ab090c233d1000eb46f4bd0c65 (plain) (blame)
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
use adw::prelude::*;
use relm4::{gtk, prelude::{AsyncComponent, AsyncComponentParts}, AsyncComponentSender};

#[derive(Debug, Default)]
pub(crate) struct SmartSummaryButton {
    busy: bool,
}

#[derive(Debug, thiserror::Error)]
pub(crate) enum Error {

}

#[derive(Debug)]
pub(crate) enum Input {
    ButtonPressed,
    Text(String)
}

#[derive(Debug)]
pub(crate) enum Output {
    Start,
    Chunk(String),
    Done,

    Error(Error)
}

#[relm4::component(pub(crate) async)]
impl AsyncComponent for SmartSummaryButton {
    type Input = Input;
    type Output = Output;

    type Init = ();
    type CommandOutput = ();

    view! {
        #[root]
        #[name = "button"]
        gtk::Button {
            connect_clicked => Input::ButtonPressed,
            #[watch]
            set_sensitive: !model.busy,
            set_tooltip_markup: Some("<b>Smart Summary</b>\nAsk a language model for a single-sentence summary."),

            if model.busy {
                gtk::Spinner { set_spinning: true }
            } else {
                gtk::Label { set_markup: "✨" }
            }

        }
    }

    async fn init(
        _init: Self::Init,
        root: Self::Root,
        sender: AsyncComponentSender<Self>
    ) -> AsyncComponentParts<Self> {
        let model = Self::default();
        let widgets = view_output!();

        AsyncComponentParts { model, widgets }
    }

    async fn update_with_view(
        &mut self,
        widgets: &mut Self::Widgets,
        msg: Self::Input,
        sender: AsyncComponentSender<Self>,
        _root: &Self::Root
    ) {
        match msg {
            Input::ButtonPressed => if let Ok(()) = sender.output(Output::Start) {
                self.busy = true;
                log::debug!("Requesting text to summarize from parent component...");
                self.update_view(widgets, sender.clone());
            },
            Input::Text(text) => {
                log::debug!("Would generate summary for the following text:\n{}", text);
                tokio::time::sleep(std::time::Duration::from_millis(450)).await;

                for i in ["I'", "m ", "sorry,", " I", " am ", "unable", " to", " ", "write", " you ", "a summary.", " I", " am", " not ", "really ", "an ", "LLM."] {
                    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
                    let _ = sender.output(Output::Chunk(i.to_string()));
                }

                log::debug!("Done with the summary.");
                self.busy = false;
                let _ = sender.output(Output::Done);
                self.update_view(widgets, sender.clone());
            }
        }
    }
}