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:
@@ -1,7 +1,7 @@
|
|||||||
# Hyprvoice
|
# Hyprvoice
|
||||||
|
|
||||||
> **Voice‑powered typing for Wayland/Hyprland — press to toggle, speak, instant paste.**
|
> Voice‑powered 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** (Hyprland‑friendly): press to start, press to stop.
|
- Toggle workflow (Hyprland‑friendly): 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).
|
||||||
- **Clipboard‑based 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 toggle‑off 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 → recording → transcribing → 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 toggle‑to‑inject 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 auto‑stop 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
|
||||||
|
|||||||
Reference in New Issue
Block a user