Skip to content

Commit

Permalink
separate speaker functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
DGrothe-PhD committed Jul 4, 2024
1 parent 1a21bff commit 7fa92c8
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 99 deletions.
119 changes: 20 additions & 99 deletions jarvis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@
import locale
import re

import sys
import platform
import traceback

import speech_recognition as sr
import pyttsx3
import pywhatkit

import wikipedia

from speakerSetup import SpeakerStatus
from videoText import RbbWeather
#from videoText import RbbText
from videoText import ARDText

## We'll set German wikipedia as default.
Expand All @@ -26,79 +23,17 @@
# pylint: disable=broad-exception-caught
# pylint: disable=too-few-public-methods

### disable false positives of not callable
# pylint: disable=E1102

# pylint: disable=E0401
### E0401 as pylint (GitHub/Linux) cannot install Windows package

def is_windows_platform() -> bool:
"""True if system is Windows"""
return platform.system() == 'Windows'

class SpeakerInitializeError(Exception):
"""Represent speaker initialization errors"""


class JarvisStatus:
"""initialize speaker and other settings"""
debugSwitchOffSpeaker = False
engine = None
"""initialize Jarvis settings"""
isRunning = True
engineUsed = ""
searchingEngine = ""
countErrors = 0
wikifound = []
speak = None

@staticmethod
def initializePyTTSSpeaker() -> bool:
"""Tries to initialize py3-tts speaker"""
try:
JarvisStatus.engine = pyttsx3.init()
voices = JarvisStatus.engine.getProperty('voices')
JarvisStatus.engine.setProperty('voice', voices[0].id)
except (RuntimeError, Exception):
print("Sorry, pyttsx3 is not working.")
# goal: if debug mode tell me, else keep quiet
traceback.print_exc(limit=2, file=sys.stdout)
JarvisStatus.engine = None
return False
return True

@staticmethod
def initializeSpVoiceSpeaker() -> bool:
"""Tries to initialize Windows speaker"""
if not is_windows_platform():
raise SpeakerInitializeError("Cannot initialize SpVoice. Windows platform required")
from win32com.client import Dispatch
try:
JarvisStatus.speak = Dispatch("SAPI.SpVoice").Speak
except Exception as exc:
traceback.print_exc(limit=2, file=sys.stdout)
raise SpeakerInitializeError("Cannot initialize SpVoice") from exc
return True
speaker = SpeakerStatus()

@staticmethod
def initializeSpeaker() -> bool:
"""setup of speaking functionality"""
try:
# second member will be evaluated only if first will fail
return JarvisStatus.initializePyTTSSpeaker() or JarvisStatus.initializeSpVoiceSpeaker()
except SpeakerInitializeError:
JarvisStatus.debugSwitchOffSpeaker = True
return False


JarvisStatus.initializeSpeaker()

def talk(text):
"""lets system's voice speak the text"""
if JarvisStatus.engine:
#and not JarvisStatus.debugSwitchOffSpeaker:
JarvisStatus.engine.say(text)
JarvisStatus.engine.runAndWait()
elif JarvisStatus.speak:
JarvisStatus.speak(text)

def makeReadable(text):
"""Replace for better speaker functionality:
Expand Down Expand Up @@ -131,7 +66,7 @@ def takeCommand():
# JarvisStatus.isRunning = False
except Exception:
# rarely happening, however needs test before removal
talk("Beim Einlesen des Sprachkommandos ist etwas schiefgelaufen.")
speaker.talk("Beim Einlesen des Sprachkommandos ist etwas schiefgelaufen.")
JarvisStatus.countErrors += 1
if JarvisStatus.countErrors >= 3:
JarvisStatus.isRunning = False
Expand All @@ -143,16 +78,16 @@ class utilities:
@staticmethod
def searchWikipedia(text, show_all = False):
"""get the first few lines of Wikipedia article"""
JarvisStatus.engineUsed = "wikipedia"
JarvisStatus.searchingEngine = "wikipedia"
JarvisStatus.wikifound = wikipedia.search(text, results=3)
if len(JarvisStatus.wikifound) > 1 and not show_all:
answersFound = " oder ".join(JarvisStatus.wikifound)
print(answersFound)
talk(answersFound)
speaker.talk(answersFound)
else:
info = wikipedia.summary(text, sentences = 2)
print(info)
talk(info)
speaker.talk(info)

def runJarvis():
"""main function"""
Expand All @@ -161,14 +96,14 @@ def runJarvis():
#
if 'spiel' in command:
song = command.replace('spiel', '')
JarvisStatus.engineUsed = "YouTube"
talk('Es läuft ' + song)
JarvisStatus.searchingEngine = "YouTube"
speaker.talk('Es läuft ' + song)
pywhatkit.playonyt(song)
#
elif 'zeit' in command:
time = datetime.datetime.now().strftime('%H:%M')
print(time)
talk(f"Es ist jetzt {time} Uhr.")
speaker.talk(f"Es ist jetzt {time} Uhr.")
#
elif 'wikipedia' in command:
person = command.replace('wikipedia', '')
Expand All @@ -178,26 +113,15 @@ def runJarvis():
textMdax = ARDText(716)
textResult = makeReadable(textMdax.content)
print(textResult)
talk(textResult)
speaker.talk(textResult)
textMdax.extractAndPreparePage(716, 2)
textResult = makeReadable(textMdax.content)
print(textResult)
talk(textResult)
#elif 'was' in command:
# person = command.replace('was', '')
# utilities.searchWikipedia(person)
#
#elif 'wann' in command:
# person = command.replace('wann', '')
# utilities.searchWikipedia(person)
#
#elif 'wo' in command:
# person = command.replace('wo', '')
# utilities.searchWikipedia(person)
speaker.talk(textResult)
#
elif 'zeige alle' in command:
if len(JarvisStatus.wikifound) < 1:
talk("Keine Einträge")
speaker.talk("Keine Einträge")
return
for person in JarvisStatus.wikifound:
utilities.searchWikipedia(person, True)
Expand All @@ -206,35 +130,32 @@ def runJarvis():
elif 'datum' in command:
date = datetime.datetime.now().strftime('%W. KW, %A den %d. %B %Y')
print(date)
talk(date)
speaker.talk(date)
#
elif 'wetter' in command:
textHeute = RbbWeather()
print(textHeute.content)
talk(textHeute.content)
speaker.talk(textHeute.content)
#
elif 'stop listening' in command or 'stop listing' in command \
or (command.startswith('stop') and len(command)< 50):
talk('Bye, until next time.')
speaker.talk('Bye, until next time.')
JarvisStatus.isRunning = False
else:
talk('Entschuldigung, ich habe nicht verstanden.')
speaker.talk('Entschuldigung, ich habe nicht verstanden.')

while JarvisStatus.isRunning:
print("...")# without it, it didn't stop listening
try:
runJarvis()
except KeyboardInterrupt:
print("Tschüs.")
talk("Tschüs, bis zum nächsten Mal.")
speaker.talk("Tschüs, bis zum nächsten Mal.")
break
except Exception as e:
talk(f"Entschuldigung, {JarvisStatus.engineUsed} konnte es nicht finden.")
speaker.talk(f"Entschuldigung, {JarvisStatus.searchingEngine} konnte es nicht finden.")
print(e)

# pylint: disable=invalid-name
# pylint: enable=broad-exception-caught
# pylint: enable=too-few-public-methods
# pylint: enable=E1102
# pylint: enable=E0401
### no issue on a real system though
91 changes: 91 additions & 0 deletions speakerSetup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import sys
import platform
import traceback

import pyttsx3


# pylint: disable=invalid-name
# pylint: disable=broad-exception-caught
# pylint: disable=too-few-public-methods

### disable false positives of not callable
# pylint: disable=E1102

# pylint: disable=E0401
### E0401 as pylint (GitHub/Linux) cannot install Windows package


class SpeakerInitializeError(Exception):
"""Represent speaker initialization errors"""

class SpeakerStatus:
"""initialize speaker and other settings."""
debugSwitchOffSpeaker = False
engine = None
speak = None

@staticmethod
def is_windows_platform() -> bool:
"""True if system is Windows"""
return platform.system() == 'Windows'

@staticmethod
def initializePyTTSSpeaker() -> bool:
"""Tries to initialize py3-tts speaker"""
try:
SpeakerStatus.engine = pyttsx3.init()
voices = SpeakerStatus.engine.getProperty('voices')
SpeakerStatus.engine.setProperty('voice', voices[0].id)
except (RuntimeError, Exception):
print("Sorry, pyttsx3 is not working.")
# goal: if debug mode tell me, else keep quiet
#traceback.print_exc(limit=2, file=sys.stdout)
SpeakerStatus.engine = None
return False
return True

@staticmethod
def initializeSpVoiceSpeaker() -> bool:
"""Tries to initialize Windows speaker"""
if not SpeakerStatus.is_windows_platform():
raise SpeakerInitializeError("Cannot initialize SpVoice. Windows platform required")
from win32com.client import Dispatch
try:
SpeakerStatus.speak = Dispatch("SAPI.SpVoice").Speak
except Exception as exc:
#traceback.print_exc(limit=2, file=sys.stdout)
raise SpeakerInitializeError("Cannot initialize SpVoice") from exc
return True

@staticmethod
def initializeSpeaker() -> bool:
"""setup of speaking functionality"""
try:
# second member will be evaluated only if first will fail
return SpeakerStatus.initializePyTTSSpeaker() or SpeakerStatus.initializeSpVoiceSpeaker()
except SpeakerInitializeError:
print("No speaker has been configured.")
SpeakerStatus.debugSwitchOffSpeaker = True
return False

def __init__(self):
SpeakerStatus.initializeSpeaker()

def talk(self, text):
"""lets system's voice speak the text"""
if SpeakerStatus.engine:
#and not SpeakerStatus.debugSwitchOffSpeaker:
SpeakerStatus.engine.say(text)
SpeakerStatus.engine.runAndWait()
elif SpeakerStatus.speak:
SpeakerStatus.speak(text)



# pylint: disable=invalid-name
# pylint: enable=broad-exception-caught
# pylint: enable=too-few-public-methods
# pylint: enable=E1102
# pylint: enable=E0401
### no issue on a real system though

0 comments on commit 7fa92c8

Please sign in to comment.