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.")