rewrite readme

This commit is contained in:
LeonardoTrapani
2025-08-18 19:08:29 +02:00
parent e8fd6c1d49
commit afb77605fb
+364 -211
View File
@@ -1,59 +1,129 @@
# Hyprvoice # Hyprvoice - Voice-Powered Typing for Wayland
> Voicepowered typing for Wayland/Hyprland — press to toggle, speak, instant paste. Press a toggle key, speak, and get instant text input. A speech-to-text tool designed for Wayland/Hyprland with toggle-based workflow and seamless text injection.
> 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) ## Features
--- - **Toggle workflow**: Press once to start recording, press again to stop and inject text
- **Wayland native**: Built specifically for modern Linux desktops (Hyprland, etc.)
- **Real-time feedback**: Desktop notifications for recording states and transcription status
- **Multiple transcription backends**: OpenAI Whisper (planned: whisper.cpp for local processing)
- **Smart text injection**: Clipboard save/restore with direct typing fallback
- **Daemon architecture**: Lightweight control plane with efficient pipeline management
## TL;DR **Status:** Early development - core functionality working, transcription integration in progress
- Toggle workflow (Hyprlandfriendly): press to start, press to stop. ## Installation
- Pipeline owns state; daemon is a thin control plane (IPC + lifecycle).
- Notifications for key events (recording started/ended, aborted).
- Audio capture via PipeWire (`pw-record`) with backpressure.
- ASR + clipboard injection are planned; injection is currently stubbed.
--- ### From AUR (Arch Linux)
## Requirements
- Go 1.24.5+ (for building from source)
- Wayland + Hyprland
- PipeWire tools: `pw-record` and `pw-cli`
- systemd --user (service)
- Optional: libnotify/`notify-send` (desktop notifications)
- Planned/optional: `wl-clipboard` (clipboard save/restore), `wtype`/`ydotool` (text injection)
> Other distros may work, but Arch/Hyprland is the primary target for now.
---
## Install (Arch / Hyprland)
```bash ```bash
# AUR # Using your preferred AUR helper
yay -S hyprvoice # or: yay -S hyprvoice-bin yay -S hyprvoice-bin
# or
paru -S hyprvoice-bin
# Enable user service # Enable user service
systemctl --user enable --now hyprvoice.service systemctl --user enable --now hyprvoice.service
```
# Hyprland keybind (toggle) ### Download Binary
1. Download from [GitHub Releases](https://github.com/leonardotrapani/hyprvoice/releases)
2. Install:
```bash
wget https://github.com/leonardotrapani/hyprvoice/releases/latest/download/hyprvoice-linux-x86_64
mkdir -p ~/.local/bin
mv hyprvoice-linux-x86_64 ~/.local/bin/hyprvoice
chmod +x ~/.local/bin/hyprvoice
# Add to PATH (add to ~/.bashrc or ~/.zshrc)
export PATH="$HOME/.local/bin:$PATH"
```
### Build from Source
```bash
git clone https://github.com/leonardotrapani/hyprvoice.git
cd hyprvoice
# Build the binary
CGO_ENABLED=1 go build -o hyprvoice ./cmd/hyprvoice
# Install locally
sudo cp hyprvoice /usr/local/bin/
```
## Requirements
- **Wayland desktop** (Hyprland, Niri, GNOME, KDE, etc.)
- **PipeWire audio system** with tools
- **System packages**:
```bash
# Arch Linux
sudo pacman -S pipewire pipewire-pulse pw-record wl-clipboard
# Ubuntu/Debian
sudo apt install pipewire-pulse pipewire-bin wl-clipboard
# Fedora
sudo dnf install pipewire-utils wl-clipboard
```
**For text injection (recommended):**
```bash
# Arch Linux
sudo pacman -S wtype
# Ubuntu/Debian
sudo apt install wtype
# Alternative: ydotool (if wtype unavailable)
# Follow ydotool setup for user permissions
```
**Optional:**
- `notify-send` (desktop notifications)
- `systemd --user` (daemon service)
## Quick Start
1. **Setup daemon service:**
```bash
# Enable and start the user service (reccomended)
systemctl --user enable --now hyprvoice.service
# Or run manually in background
hyprvoice serve &
```
2. **Configure Hyprland keybind:**
```bash
# Add to ~/.config/hypr/hyprland.conf
bind = SUPER, R, exec, hyprvoice toggle bind = SUPER, R, exec, hyprvoice toggle
``` ```
--- 3. **Test voice input:**
## Usage ```bash
# Check daemon status
hyprvoice status
### Basic Usage # Toggle recording (or use Super+R)
hyprvoice toggle
# Speak something...
hyprvoice toggle # Stop and transcribe
```
- Press your toggle key to start; press again to stop. ## Quick Reference
- Audio is captured via PipeWire; the pipeline enters `transcribing` after the first frame.
- On toggleoff during `transcribing`, an `inject` action is sent. Injection is currently simulated (no clipboard paste yet).
### CLI Commands ### Common Commands
```bash ```bash
# Start the daemon # Start the daemon
@@ -68,37 +138,147 @@ hyprvoice status
# Get protocol version # Get protocol version
hyprvoice version hyprvoice version
# Stop the daemon # Stop the daemon (if not using systemd service)
hyprvoice stop hyprvoice stop
``` ```
--- ### Keybinding Pattern
## Status Most setups use this toggle pattern in window manager config:
| Component | State | Notes | ```bash
| ---------------------- | ----- | -------------------------------------------------------- | bind = SUPER, R, exec, hyprvoice toggle
| Daemon (control plane) | ✅ | IPC server, lifecycle; forwards status from the pipeline | ```
| Recording control | ✅ | `hyprvoice toggle` |
| Desktop notifications | ✅ | `notify-send` (logs fallback) |
| Audio capture | ✅ | PipeWire (`pw-record`) frames + bounded channels |
| Simple transcriber | ✅ | Collect audio and transcribe when complete |
| OpenAI adapter | ✅ | HTTP API calls with clean audio buffering |
| whisper.cpp adapter | ⏳ | Local inference ready for implementation |
| Text injection | ⏳ | Not implemented; will use clipboard + `wtype`/`ydotool` |
| Service management | 🔄 | `systemd --user` unit example provided |
Legend: ✅ done · 🔄 in progress · ⏳ planned ## Keyboard Shortcuts Setup
--- ### Hyprland
## How it works Add to your `~/.config/hypr/hyprland.conf`:
- Model: The pipeline owns all runtime state; the daemon is a control plane (IPC + lifecycle) that starts/stops a pipeline instance and forwards status. ```bash
- State machine (pipeline): `idle → recording → transcribing → injecting → idle`. # Hyprvoice - Voice to Text (toggle recording)
- Rule: switch to `transcribing` as soon as the first audio frame arrives. bind = SUPER, R, exec, hyprvoice toggle
### Diagrams # Optional: Status check
bind = SUPER SHIFT, R, exec, hyprvoice status && notify-send "Hyprvoice" "$(hyprvoice status)"
```
## Usage Examples
### Basic Toggle Workflow
1. **Press keybind** → Recording starts (notification appears)
2. **Speak your text** → Audio captured in real-time
3. **Press keybind again** → Recording stops, transcription begins
4. **Text appears** → Injected at cursor position or clipboard
### CLI Usage
```bash
# Start daemon manually (if not using systemd service)
hyprvoice serve
# In another terminal: toggle recording
hyprvoice toggle
# ... speak ...
hyprvoice toggle
# Check what's happening
hyprvoice status
```
## Configuration
Configuration will be read from `~/.config/hyprvoice/config.toml` (planned). Currently, the daemon uses default settings.
### Transcription Providers
Hyprvoice will support multiple transcription backends:
#### OpenAI Whisper API (Planned)
Fast, accurate cloud-based transcription:
```toml
[transcription]
provider = "openai"
api_key = "your_openai_api_key"
model = "whisper-1"
language = "auto" # or "en", "es", etc.
```
#### whisper.cpp Local (Planned)
Private, offline transcription using local models:
```toml
[transcription]
provider = "whisper_cpp"
model_path = "~/models/ggml-base.en.bin"
threads = 4
```
### Service Configuration
#### Systemd Service
The daemon runs as a user service:
```bash
# Create service file
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/hyprvoice.service << 'EOF'
[Unit]
Description=Hyprvoice voice-to-text daemon
After=pipewire.service
[Service]
Type=simple
ExecStart=/usr/local/bin/hyprvoice serve
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
EOF
# Enable and start
systemctl --user daemon-reload
systemctl --user enable --now hyprvoice.service
```
### File Locations
- **Socket**: `~/.cache/hyprvoice/control.sock` - IPC communication
- **PID file**: `~/.cache/hyprvoice/hyprvoice.pid` - Process tracking
- **Config**: `~/.config/hyprvoice/config.toml` - User settings (planned)
## Development Status
| Component | Status | Notes |
| --------------------- | ------ | --------------------------------- |
| Core daemon & IPC | ✅ | Unix socket control plane |
| Recording workflow | ✅ | Toggle recording via PipeWire |
| Audio capture | ✅ | Efficient PipeWire integration |
| Desktop notifications | ✅ | Status feedback via notify-send |
| OpenAI transcription | ✅ | HTTP API integration |
| Text injection | ⏳ | Clipboard + typing implementation |
| Configuration system | ⏳ | TOML-based user settings |
| Comprehensive tests | ⏳ | Pipeline and integration testing |
| whisper.cpp support | ⏳ | Local model inference |
**Legend**: ✅ Complete · ⏳ Planned
## Architecture Overview
Hyprvoice uses a **daemon + pipeline** architecture for efficient resource management:
- **Control Daemon**: Lightweight IPC server managing lifecycle
- **Pipeline**: Stateful audio processing (recording → transcribing → injecting)
- **State Machine**: `idle → recording → transcribing → injecting → idle`
### System Architecture
```mermaid ```mermaid
flowchart LR flowchart LR
@@ -136,24 +316,15 @@ stateDiagram-v2
injecting --> idle: abort injecting --> idle: abort
``` ```
### Transcription Strategy ### How It Works
Hyprvoice uses a **simple collect-and-transcribe** approach for reliable transcription: 1. **Toggle recording** → Pipeline starts, audio capture begins
2. **Audio streaming** → PipeWire frames buffered for transcription
3. **Toggle stop** → Recording ends, transcription starts
4. **Text injection** → Result typed or copied to clipboard
5. **Return to idle** → Pipeline cleaned up, ready for next session
- **Collect all audio** during recording session ### Data Flow
- **Single transcription** when recording stops
- **Clean, predictable results** with full context
- **Provider-agnostic adapter** pattern for different backends
**Architecture:**
```
Audio Frames → Audio Buffer → Backend Adapter → Transcription
[OpenAI API, whisper.cpp, etc.]
```
### Data flow
1. `toggle` (daemon) → create pipeline → recording 1. `toggle` (daemon) → create pipeline → recording
2. First frame arrives → transcribing (daemon may notify `Transcribing` later) 2. First frame arrives → transcribing (daemon may notify `Transcribing` later)
@@ -162,182 +333,164 @@ Audio Frames → Audio Buffer → Backend Adapter → Transcription
5. Complete → idle; pipeline stops; daemon clears reference 5. Complete → idle; pipeline stops; daemon clears reference
6. Notifications at key transitions 6. Notifications at key transitions
--- ## Troubleshooting
## Build from source ### Common Issues
#### Daemon Issues
**Daemon won't start:**
```bash
# Check if already running
hyprvoice status
# Check for stale files
ls -la ~/.cache/hyprvoice/
# Clean up and restart
rm -f ~/.cache/hyprvoice/hyprvoice.pid
rm -f ~/.cache/hyprvoice/control.sock
hyprvoice serve
```
**Command not found:**
```bash
# Check installation
which hyprvoice
# Add to PATH if using ~/.local/bin
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
```
#### Audio Issues
**No audio recording:**
```bash
# Check PipeWire is running
systemctl --user status pipewire
# Test microphone
pw-record --help
pw-record test.wav
# Check microphone permissions and levels
```
**Audio device issues:**
```bash
# List available audio devices
pw-cli list-objects | grep -A5 -B5 Audio
# Check microphone is not muted in system settings
```
#### Notification Issues
**No desktop notifications:**
```bash
# Test notify-send directly
notify-send "Test" "This is a test notification"
# Install if missing
sudo pacman -S libnotify # Arch
sudo apt install libnotify-bin # Ubuntu/Debian
```
#### Text Injection Issues
**Text not appearing (when implemented):**
- Ensure cursor is in a text field when toggling off recording
- Check that `wtype` or clipboard tools are installed
- Verify window manager supports the text injection method used
### Debug Mode
```bash
# Run daemon with verbose output
hyprvoice serve
# Check logs from systemd service (or just see results from hyprvoice serve)
journalctl --user -u hyprvoice.service -f
# Test individual commands
hyprvoice toggle
hyprvoice status
```
## Development
### Building from Source
```bash ```bash
git clone https://github.com/leonardotrapani/hyprvoice.git git clone https://github.com/leonardotrapani/hyprvoice.git
cd hyprvoice cd hyprvoice
# Build the binary # Install Go dependencies
go mod download
# Build
CGO_ENABLED=1 go build -o hyprvoice ./cmd/hyprvoice CGO_ENABLED=1 go build -o hyprvoice ./cmd/hyprvoice
# Run tests (when available) # Run tests
go test ./... go test ./...
# Install locally # Install locally
sudo cp hyprvoice /usr/local/bin/ sudo cp hyprvoice /usr/local/bin/
``` ```
### Dependencies
- Cobra CLI - Command-line interface framework
- Go 1.24.5+ - Programming language runtime
---
## Configuration
### File Locations
- Socket: `~/.cache/hyprvoice/control.sock` - IPC communication
- PID file: `~/.cache/hyprvoice/hyprvoice.pid` - Process tracking
### Systemd Service
In the future, this will be implemented with the command `hyprvoice install`
The daemon runs as a user service. To create a systemd service file:
```bash
# Create service file at ~/.config/systemd/user/hyprvoice.service
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/hyprvoice.service << 'EOF'
[Unit]
Description=Hyprvoice daemon
After=pipewire.service
[Service]
Type=simple
ExecStart=/usr/local/bin/hyprvoice serve
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
EOF
# Enable and start
systemctl --user daemon-reload
systemctl --user enable --now hyprvoice.service
```
---
## Development
### Project Structure ### Project Structure
``` ```
hyprvoice/ hyprvoice/
├── cmd/hyprvoice/ # Main CLI application ├── cmd/hyprvoice/ # CLI application entry point
├── internal/ ├── internal/
│ ├── bus/ # IPC (Unix socket) + PID management │ ├── bus/ # IPC (Unix socket) + PID management
│ ├── daemon/ # Control plane (IPC server, lifecycle; no state) │ ├── daemon/ # Control daemon (lifecycle management)
│ ├── notify/ # Desktop notifications │ ├── notify/ # Desktop notification integration
│ ├── pipeline/ # Pipeline + state machine (record/transcribe/inject) │ ├── pipeline/ # Audio processing pipeline + state machine
│ ├── recording/ # Audio capture via PipeWire │ ├── recording/ # PipeWire audio capture
│ └── transcriber/ # Simple transcriber + adapters (OpenAI, whisper.cpp) │ └── transcriber/ # Transcription adapters (OpenAI, whisper.cpp)
├── go.mod # Go module definition ├── go.mod # Go module definition
└── README.md └── README.md
``` ```
### State Machine ### Development Workflow
The pipeline operates with these states:
- idle → recording → transcribing → injecting → idle
### IPC Protocol
Single-character commands over Unix socket:
- `t` - Toggle recording
- `s` - Get status
- `v` - Get protocol version
- `q` - Quit daemon
### Running in Development
```bash ```bash
# Terminal 1: Start daemon with logs # Terminal 1: Run daemon with logs
go run ./cmd/hyprvoice serve go run ./cmd/hyprvoice serve
# Terminal 2: Test commands # Terminal 2: Test commands
go run ./cmd/hyprvoice toggle go run ./cmd/hyprvoice toggle
go run ./cmd/hyprvoice status go run ./cmd/hyprvoice status
go run ./cmd/hyprvoice stop
``` ```
--- ### IPC Protocol
## Direction / Roadmap Simple single-character commands over Unix socket:
- **ASR integration**: OpenAI adapter complete; whisper.cpp adapter ready for implementation. - `t` - Toggle recording on/off
- **Proper injection**: clipboard save/restore + Ctrl+V, with `wtype`/`ydotool` fallbacks. - `s` - Get current status
- **Configuration options**: devices, sample rate, transcription providers. - `v` - Get protocol version
- **Enhanced features**: VAD for auto-stop, improved chunking strategies if needed. - `q` - Quit daemon gracefully
- **Tests**: comprehensive testing for pipeline state transitions and transcription.
- Direction is flexible; we can adjust based on UX feedback and performance needs.
---
## Troubleshooting
### Common Issues
**Daemon won't start**
```bash
# Check if already running
hyprvoice status
# Check PID file
ls -la ~/.cache/hyprvoice/
# Remove stale files
rm ~/.cache/hyprvoice/hyprvoice.pid
rm ~/.cache/hyprvoice/control.sock
```
**No notifications**
```bash
# Test notify-send
notify-send "Test notification"
# Check if libnotify is installed
which notify-send
```
**Permission errors**
```bash
# Check socket permissions
ls -la ~/.cache/hyprvoice/control.sock
# Recreate cache directory
rm -rf ~/.cache/hyprvoice
mkdir -p ~/.cache/hyprvoice
```
### Debug Mode
```bash
# Run with verbose logging
hyprvoice serve 2>&1 | tee hyprvoice.log
```
---
## Contributing ## Contributing
- All PRs and issues welcome. Contributions welcome! Please:
- Follow existing code conventions
- Add tests for new functionality
- Update documentation for user-facing changes
--- - Follow existing code conventions and patterns
- Add tests for new functionality when available
- Update documentation for user-facing changes
- Test on Hyprland/Wayland before submitting PRs
## License ## License
MIT see [LICENSE.md](LICENSE.md) MIT License - see [LICENSE.md](LICENSE.md) for details.