horavox 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
horavox-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jakub T. Jankiewicz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
horavox-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,323 @@
1
+ Metadata-Version: 2.4
2
+ Name: horavox
3
+ Version: 0.1.0
4
+ Summary: HoraVox - a multi-language speaking clock using local AI voice models
5
+ Author-email: "Jakub T. Jankiewicz" <me@jcubic.pl>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/jcubic/horavox
8
+ Project-URL: Repository, https://github.com/jcubic/horavox
9
+ Project-URL: Issues, https://github.com/jcubic/horavox/issues
10
+ Keywords: tts,text-to-speech,clock,piper,speaking-clock,accessibility
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: piper-tts
21
+ Requires-Dist: daemonize
22
+ Dynamic: license-file
23
+
24
+ # HoraVox
25
+
26
+ [![pip](https://img.shields.io/badge/pip-0.1.0-blue.svg)](https://pypi.org/project/horavox/)
27
+ [![LICENSE MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jcubic/horavox/blob/master/LICENSE)
28
+
29
+ *Hora* (Latin: hour) + *Vox* (Latin: voice) -- the voice of the hour.
30
+
31
+ A multi-language speaking clock that announces the time using [Piper](https://github.com/rhasspy/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.
32
+
33
+ ## Features
34
+
35
+ - **Natural time idioms** -- not just "it is 14:30" but "half past two" (English) or "wpół do trzeciej" (Polish)
36
+ - **Classic & modern modes** -- idiomatic ("quarter past five") or digital ("five fifteen")
37
+ - **Multi-language** -- add a new language by creating a JSON file in `data/lang/`
38
+ - **Fully offline** -- uses local AI voice models, no API key or cloud service needed
39
+ - **Voice management** -- browse, download, and auto-detect Piper voices from Hugging Face
40
+ - **Bluetooth audio fix** -- plays a silent MP3 before speech to prevent clipping on Bluetooth speakers
41
+ - **Flexible scheduling** -- restrict announcements to a time range (e.g., 7:00--22:00)
42
+ - **Configurable interval** -- announce every N minutes with `--freq` (e.g., every 30 min)
43
+ - **Volume control** -- set volume 0--100% with `--volume`
44
+ - **Background mode** -- run as a daemon with `--background`, stop with `--stop`
45
+ - **Hour beeps** -- 2 beeps on the full hour, 1 beep on the half hour
46
+ - **Simulated time** -- debug with `--time HH:MM` to set a fake starting time
47
+ - **Silent by default** -- no terminal output unless `--verbose` is passed
48
+
49
+ ## Requirements
50
+
51
+ - **Python 3.10+** and **pip**
52
+ - `aplay` (ALSA utils, for WAV playback) -- `sudo apt install alsa-utils`
53
+ - `mpg123` (for MP3 playback) -- `sudo apt install mpg123`
54
+
55
+ ## Installation
56
+
57
+ ### From PyPI
58
+
59
+ ```bash
60
+ pip install horavox
61
+ ```
62
+
63
+ This installs the `vox` command.
64
+
65
+ ### From source
66
+
67
+ ```bash
68
+ git clone https://github.com/jcubic/horavox.git
69
+ cd horavox
70
+ pip install .
71
+ ```
72
+
73
+ This installs the `vox` command from the local source, including all dependencies.
74
+
75
+ ## Usage
76
+
77
+ ### Speak the current time and exit
78
+
79
+ ```bash
80
+ vox --now
81
+ ```
82
+
83
+ ### Run as a clock (announces on the hour)
84
+
85
+ ```bash
86
+ vox
87
+ ```
88
+
89
+ ### Switch between classic and modern time style
90
+
91
+ ```bash
92
+ vox --mode classic # "quarter past five", "za kwadrans szósta" (default)
93
+ vox --mode modern # "five fifteen", "siedemnasta piętnaście"
94
+ ```
95
+
96
+ Classic mode uses idiomatic expressions (quarters, halves, past/to) with 12-hour names. Modern mode reads the time digitally (hour + minutes) using 24-hour names in Polish.
97
+
98
+ ### List available voices for a language
99
+
100
+ ```bash
101
+ vox --list-voices --lang pl
102
+ vox --list-voices --lang en
103
+ ```
104
+
105
+ ### Install and use a specific voice
106
+
107
+ ```bash
108
+ vox --voice en_US-lessac-medium
109
+ ```
110
+
111
+ Voices are auto-downloaded from Hugging Face if not already installed.
112
+
113
+ ### Limit speaking hours
114
+
115
+ ```bash
116
+ vox --start 7 --end 22
117
+ vox --start 7:30 --end 22:30
118
+ ```
119
+
120
+ Accepts `H`, `HH`, `H:MM`, or `HH:MM`. Supports midnight wrap (e.g., `--start 22 --end 6`).
121
+
122
+ ### Announce every 30 minutes
123
+
124
+ ```bash
125
+ vox --freq 30
126
+ ```
127
+
128
+ Valid values for `--freq` must divide 60 evenly: 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60.
129
+
130
+ ### Debug with simulated time
131
+
132
+ ```bash
133
+ vox --time 16:00 --exit
134
+ ```
135
+
136
+ ### Run in the background
137
+
138
+ ```bash
139
+ vox --lang pl --voice pl_PL-darkman-medium --start 8 --end 0 --background
140
+ ```
141
+
142
+ Stop the background daemon:
143
+
144
+ ```bash
145
+ vox --stop
146
+ ```
147
+
148
+ ### Set volume
149
+
150
+ ```bash
151
+ vox --volume 50 # 50% volume
152
+ vox --volume 0 # silent, same as --nosound
153
+ ```
154
+
155
+ `--nosound` is equivalent to `--volume 0` -- both skip voice loading and audio playback entirely.
156
+
157
+ ### Enable log output
158
+
159
+ ```bash
160
+ vox --verbose
161
+ ```
162
+
163
+ ### All options
164
+
165
+ ```
166
+ usage: vox [-h] [--lang LANG] [--mode {classic,modern}] [--voice NAME]
167
+ [--list-voices] [--start HH:MM] [--end HH:MM] [--freq MIN]
168
+ [--time HH:MM] [--exit] [--now] [--background] [--stop]
169
+ [--verbose] [--volume PCT] [--nosound] [--debug]
170
+
171
+ HoraVox — announces the time using text-to-speech
172
+
173
+ options:
174
+ --lang LANG Language code, e.g. pl, en (default: from system locale)
175
+ --mode MODE Time style: classic (idiomatic) or modern (digital) (default: classic)
176
+ --voice NAME Voice name, e.g. en_US-lessac-medium (auto-downloads if missing)
177
+ --list-voices List available Piper voices for the current language and exit
178
+ --start HH:MM Start time for speaking range (default: 0:00)
179
+ --end HH:MM End time for speaking range (default: 23:59)
180
+ --freq MIN Announcement interval in minutes (default: 60)
181
+ --time HH:MM Set simulated start time for debugging (e.g., 16:00)
182
+ --exit Run once and exit (for debugging)
183
+ --now Speak the current time (with minutes) and exit
184
+ --background Run as a background daemon
185
+ --stop Stop the background daemon and exit
186
+ --verbose Show log messages (silent by default)
187
+ --volume PCT Volume level 0-100 percent (default: 100, 0 = no sound)
188
+ --nosound Same as --volume 0 — skip voice loading and audio playback
189
+ --debug Alias for --nosound --verbose
190
+ ```
191
+
192
+ ## Adding a new language
193
+
194
+ Create a JSON file in `data/lang/<code>.json` (e.g., `de.json` for German). The file contains two mode sections:
195
+
196
+ ```json
197
+ {
198
+ "classic": {
199
+ "hours": ["midnight", "one o'clock", "...", "eleven o'clock"],
200
+ "hours_alt": ["midnight", "one", "...", "eleven"],
201
+ "minutes": {
202
+ "1": "one", "2": "two", "...": "...", "29": "twenty nine"
203
+ },
204
+ "patterns": {
205
+ "full_hour": "{hour}",
206
+ "quarter_past": "quarter past {hour_alt}",
207
+ "half_past": "half past {hour_alt}",
208
+ "quarter_to": "quarter to {next_hour_alt}",
209
+ "minutes_past": "{minutes} past {hour_alt}",
210
+ "minutes_to": "{minutes} to {next_hour_alt}"
211
+ }
212
+ },
213
+ "modern": {
214
+ "hours": ["midnight", "one o'clock", "..."],
215
+ "hours_alt": ["twelve", "one", "..."],
216
+ "minutes": {
217
+ "1": "oh one", "...": "...", "59": "fifty nine"
218
+ },
219
+ "patterns": {
220
+ "full_hour": "{hour}",
221
+ "time": "{hour_alt} {minutes}"
222
+ }
223
+ }
224
+ }
225
+ ```
226
+
227
+ ### Fields
228
+
229
+ **Classic mode** (idiomatic -- quarters, halves, past/to):
230
+
231
+ | Field | Required | Description |
232
+ |---|---|---|
233
+ | `hours` | Yes | 24 entries (index 0 = midnight, 12 = noon, etc.) used in `{hour}` and `{next_hour}` |
234
+ | `hours_alt` | No | 24 entries for alternate forms (e.g., genitive case). Defaults to `hours` if omitted |
235
+ | `minutes` | Yes | Keys `"1"` through `"29"` -- spoken forms for minute counts |
236
+ | `patterns` | Yes | 6 patterns: `full_hour`, `quarter_past`, `half_past`, `quarter_to`, `minutes_past`, `minutes_to` |
237
+
238
+ **Modern mode** (digital -- hour + minutes):
239
+
240
+ | Field | Required | Description |
241
+ |---|---|---|
242
+ | `hours` | Yes | 24 entries for full-hour announcements (can include "midnight", "noon") |
243
+ | `hours_alt` | No | 24 entries for the hour in `{hour_alt} {minutes}` patterns. Defaults to `hours` |
244
+ | `minutes` | Yes | Keys `"1"` through `"59"` -- spoken forms for all minute values |
245
+ | `patterns` | Yes | 2 patterns: `full_hour` and `time` |
246
+
247
+ ### Placeholders
248
+
249
+ | Placeholder | Meaning |
250
+ |---|---|
251
+ | `{hour}` | Current hour from `hours` |
252
+ | `{hour_alt}` | Current hour from `hours_alt` |
253
+ | `{next_hour}` | Next hour from `hours` |
254
+ | `{next_hour_alt}` | Next hour from `hours_alt` |
255
+ | `{minutes}` | Minute count from `minutes` map |
256
+ | `{remaining}` | Minutes remaining to next hour (same source as `{minutes}`) |
257
+
258
+ ### Pattern rules
259
+
260
+ | Pattern | When | Example (English) |
261
+ |---|---|---|
262
+ | `full_hour` | :00 | "three o'clock" |
263
+ | `quarter_past` | :15 | "quarter past three" |
264
+ | `half_past` | :30 | "half past three" |
265
+ | `quarter_to` | :45 | "quarter to four" |
266
+ | `minutes_past` | :01--:29 (not :15) | "ten past three" |
267
+ | `minutes_to` | :31--:59 (not :45) | "ten to four" |
268
+
269
+ ## Project structure
270
+
271
+ ```
272
+ src/horavox/
273
+ __init__.py Package init
274
+ cli.py Main script (installed as `vox` via pip)
275
+ data/
276
+ lang/
277
+ en.json English time data
278
+ pl.json Polish time data
279
+ blank.mp3 Silent MP3 for Bluetooth audio wake-up
280
+ beep.mp3 Beep sound for hour/half-hour signals
281
+ pyproject.toml Package configuration
282
+
283
+ ~/.horavox/ Runtime data (created automatically)
284
+ voices/ Downloaded Piper voice models (.onnx)
285
+ cache/ Voice catalog cache + PID file
286
+ horavox.log Spoken words + error log
287
+ ```
288
+
289
+ ## Development
290
+
291
+ ```bash
292
+ git clone https://github.com/jcubic/horavox.git
293
+ cd horavox
294
+ pip install -r requirements.txt
295
+ ```
296
+
297
+ This installs only the dependencies without installing the package itself. You can then run the script directly:
298
+
299
+ ```bash
300
+ python src/horavox/cli.py --now
301
+ ```
302
+
303
+ Alternatively, install in editable mode to get the `vox` command that reflects your source changes:
304
+
305
+ ```bash
306
+ pip install -e .
307
+ ```
308
+
309
+ ### Publishing to PyPI
310
+
311
+ Update the `VERSION` variable in the `Makefile`, then run:
312
+
313
+ ```bash
314
+ make publish
315
+ ```
316
+
317
+ This updates the version in `pyproject.toml`, `cli.py`, and `README.md`, builds the package, and uploads it to PyPI.
318
+
319
+ ## License
320
+
321
+ Copyright (C) 2026 [Jakub T. Jankiewicz](https://jakub.jankiewicz.org)
322
+
323
+ Released under MIT license
@@ -0,0 +1,300 @@
1
+ # HoraVox
2
+
3
+ [![pip](https://img.shields.io/badge/pip-0.1.0-blue.svg)](https://pypi.org/project/horavox/)
4
+ [![LICENSE MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jcubic/horavox/blob/master/LICENSE)
5
+
6
+ *Hora* (Latin: hour) + *Vox* (Latin: voice) -- the voice of the hour.
7
+
8
+ A multi-language speaking clock that announces the time using [Piper](https://github.com/rhasspy/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.
9
+
10
+ ## Features
11
+
12
+ - **Natural time idioms** -- not just "it is 14:30" but "half past two" (English) or "wpół do trzeciej" (Polish)
13
+ - **Classic & modern modes** -- idiomatic ("quarter past five") or digital ("five fifteen")
14
+ - **Multi-language** -- add a new language by creating a JSON file in `data/lang/`
15
+ - **Fully offline** -- uses local AI voice models, no API key or cloud service needed
16
+ - **Voice management** -- browse, download, and auto-detect Piper voices from Hugging Face
17
+ - **Bluetooth audio fix** -- plays a silent MP3 before speech to prevent clipping on Bluetooth speakers
18
+ - **Flexible scheduling** -- restrict announcements to a time range (e.g., 7:00--22:00)
19
+ - **Configurable interval** -- announce every N minutes with `--freq` (e.g., every 30 min)
20
+ - **Volume control** -- set volume 0--100% with `--volume`
21
+ - **Background mode** -- run as a daemon with `--background`, stop with `--stop`
22
+ - **Hour beeps** -- 2 beeps on the full hour, 1 beep on the half hour
23
+ - **Simulated time** -- debug with `--time HH:MM` to set a fake starting time
24
+ - **Silent by default** -- no terminal output unless `--verbose` is passed
25
+
26
+ ## Requirements
27
+
28
+ - **Python 3.10+** and **pip**
29
+ - `aplay` (ALSA utils, for WAV playback) -- `sudo apt install alsa-utils`
30
+ - `mpg123` (for MP3 playback) -- `sudo apt install mpg123`
31
+
32
+ ## Installation
33
+
34
+ ### From PyPI
35
+
36
+ ```bash
37
+ pip install horavox
38
+ ```
39
+
40
+ This installs the `vox` command.
41
+
42
+ ### From source
43
+
44
+ ```bash
45
+ git clone https://github.com/jcubic/horavox.git
46
+ cd horavox
47
+ pip install .
48
+ ```
49
+
50
+ This installs the `vox` command from the local source, including all dependencies.
51
+
52
+ ## Usage
53
+
54
+ ### Speak the current time and exit
55
+
56
+ ```bash
57
+ vox --now
58
+ ```
59
+
60
+ ### Run as a clock (announces on the hour)
61
+
62
+ ```bash
63
+ vox
64
+ ```
65
+
66
+ ### Switch between classic and modern time style
67
+
68
+ ```bash
69
+ vox --mode classic # "quarter past five", "za kwadrans szósta" (default)
70
+ vox --mode modern # "five fifteen", "siedemnasta piętnaście"
71
+ ```
72
+
73
+ Classic mode uses idiomatic expressions (quarters, halves, past/to) with 12-hour names. Modern mode reads the time digitally (hour + minutes) using 24-hour names in Polish.
74
+
75
+ ### List available voices for a language
76
+
77
+ ```bash
78
+ vox --list-voices --lang pl
79
+ vox --list-voices --lang en
80
+ ```
81
+
82
+ ### Install and use a specific voice
83
+
84
+ ```bash
85
+ vox --voice en_US-lessac-medium
86
+ ```
87
+
88
+ Voices are auto-downloaded from Hugging Face if not already installed.
89
+
90
+ ### Limit speaking hours
91
+
92
+ ```bash
93
+ vox --start 7 --end 22
94
+ vox --start 7:30 --end 22:30
95
+ ```
96
+
97
+ Accepts `H`, `HH`, `H:MM`, or `HH:MM`. Supports midnight wrap (e.g., `--start 22 --end 6`).
98
+
99
+ ### Announce every 30 minutes
100
+
101
+ ```bash
102
+ vox --freq 30
103
+ ```
104
+
105
+ Valid values for `--freq` must divide 60 evenly: 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60.
106
+
107
+ ### Debug with simulated time
108
+
109
+ ```bash
110
+ vox --time 16:00 --exit
111
+ ```
112
+
113
+ ### Run in the background
114
+
115
+ ```bash
116
+ vox --lang pl --voice pl_PL-darkman-medium --start 8 --end 0 --background
117
+ ```
118
+
119
+ Stop the background daemon:
120
+
121
+ ```bash
122
+ vox --stop
123
+ ```
124
+
125
+ ### Set volume
126
+
127
+ ```bash
128
+ vox --volume 50 # 50% volume
129
+ vox --volume 0 # silent, same as --nosound
130
+ ```
131
+
132
+ `--nosound` is equivalent to `--volume 0` -- both skip voice loading and audio playback entirely.
133
+
134
+ ### Enable log output
135
+
136
+ ```bash
137
+ vox --verbose
138
+ ```
139
+
140
+ ### All options
141
+
142
+ ```
143
+ usage: vox [-h] [--lang LANG] [--mode {classic,modern}] [--voice NAME]
144
+ [--list-voices] [--start HH:MM] [--end HH:MM] [--freq MIN]
145
+ [--time HH:MM] [--exit] [--now] [--background] [--stop]
146
+ [--verbose] [--volume PCT] [--nosound] [--debug]
147
+
148
+ HoraVox — announces the time using text-to-speech
149
+
150
+ options:
151
+ --lang LANG Language code, e.g. pl, en (default: from system locale)
152
+ --mode MODE Time style: classic (idiomatic) or modern (digital) (default: classic)
153
+ --voice NAME Voice name, e.g. en_US-lessac-medium (auto-downloads if missing)
154
+ --list-voices List available Piper voices for the current language and exit
155
+ --start HH:MM Start time for speaking range (default: 0:00)
156
+ --end HH:MM End time for speaking range (default: 23:59)
157
+ --freq MIN Announcement interval in minutes (default: 60)
158
+ --time HH:MM Set simulated start time for debugging (e.g., 16:00)
159
+ --exit Run once and exit (for debugging)
160
+ --now Speak the current time (with minutes) and exit
161
+ --background Run as a background daemon
162
+ --stop Stop the background daemon and exit
163
+ --verbose Show log messages (silent by default)
164
+ --volume PCT Volume level 0-100 percent (default: 100, 0 = no sound)
165
+ --nosound Same as --volume 0 — skip voice loading and audio playback
166
+ --debug Alias for --nosound --verbose
167
+ ```
168
+
169
+ ## Adding a new language
170
+
171
+ Create a JSON file in `data/lang/<code>.json` (e.g., `de.json` for German). The file contains two mode sections:
172
+
173
+ ```json
174
+ {
175
+ "classic": {
176
+ "hours": ["midnight", "one o'clock", "...", "eleven o'clock"],
177
+ "hours_alt": ["midnight", "one", "...", "eleven"],
178
+ "minutes": {
179
+ "1": "one", "2": "two", "...": "...", "29": "twenty nine"
180
+ },
181
+ "patterns": {
182
+ "full_hour": "{hour}",
183
+ "quarter_past": "quarter past {hour_alt}",
184
+ "half_past": "half past {hour_alt}",
185
+ "quarter_to": "quarter to {next_hour_alt}",
186
+ "minutes_past": "{minutes} past {hour_alt}",
187
+ "minutes_to": "{minutes} to {next_hour_alt}"
188
+ }
189
+ },
190
+ "modern": {
191
+ "hours": ["midnight", "one o'clock", "..."],
192
+ "hours_alt": ["twelve", "one", "..."],
193
+ "minutes": {
194
+ "1": "oh one", "...": "...", "59": "fifty nine"
195
+ },
196
+ "patterns": {
197
+ "full_hour": "{hour}",
198
+ "time": "{hour_alt} {minutes}"
199
+ }
200
+ }
201
+ }
202
+ ```
203
+
204
+ ### Fields
205
+
206
+ **Classic mode** (idiomatic -- quarters, halves, past/to):
207
+
208
+ | Field | Required | Description |
209
+ |---|---|---|
210
+ | `hours` | Yes | 24 entries (index 0 = midnight, 12 = noon, etc.) used in `{hour}` and `{next_hour}` |
211
+ | `hours_alt` | No | 24 entries for alternate forms (e.g., genitive case). Defaults to `hours` if omitted |
212
+ | `minutes` | Yes | Keys `"1"` through `"29"` -- spoken forms for minute counts |
213
+ | `patterns` | Yes | 6 patterns: `full_hour`, `quarter_past`, `half_past`, `quarter_to`, `minutes_past`, `minutes_to` |
214
+
215
+ **Modern mode** (digital -- hour + minutes):
216
+
217
+ | Field | Required | Description |
218
+ |---|---|---|
219
+ | `hours` | Yes | 24 entries for full-hour announcements (can include "midnight", "noon") |
220
+ | `hours_alt` | No | 24 entries for the hour in `{hour_alt} {minutes}` patterns. Defaults to `hours` |
221
+ | `minutes` | Yes | Keys `"1"` through `"59"` -- spoken forms for all minute values |
222
+ | `patterns` | Yes | 2 patterns: `full_hour` and `time` |
223
+
224
+ ### Placeholders
225
+
226
+ | Placeholder | Meaning |
227
+ |---|---|
228
+ | `{hour}` | Current hour from `hours` |
229
+ | `{hour_alt}` | Current hour from `hours_alt` |
230
+ | `{next_hour}` | Next hour from `hours` |
231
+ | `{next_hour_alt}` | Next hour from `hours_alt` |
232
+ | `{minutes}` | Minute count from `minutes` map |
233
+ | `{remaining}` | Minutes remaining to next hour (same source as `{minutes}`) |
234
+
235
+ ### Pattern rules
236
+
237
+ | Pattern | When | Example (English) |
238
+ |---|---|---|
239
+ | `full_hour` | :00 | "three o'clock" |
240
+ | `quarter_past` | :15 | "quarter past three" |
241
+ | `half_past` | :30 | "half past three" |
242
+ | `quarter_to` | :45 | "quarter to four" |
243
+ | `minutes_past` | :01--:29 (not :15) | "ten past three" |
244
+ | `minutes_to` | :31--:59 (not :45) | "ten to four" |
245
+
246
+ ## Project structure
247
+
248
+ ```
249
+ src/horavox/
250
+ __init__.py Package init
251
+ cli.py Main script (installed as `vox` via pip)
252
+ data/
253
+ lang/
254
+ en.json English time data
255
+ pl.json Polish time data
256
+ blank.mp3 Silent MP3 for Bluetooth audio wake-up
257
+ beep.mp3 Beep sound for hour/half-hour signals
258
+ pyproject.toml Package configuration
259
+
260
+ ~/.horavox/ Runtime data (created automatically)
261
+ voices/ Downloaded Piper voice models (.onnx)
262
+ cache/ Voice catalog cache + PID file
263
+ horavox.log Spoken words + error log
264
+ ```
265
+
266
+ ## Development
267
+
268
+ ```bash
269
+ git clone https://github.com/jcubic/horavox.git
270
+ cd horavox
271
+ pip install -r requirements.txt
272
+ ```
273
+
274
+ This installs only the dependencies without installing the package itself. You can then run the script directly:
275
+
276
+ ```bash
277
+ python src/horavox/cli.py --now
278
+ ```
279
+
280
+ Alternatively, install in editable mode to get the `vox` command that reflects your source changes:
281
+
282
+ ```bash
283
+ pip install -e .
284
+ ```
285
+
286
+ ### Publishing to PyPI
287
+
288
+ Update the `VERSION` variable in the `Makefile`, then run:
289
+
290
+ ```bash
291
+ make publish
292
+ ```
293
+
294
+ This updates the version in `pyproject.toml`, `cli.py`, and `README.md`, builds the package, and uploads it to PyPI.
295
+
296
+ ## License
297
+
298
+ Copyright (C) 2026 [Jakub T. Jankiewicz](https://jakub.jankiewicz.org)
299
+
300
+ Released under MIT license
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "horavox"
7
+ version = "0.1.0"
8
+ description = "HoraVox - a multi-language speaking clock using local AI voice models"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ {name = "Jakub T. Jankiewicz", email = "me@jcubic.pl"},
14
+ ]
15
+ keywords = ["tts", "text-to-speech", "clock", "piper", "speaking-clock", "accessibility"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: End Users/Desktop",
20
+ "Operating System :: POSIX :: Linux",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Multimedia :: Sound/Audio :: Speech",
23
+ ]
24
+ dependencies = [
25
+ "piper-tts",
26
+ "daemonize",
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/jcubic/horavox"
31
+ Repository = "https://github.com/jcubic/horavox"
32
+ Issues = "https://github.com/jcubic/horavox/issues"
33
+
34
+ [project.scripts]
35
+ vox = "horavox.cli:main"
36
+
37
+ [tool.setuptools.packages.find]
38
+ where = ["src"]
39
+
40
+ [tool.setuptools.package-data]
41
+ horavox = ["data/**/*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ from horavox.cli import main, __version__