From e8b9c1eff03ee00b3e3ef0adbeb3b0d2f2c24010 Mon Sep 17 00:00:00 2001 From: LeonardoTrapani Date: Fri, 10 Oct 2025 20:04:39 +0200 Subject: [PATCH] add cancel action to pipeline to stop without transcribing --- README.md | 10 ++++++++++ cmd/hyprvoice/main.go | 16 ++++++++++++++++ internal/daemon/daemon.go | 17 +++++++++++++++-- internal/pipeline/pipeline.go | 5 +++-- packaging/PKGBUILD | 4 ++-- 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 91bfb89..c1e9120 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,9 @@ hyprvoice serve # Toggle recording on/off hyprvoice toggle +# Cancel current operation +hyprvoice cancel + # Check current status hyprvoice status @@ -145,6 +148,7 @@ Most setups use this toggle pattern in window manager config: ```bash bind = SUPER, R, exec, hyprvoice toggle +bind = SUPER SHIFT, R, exec, hyprvoice cancel # Optional: cancel current operation ``` ## Keyboard Shortcuts Setup @@ -157,6 +161,9 @@ Add to your `~/.config/hypr/hyprland.conf`: # Hyprvoice - Voice to Text (toggle recording) bind = SUPER, R, exec, hyprvoice toggle +# Optional: Cancel current operation +bind = SUPER SHIFT, C, exec, hyprvoice cancel + # Optional: Status check bind = SUPER SHIFT, R, exec, hyprvoice status && notify-send "Hyprvoice" "$(hyprvoice status)" ``` @@ -170,6 +177,8 @@ bind = SUPER SHIFT, R, exec, hyprvoice status && notify-send "Hyprvoice" "$(hypr 3. **Press keybind again** → Recording stops, transcription begins 4. **Text appears** → Injected at cursor position or clipboard +**Cancel anytime:** Press your cancel keybind (e.g., `SUPER+SHIFT+C`) to abort the current operation and return to idle. + ### CLI Usage ```bash @@ -615,6 +624,7 @@ go run ./cmd/hyprvoice stop Simple single-character commands over Unix socket: - `t` - Toggle recording on/off +- `c` - Cancel current operation - `s` - Get current status - `v` - Get protocol version - `q` - Quit daemon gracefully diff --git a/cmd/hyprvoice/main.go b/cmd/hyprvoice/main.go index f398d7e..8ca4404 100644 --- a/cmd/hyprvoice/main.go +++ b/cmd/hyprvoice/main.go @@ -28,6 +28,7 @@ func init() { rootCmd.AddCommand( serveCmd(), toggleCmd(), + cancelCmd(), statusCmd(), versionCmd(), stopCmd(), @@ -109,6 +110,21 @@ func stopCmd() *cobra.Command { } } +func cancelCmd() *cobra.Command { + return &cobra.Command{ + Use: "cancel", + Short: "Cancel current operation", + RunE: func(cmd *cobra.Command, args []string) error { + resp, err := bus.SendCommand('c') + if err != nil { + return fmt.Errorf("failed to cancel operation: %w", err) + } + fmt.Print(resp) + return nil + }, + } +} + func configureCmd() *cobra.Command { return &cobra.Command{ Use: "configure", diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index d051bd2..4de2036 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -162,6 +162,9 @@ func (d *Daemon) handle(c net.Conn) { case 't': d.toggle() fmt.Fprint(c, "OK toggled\n") + case 'c': + d.cancelPipeline() + fmt.Fprint(c, "OK cancelled\n") case 's': status := d.status() fmt.Fprintf(c, "STATUS status=%s\n", status) @@ -191,7 +194,7 @@ func (d *Daemon) toggle() { go d.monitorPipelineErrors(p) case pipeline.Recording: - d.stopPipeline() // aborted during recording (chunks not sent to transcriber yet) + d.stopPipeline() go d.notifier.Error("Recording Aborted") case pipeline.Transcribing: @@ -207,11 +210,21 @@ func (d *Daemon) toggle() { go d.notifier.Notify("Hyprvoice", "Recording Ended... Transcribing") case pipeline.Injecting: - d.stopPipeline() // aborted during injection + d.stopPipeline() go d.notifier.Error("Injection Aborted") } } +func (d *Daemon) cancelPipeline() { + switch d.status() { + case pipeline.Idle: + log.Printf("Daemon: Cancel requested but pipeline is idle, ignoring") + default: + d.stopPipeline() + go d.notifier.Notify("Hyprvoice", "Operation Cancelled") + } +} + func (d *Daemon) monitorPipelineErrors(p pipeline.Pipeline) { errorCh := p.GetErrorCh() for { diff --git a/internal/pipeline/pipeline.go b/internal/pipeline/pipeline.go index 16aeee7..e71e3df 100644 --- a/internal/pipeline/pipeline.go +++ b/internal/pipeline/pipeline.go @@ -30,6 +30,7 @@ const ( const ( Inject Action = "inject" + Cancel Action = "cancel" ) type Pipeline interface { @@ -115,7 +116,8 @@ func (p *pipeline) run(ctx context.Context) { defer func() { if stopErr := t.Stop(ctx); stopErr != nil { log.Printf("Pipeline: Error stopping transcriber: %v", stopErr) - p.sendError("Transcription Error", "Failed to stop transcriber cleanly", stopErr) + // Silently call an error now because on simple transcriber we just transcribe all audio when we stop, and might fail when force stop + //p.sendError("Transcription Error", "Failed to stop transcriber cleanly", stopErr) } }() @@ -232,7 +234,6 @@ func (p *pipeline) handleInjectAction(ctx context.Context, recorder *recording.R log.Printf("Pipeline: Text injection completed successfully") } - // Return to idle state after injection is complete p.setStatus(Idle) } diff --git a/packaging/PKGBUILD b/packaging/PKGBUILD index a4f116a..f9c7bba 100644 --- a/packaging/PKGBUILD +++ b/packaging/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Leonardo Trapani pkgname=hyprvoice-bin -pkgver=0.1.5 +pkgver=0.1.6 pkgrel=1 pkgdesc="Voice-powered typing for Wayland/Hyprland" arch=('x86_64') @@ -25,7 +25,7 @@ source=( "hyprvoice-${pkgver}::https://github.com/leonardotrapani/hyprvoice/releases/download/${pkgver}/hyprvoice-linux-x86_64" "hyprvoice.service" ) -sha256sums=('c3b881864b126341f4b456be3422a4a76657019f750676ba4967776adc931fb8' +sha256sums=('5dc88ac616659adb2026043c0c9bd046f3dcfdb1fcca8962ef5994d5c245c631' 'bc4d17afa3a56fc50b09faae4cef9faf2a4ec7f08798b4098ba41ad78b02ab20') install=hyprvoice.install