Skip to content

Commit e2fd3c2

Browse files
authored
Merge pull request #3139 from RetiredWizard/fruitspellbkend
spell_jam: refactor for switchable TTS backend
2 parents 9eae9fc + 3b8783a commit e2fd3c2

File tree

3 files changed

+66
-46
lines changed

3 files changed

+66
-46
lines changed

Fruit_Jam/Fruit_Jam_Spell_Jam/aws_polly.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def text_to_speech_polly_http(
199199
text,
200200
access_key,
201201
secret_key,
202-
output_file="/saves/awspollyoutput.mp3",
202+
output_file="/saves/tts_output.mp3",
203203
voice_id="Joanna",
204204
region="us-east-1",
205205
output_format="mp3",

Fruit_Jam/Fruit_Jam_Spell_Jam/code.py

Lines changed: 17 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
22
# SPDX-License-Identifier: MIT
3-
import os
3+
44
import sys
55
import time
6-
76
import supervisor
7+
88
from adafruit_fruitjam import FruitJam
99
from adafruit_fruitjam.peripherals import request_display_config
10-
import adafruit_connection_manager
11-
import adafruit_requests
1210
from displayio import OnDiskBitmap, TileGrid, Group
1311
from adafruit_bitmap_font import bitmap_font
1412
from adafruit_display_text.bitmap_label import Label
1513

16-
from aws_polly import text_to_speech_polly_http
17-
1814
from launcher_config import LauncherConfig
1915

16+
# comment out one of these imports depending on which TTS engine you want to use
17+
from tts_aws import WordFetcherTTS
18+
# from tts_local import WordFetcherTTS
19+
20+
# read the user settings
2021
launcher_config = LauncherConfig()
2122

2223
# constants
@@ -60,55 +61,26 @@
6061

6162
fj.neopixels.brightness = 0.1
6263

63-
# AWS auth requires us to have accurate date/time
64-
now = fj.sync_time()
65-
66-
# setup adafruit_requests session
67-
# pylint: disable=protected-access
68-
pool = adafruit_connection_manager.get_radio_socketpool(fj.network._wifi.esp)
69-
ssl_context = adafruit_connection_manager.get_radio_ssl_context(fj.network._wifi.esp)
70-
requests = adafruit_requests.Session(pool, ssl_context)
71-
72-
# read AWS keys from settings.toml
73-
AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY")
74-
AWS_SECRET_KEY = os.getenv("AWS_SECRET_KEY")
75-
76-
77-
def fetch_word(word, voice="Joanna"):
78-
"""
79-
Fetch an MP3 saying a word from AWS Polly
80-
:param word: The word to speak
81-
:param voice: The AWS Polly voide ID to use
82-
:return: Boolean, whether the request was successful.
83-
"""
84-
85-
if AWS_ACCESS_KEY is None or AWS_SECRET_KEY is None:
86-
return False
87-
88-
fj.neopixels.fill(0xFFFF00)
89-
success = text_to_speech_polly_http(
90-
requests,
91-
text=word,
92-
access_key=AWS_ACCESS_KEY,
93-
secret_key=AWS_SECRET_KEY,
94-
voice_id=voice,
95-
)
96-
fj.neopixels.fill(0x00FF00)
97-
return success
98-
64+
word_fetcher = WordFetcherTTS(fj, launcher_config)
9965

10066
def say_and_spell_lastword():
10167
"""
10268
Say the last word, then spell it out one letter at a time, finally say it once more.
10369
"""
10470
if sayword:
105-
fj.play_mp3_file("/saves/awspollyoutput.mp3")
71+
if word_fetcher.output_path[-4:] == ".mp3":
72+
fj.play_mp3_file(word_fetcher.output_path)
73+
elif word_fetcher.output_path[-4:] == ".wav":
74+
fj.play_file(word_fetcher.output_path)
10675
time.sleep(0.2)
10776
for letter in lastword:
10877
fj.play_mp3_file(f"spell_jam_assets/letter_mp3s/{letter.upper()}.mp3")
10978
time.sleep(0.2)
11079
if sayword:
111-
fj.play_mp3_file("/saves/awspollyoutput.mp3")
80+
if word_fetcher.output_path[-4:] == ".mp3":
81+
fj.play_mp3_file(word_fetcher.output_path)
82+
elif word_fetcher.output_path[-4:] == ".wav":
83+
fj.play_file(word_fetcher.output_path)
11284
fj.neopixels.fill(0x000000)
11385

11486

@@ -133,7 +105,7 @@ def say_and_spell_lastword():
133105
elif c == "\n":
134106
if curword:
135107
lastword = curword
136-
sayword = fetch_word(lastword)
108+
sayword = word_fetcher.fetch_word(lastword)
137109
say_and_spell_lastword()
138110
curword = ""
139111
else:
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
4+
# tts_aws.py
5+
import os
6+
import adafruit_connection_manager
7+
import adafruit_requests
8+
from aws_polly import text_to_speech_polly_http
9+
10+
class WordFetcherTTS():
11+
def __init__(self, fj=None, launcher_config=None, output_path="/saves/tts_output.mp3"):
12+
13+
self.output_path = output_path
14+
self.fj = fj
15+
self.launcher_config = launcher_config
16+
17+
# AWS auth requires us to have accurate date/time
18+
fj.sync_time()
19+
20+
# setup adafruit_requests session
21+
pool = adafruit_connection_manager.get_radio_socketpool(fj.network._wifi.esp)
22+
ssl_context = adafruit_connection_manager.get_radio_ssl_context(fj.network._wifi.esp)
23+
self.requests = adafruit_requests.Session(pool, ssl_context)
24+
self.AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY")
25+
self.AWS_SECRET_KEY = os.getenv("AWS_SECRET_KEY")
26+
27+
def fetch_word(self, word: str, voice: str = "Joanna") -> bool:
28+
if not self.AWS_ACCESS_KEY or not self.AWS_SECRET_KEY:
29+
print("Missing AWS credentials.")
30+
return False
31+
32+
if self.fj:
33+
self.fj.neopixels.fill(0xFFFF00)
34+
35+
success = text_to_speech_polly_http(
36+
self.requests,
37+
text=word,
38+
access_key=self.AWS_ACCESS_KEY,
39+
secret_key=self.AWS_SECRET_KEY,
40+
output_file=self.output_path,
41+
voice_id=voice,
42+
region="us-east-1",
43+
output_format="mp3",
44+
)
45+
46+
if self.fj:
47+
self.fj.neopixels.fill(0x00FF00)
48+
return success

0 commit comments

Comments
 (0)