Skip to content

Commit afabe61

Browse files
committed
adding Pi KittenTTS demo code
1 parent e804e24 commit afabe61

File tree

3 files changed

+196
-0
lines changed

3 files changed

+196
-0
lines changed

Raspberry_Pi_KittenTTS/code.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
import json
5+
import time
6+
import glob
7+
import os
8+
import tomllib
9+
from datetime import datetime
10+
import board
11+
from digitalio import DigitalInOut, Direction, Pull
12+
from adafruit_debouncer import Debouncer
13+
14+
15+
from kittentts import KittenTTS
16+
import soundfile as sf
17+
18+
19+
print("initializing...")
20+
21+
with open("weather_narrator.toml", "rb") as f:
22+
config = tomllib.load(f)
23+
voice = config.get("voice", None)
24+
sound_device = config.get("sound_device", None)
25+
26+
day_of_month_words = [
27+
"1st",
28+
"2nd",
29+
"3rd",
30+
"4th",
31+
"5th",
32+
"6th",
33+
"7th",
34+
"8th",
35+
"9th",
36+
"10th",
37+
"11th",
38+
"12th",
39+
"13th",
40+
"14th",
41+
"15th",
42+
"16th",
43+
"17th",
44+
"18th",
45+
"19th",
46+
"20th",
47+
"21st",
48+
"22nd",
49+
"23rd",
50+
"24th",
51+
"25th",
52+
"26th",
53+
"27th",
54+
"28th",
55+
"29th",
56+
"30th",
57+
"31st",
58+
]
59+
60+
button = DigitalInOut(board.D17)
61+
button.direction = Direction.INPUT
62+
button.pull = Pull.UP
63+
64+
debounced_btn = Debouncer(button)
65+
66+
with open("forecast.json", "r") as f:
67+
forecast = json.load(f)
68+
69+
m = KittenTTS("KittenML/kitten-tts-nano-0.1")
70+
71+
72+
def generate_date_time_audio(date_obj):
73+
replacements = {
74+
"00": "oh clock",
75+
"01": "oh 1",
76+
"02": "oh 2",
77+
"03": "oh 3",
78+
"04": "oh 4",
79+
"05": "oh 5",
80+
"06": "oh 6",
81+
"07": "oh 7",
82+
"08": "oh 8",
83+
"09": "oh 9",
84+
}
85+
86+
now_date_obj = datetime.now()
87+
try:
88+
os.remove("date.wav")
89+
except FileNotFoundError:
90+
pass
91+
month = date_obj.strftime("%B")
92+
day_word = day_of_month_words[date_obj.day - 1]
93+
date_script = f"{month} {day_word}, {date_obj.year}."
94+
95+
time_script = now_date_obj.strftime("%-I %M %p")
96+
for key, val in replacements.items():
97+
time_script = time_script.replace(key, val)
98+
99+
date_script += f" The time is: {time_script}."
100+
audio = m.generate(date_script, voice=voice)
101+
sf.write("date.wav", audio, 24000)
102+
103+
104+
print("Press button to hear time and weather...")
105+
while True:
106+
debounced_btn.update()
107+
if debounced_btn.fell:
108+
print("just pressed")
109+
110+
dt_format = "%Y-%m-%dT%H:%M:%S%z"
111+
forecast_date_obj = datetime.strptime(
112+
forecast["properties"]["periods"][0]["startTime"], dt_format
113+
)
114+
115+
generate_date_time_audio(forecast_date_obj)
116+
117+
files_to_read = glob.glob("sound_files/*.wav")
118+
sorted_files_asc = sorted(files_to_read, key=os.path.getmtime)
119+
sorted_files_asc.insert(0, "date.wav")
120+
for file in sorted_files_asc:
121+
if sound_device is None:
122+
os.system(f"aplay {file}")
123+
else:
124+
os.system(f"aplay -D {sound_device} {file}")
125+
126+
time.sleep(0.01)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
import json
5+
import os
6+
import tomllib
7+
import shutil
8+
import requests
9+
from kittentts import KittenTTS
10+
import soundfile as sf
11+
12+
13+
with open("weather_narrator.toml", "rb") as f:
14+
config = tomllib.load(f)
15+
16+
m = KittenTTS("KittenML/kitten-tts-nano-0.1")
17+
18+
replacements = {"mph": "miles per hour"}
19+
20+
# latlng_lookup_url = "https://api.weather.gov/points/{lat},{lon}"
21+
22+
voice = config.get("voice", None)
23+
location_points = config.get("location_points", "36,33")
24+
25+
weather_data = requests.get(
26+
f"https://api.weather.gov/gridpoints/TOP/{location_points}/forecast", timeout=20
27+
).json()
28+
print("Got weather. Building script...")
29+
30+
with open("forecast.json", "w") as f:
31+
json.dump(weather_data, f)
32+
33+
forecast_length = config.get("forecast_length", None)
34+
35+
shutil.rmtree("sound_files", ignore_errors=True)
36+
os.mkdir("sound_files")
37+
38+
for i, period in enumerate(weather_data["properties"]["periods"]):
39+
if forecast_length is None or i < forecast_length:
40+
filename = period["name"].replace(" ", "_")
41+
outstr = ""
42+
if i == 0:
43+
outstr += f'Current Temperature is {period["temperature"]} degrees. '
44+
outstr += f'{period["name"]} {period["detailedForecast"]}'
45+
46+
for key, replacement in replacements.items():
47+
outstr = outstr.replace(key, replacement)
48+
print(f"script: {outstr}")
49+
print("Generating audio...")
50+
audio = m.generate(outstr, voice=voice)
51+
output_file = f"sound_files/{filename}.wav"
52+
print(f"Writing {output_file}")
53+
sf.write(output_file, audio, 24000)
54+
print("Audio generation complete")
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
voice = "expr-voice-3-f"
5+
location_points = "36,33"
6+
forecast_length = 3
7+
#sound_device = "plughw:3,0"
8+
available_voices = [
9+
'expr-voice-2-m',
10+
'expr-voice-2-f',
11+
'expr-voice-3-m',
12+
'expr-voice-3-f',
13+
'expr-voice-4-m',
14+
'expr-voice-4-f',
15+
'expr-voice-5-m',
16+
'expr-voice-5-f' ]

0 commit comments

Comments
 (0)