Rewrite README to reflect pipeline-owned state, daemon as thin control plane, current status, and updated roadmap. Document PipeWire recording, action channel for inject, and adjust diagrams/structure accordingly.

This commit is contained in:
LeonardoTrapani
2025-08-14 19:35:16 +02:00
parent 61e62b749f
commit 0619a36abd
+75 -60
View File
@@ -1,7 +1,7 @@
# Hyprvoice # Hyprvoice
> **Voicepowered typing for Wayland/Hyprland — press to toggle, speak, instant paste.** > Voicepowered typing for Wayland/Hyprland — press to toggle, speak, instant paste.
> Streams audio while you talk and **pastes the final text the moment you toggle off** → aims to be the **fastest feel** on Wayland. > Streams audio while you talk and pastes the final text the moment you toggle off → aims to be the fastest feel on Wayland.
**Status:** Early development (expect rough edges) **Status:** Early development (expect rough edges)
@@ -9,23 +9,22 @@
## TL;DR ## TL;DR
- **Toggle workflow** (Hyprlandfriendly): press to start, press to stop. - Toggle workflow (Hyprlandfriendly): press to start, press to stop.
- **Cloud streaming ASR** (MVP) → **single final paste** into the focused window. - Pipeline owns state; daemon is a thin control plane (IPC + lifecycle).
- **Daemon with clear states & events**; desktop notifications. - Notifications for key events (recording started/ended, aborted).
- **Clipboardbased injection** (save/restore) with **`wtype`** - Audio capture via PipeWire (`pw-record`) with backpressure.
- **Unixy pipeline** (small pieces, bounded channels). - ASR + clipboard injection are planned; injection is currently stubbed.
--- ---
## Requirements ## Requirements
- **Go 1.24.5+** (for building from source) - Go 1.24.5+ (for building from source)
- Wayland + **Hyprland** - Wayland + Hyprland
- **PipeWire** (audio capture) - PipeWire tools: `pw-record` and `pw-cli`
- **systemd --user** (service) - systemd --user (service)
- **wl-clipboard** (clipboard save/restore) - Optional: libnotify/`notify-send` (desktop notifications)
- **libnotify**/`notify-send` (optional notifications) - Planned/optional: `wl-clipboard` (clipboard save/restore), `wtype`/`ydotool` (text injection)
- `wtype` or `ydotool` (optional text injection fallback)
> Other distros may work, but Arch/Hyprland is the primary target for now. > Other distros may work, but Arch/Hyprland is the primary target for now.
@@ -49,10 +48,9 @@ bind = SUPER, R, exec, hyprvoice toggle
## Usage ## Usage
### Basic Usage ### Basic Usage
- Press your **toggle** key to start; press again to stop. - Press your toggle key to start; press again to stop.
- Audio streams to the cloud ASR while you speak. - Audio is captured via PipeWire; the pipeline enters `transcribing` after the first frame.
- On stop (or VAD endpoint), Hyprvoice **pastes once** into the focused window. - On toggleoff during `transcribing`, an `inject` action is sent. Injection is currently simulated (no clipboard paste yet).
- Injection flow: **save clipboard → copy final text → send Ctrl+V → restore clipboard**.
### CLI Commands ### CLI Commands
```bash ```bash
@@ -76,15 +74,15 @@ hyprvoice stop
## Status ## Status
| Component | State | Notes | | Component | State | Notes |
| -------------------------- | ----- | ------------------------------------------- | | -------------------------- | ----- | ---------------------------------------------------------- |
| **Daemon (control plane)** | ✅ | State, IPC, worker orchestration | | Daemon (control plane) | ✅ | IPC server, lifecycle; forwards status from the pipeline |
| **Recording control** | ✅ | `hyprvoice toggle` | | Recording control | ✅ | `hyprvoice toggle` |
| **Desktop notifications** | ✅ | `notify-send` (logs fallback) | | Desktop notifications | ✅ | `notify-send` (logs fallback) |
| **Audio capture** | 🔄 | PipeWire + VAD | | Audio capture | | PipeWire (`pw-record`) frames + bounded channels |
| **ASR backends** | 🔄 | Cloud **streaming** now; local Whisper next | | ASR backends | | Not implemented yet (cloud/local planned) |
| **Text injection** | 🔄 | Clipboard paste → `wtype``ydotool` | | Text injection | | Not implemented; will use clipboard + `wtype`/`ydotool` |
| **Service management** | 🔄 | `systemd --user` | | Service management | 🔄 | `systemd --user` unit example provided |
Legend: ✅ done · 🔄 in progress · ⏳ planned Legend: ✅ done · 🔄 in progress · ⏳ planned
@@ -92,9 +90,9 @@ Legend: ✅ done · 🔄 in progress · ⏳ planned
## How it works ## How it works
- **Model:** pipeline + central state (daemon = control plane). - Model: The pipeline owns all runtime state; the daemon is a control plane (IPC + lifecycle) that starts/stops a pipeline instance and forwards status.
- **State machine:** `idle → recording → transcribing → injecting → idle`. - State machine (pipeline): `idle → recording → transcribing → injecting → idle`.
- **Rule:** switch to **`transcribing`**\*\* as soon as the first audio frame is sent\*\* to the ASR. - Rule: switch to `transcribing` as soon as the first audio frame arrives.
### ASCII diagram ### ASCII diagram
@@ -102,34 +100,32 @@ Legend: ✅ done · 🔄 in progress · ⏳ planned
+-------------------+ Unix socket IPC +-----------+ +-------------------+ Unix socket IPC +-----------+
CLI cmd → | Control Daemon | <---------------------------- | CLI/Tool | CLI cmd → | Control Daemon | <---------------------------- | CLI/Tool |
|-------------------| +-----------+ |-------------------| +-----------+
| State: idle/rec/ | | Lifecycle only | events events
| transcribing/... | events events | (start/stop pipe) | -----> [Notifications] -----> notify-send/log
| Event bus (chan) | -----> [Notifications] -----> notify-send/log
| | | |
| frames finals | | status ←------+
+--+-----------+----+ +--+-----------+----+
| | |
Audio | | Final Text Audio | frames
Frames v v Frames v
+--------+ +--------+ text +-----------+ +---------------------------- Pipeline ----------------------------+
| Audio |-->| ASR | -------------->| Injection | | +--------+ +-------------+ +-----------+ |
| Capture| | Stream | | Worker | | | Audio |-->| Transcribing| ...→ | Injecting | → idle |
+--------+ +--------+ +-----------+ | | Capture| | (ASR TBD) | | (stub) | |
| ^ | +--------+ +-------------+ +-----------+ |
+--------------+ +------------------------------------------------------------------+
backpressure via bounded channels
State (daemon): State (pipeline):
idle --toggle--> recording --first frame--> transcribing --final--> injecting --done--> idle idle --toggle--> recording --first frame--> transcribing --inject--> injecting --done--> idle
``` ```
### Data flow ### Data flow
1. `toggle`**recording** 1. `toggle` (daemon) → create pipeline → recording
2. First frame sent → **transcribing** 2. First frame arrives → transcribing (daemon may notify `Transcribing` later)
3. Cloud ASR returns **final****injecting** 3. Second `toggle` during transcribing → send `inject` action → injecting (simulated)
4. Paste once → **idle** 4. Complete → idle; pipeline stops; daemon clears reference
5. Notifications at each transition 5. Notifications at key transitions
--- ---
@@ -150,16 +146,16 @@ sudo cp hyprvoice /usr/local/bin/
``` ```
### Dependencies ### Dependencies
- **Cobra CLI** - Command-line interface framework - Cobra CLI - Command-line interface framework
- **Go 1.24.5+** - Programming language runtime - Go 1.24.5+ - Programming language runtime
--- ---
## Configuration ## Configuration
### File Locations ### File Locations
- **Socket**: `~/.cache/hyprvoice/control.sock` - IPC communication - Socket: `~/.cache/hyprvoice/control.sock` - IPC communication
- **PID file**: `~/.cache/hyprvoice/hyprvoice.pid` - Process tracking - PID file: `~/.cache/hyprvoice/hyprvoice.pid` - Process tracking
### Systemd Service ### Systemd Service
The daemon runs as a user service. To create a systemd service file: The daemon runs as a user service. To create a systemd service file:
@@ -196,17 +192,17 @@ systemctl --user enable --now hyprvoice.service
hyprvoice/ hyprvoice/
├── cmd/hyprvoice/ # Main CLI application ├── cmd/hyprvoice/ # Main CLI application
├── internal/ ├── internal/
│ ├── bus/ # IPC communication (Unix sockets) │ ├── bus/ # IPC (Unix socket) + PID management
│ ├── daemon/ # Main daemon logic and state management │ ├── daemon/ # Control plane (IPC server, lifecycle; no state)
│ ├── notify/ # Desktop notifications │ ├── notify/ # Desktop notifications
│ └── pipeline/ # Audio processing pipeline │ └── pipeline/ # Pipeline + state machine (record/transcribe/inject)
├── go.mod # Go module definition ├── go.mod # Go module definition
└── README.md └── README.md
``` ```
### State Machine ### State Machine
The daemon operates with these states: The pipeline operates with these states:
- **idle****recording****transcribing****injecting****idle** - idle → recordingtranscribing → injecting → idle
### IPC Protocol ### IPC Protocol
Single-character commands over Unix socket: Single-character commands over Unix socket:
@@ -227,6 +223,25 @@ go run ./cmd/hyprvoice status
--- ---
## Recent changes
- Migrated runtime state from the daemon to the pipeline. The daemon now just starts/stops the pipeline and proxies status.
- Introduced an action channel for control (`inject`), enabling toggletoinject behavior while transcribing.
- Implemented PipeWire recording via `pw-record` with bounded channels and basic backpressure logging.
- Desktop notifications wired for start/end/abort (transcribing notification hook available).
- Added CLI commands: `serve`, `toggle`, `status`, `version`, `stop`.
## Direction / Roadmap
- ASR integration: start with a cloud streaming backend; add a local backend later.
- Proper injection: clipboard save/restore + Ctrl+V, with `wtype`/`ydotool` fallbacks.
- VAD / endpointing to autostop on silence (in addition to manual toggle).
- Configuration for devices, sample rate, and buffer sizing.
- Tests for pipeline state transitions and IPC.
- Direction is flexible; we can adjust based on UX feedback and perf.
---
## Troubleshooting ## Troubleshooting
### Common Issues ### Common Issues