diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c246d5a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+References/
+env/
+.vscode/
+__pycache__/
+experiments/
+*.log
+config.py
+*.pickle
+credentials.json
+*note.txt
+*.png
+*.mp4
+*dbs.txt
\ No newline at end of file
diff --git a/Jarvis/__init__.py b/Jarvis/__init__.py
new file mode 100644
index 0000000..a46e419
--- /dev/null
+++ b/Jarvis/__init__.py
@@ -0,0 +1,149 @@
+import speech_recognition as sr
+import pyttsx3
+
+from Jarvis.features import date_time
+from Jarvis.features import launch_app
+from Jarvis.features import website_open
+from Jarvis.features import weather
+from Jarvis.features import wikipedia
+from Jarvis.features import news
+from Jarvis.features import send_email
+from Jarvis.features import google_search
+from Jarvis.features import google_calendar
+from Jarvis.features import note
+from Jarvis.features import system_stats
+from Jarvis.features import loc
+
+
+engine = pyttsx3.init('sapi5')
+voices = engine.getProperty('voices')
+engine.setProperty('voices', voices[0].id)
+
+class JarvisAssistant:
+ def __init__(self):
+ pass
+
+ def mic_input(self):
+ """
+ Fetch input from mic
+ return: user's voice input as text if true, false if fail
+ """
+ try:
+ r = sr.Recognizer()
+ # r.pause_threshold = 1
+ # r.adjust_for_ambient_noise(source, duration=1)
+ with sr.Microphone() as source:
+ print("Listening....")
+ r.energy_threshold = 4000
+ audio = r.listen(source)
+ try:
+ print("Recognizing...")
+ command = r.recognize_google(audio, language='en-in').lower()
+ print(f'You said: {command}')
+ except:
+ print('Please try again')
+ command = self.mic_input()
+ return command
+ except Exception as e:
+ print(e)
+ return False
+
+
+ def tts(self, text):
+ """
+ Convert any text to speech
+ :param text: text(String)
+ :return: True/False (Play sound if True otherwise write exception to log and return False)
+ """
+ try:
+ engine.say(text)
+ engine.runAndWait()
+ engine.setProperty('rate', 175)
+ return True
+ except:
+ t = "Sorry I couldn't understand and handle this input"
+ print(t)
+ return False
+
+ def tell_me_date(self):
+
+ return date_time.date()
+
+ def tell_time(self):
+
+ return date_time.time()
+
+ def launch_any_app(self, path_of_app):
+ """
+ Launch any windows application
+ :param path_of_app: path of exe
+ :return: True is success and open the application, False if fail
+ """
+ return launch_app.launch_app(path_of_app)
+
+ def website_opener(self, domain):
+ """
+ This will open website according to domain
+ :param domain: any domain, example "youtube.com"
+ :return: True if success, False if fail
+ """
+ return website_open.website_opener(domain)
+
+
+ def weather(self, city):
+ """
+ Return weather
+ :param city: Any city of this world
+ :return: weather info as string if True, or False
+ """
+ try:
+ res = weather.fetch_weather(city)
+ except Exception as e:
+ print(e)
+ res = False
+ return res
+
+ def tell_me(self, topic):
+ """
+ Tells about anything from wikipedia
+ :param topic: any string is valid options
+ :return: First 500 character from wikipedia if True, False if fail
+ """
+ return wikipedia.tell_me_about(topic)
+
+ def news(self):
+ """
+ Fetch top news of the day from google news
+ :return: news list of string if True, False if fail
+ """
+ return news.get_news()
+
+ def send_mail(self, sender_email, sender_password, receiver_email, msg):
+
+ return send_email.mail(sender_email, sender_password, receiver_email, msg)
+
+ def google_calendar_events(self, text):
+ service = google_calendar.authenticate_google()
+ date = google_calendar.get_date(text)
+
+ if date:
+ return google_calendar.get_events(date, service)
+ else:
+ pass
+
+ def search_anything_google(self, command):
+ google_search.google_search(command)
+
+ def take_note(self, text):
+ note.note(text)
+
+ def system_info(self):
+ return system_stats.system_stats()
+
+ def location(self, location):
+ current_loc, target_loc, distance = loc.loc(location)
+ return current_loc, target_loc, distance
+
+ def my_location(self):
+ city, state, country = loc.my_location()
+ return city, state, country
\ No newline at end of file
diff --git a/Jarvis/features/__init__.py b/Jarvis/features/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/Jarvis/features/date_time.py b/Jarvis/features/date_time.py
new file mode 100644
index 0000000..b544c87
--- /dev/null
+++ b/Jarvis/features/date_time.py
@@ -0,0 +1,27 @@
+import datetime
+
+
+def date():
+ """
+ Just return date as string
+ :return: date if success, False if fail
+ """
+ try:
+ date = datetime.datetime.now().strftime("%b %d %Y")
+ except Exception as e:
+ print(e)
+ date = False
+ return date
+
+
+def time():
+ """
+ Just return time as string
+ :return: time if success, False if fail
+ """
+ try:
+ time = datetime.datetime.now().strftime("%H:%M:%S")
+ except Exception as e:
+ print(e)
+ time = False
+ return time
\ No newline at end of file
diff --git a/Jarvis/features/google_calendar.py b/Jarvis/features/google_calendar.py
new file mode 100644
index 0000000..206d664
--- /dev/null
+++ b/Jarvis/features/google_calendar.py
@@ -0,0 +1,142 @@
+from __future__ import print_function
+import datetime, pytz, pyttsx3, pickle, os.path
+from googleapiclient.discovery import build
+from google_auth_oauthlib.flow import InstalledAppFlow
+from google.auth.transport.requests import Request
+
+
+
+MONTHS = ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"]
+DAYS = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
+DAY_EXTENSIONS = ["rd", "th", "st", "nd"]
+
+
+
+
+
+def speak(text):
+ engine = pyttsx3.init('sapi5')
+ voices = engine.getProperty('voices')
+ engine.setProperty('voices', voices[0].id)
+ engine.say(text)
+ engine.runAndWait()
+ engine.setProperty('rate', 180)
+
+
+
+
+# If modifying these scopes, delete the file token.pickle.
+SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
+
+
+def authenticate_google():
+ """Shows basic usage of the Google Calendar API.
+ Prints the start and name of the next 10 events on the user's calendar.
+ """
+ creds = None
+ # The file token.pickle stores the user's access and refresh tokens, and is
+ # created automatically when the authorization flow completes for the first
+ # time.
+ if os.path.exists('token.pickle'):
+ with open('token.pickle', 'rb') as token:
+ creds = pickle.load(token)
+ # If there are no (valid) credentials available, let the user log in.
+ if not creds or not creds.valid:
+ if creds and creds.expired and creds.refresh_token:
+ creds.refresh(Request())
+ else:
+ flow = InstalledAppFlow.from_client_secrets_file(
+ 'credentials.json', SCOPES)
+ creds = flow.run_local_server(port=0)
+ # Save the credentials for the next run
+ with open('token.pickle', 'wb') as token:
+ pickle.dump(creds, token)
+
+ service = build('calendar', 'v3', credentials=creds)
+
+ return service
+
+def get_events(day, service):
+ # Call the Calendar API
+ date = datetime.datetime.combine(day, datetime.datetime.min.time())
+ end_date = datetime.datetime.combine(day, datetime.datetime.max.time())
+ utc = pytz.UTC
+ date = date.astimezone(utc)
+ end_date = end_date.astimezone(utc)
+
+
+
+ events_result = service.events().list(calendarId='primary', timeMin=date.isoformat(), timeMax=end_date.isoformat(),
+ singleEvents=True,
+ orderBy='startTime').execute()
+ events = events_result.get('items', [])
+
+ if not events:
+ speak('No upcoming events found.')
+ else:
+ speak(f"You have {len(events)} events on this day.")
+
+ for event in events:
+ start = event['start'].get('dateTime', event['start'].get('date'))
+ print(start, event['summary'])
+ start_time = str(start.split("T")[1].split("+")[0]) # get the hour the event starts
+ if int(start_time.split(":")[0]) < 12: # if the event is in the morning
+ start_time = start_time + "am"
+ else:
+ start_time = str(int(start_time.split(":")[0])-12) # convert 24 hour time to regular
+ start_time = start_time + "pm"
+
+ speak(event["summary"] + " at " + start_time)
+
+
+def get_date(text):
+ today = datetime.date.today()
+
+ if text.count("today") > 0:
+ return today
+
+ day = -1
+ day_of_week = -1
+ month = -1
+ year = today.year
+
+ for word in text.split():
+ if word in MONTHS:
+ month = MONTHS.index(word) + 1
+ elif word in DAYS:
+ day_of_week = DAYS.index(word)
+ elif word.isdigit():
+ day = int(word)
+ else:
+ for ext in DAY_EXTENSIONS:
+ found = word.find(ext)
+ if found > 0:
+ try:
+ day = int(word[:found])
+ except:
+ pass
+
+ if month < today.month and month != -1:
+ year = year+1
+
+
+ if month == -1 and day != -1:
+ if day < today.day:
+ month = today.month + 1
+ else:
+ month = today.month
+
+
+ if month == -1 and day == -1 and day_of_week != -1:
+ current_day_of_week = today.weekday()
+ dif = day_of_week - current_day_of_week
+
+ if dif < 0:
+ dif += 7
+ if text.count("next") >= 1:
+ dif += 7
+
+ return today + datetime.timedelta(dif)
+
+ if day != -1:
+ return datetime.date(month=month, day=day, year=year)
\ No newline at end of file
diff --git a/Jarvis/features/google_search.py b/Jarvis/features/google_search.py
new file mode 100644
index 0000000..397ba93
--- /dev/null
+++ b/Jarvis/features/google_search.py
@@ -0,0 +1,31 @@
+from selenium import webdriver
+from selenium.webdriver.common.keys import Keys
+import re, pyttsx3
+
+
+
+def speak(text):
+ engine = pyttsx3.init('sapi5')
+ voices = engine.getProperty('voices')
+ engine.setProperty('voices', voices[0].id)
+ engine.say(text)
+ engine.runAndWait()
+ engine.setProperty('rate', 180)
+
+
+def google_search(command):
+
+ reg_ex = re.search('search google for (.*)', command)
+ search_for = command.split("for", 1)[1]
+ url = 'https://www.google.com/'
+ if reg_ex:
+ subgoogle = reg_ex.group(1)
+ url = url + 'r/' + subgoogle
+ speak("Okay sir!")
+ speak(f"Searching for {subgoogle}")
+ driver = webdriver.Chrome(
+ executable_path='driver/chromedriver.exe')
+ driver.get('https://www.google.com')
+ search = driver.find_element_by_name('q')
+ search.send_keys(str(search_for))
+ search.send_keys(Keys.RETURN)
\ No newline at end of file
diff --git a/Jarvis/features/gui.py b/Jarvis/features/gui.py
new file mode 100644
index 0000000..eb6196d
--- /dev/null
+++ b/Jarvis/features/gui.py
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'gui.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.2
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("Jarvis 2.0")
+ MainWindow.resize(1440, 900)
+ self.centralwidget = QtWidgets.QWidget(MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.label = QtWidgets.QLabel(self.centralwidget)
+ self.label.setGeometry(QtCore.QRect(0, 0, 1440, 900))
+ self.label.setText("")
+ self.label.setPixmap(QtGui.QPixmap("Jarvis/utils/images/live_wallpaper.gif"))
+ self.label.setScaledContents(True)
+ self.label.setObjectName("label")
+ self.pushButton = QtWidgets.QPushButton(self.centralwidget)
+ self.pushButton.setGeometry(QtCore.QRect(1180, 800, 101, 51))
+ self.pushButton.setStyleSheet("background-color: rgb(0, 170, 255);\n"
+"font: 75 18pt \"MS Shell Dlg 2\";")
+ self.pushButton.setObjectName("pushButton")
+ self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
+ self.pushButton_2.setGeometry(QtCore.QRect(1310, 800, 101, 51))
+ self.pushButton_2.setStyleSheet("background-color:rgb(255, 0, 0);\n"
+"font: 75 18pt \"MS Shell Dlg 2\";")
+ self.pushButton_2.setObjectName("pushButton_2")
+ self.label_2 = QtWidgets.QLabel(self.centralwidget)
+ self.label_2.setGeometry(QtCore.QRect(10, 10, 401, 91))
+ self.label_2.setText("")
+ self.label_2.setPixmap(QtGui.QPixmap("Jarvis/utils/images/initiating.gif"))
+ self.label_2.setObjectName("label_2")
+ self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
+ self.textBrowser.setGeometry(QtCore.QRect(640, 30, 291, 61))
+ self.textBrowser.setStyleSheet("font: 75 16pt \"MS Shell Dlg 2\";\n"
+"background-color:transparent;\ncolor:white;"
+"border-radius:none;\n"
+"")
+ self.textBrowser.setObjectName("textBrowser")
+ self.textBrowser_2 = QtWidgets.QTextBrowser(self.centralwidget)
+ self.textBrowser_2.setGeometry(QtCore.QRect(930, 30, 291, 61))
+ self.textBrowser_2.setStyleSheet("font: 75 16pt \"MS Shell Dlg 2\";\n"
+"background-color:transparent;\ncolor:white;"
+"border-radius:none;")
+ self.textBrowser_2.setObjectName("textBrowser_2")
+ self.textBrowser_3 = QtWidgets.QTextBrowser(self.centralwidget)
+ self.textBrowser_3.setGeometry(QtCore.QRect(1000, 500, 431, 281))
+ self.textBrowser_3.setStyleSheet("font: 11pt \"MS Shell Dlg 2\";\n"
+"background-color:transparent;\ncolor:white;")
+ self.textBrowser_3.setObjectName("textBrowser_3")
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtWidgets.QMenuBar(MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 1440, 26))
+ self.menubar.setObjectName("menubar")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtWidgets.QStatusBar(MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+
+ self.retranslateUi(MainWindow)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ _translate = QtCore.QCoreApplication.translate
+ MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
+ self.pushButton.setText(_translate("MainWindow", "Run"))
+ self.pushButton_2.setText(_translate("MainWindow", "Exit"))
+
+
+if __name__ == "__main__":
+ import sys
+ app = QtWidgets.QApplication(sys.argv)
+ MainWindow = QtWidgets.QMainWindow()
+ ui = Ui_MainWindow()
+ ui.setupUi(MainWindow)
+ MainWindow.show()
+ sys.exit(app.exec_())
diff --git a/Jarvis/features/launch_app.py b/Jarvis/features/launch_app.py
new file mode 100644
index 0000000..307806c
--- /dev/null
+++ b/Jarvis/features/launch_app.py
@@ -0,0 +1,9 @@
+import subprocess
+
+def launch_app(path_of_app):
+ try:
+ subprocess.call([path_of_app])
+ return True
+ except Exception as e:
+ print(e)
+ return False
\ No newline at end of file
diff --git a/Jarvis/features/loc.py b/Jarvis/features/loc.py
new file mode 100644
index 0000000..6281072
--- /dev/null
+++ b/Jarvis/features/loc.py
@@ -0,0 +1,37 @@
+import webbrowser, requests
+from geopy.geocoders import Nominatim
+from geopy.distance import great_circle
+import geocoder
+
+def loc(place):
+ webbrowser.open("http://www.google.com/maps/place/" + place + "")
+ geolocator = Nominatim(user_agent="myGeocoder")
+ location = geolocator.geocode(place, addressdetails=True)
+ target_latlng = location.latitude, location.longitude
+ location = location.raw['address']
+ target_loc = {'city': location.get('city', ''),
+ 'state': location.get('state', ''),
+ 'country': location.get('country', '')}
+
+ current_loc = geocoder.ip('me')
+ current_latlng = current_loc.latlng
+
+ distance = str(great_circle(current_latlng, target_latlng))
+ distance = str(distance.split(' ',1)[0])
+ distance = round(float(distance), 2)
+
+ return current_loc, target_loc, distance
+
+def my_location():
+ ip_add = requests.get('https://api.ipify.org').text
+ url = 'https://get.geojs.io/v1/ip/geo/' + ip_add + '.json'
+ geo_requests = requests.get(url)
+ geo_data = geo_requests.json()
+ city = geo_data['city']
+ state = geo_data['region']
+ country = geo_data['country']
+
+ return city, state,country
+
+
+
diff --git a/Jarvis/features/news.py b/Jarvis/features/news.py
new file mode 100644
index 0000000..26914de
--- /dev/null
+++ b/Jarvis/features/news.py
@@ -0,0 +1,19 @@
+import requests
+import json
+
+
+
+def get_news():
+ url = 'http://newsapi.org/v2/top-headlines?sources=the-times-of-india&apiKey=ae5ccbe2006a4debbe6424d7e4b569ec'
+ news = requests.get(url).text
+ news_dict = json.loads(news)
+ articles = news_dict['articles']
+ try:
+
+ return articles
+ except:
+ return False
+
+
+def getNewsUrl():
+ return 'http://newsapi.org/v2/top-headlines?sources=the-times-of-india&apiKey=ae5ccbe2006a4debbe6424d7e4b569ec'
diff --git a/Jarvis/features/note.py b/Jarvis/features/note.py
new file mode 100644
index 0000000..2b2c50d
--- /dev/null
+++ b/Jarvis/features/note.py
@@ -0,0 +1,11 @@
+import subprocess
+import datetime
+
+def note(text):
+ date = datetime.datetime.now()
+ file_name = str(date).replace(":", "-") + "-note.txt"
+ with open(file_name, "w") as f:
+ f.write(text)
+ notepad = "C://Program Files (x86)//Notepad++//notepad++.exe"
+ subprocess.Popen([notepad, file_name])
+
diff --git a/Jarvis/features/send_email.py b/Jarvis/features/send_email.py
new file mode 100644
index 0000000..3c06ff2
--- /dev/null
+++ b/Jarvis/features/send_email.py
@@ -0,0 +1,15 @@
+import smtplib
+
+
+def mail(sender_email, sender_password, receiver_email, msg):
+ try:
+ mail = smtplib.SMTP('smtp.gmail.com', 587)
+ mail.ehlo()
+ mail.starttls()
+ mail.login(sender_email, sender_password)
+ mail.sendmail(sender_email, receiver_email, msg)
+ mail.close()
+ return True
+ except Exception as e:
+ print(e)
+ return False
\ No newline at end of file
diff --git a/Jarvis/features/system_stats.py b/Jarvis/features/system_stats.py
new file mode 100644
index 0000000..663c977
--- /dev/null
+++ b/Jarvis/features/system_stats.py
@@ -0,0 +1,21 @@
+import psutil, pyttsx3, math
+
+def convert_size(size_bytes):
+ if size_bytes == 0:
+ return "0B"
+ size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
+ i = int(math.floor(math.log(size_bytes, 1024)))
+ p = math.pow(1024, i)
+ s = round(size_bytes / p, 2)
+ print("%s %s" % (s, size_name[i]))
+ return "%s %s" % (s, size_name[i])
+
+
+def system_stats():
+ cpu_stats = str(psutil.cpu_percent())
+ battery_percent = psutil.sensors_battery().percent
+ memory_in_use = convert_size(psutil.virtual_memory().used)
+ total_memory = convert_size(psutil.virtual_memory().total)
+ final_res = f"Currently {cpu_stats} percent of CPU, {memory_in_use} of RAM out of total {total_memory} is being used and battery level is at {battery_percent} percent"
+ return final_res
+
diff --git a/Jarvis/features/weather.py b/Jarvis/features/weather.py
new file mode 100644
index 0000000..9fe9d49
--- /dev/null
+++ b/Jarvis/features/weather.py
@@ -0,0 +1,42 @@
+import requests
+from Jarvis.config import config
+
+
+
+def fetch_weather(city):
+ """
+ City to weather
+ :param city: City
+ :return: weather
+ """
+ api_key = config.weather_api_key
+ units_format = "&units=metric"
+
+ base_url = "http://api.openweathermap.org/data/2.5/weather?q="
+ complete_url = base_url + city + "&appid=" + api_key + units_format
+
+ response = requests.get(complete_url)
+
+ city_weather_data = response.json()
+
+ if city_weather_data["cod"] != "404":
+ main_data = city_weather_data["main"]
+ weather_description_data = city_weather_data["weather"][0]
+ weather_description = weather_description_data["description"]
+ current_temperature = main_data["temp"]
+ current_pressure = main_data["pressure"]
+ current_humidity = main_data["humidity"]
+ wind_data = city_weather_data["wind"]
+ wind_speed = wind_data["speed"]
+
+ final_response = f"""
+ The weather in {city} is currently {weather_description}
+ with a temperature of {current_temperature} degree celcius,
+ atmospheric pressure of {current_pressure} hectoPascals,
+ humidity of {current_humidity} percent
+ and wind speed reaching {wind_speed} kilometers per hour"""
+
+ return final_response
+
+ else:
+ return "Sorry Sir, I couldn't find the city in my database. Please try again"
\ No newline at end of file
diff --git a/Jarvis/features/website_open.py b/Jarvis/features/website_open.py
new file mode 100644
index 0000000..7a4f8c7
--- /dev/null
+++ b/Jarvis/features/website_open.py
@@ -0,0 +1,10 @@
+import webbrowser
+
+def website_opener(domain):
+ try:
+ url = 'https://www.' + domain
+ webbrowser.open(url)
+ return True
+ except Exception as e:
+ print(e)
+ return False
\ No newline at end of file
diff --git a/Jarvis/features/wikipedia.py b/Jarvis/features/wikipedia.py
new file mode 100644
index 0000000..2ee4d1e
--- /dev/null
+++ b/Jarvis/features/wikipedia.py
@@ -0,0 +1,13 @@
+import wikipedia
+import re
+
+def tell_me_about(topic):
+ try:
+ # info = str(ny.content[:500].encode('utf-8'))
+ # res = re.sub('[^a-zA-Z.\d\s]', '', info)[1:]
+ res = wikipedia.summary(topic, sentences=3)
+
+ return res
+ except Exception as e:
+ print(e)
+ return False
diff --git a/Jarvis/features/youtube_search.py b/Jarvis/features/youtube_search.py
new file mode 100644
index 0000000..7c5efa5
--- /dev/null
+++ b/Jarvis/features/youtube_search.py
@@ -0,0 +1,22 @@
+import webbrowser, urllib, re
+import urllib.parse
+import urllib.request
+
+domain = input("Enter the song name: ")
+song = urllib.parse.urlencode({"search_query" : domain})
+print("Song" + song)
+
+# fetch the ?v=query_string
+result = urllib.request.urlopen("http://www.youtube.com/results?" + song)
+print(result)
+
+# make the url of the first result song
+search_results = re.findall(r'href=\"\/watch\?v=(.{4})', result.read().decode())
+print(search_results)
+
+# make the final url of song selects the very first result from youtube result
+url = "http://www.youtube.com/watch?v="+str(search_results)
+
+# play the song using webBrowser module which opens the browser
+# webbrowser.open(url, new = 1)
+webbrowser.open_new(url)
\ No newline at end of file
diff --git a/Jarvis/utils/images/initiating.gif b/Jarvis/utils/images/initiating.gif
new file mode 100644
index 0000000..949af7f
Binary files /dev/null and b/Jarvis/utils/images/initiating.gif differ
diff --git a/Jarvis/utils/images/live_wallpaper.gif b/Jarvis/utils/images/live_wallpaper.gif
new file mode 100644
index 0000000..819ba31
Binary files /dev/null and b/Jarvis/utils/images/live_wallpaper.gif differ
diff --git a/Jarvis/utils/images/loading.gif b/Jarvis/utils/images/loading.gif
new file mode 100644
index 0000000..7beabc1
Binary files /dev/null and b/Jarvis/utils/images/loading.gif differ
diff --git a/Jarvis/utils/images/loading_1.gif b/Jarvis/utils/images/loading_1.gif
new file mode 100644
index 0000000..d835a89
Binary files /dev/null and b/Jarvis/utils/images/loading_1.gif differ
diff --git a/Jarvis/utils/images/program_load.gif b/Jarvis/utils/images/program_load.gif
new file mode 100644
index 0000000..753d0a0
Binary files /dev/null and b/Jarvis/utils/images/program_load.gif differ
diff --git a/README.md b/README.md
index d15543f..da6dec1 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,86 @@
-# Jarvis
-JARVIS (Just a Rather Very Intelligent System)
+# JARVIS (Just a Rather Very Intelligent System)
+
+#### This was my attempt to make a voice assistant similar to JARVIS (in iron man movie)
+#### Let's be honest, it's not as intelligent as in the movie, but it can do a lot of cool things and automate your daily tasks you do on your personal computers/laptops.
+
+## Built with
+
+
+
+
+## Features
+
+It can do a lot of cool things, some of them being:
+
+- Greet user
+- Tell current time and date
+- Launch applications/softwares
+- Open any website
+- Tells about weather of any city
+- Open location of any place plus tells the distance between your place and queried place
+- Tells your current system status (RAM Usage, battery health, CPU usage)
+- Tells about your upcoming events (Google Calendar)
+- Tells about any person (via Wikipedia)
+- Can search anything on Google
+- Can play any song on YouTube
+- Tells top headlines (via Times of India)
+- Plays music
+- Send email (with subject and content)
+- Calculate any mathematical expression (example: Jarvis, calculate x + 135 - 234 = 345)
+- Answer any generic question (via Wolframalpha)
+- Take important note in notepad
+- Tells a random joke
+- Tells your IP address
+- Can switch the window
+- Can take screenshot and save it with custom filename
+- Can hide all files in a folder and also make them visible again
+- Has a cool Graphical User Interface
+
+## API Keys
+To run this program you will require a bunch of API keys. Register your API key by clicking the following links
+
+- [OpenWeatherMap API](https://openweathermap.org/api)
+- [Wolframalpha](https://www.wolframalpha.com/)
+- [Google Calendar API](https://developers.google.com/calendar/auth)
+
+## Installation
+
+- First clone the repo
+- Make a config.py file and include the following in it:
+ ```weather_api_key = ""
+ email = ""
+ email_password = ""
+ wolframalpha_id = ""
+- Copy the config.py file in Jarvis>config folder
+- Make a new python environment
+ If you are using anaconda just type ```conda create -n jarvis python==3.8.5 ``` in anaconda prompt
+- To activate the environment ``` conda activate jarvis ```
+- Navigate to the directory of your project
+- Install all the requirements by just hitting ``` pip install -r requirements.txt ```
+- Install PyAudio from wheel file by following instructions given [here](https://stackoverflow.com/a/55630212)
+- Run the program by ``` python main.py ```
+- Enjoy !!!!
+
+## Code Structure
+
+
+ ├── driver
+ ├── Jarvis # Main folder for features
+ │ ├── config # Contains all secret API Keys
+ │ ├── features # All functionalities of JARVIS
+ │ └── utils # GUI images
+ ├── __init__.py # Definition of feature's functions
+ ├── gui.ui # GUI file (in .ui format)
+ ├── main.py # main driver program of Jarvis
+ ├── requirements.txt # all dependencies of the program
+
+- The code structure if pretty simple. The code is completely modularized and is highly customizable
+- To add a new feature:
+ - Make a new file in features folder, write the feature's function you want to include
+ - Add the function's definition to __init__.py
+ - Add the voice commands through which you want to invoke the function
+
+## Future Improvements
+- Generalized conversations can be made possible by incorporating Natural Language Processing
+- GUI can be made more nicer to look at and functional
+- More functionalities can be added
diff --git a/driver/chromedriver.exe b/driver/chromedriver.exe
new file mode 100644
index 0000000..38ea5f5
Binary files /dev/null and b/driver/chromedriver.exe differ
diff --git a/gui.ui b/gui.ui
new file mode 100644
index 0000000..c2dad24
--- /dev/null
+++ b/gui.ui
@@ -0,0 +1,146 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 1440
+ 900
+
+
+
+ MainWindow
+
+
+
+
+
+ 0
+ 0
+ 1440
+ 900
+
+
+
+
+
+
+ Jarvis/utils/images/live_wallpaper.gif
+
+
+ true
+
+
+
+
+
+ 1180
+ 790
+ 101
+ 51
+
+
+
+ background-color: rgb(0, 170, 255);
+font: 75 18pt "MS Shell Dlg 2";
+
+
+ Run
+
+
+
+
+
+ 1310
+ 790
+ 101
+ 51
+
+
+
+ background-color:rgb(255, 0, 0);
+font: 75 18pt "MS Shell Dlg 2";
+
+
+ Exit
+
+
+
+
+
+ 10
+ 10
+ 401
+ 91
+
+
+
+
+
+
+ Jarvis/utils/images/initiating.gif
+
+
+
+
+
+ 640
+ 30
+ 291
+ 61
+
+
+
+ font: 75 16pt "MS Shell Dlg 2";
+background-color:transparent;
+border-radius:none;
+
+
+
+
+
+
+ 930
+ 30
+ 291
+ 61
+
+
+
+ font: 75 16pt "MS Shell Dlg 2";
+background-color:transparent;
+border-radius:none;
+
+
+
+
+
+ 1000
+ 500
+ 431
+ 281
+
+
+
+ font: 11pt "MS Shell Dlg 2";
+background-color:transparent;
+
+
+
+
+
+
+
+
+
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..68cd82f
--- /dev/null
+++ b/main.py
@@ -0,0 +1,377 @@
+from Jarvis import JarvisAssistant
+import re
+import os
+import random
+import pprint
+import datetime
+import requests
+import sys
+import urllib.parse
+import pyjokes
+import time
+import pyautogui
+import pywhatkit
+import wolframalpha
+from PIL import Image
+from PyQt5 import QtWidgets, QtCore, QtGui
+from PyQt5.QtCore import QTimer, QTime, QDate, Qt
+from PyQt5.QtGui import QMovie
+from PyQt5.QtCore import *
+from PyQt5.QtGui import *
+from PyQt5.QtWidgets import *
+from PyQt5.uic import loadUiType
+from Jarvis.features.gui import Ui_MainWindow
+from Jarvis.config import config
+
+obj = JarvisAssistant()
+
+# ================================ MEMORY ===========================================================================================================
+
+GREETINGS = ["hi jarvis", "jarvis", "wake up jarvis", "you there jarvis", "time to work jarvis", "hey jarvis",
+ "ok jarvis", "are you there"]
+GREETINGS_RES = ["always there for you wasii", "i am ready wasii",
+ "your wish my command", "how can i help you wasii?", "i am online and ready wasii"]
+
+EMAIL_DIC = {
+ 'myself': 'support@hackerwasii.com',
+ 'my official email': 'support@hackerwasii.com',
+ 'my second email': 'support@hackerwasii.com',
+ 'my official mail': 'support@hackerwasii.com',
+ 'my second mail': 'support@hackerwasii.com'
+}
+
+CALENDAR_STRS = ["what do i have", "do i have plans", "am i busy"]
+# =======================================================================================================================================================
+
+
+def speak(text):
+ obj.tts(text)
+
+
+app_id = config.wolframalpha_id
+
+
+def computational_intelligence(question):
+ try:
+ client = wolframalpha.Client(app_id)
+ answer = client.query(question)
+ answer = next(answer.results).text
+ print(answer)
+ return answer
+ except:
+ speak("Sorry sir I couldn't fetch your question's answer. Please try again ")
+ return None
+
+def startup():
+ speak("Initializing Jarvis, wait a moment wasii")
+ speak("Starting all systems applications")
+ speak("Installing and checking all drivers")
+ speak("Caliberating and examining all the core processors")
+ speak("Checking the internet connection")
+ speak("Wait a moment wasii")
+ speak("All drivers are up and running")
+ speak("All systems have been activated")
+ speak("Now I am online")
+ hour = int(datetime.datetime.now().hour)
+ if hour>=0 and hour<=12:
+ speak("Good Morning")
+ elif hour>12 and hour<18:
+ speak("Good afternoon")
+ else:
+ speak("Good evening")
+ c_time = obj.tell_time()
+ speak(f"Currently it is {c_time}")
+ speak("I am Jarvis. Online and ready sir wasii. Please tell me how may I help you")
+
+
+
+
+def wish():
+ hour = int(datetime.datetime.now().hour)
+ if hour>=0 and hour<=12:
+ speak("Good Morning")
+ elif hour>12 and hour<18:
+ speak("Good afternoon")
+ else:
+ speak("Good evening")
+ c_time = obj.tell_time()
+ speak(f"Currently it is {c_time}")
+ speak("I am Jarvis. Online and ready sir. Please tell me how may I help you")
+# if __name__ == "__main__":
+
+
+class MainThread(QThread):
+ def __init__(self):
+ super(MainThread, self).__init__()
+
+ def run(self):
+ self.TaskExecution()
+
+ def TaskExecution(self):
+ startup()
+ wish()
+
+ while True:
+ command = obj.mic_input()
+
+ if re.search('date', command):
+ date = obj.tell_me_date()
+ print(date)
+ speak(date)
+
+ elif "time" in command:
+ time_c = obj.tell_time()
+ print(time_c)
+ speak(f"Sir the time is {time_c}")
+
+ elif re.search('launch', command):
+ dict_app = {
+ 'chrome': 'C:/Program Files/Google/Chrome/Application/chrome'
+ }
+
+ app = command.split(' ', 1)[1]
+ path = dict_app.get(app)
+
+ if path is None:
+ speak('Application path not found')
+ print('Application path not found')
+
+ else:
+ speak('Launching: ' + app + 'for you sir!')
+ obj.launch_any_app(path_of_app=path)
+
+ elif command in GREETINGS:
+ speak(random.choice(GREETINGS_RES))
+
+ elif re.search('open', command):
+ domain = command.split(' ')[-1]
+ open_result = obj.website_opener(domain)
+ speak(f'Alright sir !! Opening {domain}')
+ print(open_result)
+
+ elif re.search('weather', command):
+ city = command.split(' ')[-1]
+ weather_res = obj.weather(city=city)
+ print(weather_res)
+ speak(weather_res)
+
+ elif re.search('tell me about', command):
+ topic = command.split(' ')[-1]
+ if topic:
+ wiki_res = obj.tell_me(topic)
+ print(wiki_res)
+ speak(wiki_res)
+ else:
+ speak(
+ "Sorry sir. I couldn't load your query from my database. Please try again")
+
+ elif "buzzing" in command or "news" in command or "headlines" in command:
+ news_res = obj.news()
+ speak('Source: The Times Of India')
+ speak('Todays Headlines are..')
+ for index, articles in enumerate(news_res):
+ pprint.pprint(articles['title'])
+ speak(articles['title'])
+ if index == len(news_res)-2:
+ break
+ speak('These were the top headlines, Have a nice day Sir!!..')
+
+ elif 'search google for' in command:
+ obj.search_anything_google(command)
+
+ elif "play music" in command or "hit some music" in command:
+ music_dir = "F://Songs//Imagine_Dragons"
+ songs = os.listdir(music_dir)
+ for song in songs:
+ os.startfile(os.path.join(music_dir, song))
+
+ elif 'youtube' in command:
+ video = command.split(' ')[1]
+ speak(f"Okay sir, playing {video} on youtube")
+ pywhatkit.playonyt(video)
+
+ elif "email" in command or "send email" in command:
+ sender_email = config.email
+ sender_password = config.email_password
+
+ try:
+ speak("Whom do you want to email sir ?")
+ recipient = obj.mic_input()
+ receiver_email = EMAIL_DIC.get(recipient)
+ if receiver_email:
+
+ speak("What is the subject sir ?")
+ subject = obj.mic_input()
+ speak("What should I say?")
+ message = obj.mic_input()
+ msg = 'Subject: {}\n\n{}'.format(subject, message)
+ obj.send_mail(sender_email, sender_password,
+ receiver_email, msg)
+ speak("Email has been successfully sent")
+ time.sleep(2)
+
+ else:
+ speak(
+ "I coudn't find the requested person's email in my database. Please try again with a different name")
+
+ except:
+ speak("Sorry sir. Couldn't send your mail. Please try again")
+
+ elif "calculate" in command:
+ question = command
+ answer = computational_intelligence(question)
+ speak(answer)
+
+ elif "what is" in command or "who is" in command:
+ question = command
+ answer = computational_intelligence(question)
+ speak(answer)
+
+ elif "what do i have" in command or "do i have plans" or "am i busy" in command:
+ obj.google_calendar_events(command)
+
+ if "make a note" in command or "write this down" in command or "remember this" in command:
+ speak("What would you like me to write down?")
+ note_text = obj.mic_input()
+ obj.take_note(note_text)
+ speak("I've made a note of that")
+
+ elif "close the note" in command or "close notepad" in command:
+ speak("Okay sir, closing notepad")
+ os.system("taskkill /f /im notepad++.exe")
+
+ if "joke" in command:
+ joke = pyjokes.get_joke()
+ print(joke)
+ speak(joke)
+
+ elif "system" in command:
+ sys_info = obj.system_info()
+ print(sys_info)
+ speak(sys_info)
+
+ elif "where is" in command:
+ place = command.split('where is ', 1)[1]
+ current_loc, target_loc, distance = obj.location(place)
+ city = target_loc.get('city', '')
+ state = target_loc.get('state', '')
+ country = target_loc.get('country', '')
+ time.sleep(1)
+ try:
+
+ if city:
+ res = f"{place} is in {state} state and country {country}. It is {distance} km away from your current location"
+ print(res)
+ speak(res)
+
+ else:
+ res = f"{state} is a state in {country}. It is {distance} km away from your current location"
+ print(res)
+ speak(res)
+
+ except:
+ res = "Sorry sir, I couldn't get the co-ordinates of the location you requested. Please try again"
+ speak(res)
+
+ elif "ip address" in command:
+ ip = requests.get('https://api.ipify.org').text
+ print(ip)
+ speak(f"Your ip address is {ip}")
+
+ elif "switch the window" in command or "switch window" in command:
+ speak("Okay sir, Switching the window")
+ pyautogui.keyDown("alt")
+ pyautogui.press("tab")
+ time.sleep(1)
+ pyautogui.keyUp("alt")
+
+ elif "where i am" in command or "current location" in command or "where am i" in command:
+ try:
+ city, state, country = obj.my_location()
+ print(city, state, country)
+ speak(
+ f"You are currently in {city} city which is in {state} state and country {country}")
+ except Exception as e:
+ speak(
+ "Sorry sir, I coundn't fetch your current location. Please try again")
+
+ elif "take screenshot" in command or "take a screenshot" in command or "capture the screen" in command:
+ speak("By what name do you want to save the screenshot?")
+ name = obj.mic_input()
+ speak("Alright sir, taking the screenshot")
+ img = pyautogui.screenshot()
+ name = f"{name}.png"
+ img.save(name)
+ speak("The screenshot has been succesfully captured")
+
+ elif "show me the screenshot" in command:
+ try:
+ img = Image.open('D://JARVIS//JARVIS_2.0//' + name)
+ img.show(img)
+ speak("Here it is sir")
+ time.sleep(2)
+
+ except IOError:
+ speak("Sorry sir, I am unable to display the screenshot")
+
+ elif "hide all files" in command or "hide this folder" in command:
+ os.system("attrib +h /s /d")
+ speak("Sir, all the files in this folder are now hidden")
+
+ elif "visible" in command or "make files visible" in command:
+ os.system("attrib -h /s /d")
+ speak("Sir, all the files in this folder are now visible to everyone. I hope you are taking this decision in your own peace")
+
+ # if "calculate" in command or "what is" in command:
+ # query = command
+ # answer = computational_intelligence(query)
+ # speak(answer)
+
+
+
+ elif "goodbye" in command or "offline" in command or "bye" in command:
+ speak("Alright sir, going offline. It was nice working with you")
+ sys.exit()
+
+
+startExecution = MainThread()
+
+
+class Main(QMainWindow):
+ def __init__(self):
+ super().__init__()
+ self.ui = Ui_MainWindow()
+ self.ui.setupUi(self)
+ self.ui.pushButton.clicked.connect(self.startTask)
+ self.ui.pushButton_2.clicked.connect(self.close)
+
+ def __del__(self):
+ sys.stdout = sys.__stdout__
+
+ # def run(self):
+ # self.TaskExection
+ def startTask(self):
+ self.ui.movie = QtGui.QMovie("Jarvis/utils/images/live_wallpaper.gif")
+ self.ui.label.setMovie(self.ui.movie)
+ self.ui.movie.start()
+ self.ui.movie = QtGui.QMovie("Jarvis/utils/images/initiating.gif")
+ self.ui.label_2.setMovie(self.ui.movie)
+ self.ui.movie.start()
+ timer = QTimer(self)
+ timer.timeout.connect(self.showTime)
+ timer.start(1000)
+ startExecution.start()
+
+ def showTime(self):
+ current_time = QTime.currentTime()
+ current_date = QDate.currentDate()
+ label_time = current_time.toString('hh:mm:ss')
+ label_date = current_date.toString(Qt.ISODate)
+ self.ui.textBrowser.setText(label_date)
+ self.ui.textBrowser_2.setText(label_time)
+
+
+app = QApplication(sys.argv)
+jarvis = Main()
+jarvis.show()
+exit(app.exec_())
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..f4fd586
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,80 @@
+astroid==2.4.2
+attrs==20.3.0
+autopep8==1.5.4
+beautifulsoup4==4.9.3
+cachetools==4.1.1
+certifi==2020.11.8
+chardet==3.0.4
+click==7.1.2
+colorama==0.4.4
+comtypes==1.1.7
+decorator==4.4.2
+flake8==3.8.4
+future==0.18.2
+geocoder==1.38.1
+geographiclib==1.50
+geopy==2.0.0
+google-api-core==1.23.0
+google-api-python-client==1.12.8
+google-auth==1.23.0
+google-auth-httplib2==0.0.4
+google-auth-oauthlib==0.4.2
+googleapis-common-protos==1.52.0
+httplib2==0.18.1
+hurry==1.1
+hurry.filesize==0.9
+idna==2.10
+isort==5.6.4
+lazy-object-proxy==1.4.3
+lxml==4.6.2
+mccabe==0.6.1
+more-itertools==8.6.0
+MouseInfo==0.1.3
+numpy==1.19.5
+oauthlib==3.1.0
+Pillow==8.0.1
+pprintpp==0.4.0
+protobuf==3.14.0
+psutil==5.7.3
+pyasn1==0.4.8
+pyasn1-modules==0.2.8
+PyAutoGUI==0.9.52
+pycodestyle==2.6.0
+pyflakes==2.2.0
+PyGetWindow==0.0.9
+pyjokes==0.6.0
+pylint==2.6.0
+PyMsgBox==1.0.9
+pyperclip==1.8.1
+pypiwin32==223
+PyQt5==5.15.2
+pyqt5-plugins==5.15.2.2.0.1
+PyQt5-sip==12.8.1
+pyqt5-tools==5.15.2.3
+PyRect==0.1.4
+PyScreeze==0.1.26
+python-dotenv==0.15.0
+pyttsx3==2.90
+PyTweening==1.0.3
+pytz==2020.4
+pywhatkit==3.2
+pywin32==300
+qt5-applications==5.15.2.2.1
+qt5-tools==5.15.2.1.0.1
+ratelim==0.1.6
+requests==2.25.0
+requests-oauthlib==1.3.0
+rsa==4.6
+selenium==3.141.0
+six==1.15.0
+soupsieve==2.0.1
+SpeechRecognition==3.8.1
+toml==0.10.2
+uritemplate==3.0.1
+urllib3==1.26.2
+wikipedia==1.4.0
+wincertstore==0.2
+wolframalpha==4.1.1
+wrapt==1.12.1
+xml-python==0.3.5
+xmltodict==0.12.0
\ No newline at end of file