Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,6 @@ jobs:
with:
workspaces: "./src-tauri -> target"

- name: Use mock TranscriptionManager (CI only)
working-directory: src-tauri
run: |
# Swap to mock adapter - avoids compiling whisper/Vulkan
cp src/managers/transcription_mock.rs src/managers/transcription.rs
sed -i '/^transcribe-rs/d' Cargo.toml

- name: Run Rust tests
working-directory: src-tauri
run: cargo test
65 changes: 40 additions & 25 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,49 +34,58 @@ Parrot is a cross-platform desktop text-to-speech (TTS) app built with Tauri 2.x
### Backend Structure (`src-tauri/src/`)

**Core entry points:**

- `lib.rs` — Tauri setup, manager initialization, plugin wiring, command export via tauri-specta
- `main.rs` — Binary entry: CLI arg parsing, Linux GPU workaround, delegates to `lib.rs`
- `settings.rs` — `AppSettings` struct and persistence via `tauri-plugin-store` (`settings_store.json`)
- `cli.rs` — CLI argument definitions (clap derive macros)
- `signal_handle.rs` — Unix signal handlers (SIGUSR1/SIGUSR2) and shared `send_transcription_input()` helper

**Action pipeline:**

- `action_coordinator.rs` — Serializes shortcut lifecycle events through a single background thread; prevents concurrent TTS requests; debounces repeated keys (30ms)
- `actions.rs` — Action type definitions: `speak`, `cancel`, `play_pause`
- `audio_feedback.rs` — Plays start/stop audio cues via rodio
- `input.rs` — Enigo initialization for keyboard/mouse control (macOS requires accessibility permissions)

**Window management:**

- `overlay.rs` — Speaking overlay window lifecycle management
- `tray.rs` / `tray_i18n.rs` — System tray icon, context menu, and i18n-aware menu labels

**Utilities:**

- `shortcut.rs` — Global shortcut initialization and coordination
- `utils.rs` — Shared helpers (tray refresh, cancellation token management)

**Managers** (`managers/`):

- `tts.rs` — Core TTS engine: Kokoro model lifecycle, up to 2 parallel synthesis workers, crossfade between audio chunks (240 samples @ 24 kHz), audio playback via rodio/cpal, pause/resume, configurable model-unload timeout
- `model.rs` — Model catalog (Kokoro-82M), multi-component downloads with progress events, cancellation, extraction, and deletion
- `history.rs` — SQLite database (rusqlite) for TTS history: WAV file storage, configurable entry limit and retention policy

**Commands** (`commands/`):

- `mod.rs` — General: `get_app_settings`, `cancel_operation`, `toggle_tts_pause`, `preload_tts_model`, `get_model_status`, shortcut init/suspend/resume, permission helpers, `is_laptop`
- `audio.rs` — Audio devices: `get_available_output_devices`, `set_selected_output_device`, `play_test_sound`, `check_custom_sounds`
- `models.rs` — Models: `get_available_models`, `get_kokoro_voices`, `download_model`, `delete_model`, `set_active_model`, `cancel_download`
- `history.rs` — History: `get_history_entries`, `toggle_history_entry_saved`, `delete_history_entry`, `update_history_limit`, `update_history_retention_period`

**Audio Toolkit** (`audio_toolkit/`):

- `audio/device.rs` — Output device enumeration via cpal
- `audio/resampler.rs` — Audio resampling (rubato)
- `audio/utils.rs` — WAV file writing and audio utilities
- `constants.rs` — Shared audio constants

**Shortcut system** (`shortcut/`):

- Dual-backend architecture: **HandyKeys** (default on macOS) and **Tauri** via `tauri-plugin-global-shortcut` (default on Windows/Linux)
- Runtime switching via the `keyboard_implementation` setting; HandyKeys auto-falls back to Tauri with persistence on failure
- `handler.rs` — Routes shortcut events through ActionCoordinator

**Helpers** (`helpers/`):

- `clamshell.rs` — `is_laptop()`: detects laptop (clamshell) vs. desktop

### Frontend Structure (`src/`)
Expand Down Expand Up @@ -108,32 +117,34 @@ Parrot is a cross-platform desktop text-to-speech (TTS) app built with Tauri 2.x
All user-facing strings must use i18next. ESLint enforces this — hardcoded strings in JSX will fail linting.

**Adding new text:**

1. Add the key to `src/i18n/locales/en/translation.json`
2. Use in component: `const { t } = useTranslation(); t('key.path')`

**Supported languages (17):**

| Code | Language | Notes |
| ---- | -------- | ----- |
| `en` | English | Source language |
| `zh` | Simplified Chinese | |
| `zh-TW` | Traditional Chinese | |
| `es` | Spanish | |
| `fr` | French | |
| `de` | German | |
| `ja` | Japanese | |
| `ko` | Korean | |
| `vi` | Vietnamese | |
| `pl` | Polish | |
| `it` | Italian | |
| `ru` | Russian | |
| `uk` | Ukrainian | |
| `pt` | Portuguese | |
| `cs` | Czech | |
| `tr` | Turkish | |
| `ar` | Arabic | RTL |
| Code | Language | Notes |
| ------- | ------------------- | --------------- |
| `en` | English | Source language |
| `zh` | Simplified Chinese | |
| `zh-TW` | Traditional Chinese | |
| `es` | Spanish | |
| `fr` | French | |
| `de` | German | |
| `ja` | Japanese | |
| `ko` | Korean | |
| `vi` | Vietnamese | |
| `pl` | Polish | |
| `it` | Italian | |
| `ru` | Russian | |
| `uk` | Ukrainian | |
| `pt` | Portuguese | |
| `cs` | Czech | |
| `tr` | Turkish | |
| `ar` | Arabic | RTL |

**Adding a new language:**

1. Create `src/i18n/locales/{code}/translation.json`
2. Add metadata to `src/i18n/languages.ts`
3. For RTL languages, set `direction: "rtl"` in the metadata entry
Expand All @@ -153,11 +164,13 @@ src/i18n/
## Code Style

**Rust:**

- Run `cargo fmt` and `cargo clippy` before committing
- Handle errors explicitly — avoid `unwrap()` in production code paths
- Add doc comments for public APIs

**TypeScript/React:**

- Strict TypeScript — avoid `any`
- Functional components with hooks
- Tailwind CSS for styling
Expand All @@ -179,22 +192,24 @@ Use conventional commits:
Parrot supports CLI flags for integration with scripts, window managers, and autostart configurations.

**Implementation files:**

- `src-tauri/src/cli.rs` — Argument definitions (clap derive)
- `src-tauri/src/main.rs` — Argument parsing before Tauri initialization
- `src-tauri/src/lib.rs` — CLI overrides applied in the setup closure and single-instance callback
- `src-tauri/src/signal_handle.rs` — Shared `send_transcription_input()` used by both signal handlers and CLI

**Available flags:**

| Flag | Description |
| ---- | ----------- |
| Flag | Description |
| ------------------------ | ---------------------------------------------------------------------------- |
| `--toggle-transcription` | Trigger TTS speak on a running instance (via `tauri_plugin_single_instance`) |
| `--cancel` | Cancel the current TTS operation on a running instance |
| `--start-hidden` | Launch without showing the main window (tray icon still visible) |
| `--no-tray` | Launch without the system tray icon (closing window quits the app) |
| `--debug` | Enable debug mode with verbose (Trace) logging |
| `--cancel` | Cancel the current TTS operation on a running instance |
| `--start-hidden` | Launch without showing the main window (tray icon still visible) |
| `--no-tray` | Launch without the system tray icon (closing window quits the app) |
| `--debug` | Enable debug mode with verbose (Trace) logging |

**Key design decisions:**

- CLI flags are runtime-only overrides — they do **not** modify persisted settings
- Remote flags (`--toggle-transcription`, `--cancel`) work by launching a second instance that forwards its args to the running instance via `tauri_plugin_single_instance`, then exits immediately
- `CliArgs` is stored in Tauri managed state (`.manage()`) so it's accessible in `on_window_event` and other handlers
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ We use GitHub Discussions for feature requests rather than issues. This keeps is
### Before Suggesting a Feature

1. **Search existing discussions** at [github.com/rishiskhare/parrot/discussions](https://github.com/rishiskhare/parrot/discussions)

### Submitting a Feature Request

1. Go to [Discussions](https://github.com/rishiskhare/parrot/discussions)
Expand Down
38 changes: 19 additions & 19 deletions CONTRIBUTING_TRANSLATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,25 +151,25 @@ Some languages have complex plural rules. For now, use a general form that works

## Currently Supported Languages

| Language | Code | Status |
| ------------------- | ------ | ----------------- |
| English | `en` | Complete (source) |
| Arabic | `ar` | Complete |
| Chinese (Simplified)| `zh` | Complete |
| Chinese (Traditional)| `zh-TW` | Complete |
| Czech | `cs` | Complete |
| French | `fr` | Complete |
| German | `de` | Complete |
| Italian | `it` | Complete |
| Japanese | `ja` | Complete |
| Korean | `ko` | Complete |
| Polish | `pl` | Complete |
| Portuguese | `pt` | Complete |
| Russian | `ru` | Complete |
| Spanish | `es` | Complete |
| Turkish | `tr` | Complete |
| Ukrainian | `uk` | Complete |
| Vietnamese | `vi` | Complete |
| Language | Code | Status |
| --------------------- | ------- | ----------------- |
| English | `en` | Complete (source) |
| Arabic | `ar` | Complete |
| Chinese (Simplified) | `zh` | Complete |
| Chinese (Traditional) | `zh-TW` | Complete |
| Czech | `cs` | Complete |
| French | `fr` | Complete |
| German | `de` | Complete |
| Italian | `it` | Complete |
| Japanese | `ja` | Complete |
| Korean | `ko` | Complete |
| Polish | `pl` | Complete |
| Portuguese | `pt` | Complete |
| Russian | `ru` | Complete |
| Spanish | `es` | Complete |
| Turkish | `tr` | Complete |
| Ukrainian | `uk` | Complete |
| Vietnamese | `vi` | Complete |

---

Expand Down
Loading
Loading