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

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

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

}

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

    Error(Error)
}

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

    type Init = gtk::TextBuffer;
    type CommandOutput = ();

    view! {
        #[root]
        #[name = "button"]
        gtk::Button {
            connect_clicked => (),
            #[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 = SmartSummaryButton {
            content_buffer: init,
            ..Default::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) {
        log::debug!("Starting Smart Summary generation");
        self.busy = true;
        let _ = sender.output(Output::Start);
        self.update_view(widgets, sender.clone());

        let text = self.content_buffer.text(
            &self.content_buffer.start_iter(),
            &self.content_buffer.end_iter(),
            false
        );
        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());
    }
}