Preview:
Simple 'Jarvis' voice assistant starter.

Features:
- Wake word ("jarvis")
- Speech recognition (microphone -> text)
- Text-to-speech replies
- Commands: time, date, wikipedia summary, open website, google search, play youtube (if pywhatkit installed),
  take a quick note, tell a joke, and simple system commands (commented / require permission).
- Expand by adding custom command handlers in `handle_command`.
"""

import speech_recognition as sr
import pyttsx3
import datetime
import webbrowser
import wikipedia
import os
import sys

# Optional imports (wrapped so code still runs if they're missing)
try:
    import pyjokes
except Exception:
    pyjokes = None

try:
    import pywhatkit
except Exception:
    pywhatkit = None

WAKE_WORD = "jarvis"  # you can change this

# initialize TTS
tts = pyttsx3.init()
voices = tts.getProperty("voices")
# choose voice (0 or 1 usually)
if len(voices) > 0:
    tts.setProperty("voice", voices[0].id)
tts.setProperty("rate", 170)


def speak(text: str):
    """Speak the provided text and print it."""
    print("Jarvis:", text)
    tts.say(text)
    tts.runAndWait()


# initialize recognizer
recognizer = sr.Recognizer()
recognizer.energy_threshold = 400  # may need tuning
recognizer.pause_threshold = 0.6


def listen(timeout=None, phrase_time_limit=8):
    """Listen from microphone and return recognized text, or None."""
    with sr.Microphone() as mic:
        print("Listening...")
        try:
            audio = recognizer.listen(mic, timeout=timeout, phrase_time_limit=phrase_time_limit)
            text = recognizer.recognize_google(audio)
            print("You:", text)
            return text.lower()
        except sr.WaitTimeoutError:
            return None
        except sr.UnknownValueError:
            return None
        except sr.RequestError:
            speak("Sorry, I couldn't reach the speech recognition service.")
            return None


def get_time():
    now = datetime.datetime.now()
    return now.strftime("%I:%M %p")


def get_date():
    now = datetime.datetime.now()
    return now.strftime("%A, %B %d, %Y")


# simple note-taking (appends to a file)
NOTES_FILE = "jarvis_notes.txt"


def save_note(text):
    with open(NOTES_FILE, "a", encoding="utf-8") as f:
        f.write(f"{datetime.datetime.now().isoformat()} - {text}\n")
    speak("I've saved that note.")


def handle_command(command: str):
    """Parse and handle a recognized command (without the wake word)."""
    if command is None:
        return

    # small normalization
    cmd = command.strip().lower()

    # Greetings
    if any(p in cmd for p in ("hello", "hi", "hey")):
        speak("Hello. How can I help you?")

    # Time & Date
    elif "time" in cmd:
        speak(f"The time is {get_time()}.")
    elif "date" in cmd or "day" in cmd:
        speak(f"Today is {get_date()}.")

    # Wikipedia quick summary: "wikipedia <topic>" or "tell me about <topic>"
    elif cmd.startswith("wikipedia ") or cmd.startswith("tell me about "):
        # extract topic
        topic = cmd.replace("wikipedia ", "").replace("tell me about ", "").strip()
        if topic:
            speak(f"Searching Wikipedia for {topic}")
            try:
                summary = wikipedia.summary(topic, sentences=2, auto_suggest=True, redirect=True)
                speak(summary)
            except Exception as e:
                speak("Sorry, I couldn't find anything on Wikipedia for that topic.")
        else:
            speak("What should I search on Wikipedia?")

    # Open website / search
    elif cmd.startswith("open "):
        site = cmd.replace("open ", "").strip()
        if not site.startswith("http"):
            # allow simple domain names or "youtube" -> open youtube
            if "." not in site:
                site = "https://www." + site + ".com"
            else:
                site = "https://" + site
        speak(f"Opening {site}")
        webbrowser.open(site)

    elif "search for" in cmd or cmd.startswith("google "):
        # google <query> or search for <query>
        q = cmd.replace("search for", "").replace("google", "").strip()
        if q:
            url = "https://www.google.com/search?q=" + webbrowser.quote(q)
            speak(f"Searching Google for {q}")
            webbrowser.open(url)
        else:
            speak("What would you like me to search for?")

    # Play YouTube (pywhatkit)
    elif "play" in cmd and "youtube" in cmd or cmd.startswith("play "):
        # attempt to extract title after "play"
        q = cmd.replace("play", "").replace("on youtube", "").replace("youtube", "").strip()
        if q:
            if pywhatkit:
                speak(f"Playing {q} on YouTube")
                pywhatkit.playonyt(q)
            else:
                speak("pywhatkit is not installed. I'll open YouTube search instead.")
                webbrowser.open("https://www.youtube.com/results?search_query=" + webbrowser.quote(q))
        else:
            speak("What do you want me to play?")

    # Jokes
    elif "joke" in cmd:
        if pyjokes:
            speak(pyjokes.get_joke())
        else:
            speak("I don't have jokes installed, but here's one: Why did the programmer quit his job? Because he didn't get arrays.")

    # Note saving: "remember" or "note"
    elif cmd.startswith("remember ") or cmd.startswith("note "):
        note_text = cmd.replace("remember ", "").replace("note ", "").strip()
        if note_text:
            save_note(note_text)
        else:
            speak("What would you like me to remember?")

    # Read notes
    elif "read my notes" in cmd or "read notes" in cmd:
        if os.path.exists(NOTES_FILE):
            with open(NOTES_FILE, "r", encoding="utf-8") as f:
                notes = f.read().strip()
            if notes:
                speak("Here are your notes.")
                print(notes)
                speak("I have printed them to the console as well.")
            else:
                speak("You have no notes.")
        else:
            speak("You have no notes yet.")

    # Basic exit
    elif any(p in cmd for p in ("exit", "quit", "goodbye", "shutdown jarvis")):
        speak("Goodbye.")
        sys.exit(0)

    # Fallback
    else:
        # if nothing matched, suggest searching the web
        speak("I didn't quite catch a specific command. Would you like me to search the web for that?")
        # naive behavior: open google search
        webbrowser.open("https://www.google.com/search?q=" + webbrowser.quote(cmd))


def main_loop():
    speak("Jarvis online. Say 'Jarvis' to wake me.")
    while True:
        text = listen(timeout=5, phrase_time_limit=4)
        if text is None:
            continue

        # if wake word present, listen for a command
        if WAKE_WORD in text:
            # optional feedback
            speak("Yes?")
            # listen for the actual command now (give a longer phrase limit)
            command = listen(timeout=6, phrase_time_limit=10)
            # if recognition failed, try quick text fallback (re-ask)
            if command is None:
                speak("I didn't catch that. Please say it again.")
                command = listen(timeout=6, phrase_time_limit=10)
            handle_command(command)
        else:
            # ignore background speech
            print("(wake word not detected)")

if __name__ == "__main__":
    try:
        main_loop()
    except KeyboardInterrupt:
        speak("Shutting down. Bye.")
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter