From 7a1b818d1edf5347d8215e164edf77e4210fa4dd Mon Sep 17 00:00:00 2001 From: Vika Date: Thu, 22 Aug 2024 18:01:44 +0300 Subject: SmartSummaryButton: ask parent component for text On receving `smart_summary::Output::Start`, one must reply with `smart_summary::Input::Text(text)` to start the actual summarization. --- src/components/smart_summary.rs | 73 ++++++++++++++++++++++++----------------- src/lib.rs | 32 ++++++++++++++---- 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/components/smart_summary.rs b/src/components/smart_summary.rs index 37bbd74..b360d77 100644 --- a/src/components/smart_summary.rs +++ b/src/components/smart_summary.rs @@ -3,7 +3,6 @@ use relm4::{gtk, prelude::{AsyncComponent, AsyncComponentParts}, AsyncComponentS #[derive(Debug, Default)] pub(crate) struct SmartSummaryButton { - content_buffer: gtk::TextBuffer, busy: bool, } @@ -12,6 +11,12 @@ pub(crate) enum Error { } +#[derive(Debug)] +pub(crate) enum Input { + ButtonPressed, + Text(String) +} + #[derive(Debug)] pub(crate) enum Output { Start, @@ -23,17 +28,17 @@ pub(crate) enum Output { #[relm4::component(pub(crate) async)] impl AsyncComponent for SmartSummaryButton { - type Input = (); + type Input = Input; type Output = Output; - type Init = gtk::TextBuffer; + type Init = (); type CommandOutput = (); view! { #[root] #[name = "button"] gtk::Button { - connect_clicked => (), + connect_clicked => Input::ButtonPressed, #[watch] set_sensitive: !model.busy, set_tooltip_markup: Some("Smart Summary\nAsk a language model for a single-sentence summary."), @@ -47,38 +52,44 @@ impl AsyncComponent for SmartSummaryButton { } } - async fn init(init: Self::Init, root: Self::Root, sender: AsyncComponentSender) -> AsyncComponentParts { - let model = SmartSummaryButton { - content_buffer: init, - ..Default::default() - }; + async fn init( + _init: Self::Init, + root: Self::Root, + sender: AsyncComponentSender + ) -> AsyncComponentParts { + 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, _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())); + async fn update_with_view( + &mut self, + widgets: &mut Self::Widgets, + msg: Self::Input, + sender: AsyncComponentSender, + _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()); + } } - - log::debug!("Done with the summary."); - self.busy = false; - let _ = sender.output(Output::Done); - self.update_view(widgets, sender.clone()); } } diff --git a/src/lib.rs b/src/lib.rs index f95a40a..244c09f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,9 @@ use relm4::{gtk, prelude::{AsyncComponent, AsyncComponentController, AsyncCompon pub mod components { pub(crate) mod smart_summary; - pub(crate) use smart_summary::{SmartSummaryButton, Output as SmartSummaryOutput}; + pub(crate) use smart_summary::{ + SmartSummaryButton, Output as SmartSummaryOutput, Input as SmartSummaryInput + }; } mod widgets; pub mod secrets; @@ -36,6 +38,14 @@ pub struct PostComposerModel { #[do_not_track] smart_summary: AsyncController, } +impl PostComposerModel { + fn busy_changed(&self) -> bool { + self.changed(Self::submit_busy_guard() | Self::smart_summary_busy_guard()) + } + fn busy(&self) -> bool { + self.submit_busy_guard.is_some() || self.smart_summary_busy_guard.is_some() + } +} #[derive(Debug)] #[allow(private_interfaces)] @@ -72,8 +82,8 @@ impl AsyncComponent for PostComposerModel { send_button = gtk::Button { set_label: "Post", connect_clicked => Self::Input::Submit, - #[track = "model.changed(Self::submit_busy_guard())"] - set_sensitive: model.submit_busy_guard.is_none(), + #[track = "model.busy_changed()"] + set_sensitive: !model.busy(), }, bar = adw::HeaderBar::new() { @@ -128,8 +138,8 @@ impl AsyncComponent for PostComposerModel { gtk::Entry { set_hexpand: true, set_buffer: &model.summary_buffer, - #[track = "model.changed(Self::smart_summary_busy_guard() | Self::submit_busy_guard())"] - set_sensitive: model.smart_summary_busy_guard.is_none() && model.submit_busy_guard.is_none(), + #[track = "model.busy_changed()"] + set_sensitive: !model.busy(), }, model.smart_summary.widget(), @@ -264,7 +274,7 @@ impl AsyncComponent for PostComposerModel { micropub: Arc::new(init), smart_summary: components::SmartSummaryButton::builder() - .launch(content_buffer) + .launch(()) .forward(sender.input_sender(), PostComposerInput::SmartSummary), tracker: Default::default() @@ -335,7 +345,15 @@ impl AsyncComponent for PostComposerModel { self.set_smart_summary_busy_guard( Some(relm4::main_adw_application().mark_busy()) ); - self.summary_buffer.set_text(""); + if self.smart_summary.sender().send(components::SmartSummaryInput::Text( + self.content_buffer.text( + &self.content_buffer.start_iter(), + &self.content_buffer.end_iter(), + false + ).into() + )).is_ok() { + self.summary_buffer.set_text(""); + } }, PostComposerInput::SmartSummary(components::SmartSummaryOutput::Chunk(text)) => { self.summary_buffer.insert_text(self.summary_buffer.length(), text); -- cgit 1.4.1