HoraVox - a multi-language speaking clock using local AI voice models
Project description
A multi-language speaking clock that announces the time using Piper text-to-speech. It runs entirely offline using local AI voice models -- no API key or internet connection required (except for the initial voice download). It speaks the current hour on the hour using natural language idioms (e.g., "quarter past two", "wpół do czwartej") and supports any language through JSON data files.
Features
- Natural time idioms -- not just "it is 14:30" but "half past two" (English) or "wpół do trzeciej" (Polish)
- Classic & modern modes -- idiomatic ("quarter past five") or digital ("five fifteen")
- Multi-language -- add a new language by creating a JSON file in
data/lang/ - Fully offline -- uses local AI voice models, no API key or cloud service needed
- Voice management -- browse, download, and auto-detect Piper voices from Hugging Face
- Bluetooth audio fix -- plays a silent MP3 before speech to prevent clipping on Bluetooth speakers
- Flexible scheduling -- restrict announcements to a time range (e.g., 7:00--22:00)
- Configurable interval -- announce every N minutes with
--freq(e.g., every 30 min) - Volume control -- set volume 0--100% with
--volume - Background mode -- run as a daemon with
--background, stop with--stop - Hour beeps -- 2 beeps on the full hour, 1 beep on the half hour
- Simulated time -- debug with
--time HH:MMto set a fake starting time - Silent by default -- no terminal output unless
--verboseis passed
Requirements
- Python 3.10+ and pip
aplay(ALSA utils, for WAV playback) --sudo apt install alsa-utilsmpg123(for MP3 playback) --sudo apt install mpg123
Installation
From PyPI
pip install horavox
This installs the vox command.
From source
git clone https://github.com/jcubic/horavox.git
cd horavox
pip install .
This installs the vox command from the local source, including all dependencies.
Usage
HoraVox uses git-style subcommands:
vox <command> [options]
| Command | Description |
|---|---|
vox clock |
Run the speaking clock |
vox now |
Speak the current time once |
vox stop |
Stop running background instances |
vox voice |
Manage Piper voice models |
Run vox <command> --help for command-specific options.
vox clock
Run the speaking clock in foreground or as a background daemon:
vox clock # announce every hour
vox clock --freq 30 # every 30 minutes
vox clock --start 7 --end 22 # only between 7:00-22:00
vox clock --mode modern # digital style ("siedemnasta piętnaście")
vox clock --background # run as a daemon
vox clock --lang pl --voice pl_PL-darkman-medium # specific language and voice
vox clock --volume 50 # 50% volume
Time range accepts H, HH, H:MM, or HH:MM. Supports midnight wrap (e.g., --start 22 --end 6).
Valid --freq values must divide 60 evenly: 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60.
Classic mode (default) uses idiomatic expressions -- "quarter past five", "wpół do szóstej". Modern mode reads the time digitally -- "five fifteen", "siedemnasta piętnaście".
vox now
Speak the current time once and exit:
vox now # speak current time
vox now --time 16:00 # speak a specific time
vox now --mode modern # digital style
vox now --volume 30 # quiet
vox stop
Stop running background instances:
vox stop # interactive selection if multiple instances
vox stop --pid 12345 # stop a specific instance
vox stop --list # print PIDs (for scripting)
vox stop --list --verbose # include command lines
When multiple instances are running, vox stop shows an interactive menu with arrow-key selection.
vox voice
Interactive voice browser -- navigate with arrow keys, press i to install, u to uninstall, q to quit:
vox voice # interactive voice browser
vox voice --lang en # for a specific language
vox voice --list # non-interactive list (for scripting)
vox voice --list --lang pl # non-interactive for a specific language
Installed voices are marked with [*]. Downloads show a progress bar below the list.
Volume and sound
--nosound is equivalent to --volume 0 -- both skip voice loading and audio playback entirely. Available on vox clock and vox now.
Custom commands
Like git, any executable named vox-<name> in your $PATH can be invoked as vox <name>. This lets you extend HoraVox with your own commands or scripts:
# Create a custom command
cat > ~/bin/vox-greet << 'EOF'
#!/bin/bash
vox now --lang en --voice en_US-lessac-medium
EOF
chmod +x ~/bin/vox-greet
# Use it
vox greet
Adding a new language
Create a JSON file in data/lang/<code>.json (e.g., de.json for German). The file contains two mode sections:
{
"classic": {
"hours": ["midnight", "one o'clock", "...", "eleven o'clock"],
"hours_alt": ["midnight", "one", "...", "eleven"],
"minutes": {
"1": "one", "2": "two", "...": "...", "29": "twenty nine"
},
"patterns": {
"full_hour": "{hour}",
"quarter_past": "quarter past {hour_alt}",
"half_past": "half past {hour_alt}",
"quarter_to": "quarter to {next_hour_alt}",
"minutes_past": "{minutes} past {hour_alt}",
"minutes_to": "{minutes} to {next_hour_alt}"
}
},
"modern": {
"hours": ["midnight", "one o'clock", "..."],
"hours_alt": ["twelve", "one", "..."],
"minutes": {
"1": "oh one", "...": "...", "59": "fifty nine"
},
"patterns": {
"full_hour": "{hour}",
"time": "{hour_alt} {minutes}"
}
}
}
Fields
Classic mode (idiomatic -- quarters, halves, past/to):
| Field | Required | Description |
|---|---|---|
hours |
Yes | 24 entries (index 0 = midnight, 12 = noon, etc.) used in {hour} and {next_hour} |
hours_alt |
No | 24 entries for alternate forms (e.g., genitive case). Defaults to hours if omitted |
minutes |
Yes | Keys "1" through "29" -- spoken forms for minute counts |
patterns |
Yes | 6 patterns: full_hour, quarter_past, half_past, quarter_to, minutes_past, minutes_to |
Modern mode (digital -- hour + minutes):
| Field | Required | Description |
|---|---|---|
hours |
Yes | 24 entries for full-hour announcements (can include "midnight", "noon") |
hours_alt |
No | 24 entries for the hour in {hour_alt} {minutes} patterns. Defaults to hours |
minutes |
Yes | Keys "1" through "59" -- spoken forms for all minute values |
patterns |
Yes | 2 patterns: full_hour and time |
Placeholders
| Placeholder | Meaning |
|---|---|
{hour} |
Current hour from hours |
{hour_alt} |
Current hour from hours_alt |
{next_hour} |
Next hour from hours |
{next_hour_alt} |
Next hour from hours_alt |
{minutes} |
Minute count from minutes map |
{remaining} |
Minutes remaining to next hour (same source as {minutes}) |
Pattern rules
| Pattern | When | Example (English) |
|---|---|---|
full_hour |
:00 | "three o'clock" |
quarter_past |
:15 | "quarter past three" |
half_past |
:30 | "half past three" |
quarter_to |
:45 | "quarter to four" |
minutes_past |
:01--:29 (not :15) | "ten past three" |
minutes_to |
:31--:59 (not :45) | "ten to four" |
Project structure
src/horavox/
__init__.py Package init
cli.py Main script (installed as `vox` via pip)
data/
lang/
en.json English time data
pl.json Polish time data
blank.mp3 Silent MP3 for Bluetooth audio wake-up
beep.mp3 Beep sound for hour/half-hour signals
pyproject.toml Package configuration
~/.horavox/ Runtime data (created automatically)
voices/ Downloaded Piper voice models (.onnx)
cache/ Voice catalog cache + PID file
horavox.log Spoken words + error log
Development
See CONTRIBUTING.md for development setup, testing, and publishing instructions.
Name
The name of the project is takend from two words from Latin: Hora (hour) + Vox (voice) -- the voice of the hour.
Acknowledge
The logo use Clipart from OpenClipart and font Lovelo.
License
Copyright (C) 2026 Jakub T. Jankiewicz
Released under MIT license
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file horavox-0.2.0.tar.gz.
File metadata
- Download URL: horavox-0.2.0.tar.gz
- Upload date:
- Size: 40.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
116c4cd09bd06d959707a2328ef4fb1e09852a438e77a4bf3e0482cd89671833
|
|
| MD5 |
ad83056ab4d57138fc3d0acc6df3b9da
|
|
| BLAKE2b-256 |
5e81f802670dc066c55b93366e1caf8ac6aefcb3d0aa8d98c50a24d66be63915
|
File details
Details for the file horavox-0.2.0-py3-none-any.whl.
File metadata
- Download URL: horavox-0.2.0-py3-none-any.whl
- Upload date:
- Size: 27.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01348c0f6593ae821cb0a774c952cdda4f7ecf6428a7ea1fe5943c0ef1344e01
|
|
| MD5 |
66b6b7ad8736951b4ab148260e027014
|
|
| BLAKE2b-256 |
16a27ae9307fa64628d31a4adf639eafd3402d12c27ba529fae09c33c00c613e
|