├── .gitignore ├── LICENSE ├── README.md ├── functions ├── online_ops.py └── os_ops.py ├── main.py ├── requirements.txt └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ashutosh Krishna 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | * freeCodeCamp article: https://www.freecodecamp.org/news/python-project-how-to-build-your-own-jarvis-using-python/ 2 | 3 | * Hashnode articles: 4 | * Part 1: https://ashutoshkrris.hashnode.dev/how-to-build-your-personal-ai-assistant-using-python 5 | * Part 2: https://ashutoshkrris.hashnode.dev/how-to-implement-functionality-to-your-personal-ai-assistant-using-python 6 | 7 | Demo Video: https://vimeo.com/650156113 8 | 9 | Contents of .env file: 10 | 11 | ``` 12 | USER=None 13 | BOTNAME=JARVIS 14 | EMAIL=None 15 | PASSWORD=None 16 | NEWS_API_KEY=None 17 | OPENWEATHER_APP_ID=None 18 | TMDB_API_KEY=None 19 | ``` 20 | 21 | Replace `None` with your values 22 | -------------------------------------------------------------------------------- /functions/online_ops.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import wikipedia 3 | import pywhatkit as kit 4 | from email.message import EmailMessage 5 | import smtplib 6 | from decouple import config 7 | 8 | NEWS_API_KEY = config("NEWS_API_KEY") 9 | OPENWEATHER_APP_ID = config("OPENWEATHER_APP_ID") 10 | TMDB_API_KEY = config("TMDB_API_KEY") 11 | EMAIL = config("EMAIL") 12 | PASSWORD = config("PASSWORD") 13 | 14 | 15 | def find_my_ip(): 16 | ip_address = requests.get('https://api64.ipify.org?format=json').json() 17 | return ip_address["ip"] 18 | 19 | 20 | def search_on_wikipedia(query): 21 | results = wikipedia.summary(query, sentences=2) 22 | return results 23 | 24 | 25 | def play_on_youtube(video): 26 | kit.playonyt(video) 27 | 28 | 29 | def search_on_google(query): 30 | kit.search(query) 31 | 32 | 33 | def send_whatsapp_message(number, message): 34 | kit.sendwhatmsg_instantly(f"+91{number}", message) 35 | 36 | 37 | def send_email(receiver_address, subject, message): 38 | try: 39 | email = EmailMessage() 40 | email['To'] = receiver_address 41 | email["Subject"] = subject 42 | email['From'] = EMAIL 43 | email.set_content(message) 44 | s = smtplib.SMTP("smtp.gmail.com", 587) 45 | s.starttls() 46 | s.login(EMAIL, PASSWORD) 47 | s.send_message(email) 48 | s.close() 49 | return True 50 | except Exception as e: 51 | print(e) 52 | return False 53 | 54 | 55 | def get_latest_news(): 56 | news_headlines = [] 57 | res = requests.get( 58 | f"https://newsapi.org/v2/top-headlines?country=in&apiKey={NEWS_API_KEY}&category=general").json() 59 | articles = res["articles"] 60 | for article in articles: 61 | news_headlines.append(article["title"]) 62 | return news_headlines[:5] 63 | 64 | 65 | def get_weather_report(city): 66 | res = requests.get( 67 | f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={OPENWEATHER_APP_ID}&units=metric").json() 68 | weather = res["weather"][0]["main"] 69 | temperature = res["main"]["temp"] 70 | feels_like = res["main"]["feels_like"] 71 | return weather, f"{temperature}℃", f"{feels_like}℃" 72 | 73 | 74 | def get_trending_movies(): 75 | trending_movies = [] 76 | res = requests.get( 77 | f"https://api.themoviedb.org/3/trending/movie/day?api_key={TMDB_API_KEY}").json() 78 | results = res["results"] 79 | for r in results: 80 | trending_movies.append(r["original_title"]) 81 | return trending_movies[:5] 82 | 83 | 84 | def get_random_joke(): 85 | headers = { 86 | 'Accept': 'application/json' 87 | } 88 | res = requests.get("https://icanhazdadjoke.com/", headers=headers).json() 89 | return res["joke"] 90 | 91 | 92 | def get_random_advice(): 93 | res = requests.get("https://api.adviceslip.com/advice").json() 94 | return res['slip']['advice'] 95 | -------------------------------------------------------------------------------- /functions/os_ops.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess as sp 3 | 4 | paths = { 5 | 'notepad': "C:\\Program Files\\Notepad++\\notepad++.exe", 6 | 'discord': "C:\\Users\\ashut\\AppData\\Local\\Discord\\app-1.0.9003\\Discord.exe", 7 | 'calculator': "C:\\Windows\\System32\\calc.exe" 8 | } 9 | 10 | 11 | def open_notepad(): 12 | os.startfile(paths['notepad']) 13 | 14 | 15 | def open_discord(): 16 | os.startfile(paths['discord']) 17 | 18 | 19 | def open_cmd(): 20 | os.system('start cmd') 21 | 22 | 23 | def open_camera(): 24 | sp.run('start microsoft.windows.camera:', shell=True) 25 | 26 | 27 | def open_calculator(): 28 | sp.Popen(paths['calculator']) 29 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from functions.online_ops import find_my_ip, get_latest_news, get_random_advice, get_random_joke, get_trending_movies, get_weather_report, play_on_youtube, search_on_google, search_on_wikipedia, send_email, send_whatsapp_message 3 | import pyttsx3 4 | import speech_recognition as sr 5 | from decouple import config 6 | from datetime import datetime 7 | from functions.os_ops import open_calculator, open_camera, open_cmd, open_notepad, open_discord 8 | from random import choice 9 | from utils import opening_text 10 | from pprint import pprint 11 | 12 | 13 | USERNAME = config('USER') 14 | BOTNAME = config('BOTNAME') 15 | 16 | 17 | engine = pyttsx3.init('sapi5') 18 | 19 | # Set Rate 20 | engine.setProperty('rate', 190) 21 | 22 | # Set Volume 23 | engine.setProperty('volume', 1.0) 24 | 25 | # Set Voice (Female) 26 | voices = engine.getProperty('voices') 27 | engine.setProperty('voice', voices[1].id) 28 | 29 | 30 | # Text to Speech Conversion 31 | def speak(text): 32 | """Used to speak whatever text is passed to it""" 33 | 34 | engine.say(text) 35 | engine.runAndWait() 36 | 37 | 38 | # Greet the user 39 | def greet_user(): 40 | """Greets the user according to the time""" 41 | 42 | hour = datetime.now().hour 43 | if (hour >= 6) and (hour < 12): 44 | speak(f"Good Morning {USERNAME}") 45 | elif (hour >= 12) and (hour < 16): 46 | speak(f"Good afternoon {USERNAME}") 47 | elif (hour >= 16) and (hour < 19): 48 | speak(f"Good Evening {USERNAME}") 49 | speak(f"I am {BOTNAME}. How may I assist you?") 50 | 51 | 52 | # Takes Input from User 53 | def take_user_input(): 54 | """Takes user input, recognizes it using Speech Recognition module and converts it into text""" 55 | 56 | r = sr.Recognizer() 57 | with sr.Microphone() as source: 58 | print('Listening....') 59 | r.pause_threshold = 1 60 | audio = r.listen(source) 61 | 62 | try: 63 | print('Recognizing...') 64 | query = r.recognize_google(audio, language='en-in') 65 | if not 'exit' in query or 'stop' in query: 66 | speak(choice(opening_text)) 67 | else: 68 | hour = datetime.now().hour 69 | if hour >= 21 and hour < 6: 70 | speak("Good night sir, take care!") 71 | else: 72 | speak('Have a good day sir!') 73 | exit() 74 | except Exception: 75 | speak('Sorry, I could not understand. Could you please say that again?') 76 | query = 'None' 77 | return query 78 | 79 | 80 | if __name__ == '__main__': 81 | greet_user() 82 | while True: 83 | query = take_user_input().lower() 84 | 85 | if 'open notepad' in query: 86 | open_notepad() 87 | 88 | elif 'open discord' in query: 89 | open_discord() 90 | 91 | elif 'open command prompt' in query or 'open cmd' in query: 92 | open_cmd() 93 | 94 | elif 'open camera' in query: 95 | open_camera() 96 | 97 | elif 'open calculator' in query: 98 | open_calculator() 99 | 100 | elif 'ip address' in query: 101 | ip_address = find_my_ip() 102 | speak(f'Your IP Address is {ip_address}.\n For your convenience, I am printing it on the screen sir.') 103 | print(f'Your IP Address is {ip_address}') 104 | 105 | elif 'wikipedia' in query: 106 | speak('What do you want to search on Wikipedia, sir?') 107 | search_query = take_user_input().lower() 108 | results = search_on_wikipedia(search_query) 109 | speak(f"According to Wikipedia, {results}") 110 | speak("For your convenience, I am printing it on the screen sir.") 111 | print(results) 112 | 113 | elif 'youtube' in query: 114 | speak('What do you want to play on Youtube, sir?') 115 | video = take_user_input().lower() 116 | play_on_youtube(video) 117 | 118 | elif 'search on google' in query: 119 | speak('What do you want to search on Google, sir?') 120 | query = take_user_input().lower() 121 | search_on_google(query) 122 | 123 | elif "send whatsapp message" in query: 124 | speak( 125 | 'On what number should I send the message sir? Please enter in the console: ') 126 | number = input("Enter the number: ") 127 | speak("What is the message sir?") 128 | message = take_user_input().lower() 129 | send_whatsapp_message(number, message) 130 | speak("I've sent the message sir.") 131 | 132 | elif "send an email" in query: 133 | speak("On what email address do I send sir? Please enter in the console: ") 134 | receiver_address = input("Enter email address: ") 135 | speak("What should be the subject sir?") 136 | subject = take_user_input().capitalize() 137 | speak("What is the message sir?") 138 | message = take_user_input().capitalize() 139 | if send_email(receiver_address, subject, message): 140 | speak("I've sent the email sir.") 141 | else: 142 | speak("Something went wrong while I was sending the mail. Please check the error logs sir.") 143 | 144 | elif 'joke' in query: 145 | speak(f"Hope you like this one sir") 146 | joke = get_random_joke() 147 | speak(joke) 148 | speak("For your convenience, I am printing it on the screen sir.") 149 | pprint(joke) 150 | 151 | elif "advice" in query: 152 | speak(f"Here's an advice for you, sir") 153 | advice = get_random_advice() 154 | speak(advice) 155 | speak("For your convenience, I am printing it on the screen sir.") 156 | pprint(advice) 157 | 158 | elif "trending movies" in query: 159 | speak(f"Some of the trending movies are: {get_trending_movies()}") 160 | speak("For your convenience, I am printing it on the screen sir.") 161 | print(*get_trending_movies(), sep='\n') 162 | 163 | elif 'news' in query: 164 | speak(f"I'm reading out the latest news headlines, sir") 165 | speak(get_latest_news()) 166 | speak("For your convenience, I am printing it on the screen sir.") 167 | print(*get_latest_news(), sep='\n') 168 | 169 | elif 'weather' in query: 170 | ip_address = find_my_ip() 171 | city = requests.get(f"https://ipapi.co/{ip_address}/city/").text 172 | speak(f"Getting weather report for your city {city}") 173 | weather, temperature, feels_like = get_weather_report(city) 174 | speak(f"The current temperature is {temperature}, but it feels like {feels_like}") 175 | speak(f"Also, the weather report talks about {weather}") 176 | speak("For your convenience, I am printing it on the screen sir.") 177 | print(f"Description: {weather}\nTemperature: {temperature}\nFeels like: {feels_like}") 178 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | autopep8==1.5.7 2 | beautifulsoup4==4.9.3 3 | certifi==2021.5.30 4 | chardet==4.0.0 5 | comtypes==1.1.10 6 | idna==2.10 7 | MouseInfo==0.1.3 8 | Pillow==8.2.0 9 | PyAudio @ file:///D:/Quarantine/Python/JARVIS/PyAudio-0.2.11-cp39-cp39-win_amd64.whl 10 | PyAutoGUI==0.9.52 11 | pycodestyle==2.7.0 12 | PyGetWindow==0.0.9 13 | PyMsgBox==1.0.9 14 | pyperclip==1.8.2 15 | pypiwin32==223 16 | PyRect==0.1.4 17 | PyScreeze==0.1.27 18 | python-decouple==3.4 19 | pyttsx3==2.90 20 | PyTweening==1.0.3 21 | pywhatkit==4.8 22 | pywin32==301 23 | requests==2.25.1 24 | soupsieve==2.2.1 25 | SpeechRecognition==3.8.1 26 | toml==0.10.2 27 | urllib3==1.26.5 28 | wikipedia==1.4.0 29 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | opening_text = [ 2 | "Cool, I'm on it sir.", 3 | "Okay sir, I'm working on it.", 4 | "Just a second sir.", 5 | ] --------------------------------------------------------------------------------