1

I am making my own voice assistant on python
I want to open websites from it, for example I am saying "open google" and program opening google.com
I was trying to write webbrowser.open(url) in the commands, but when I start the program it opens website URL without any command
This is what I have for now:

import pyttsx3
import speech_recognition as sr
import sys
import subprocess
import webbrowser


def recognize_speech_from_mic(recognizer, microphone) -> dict:
    if not isinstance(recognizer, sr.Recognizer):
        raise TypeError("`recognizer` must be `Recognizer` instance")

    if not isinstance(microphone, sr.Microphone):
        raise TypeError("`microphone` must be `Microphone` instance")

    with microphone as source:
        recognizer.adjust_for_ambient_noise(source)
        audio = recognizer.listen(source)

    response = {"success": True,
                "error": None,
                "transcription": None}

    try:
        response["transcription"] = recognizer.recognize_google(audio)
    except sr.RequestError:
        response["success"] = False
        response["error"] = "API unavailable"
    except sr.UnknownValueError:
        response["error"] = "Unable to recognize speech"

    return response


my_phrases = {
# Names

              'Elsea': ["Hey there", None],
              'elsea': ["Hey there", None],
              'Elsa': ["I'm listening", None],
              'elsa': ["I'm listening", None],
              'Elsia': ["I'm here", None],
              'elsia': ["I'm here", None],
              'Chelsea': ["Go ahead", None],
              'chelsea': ["Go ahead", None],
# Main
              'hello': ['Hi!, How are you?', None],
              'what can you do': ["I can open application and that's all :)", None],
# Stop
              'stop': ['Turning off', 'exit'],
              'exit': ['Goodbye ;)', 'exit'],
              'turn off': ['One moment please...', 'exit'],
# Programs

              'open url': ['Yes,sir', webbrowser.open('google.com')],

        # Chrome
              'Chrome': ['Okay, opening Chrome', chrome],
              'open Chrome': ['Opening....', chrome],
              'chrome': ['Alright, opening Chrome', chrome],
              'open chrome': ['Yes sir', chrome],
              
              }

unknown_command_phrase = ["", None]

engine = pyttsx3.init()

en_voice_id_m = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_EN-US_DAVID_11.0"
en_voice_id_f = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_EN-US_ZIRA_11.0"
gb_voice_id_f = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_EN-GB_HAZEL_11.0"

voices = engine.getProperty('voices')
engine.setProperty('voice', en_voice_id_f)
engine.setProperty('rate', 195)
while True:
    engine.runAndWait()
    
    recognizer = sr.Recognizer()
    microphone = sr.Microphone()
    print("Say something!")
    response = recognize_speech_from_mic(recognizer, microphone)
    pattern = response['transcription']  # get transcription from response dict
    say, command = my_phrases.get(pattern, unknown_command_phrase)  # retrieve response from my_phrases
    engine = pyttsx3.init()
    engine.say(say)
    if command == None:
        print(f'Looks like you said:\n{pattern}.\n')
        pass
    elif command == 'exit':
        sys.exit()
    else: 
        subprocess.check_output(command, shell=True)  # assumes you have these properly configured
        pass

And if I write webbrowser.open(url) it opens it when I start the program, but I want to open it only if I say "Open..."
I don't know how to do it
Guys help please

2 Answers2

0

Couple of things:

  1. subprocess.check_output is used to run commands (programs). But in your patterns you have webbrowser.open() which is a function.
  2. The reason browser opens on start of your program is because the function webbrowser.open() is called while initializing your dictionary my_phrases immediately when the program starts.
    To fix this:
  3. Don't use webbrowser.open. Call the command directly with arguments 'open url': ['Yes,sir', 'chrome', 'www.google.com'],
  4. Use the argument in subprocess.check_output subprocess.check_output(**command, shell=True)
55abhilash
  • 332
  • 2
  • 9
  • It says `Traceback (most recent call last): line 145, in say, command = my_phrases.get(pattern, unknown_command_phrase) ValueError: too many values to unpack (expected 2)` –  Jun 28 '20 at 13:41
  • Umm.. ok my bad. Do this instead: phrase_list = my_phrases.get(pattern, unknown_command_phrase) say = phrase_list[0] And call subprocess.check_output as: subprocess.checkoutput(phrase_list[1], phrase_list[2], shell=True) – 55abhilash Jun 28 '20 at 14:00
  • 1
    Nothing changed( –  Jun 28 '20 at 14:29
  • Try: subprocess.checkoutput(phrase_list[1:], shell=True) I tried this one and it works for me – 55abhilash Jun 28 '20 at 14:45
  • Like this? `'open url': ['Yes,sir', 'chrome', 'www.google.com'], phrase_list = my_phrases.get(pattern, unknown_command_phrase) subprocess.checkoutput(phrase_list[1:], shell=True) ` –  Jun 28 '20 at 15:14
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/216829/discussion-between-55abhilash-and-alex-zab). – 55abhilash Jun 28 '20 at 15:18
0

You can look for "open URL" in pattern, split elements and get last word as a webpage address. I tested it and it works.

  1. Pattern is a string what you said.
  2. We look for 'open URL' in pattern
  3. If there is a 'open URL' in patter, so that means you said for example 'open url facebook'
  4. Then we split pattern and get last word in this case facebook
  5. We run 'start chrome facebook.com' in cmd 6. Chrome opens facebook
import pyttsx3
import speech_recognition as sr
import sys
import subprocess
import webbrowser


def recognize_speech_from_mic(recognizer, microphone) -> dict:
    if not isinstance(recognizer, sr.Recognizer):
        raise TypeError("`recognizer` must be `Recognizer` instance")

    if not isinstance(microphone, sr.Microphone):
        raise TypeError("`microphone` must be `Microphone` instance")

    with microphone as source:
        recognizer.adjust_for_ambient_noise(source)
        audio = recognizer.listen(source)

    response = {"success": True,
                "error": None,
                "transcription": None}

    try:
        response["transcription"] = recognizer.recognize_google(audio)
    except sr.RequestError:
        response["success"] = False
        response["error"] = "API unavailable"
    except sr.UnknownValueError:
        response["error"] = "Unable to recognize speech"

    return response


my_phrases = {
# Names
              'Elsi': ["Yes?", None],
              'elsi': ["Yes?", None],
              'Elsea': ["Hey there", None],
              'elsea': ["Hey there", None],
              'Elsa': ["I'm listening", None],
              'elsa': ["I'm listening", None],
              'Elsia': ["I'm here", None],
              'elsia': ["I'm here", None],
              'Chelsea': ["Go ahead", None],
              'chelsea': ["Go ahead", None],
              'Hey Elsi':["What's up", None],
              'hey elsi':["What's up", None],
# Main
              'hello': ['Hi!, How are you?', None],
              'who are you': ['I am Elsi, voice assistant', None],
              'what can you do': ["I can open application and that's all :)", None],
              'how can I call you?': ['You can call me Elsi', None],
              "what's your name": ['My name is Elsi', None],
# Stop
              'stop': ['Turning off', 'exit'],
              'exit': ['Goodbye ;)', 'exit'],
              'turn off': ['One moment please...', 'exit'],
# Programs

              'open URL': ['Yes,sir', 'start chrome www.google.com'],

        # Chrome
            #   'Chrome': ['Okay, opening Chrome', chrome],
            #   'open Chrome': ['Opening....', chrome],
            #   'Elsi open chrome': ['One moment', chrome],
            #   'chrome': ['Alright, opening Chrome', chrome],
            #   'open chrome': ['Yes sir', chrome],
            #   'Elsi open chrome': ['Okay, starting Chrome', chrome],
              
              }

unknown_command_phrase = ["", ""]

engine = pyttsx3.init()

en_voice_id_m = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_EN-US_DAVID_11.0"
en_voice_id_f = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_EN-US_ZIRA_11.0"
gb_voice_id_f = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_EN-GB_HAZEL_11.0"

voices = engine.getProperty('voices')
engine.setProperty('voice', en_voice_id_f)
engine.setProperty('rate', 195)
#engine.say("Hello. I'm Elsi, your voice assistant.")
while True:
    engine.runAndWait()
    
    recognizer = sr.Recognizer()
    microphone = sr.Microphone()
    print("Say something!")
    response = recognize_speech_from_mic(recognizer, microphone)
    pattern = response['transcription']  # get transcription from response dict
    say, command = my_phrases.get(pattern, unknown_command_phrase)  # retrieve response from my_phrases
    engine = pyttsx3.init()
    engine.say(say)
    if command == None:
        print(f'Looks like you said:\n{pattern}.\n')
        pass
    elif command == 'exit':
        sys.exit()
    elif 'open URL' in str(pattern):
        print(f'Looks like you said:\n{pattern}.\n')
        link_to_page = pattern.split(' ')[-1]
        engine.say('opening ' + link_to_page)
        command = 'start chrome ' + link_to_page + '.com'
        webbrowser.open(link_to_page + '.com')
    else: 
        print(f'Looks like you said:\n{pattern}.\n')
        subprocess.check_output(command, shell=True)
        pass

xszym
  • 928
  • 1
  • 5
  • 11
  • Didn't catch it, can You explain? –  Jun 28 '20 at 13:37
  • 1. Pattern is a string what you said. 2. We look for 'open URL' in pattern 3. If there is a 'open URL' in patter, so that means you said for example 'open url facebook' 4. Then we split pattern and get last word in this case facebook 5. We run 'start chrome facebook.com' in cmd 6. Chrome opens facebook – xszym Jun 28 '20 at 13:38
  • Doesn't work, I've written `if command == None: print(f'Looks like you said:\n{pattern}.\n') pass elif command == 'exit': sys.exit() elif 'try' in str(pattern): print(f'Looks like you said:\n{pattern}.\n') link_to_page = pattern.split(' ')[-1] command = 'start chrome ' + link_to_page + '.com' engine.say('opening ' + link_to_page) subprocess.check_output(command, shell=True) else: subprocess.check_output(command, shell=True) # assumes you have these properly configured pass` –  Jun 28 '20 at 13:54
  • you use 'webbrowser.open(link_to_page + '.com') instead of 'subprocess.check_output(command, shell=True)' – xszym Jun 28 '20 at 15:26
  • I add full code which works for me when I'm saying: Open URL facebook – xszym Jun 28 '20 at 20:05
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/216847/discussion-between-alex-zab-and-xszym). –  Jun 28 '20 at 21:29
  • Please visit chat, I've wroten everything there) –  Jun 29 '20 at 08:56
  • When I say 'open' it is opening 'open.com' in Edge, but when I say 'open Google' or 'open Facebook' it does nothing, and says 'Sorry, I didn't catch you' –  Jun 29 '20 at 14:52
  • It works, but why it is opening in Edge, not in chrome? –  Jun 29 '20 at 18:40