Skip to content

Commit c0a9493

Browse files
authored
Merge pull request #2513 from makermelissa/main
Last minute bug fixes for Magic Storybook
2 parents a3f079b + b08299b commit c0a9493

File tree

2 files changed

+67
-30
lines changed

2 files changed

+67
-30
lines changed

Magic_AI_Storybook/listener.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,11 @@ def recognize(self):
6161
)
6262

6363
return result.strip()
64-
except sr.RequestError:
64+
except sr.RequestError as e:
65+
print(f"Error: {e}")
6566
time.sleep(3)
6667
attempts += 1
67-
print("I wasn't able to understand you. Please repeat that.")
68+
print("Retry attempt: ", attempts)
69+
print("Failed to recognize")
6870
return None
6971
return None

Magic_AI_Storybook/story.py

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323

2424
from listener import Listener
2525

26+
# Base Path is the folder the script resides in
27+
BASE_PATH = os.path.dirname(sys.argv[0])
28+
if BASE_PATH != "":
29+
BASE_PATH += "/"
30+
31+
# General Settings
2632
STORY_WORD_LENGTH = 800
2733
REED_SWITCH_PIN = board.D17
2834
NEOPIXEL_PIN = board.D18
@@ -32,9 +38,10 @@
3238
# Quit Settings (Close book QUIT_CLOSES within QUIT_TIME_PERIOD to quit)
3339
QUIT_CLOSES = 3
3440
QUIT_TIME_PERIOD = 5 # Time period in Seconds
41+
QUIT_DEBOUNCE_DELAY = 0.25 # Time to wait before counting next closeing
3542

3643
# Neopixel Settings
37-
NEOPIXEL_COUNT = 10
44+
NEOPIXEL_COUNT = 1
3845
NEOPIXEL_BRIGHTNESS = 0.2
3946
NEOPIXEL_ORDER = neopixel.GRBW
4047
NEOPIXEL_LOADING_COLOR = (0, 255, 0, 0) # Loading/Dreaming (Green)
@@ -43,7 +50,7 @@
4350
NEOPIXEL_READING_COLOR = (0, 0, 255, 0) # Reading (Blue)
4451
NEOPIXEL_PULSE_SPEED = 0.1
4552

46-
# Image Names
53+
# Image Settings
4754
WELCOME_IMAGE = "welcome.png"
4855
BACKGROUND_IMAGE = "paper_background.png"
4956
LOADING_IMAGE = "loading.png"
@@ -52,26 +59,25 @@
5259
BUTTON_NEW_IMAGE = "button_new.png"
5360

5461
# Asset Paths
55-
BASE_PATH = os.path.dirname(sys.argv[0])
56-
if BASE_PATH != "":
57-
BASE_PATH += "/"
5862
IMAGES_PATH = BASE_PATH + "images/"
5963
FONTS_PATH = BASE_PATH + "fonts/"
6064

61-
# Font Path, Size
65+
# Font Path & Size
6266
TITLE_FONT = (FONTS_PATH + "Desdemona Black Regular.otf", 48)
6367
TITLE_COLOR = (0, 0, 0)
6468
TEXT_FONT = (FONTS_PATH + "times new roman.ttf", 24)
6569
TEXT_COLOR = (0, 0, 0)
6670

67-
# Delays to control the speed of the text
71+
# Delays Settings
72+
# Used to control the speed of the text
6873
WORD_DELAY = 0.1
6974
TITLE_FADE_TIME = 0.05
7075
TITLE_FADE_STEPS = 25
7176
TEXT_FADE_TIME = 0.25
7277
TEXT_FADE_STEPS = 51
78+
ALSA_ERROR_DELAY = 1.0 # Delay to wait after an ALSA errors
7379

74-
# Whitespace Settings in Pixels
80+
# Whitespace Settings (in Pixels)
7581
PAGE_TOP_MARGIN = 20
7682
PAGE_SIDE_MARGIN = 20
7783
PAGE_BOTTOM_MARGIN = 0
@@ -85,13 +91,15 @@
8591
WHISPER_MODEL = "whisper-1"
8692

8793
# Speech Recognition Parameters
88-
ENERGY_THRESHOLD = 1000 # Energy level for mic to detect
89-
PHRASE_TIMEOUT = 3.0 # Space between recordings for sepating phrases
90-
RECORD_TIMEOUT = 30
94+
ENERGY_THRESHOLD = 300 # Energy level for mic to detect
95+
RECORD_TIMEOUT = 30 # Maximum time in seconds to wait for speech
9196

9297
# Do some checks and Import API keys from API_KEYS_FILE
9398
config = configparser.ConfigParser()
9499

100+
if os.geteuid() != 0:
101+
print("Please run this script as root.")
102+
sys.exit(1)
95103
username = os.environ["SUDO_USER"]
96104
user_homedir = os.path.expanduser(f"~{username}")
97105
API_KEYS_FILE = API_KEYS_FILE.replace("~", user_homedir)
@@ -325,11 +333,8 @@ def _handle_sleep(self):
325333
while self._running:
326334
if self._sleeping and reed_switch.value: # Book Open
327335
self._wake()
328-
elif (
329-
not self._busy and not self._sleeping and not reed_switch.value
330-
): # Book Closed
336+
elif not self._sleeping and not reed_switch.value:
331337
self._sleep()
332-
333338
time.sleep(self.sleep_check_delay)
334339

335340
def _handle_loading_status(self):
@@ -429,13 +434,19 @@ def _fade_in_surface(self, surface, x, y, fade_time, fade_steps=50):
429434
fade_time / fade_steps * 1000
430435
) # Time to delay in ms between each fade step
431436

432-
for alpha in range(0, 255, round(255 / fade_steps)):
437+
def draw_alpha(alpha):
433438
buffer.blit(background, (-x, -y))
434439
surface.set_alpha(alpha)
435440
buffer.blit(surface, (0, 0))
436441
self._display_surface(buffer, x, y)
437442
pygame.display.update()
443+
444+
for alpha in range(0, 255, round(255 / fade_steps)):
445+
draw_alpha(alpha)
438446
pygame.time.wait(fade_delay)
447+
if self._sleep_request:
448+
draw_alpha(255) # Finish up quickly
449+
return
439450

440451
def display_current_page(self):
441452
self._busy = True
@@ -482,23 +493,33 @@ def _display_title_text(self, text, y=0):
482493
# Render the title as multiple lines if too big
483494
lines = self._wrap_text(text, self.fonts["title"], self.textarea.width)
484495
self.cursor["y"] = y
496+
delay_value = WORD_DELAY
485497
for line in lines:
486498
words = line.split(" ")
487499
self.cursor["x"] = (
488500
self.textarea.width // 2 - self.fonts["title"].size(line)[0] // 2
489501
)
490502
for word in words:
491503
text = self.fonts["title"].render(word + " ", True, TITLE_COLOR)
492-
self._fade_in_surface(
493-
text,
494-
self.cursor["x"] + self.textarea.x,
495-
self.cursor["y"] + self.textarea.y,
496-
TITLE_FADE_TIME,
497-
TITLE_FADE_STEPS,
498-
)
504+
if self._sleep_request:
505+
delay_value = 0
506+
self._display_surface(
507+
text,
508+
self.cursor["x"] + self.textarea.x,
509+
self.cursor["y"] + self.textarea.y,
510+
)
511+
else:
512+
self._fade_in_surface(
513+
text,
514+
self.cursor["x"] + self.textarea.x,
515+
self.cursor["y"] + self.textarea.y,
516+
TITLE_FADE_TIME,
517+
TITLE_FADE_STEPS,
518+
)
519+
499520
pygame.display.update()
500521
self.cursor["x"] += text.get_width()
501-
time.sleep(WORD_DELAY)
522+
time.sleep(delay_value)
502523
self.cursor["y"] += self.fonts["title"].size(line)[1]
503524

504525
def _title_text_height(self, text):
@@ -614,12 +635,14 @@ def generate_new_story(self):
614635

615636
if self._sleep_request:
616637
self._busy = False
638+
time.sleep(0.2)
639+
print("Not busy anymore")
617640
return
618641

619642
def show_waiting():
620643
# Pause for a beat because the listener doesn't
621644
# immediately start listening sometimes
622-
time.sleep(1)
645+
time.sleep(ALSA_ERROR_DELAY)
623646
self.pixels.fill(NEOPIXEL_WAITING_COLOR)
624647
self.pixels.show()
625648

@@ -654,12 +677,18 @@ def show_waiting():
654677
def _sleep(self):
655678
# Set a sleep request flag so that any busy threads know to finish up
656679
self._sleep_request = True
657-
self.listener.stop_listening()
680+
if self.listener.is_listening():
681+
self.listener.stop_listening()
658682
while self._busy:
683+
print("Still busy")
659684
time.sleep(0.1)
660685
self._sleep_request = False
661686

662-
self._closing_times.append(time.monotonic())
687+
if (
688+
len(self._closing_times) == 0
689+
or (time.monotonic() - self._closing_times[-1]) > QUIT_DEBOUNCE_DELAY
690+
):
691+
self._closing_times.append(time.monotonic())
663692

664693
# Check if we've closed the book a certain number of times
665694
# within a certain number of seconds
@@ -720,6 +749,10 @@ def _sendchat(self, prompt):
720749
def running(self):
721750
return self._running
722751

752+
@property
753+
def sleeping(self):
754+
return self._sleeping
755+
723756

724757
def parse_args():
725758
parser = argparse.ArgumentParser()
@@ -740,7 +773,9 @@ def main(args):
740773
book = Book(args.rotation)
741774
try:
742775
book.start()
743-
book.generate_new_story()
776+
while len(book.pages) == 0:
777+
if not book.sleeping:
778+
book.generate_new_story()
744779
book.display_current_page()
745780

746781
while book.running:

0 commit comments

Comments
 (0)