Hello everybody! I’m again with one more tutorial. Its World Cup season and each different particular person is rooting for his/her favourite workforce. I used to be eager about the following weblog submit thought and I believed why not create a challenge which may help you keep up to date with how the world cup is progressing? And alongside the best way, I’d be capable of educate myself (and also you) one thing new. The tip product is that this tutorial. The challenge we’re going to be creating is a Twilio software, hosted on Heroku. It’s a chat (SMS) bot or types. It is possible for you to to ship numerous particular messages to this bot and it’ll reply with the most recent World cup updates.
Listed below are some screenshots to present you some taste of the ultimate product:
Let’s start by establishing the listing construction. There can be 4 information in complete in our root folder:
Procfile
app.py
necessities.txt
runtime.txt
You may rapidly create them by operating the next command within the terminal:
$ contact Procfile app.py necessities.txt runtime.txt
Don’t fear about these information for now. I’ll let you realize their goal after we begin populating them afterward.
Create a brand new Python digital surroundings to work in. When you don’t know what a digital surroundings is and why it’s helpful to make use of it, take a look at this chapter of the Intermediate Python e book. You may create the digital surroundings by operating the next instructions within the terminal:
$ python -m venv env
$ supply env/bin/activate
You may deactivate the digital surroundings at any time by operating:
$ supply deactivate
We can be utilizing Python 3.x (I’m operating 3.6) and the next Python libraries:
Flask==0.12.2
twilio==6.14.6
requests==2.18.4
python-dateutil==2.6.1
Add these 4 strains in your necessities.txt
file and run $ pip set up -r necessities.txt
. Flask is the net growth framework we can be utilizing to create our net app. We can be utilizing the twilio library to interface with Twilio and the Requests library will assist us in consuming net APIs and get newest World Cup data. Dateutil is just getting used to deal with date-time.
Why did I point out the precise variations for these libraries? I simply began creating this challenge utilizing the most recent libraries and these are those which I used. I’m itemizing the model quantity merely to maintain this tutorial considerably future-proof in order that even when future variations of those libraries break backward compatibility, you’ll know which libraries ought to work wonderful with this tutorial. You will discover the variations of libraries put in in your system by operating $ pip freeze
.
Step 2: Outline the challenge necessities
It’s a good suggestion to listing down the options/necessities of our SMS bot. We wish it to have the ability to reply to 5 totally different sorts of messages:
at the moment
ought to return the small print of all video games taking place at the momenttomorrow
ought to return the small print of all video games taking place tomorrowfull
ought to return the entire group stage particulars- A rustic code (like
BRA
for Brazil) ought to return data associated to that individual nation listing
ought to return all the FIFA nation codes
Appropriate responses for these endpoints are:
England vs Panama at 08:00 AM
Japan vs Senegal at 11:00 AM
Poland vs Colombia at 02:00 PM
Saudi Arabia vs Egypt at 10:00 AM
Uruguay vs Russia at 10:00 AM
Spain vs Morocco at 02:00 PM
Iran vs Portugal at 02:00 PM
--- Group A ---
Russia Pts: 6
Uruguay Pts: 6
Egypt Pts: 0
Saudi Arabia Pts: 0
--- Group B ---
Spain Pts: 4
Portugal Pts: 4
Iran Pts: 3
Morocco Pts: 0
--- Group C ---
France Pts: 6
Denmark Pts: 4
Australia Pts: 1
Peru Pts: 0
--- Group D ---
Croatia Pts: 6
Nigeria Pts: 3
Iceland Pts: 1
Argentina Pts: 1
--- Group E ---
Brazil Pts: 4
Switzerland Pts: 4
Serbia Pts: 3
Costa Rica Pts: 0
--- Group F ---
Mexico Pts: 6
Sweden Pts: 3
Germany Pts: 3
Korea Republic Pts: 0
--- Group G ---
Belgium Pts: 6
England Pts: 3
Panama Pts: 0
Tunisia Pts: 0
--- Group H ---
Senegal Pts: 3
Japan Pts: 3
Poland Pts: 0
Colombia Pts: 0
- ARG (Argentina’s FIFA code)
--- Previous Matches ---
Argentina 1 vs Iceland 1
Argentina 0 vs Croatia 3
--- Future Matches ---
Nigeria vs Argentina at 02:00 PM on 26 Jun
KOR
PAN
MEX
ENG
COL
JPN
POL
SEN
RUS
EGY
POR
MAR
URU
KSA
IRN
ESP
DEN
AUS
FRA
PER
ARG
CRO
BRA
CRC
NGA
ISL
SRB
SUI
BEL
TUN
GER
SWE
Let me additionally make clear the date/time data. The API offers us with the UTC time. I’m going to transform that to my timezone America/New_york
in order that I don’t should do psychological time calculations. This may also present us with a chance to discover ways to convert timezones utilizing dateutil
.
With these necessities in thoughts, let’s transfer on.
Step 3: Discovering and exploring the FIFA API
Now we have to discover the best API which we are able to use to obtain up-to-date data. I searched round and the very best one I discovered was this web site. The precise endpoints we’re excited about are:
urls = {'group': 'https://worldcup.sfg.io/groups/group_results',
'nation': 'https://worldcup.sfg.io/matches/nation?fifa_code=",
"at the moment': 'https://worldcup.sfg.io/matches/at the moment',
'tomorrow': 'https://worldcup.sfg.io/matches/tomorrow'
}
As a substitute of utilizing the nation codes endpoint accessible at worldcup.sfg.io, we can be sustaining a neighborhood nation code listing.
nations = ['KOR', 'PAN', 'MEX', 'ENG', 'COL', 'JPN', 'POL', 'SEN',
'RUS', 'EGY', 'POR', 'MAR', 'URU', 'KSA', 'IRN', 'ESP',
'DEN', 'AUS', 'FRA', 'PER', 'ARG', 'CRO', 'BRA', 'CRC',
'NGA', 'ISL', 'SRB', 'SUI', 'BEL', 'TUN', 'GER', 'SWE']
Usually, I run a Python interpreter to check out APIs earlier than writing closing code in a .py
file. This offers me with a a lot faster option to examine whether or not my API dealing with code is working as anticipated or not.
I examined out the APIs and that is what I discovered:
- We will get “at the moment” (& “tomorrow”) data by operating the next code:
html = requests.get(urls['today']).json()
for match in html:
print(match['home_team_country'] + ' vs ' + match['away_team_country'] + ' at ' + match['datetime'] )
- We will get “nation” data by operating:
html = requests.get(urls['country']+'ARG').json()
for match in html:
if match['status'] == 'accomplished':
print(match['home_team']['country'],
match['home_team']['goals'],
"vs", match['away_team']['country'],
match['away_team']['goals'])
if match['status'] == 'future':
print(match['home_team']['country'], "vs",
match['away_team']['country'],
"at", match['datetime'])
- We will get “full” data by operating:
html = requests.get(urls['group']).json()
for group in html:
print("--- Group " + group['group']['letter'] + " ---")
for workforce in group['group']['teams']:
print(workforce['team']['country'], "Pts:", workforce['team']['points'])
- And lastly we are able to get “listing” data by merely operating:
print('n'.joing(nations))
In an effort to discover the JSON APIs, I make intensive use of JSBeautifier. It helps me discover out the best node pretty rapidly due to indentation. In an effort to use this wonderful useful resource, simply copy JSON response, paste it on the JSBeautifier web site and press “Beautify JavaScript or HTML” button.
Now that we all know which API we’re going to use and what code we want for extracting the required data, we are able to transfer on and begin enhancing the app.py
file.
Step 4: Begin writing app.py
Initially, let’s import the required libraries:
import os
from flask import Flask, request
import requests
from dateutil import parser, tz
from twilio.twiml.messaging_response import MessagingResponse
We’re going to use os
to entry surroundings variables. On this explicit challenge, we don’t have to make use of our Twilio credentials wherever however it’s nonetheless good to know that it’s best to by no means hardcode your credentials in any code file. It’s best to use surroundings variables for storing them. This fashion even when we publish our challenge in a public git repo, we received’t have to fret about leaked credentials.
We can be utilizing flask as our net growth framework of selection and requests can be used to eat on-line APIs. Furthermore, dateutil will assist us parse dates-times from the web API response.
We can be utilizing MessagingResponse
from the twilio.twiml.messaging_response
package deal to create TwiML responses. These are response templates utilized by Twilio. You may learn extra about TwiML right here.
Subsequent, we have to create the Flask object:
app = Flask(__name__)
Let’s additionally outline our native timezone utilizing the tz.gettz
methodology. I can be utilizing America/New_york
as my time zone however you should use no matter time zone you’re in in the intervening time:
to_zone = tz.gettz('America/New_York')
Our app will solely have one route. That is the /
route. This may settle for POST requests. We can be utilizing this route because the “message arrive” webhook in Twilio. Which means at any time when somebody will ship an SMS to our Twilio quantity, Twilio will ship a POST request to this webhook with the contents of that SMS. We’ll reply to this POST request with a TwiML template and that method we are going to inform Twilio what to ship again to the SMS sender.
Right here is the fundamental whats up world code simply to check issues out:
@app.route("https://yasoob.me/", strategies=['POST'])
def receive_sms():
physique = request.values.get('Physique', None)
resp = MessagingResponse()
resp.message(physique or 'Whats up World!')
return str(resp)
Lets full our app.py
script and check it out:
if __name__ == "__main__":
port = int(os.environ.get("PORT", 5000))
app.run(host="0.0.0.0", port=port)
At this level, the entire contents of this file ought to look one thing like this:
import os
from flask import Flask, request
import requests
from dateutil import parser, tz
from twilio.twiml.messaging_response import MessagingResponse
app = Flask(__name__)
to_zone = tz.gettz('America/New_York')
@app.route("https://yasoob.me/", strategies=['POST'])
def receive_sms():
physique = request.values.get('Physique', None)
resp = MessagingResponse()
resp.message(physique or 'Whats up World!')
return str(resp)
if __name__ == "__main__":
port = int(os.environ.get("PORT", 5000))
app.run(host="0.0.0.0", port=port)
Add the next line to your `Procfile:
net: python app.py
This may inform Heroku which file to run. Add the next code to the runtime.txt
file:
python-3.6.5
This may inform Heroku which Python model we need to run our code with.
Lets put this complete listing below model management utilizing git and push the code to Heroku by operating the next instructions within the terminal:
git init .
git add Procfile runtime.txt app.py necessities.txt
git commit -m "Dedicated preliminary code"
heroku create
heroku apps:rename custom_project_name
git push heroku grasp
Change custom_project_name
together with your favourite challenge title. This must be distinctive as it will dictate the URL of your net server. After this Heroku will offer you the general public URL of your server. Copy that URL and let’s enroll on Twilio.
Step 5: Get began with Twilio
Go to Twilio and join a free trial account for those who don’t have one already.
At this level Twilio ought to immediate you to pick out a brand new Twilio quantity. When you do this that you must go to the Console’s “quantity” web page and that you must configure the webhook.
Right here that you must paste the server tackle which Heroku gave you. After this, we’re carried out. Now its time to ship a message to our Twilio quantity utilizing our cell phone and it ought to echo again no matter we ship it.
I attempted it out and that is what the response appeared like:
Now that all the things is working as anticipated we are able to transfer ahead and make our app.py
file do one thing helpful.
Step 6: Ending up app.py
Let’s full the app.py
file with a practical route handler. Rewrite the receive_sms
perform based mostly on this code:
# ...
urls = {'group': 'https://worldcup.sfg.io/groups/group_results',
'nation': 'https://worldcup.sfg.io/matches/nation?fifa_code=",
"at the moment': 'https://worldcup.sfg.io/matches/at the moment',
'tomorrow': 'https://worldcup.sfg.io/matches/tomorrow'
}
#...
@app.route("https://yasoob.me/", strategies=['POST'])
def receive_sms():
physique = request.values.get('Physique', '').decrease().strip()
resp = MessagingResponse()
if physique == 'at the moment':
html = requests.get(urls['today']).json()
output = "n"
for match in html:
output += match['home_team_country'] + ' vs ' + match['away_team_country'] +
" at "+ parser.parse(match['datetime']).astimezone(to_zone).strftime('%I:%M %p') +"n"
elif physique == 'tomorrow':
html = requests.get(urls['tomorrow']).json()
output = "n"
for match in html:
output += match['home_team_country'] + ' vs ' + match['away_team_country'] +
" at "+ parser.parse(match['datetime']).astimezone(to_zone).strftime('%I:%M %p') +"n"
elif physique.higher() in nations:
html = requests.get(urls['country']+physique).json()
output = "n--- Previous Matches ---n"
for match in html:
if match['status'] == 'accomplished':
output += match['home_team']['country'] + " " +
str(match['home_team']['goals']) + " vs " +
match['away_team']['country']+ " " +
str(match['away_team']['goals']) + "n"
output += "nn--- Future Matches ---n"
for match in html:
if match['status'] == 'future':
output += match['home_team']['country'] + " vs " +
match['away_team']['country'] + " at " +
parser.parse(match['datetime']).astimezone(to_zone).strftime('%I:%M %p on %d %b') +"n"
elif physique == 'full':
html = requests.get(urls['group']).json()
output = ""
for group in html:
output += "nn--- Group " + group['group']['letter'] + " ---n"
for workforce in group['group']['teams']:
output += workforce['team']['country'] + " Pts: " + str(workforce['team']['points']) + "n"
elif physique == 'listing':
output="n".be a part of(nations)
else:
output = ('Sorry we couldn't perceive your response. '
'You may reply with "at the moment" to get at the moment's particulars, "tomorrow" '
'to get tomorrow's particulars, "full" to get the group stage standing of groups or '
'you'll be able to reply with a rustic FIFA code (like BRA, ARG) and we are going to ship you the '
'standing of that individual nation. For a listing of FIFA codes ship "listing".nnHave an excellent day!')
resp.message(output)
return str(resp)
A lot of the code is straightforward and self-explanatory aside from the date-time parsing:
parser.parse(match['datetime']).astimezone(to_zone).strftime('%I:%M %p on %d %b')
Right here I’m passing match['datetime']
to the parser.parse
methodology. After that I entry the astimezone
methodology to transform the time to my time zone and at last, I format the time to my liking.
%I
provides us the hour in 12-hour format%M
provides us the minutes%p
provides us AM/PM%d
provides us the date%b
provides us the abbreviated month (e.g Jun)
You may get particulars of the remainder of the format codes from right here.
After including this code, your full app.py
file ought to look one thing like this:
import os
from flask import Flask, request
import requests
from dateutil import parser, tz
from twilio.twiml.messaging_response import MessagingResponse
app = Flask(__name__)
to_zone = tz.gettz('America/New_York')
nations = ['KOR', 'PAN', 'MEX', 'ENG', 'COL', 'JPN', 'POL', 'SEN',
'RUS', 'EGY', 'POR', 'MAR', 'URU', 'KSA', 'IRN', 'ESP',
'DEN', 'AUS', 'FRA', 'PER', 'ARG', 'CRO', 'BRA', 'CRC',
'NGA', 'ISL', 'SRB', 'SUI', 'BEL', 'TUN', 'GER', 'SWE']
urls = {'group': 'https://worldcup.sfg.io/groups/group_results',
'nation': 'https://worldcup.sfg.io/matches/nation?fifa_code=",
"at the moment': 'https://worldcup.sfg.io/matches/at the moment',
'tomorrow': 'https://worldcup.sfg.io/matches/tomorrow'
}
@app.route("https://yasoob.me/", strategies=['POST'])
def receive_sms():
physique = request.values.get('Physique', '').decrease().strip()
resp = MessagingResponse()
if physique == 'at the moment':
html = requests.get(urls['today']).json()
output = "n"
for match in html:
output += match['home_team_country'] + ' vs ' + match['away_team_country'] +
" at "+ parser.parse(match['datetime']).astimezone(to_zone).strftime('%I:%M %p') +"n"
elif physique == 'tomorrow':
html = requests.get(urls['tomorrow']).json()
output = "n"
for match in html:
output += match['home_team_country'] + ' vs ' + match['away_team_country'] +
" at "+ parser.parse(match['datetime']).astimezone(to_zone).strftime('%I:%M %p') +"n"
elif physique.higher() in nations:
html = requests.get(urls['country']+physique).json()
output = "n--- Previous Matches ---n"
for match in html:
if match['status'] == 'accomplished':
output += match['home_team']['country'] + " " +
str(match['home_team']['goals']) + " vs " +
match['away_team']['country']+ " " +
str(match['away_team']['goals']) + "n"
output += "nn--- Future Matches ---n"
for match in html:
if match['status'] == 'future':
output += match['home_team']['country'] + " vs " +
match['away_team']['country'] + " at " +
parser.parse(match['datetime']).astimezone(to_zone).strftime('%I:%M %p on %d %b') +"n"
elif physique == 'full':
html = requests.get(urls['group']).json()
output = ""
for group in html:
output += "nn--- Group " + group['group']['letter'] + " ---n"
for workforce in group['group']['teams']:
output += workforce['team']['country'] + " Pts: " + str(workforce['team']['points']) + "n"
elif physique == 'listing':
output="n".be a part of(nations)
else:
output = ('Sorry we couldn't perceive your response. '
'You may reply with "at the moment" to get at the moment's particulars, "tomorrow" '
'to get tomorrow's particulars, "full" to get the group stage standing of groups or '
'you'll be able to reply with a rustic FIFA code (like BRA, ARG) and we are going to ship you the '
'standing of that individual nation. For a listing of FIFA codes ship "listing".nnHave an excellent day!')
resp.message(output)
return str(resp)
if __name__ == "__main__":
port = int(os.environ.get("PORT", 5000))
app.run(host="0.0.0.0", port=port)
Now we simply must commit this code to our git repo after which push it to Heroku:
git add app.py
git commit -m "up to date the code 💥"
git push heroku grasp
Now go forward and check out sending an SMS to your Twilio quantity.
Necessary Notes:
- When you don’t obtain a response to your SMS it’s best to examine your Heroku app logs for errors. You may simply entry the logs by operating
$ heroku logs
from the challenge folder - Twilio requires you to confirm the goal cell quantity earlier than you’ll be able to ship it any SMS throughout trial. Be sure to do this.
- I encountered quite a few issues once I was creating this software so don’t really feel postpone by errors. Embrace them and check out fixing them with the assistance of Google and StackOverflow.
- When you encounter any errors, don’t hesitate to ask me for assist by way of the feedback 🙂
You will discover the entire code on GitHub. You may additional lengthen the code to implement common automated updates in your favorite workforce. The chances are limitless! I hope you guys loved the tutorial. When you’ve got any feedback/suggestions/ideas please let me know by way of the feedback. Have an excellent day!