summary refs log tree commit diff
path: root/src/components/smart_summary.rs
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2024-08-22 17:49:30 +0300
committerVika <vika@fireburn.ru>2024-08-22 17:49:30 +0300
commit9868b644c8b70396417a81c23e028e9212934444 (patch)
tree618545531f6db1885ade44a3707c79d3ce41af7d /src/components/smart_summary.rs
parent0b30cc210f0b58c2b80eca9a5eed2186e6255914 (diff)
downloadbowl-9868b644c8b70396417a81c23e028e9212934444.tar.zst
Factor out the smart summary button
This is a little bit janky in my opinion, because it takes a reference
to the buffer which contents its gonna be summarizing. In a perfect
world, it would ask the parent component for the text.
Diffstat (limited to 'src/components/smart_summary.rs')
-rw-r--r--src/components/smart_summary.rs84
1 files changed, 84 insertions, 0 deletions
diff --git a/src/components/smart_summary.rs b/src/components/smart_summary.rs
new file mode 100644
index 0000000..37bbd74
--- /dev/null
+++ b/src/components/smart_summary.rs
@@ -0,0 +1,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());
+    }
+}