[How To] Building a Simple Webex Chatbot with Python Websockets & OpenWeather APIs

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
In this video, I wanted to demonstrate how  easy it can be to get started with building   a chat bot using Webex. Now for this video,  there are going to be two primary methods   that we can receive messages from the Webex cloud  whenever someone tries to send our bot a message.   So one of the methods that we can use for our  bot is something called webhooks, which is   what most people are probably going to be familiar  with. And using this method, what we do is:   every time our bot spins up - it's going to reach  out to the Webex cloud, provide a callback URL,   and tell the Webex cloud that "hey, anytime you  receive a chat message for me - go ahead and post   it to this URL and I'll take things from there".  Now that does make things easy in one aspect but   there are some challenges with that method.  So for one, if we're just working in like a   development or test environment, we're likely not  going to have a public URL that's dedicated and an   open web server to the internet - which can make  receiving the messages challenging. Now we can use   some tunneling thing, like ngrok or something like  that, to spin up a tunneled web server and use   that for development purposes. But even still what  we're going to end up having to do is use flask   or fastapi or something like that to manually  handle all the incoming HTTP calls and do our own,   you know, validation and passing off those calls  to the bot and all of that fun stuff. And for some   organizations once something like that makes  it to production, they may not want to have   a web service that's publicly accessible to the  internet and have to manage the security around   opening firewall rules and restricting IPs and all  of that. One of the other issues with webhooks is   that every time we spin down or spin up our  bot, we have to check in with the Webex cloud   and see which webhooks are already configured  and exist - and potentially update them... which   means you might be writing an entire script or  set of functions just for webhook management. The other way that we can accomplish this  is using something called websockets.   Now websockets do make life a little bit easier  by removing some of those complexities added by   webhooks. So in this case every time our bot spins  up - what we're going to do is actually just open   a direct TCP websocket out to the Webex cloud.  And you can think of this as a direct tunnel to   the Webex cloud that is just from our code that's  running the bot, out to the webex cloud itself.   And so it doesn't have to be exposed publicly  to the internet - any messages to and from   the Webex cloud are going to be traversing  that direct tunnel - so there's no need to   change firewall rules, open up additional  ports, or you know forward traffic to an   internal host or anything like that. In some of  my practice with the websockets and webhooks,   it feels to me like websockets tend to be a little  bit more responsive too and my assumption is that   we have that persistent TCP tunnel connection  up at all times - and so for each message that's   being sent and received, we're not doing the  entire TCP and SSL handshakes for every single   message, like we would be doing with webhooks. Now  with websockets, we also actually gain a couple of   additional features.. So I believe right now the  ability for your bot to mark a message as read   and show the little like 'read message' status  indicator at the bottom of the chat window,   is actually something that's only  supported in websockets right now.   There may be some other little features like  that as well. Now historically websockets were   only a function of the javascript Webex SDK  - but recently it looks like someone actually   developed a Python module that does the same  thing with python, and actually makes the bot   process super easy. So that's going to be the  module that we're going to be focusing on today. So to get started, the first thing that  we're going to have to do - is go to   developer.webex.com. And we're going to have  to generate our bot config and get our API   credentials. So once we're on the website in the  upper right-hand corner, we're going to go ahead   and click on our user icon - and head down to "My  Webex Apps" and go ahead and click on that. Once   we're here, we'll be given a couple of options for  creating a new Webex app. Today we're going to be   focusing on building a bot, so we'll go ahead  and just click "Create a Bot". In order to get   our API keys, we will have to provide a little bit  of information around our bot - including a name,   username, icon, and a description. Keep in mind  that if you ever decide to publish your Webex   bot publicly on the Webex App Hub, a lot of this  information would be public. So if it's just for   development, it doesn't really matter what you're  putting in here. But should you decide to publish   this, this is where you'd want to put a lot of  that information that's going to be public facing. So throughout this demo, we're actually going to  be building a weather bot - where you're going to   be able to send a message to the bot and ask for  the weather in your local area, and it's going to   respond back with that. So we're going to go  ahead and name our bot Weather Bot - and our   bot username is going to be 0xWeatherBot.  And it says that that name is available.   Next we can go ahead and upload an icon if we  want - or we can choose one of these defaults   that are provided to us. One thing to  note, is that the icon must be 512x512   exactly. So I do have an image that  I've already grabbed and we'll go ahead   and upload that. And for our description,  we'll just go ahead and put "test weatherbot". Alright, and if that all looks good - we'll go  ahead and click "Add Bot" down at the bottom. And   after a couple of seconds Webex will go ahead and  provision our bot and will be provided with our   bot access token. Now this access token is going  to be our API key that we use to communicate with   the Webex cloud, to send and receive messages and  register our chat bot and all of that fun stuff.   And so obviously this is the key that we're going  to want to keep secret. Webex is only going to   display it to us this one time and once we close  this page, we can never get that key again.   We obviously can regenerate the token if  we lose it or if it gets compromised or   something like that - but this individual  screen will never be shown again for this   individual token. So be sure to copy  your key and save it somewhere safe. So now that we have our bot API key, let's go  ahead and get started with building our bot.   So real quick I bought up the GitHub page for the  webex_bot module that we're going to be using...   like I said this was created I think earlier  this year or last year - and it does provide   us with the ability to quickly and easily use  websockets when connecting out to the Webex cloud.   It does wrap some of the functionality  with the existing webexteamssdk and some   other stuff like that - and gives us a  very clean and easy to use module for   building bots very quickly. So let's go ahead  and jump over to VSCode - and I'll bring up my   Linux terminal real quick. And the first thing  that we're going to go ahead and do is install   this module using "pip install webex_bot".  Alright and that installs pretty quickly. Okay and so the other thing we're going to  do before we actually start writing code,   is we're going to go ahead and export our  Webex API key as an environment variable.   So we'll go ahead and do "export  WEBEX_TOKEN=" and then our API key. Alright,   and once that's done we can go ahead and  jump over to VSCode and start working. So to begin with, I have a blank Python  file, that's just going to be called   "bot.py". And we'll go ahead and start off first  by importing our webex_bot module. We'll also go   ahead and import the os module, so that we can  get our environment variable. Next we will go   ahead and configure our environment variable by  doing "os.environ" and grabbing our Webex token.   Then we'll go ahead and create a new instance of  a Webex bot, passing our Webex token and we use a   optional parameter for approved domains. In this  case, I am saying that the only people that can   communicate with my bot is someone belonging  to the domain 0x2142.com. Instead of domain,   you could also do "approved_users" to lock  it down to individual people if you wanted.   Then once we have all that - we're actually just  going to do "bot.run()". That's all we need to   actually get our bot up and running and ready to  go. So there are a couple of pre-built commands   and modules within the bot that we can test to  make sure that our bot is functioning as expected. So let's go ahead and start our bot...  We'll bring up the terminal again real quick   and we'll go ahead and do "python bot.py". And  after a little bit of logging, we can see the   last message there at the bottom says that  websocket has been opened. So at this point,   we should be free to go ahead and open up Webex  teams, chat with our bot, and see what happens. If   we go ahead and open up Webex teams, we can  go ahead and search for our bot in the top.   So I'll search for 0xWeatherBot at Webex dot bot  - and that comes up and we'll go ahead and click   the chat icon. And now we have our space - and we  can see that our little bot icon shows up. And so   now we can chat with our bot. So we can go ahead  and start by asking for help - and this module   does have the ability to automatically figure  out which commands have been registered to it,   and then automatically print an adaptive card  with help text for each one of those commands. So by default the bot comes pre-configured  with two different commands first is going   to be the help command which we've already  used - the other one is an echo command,   where we can send a message to the bot and  have it printed back to us. So for example,   let's go ahead and type "echo"... And the bot  provides a card with some text entry for us to   put something in. So let's go ahead and put  "Hello I'm a bot!" - and then click submit.   And pretty quick our weather bot responds  back with the text that we provided it.   So if we jump back over to our Linux terminal real  quick - in the logging we can see the individual   messages that have been sent to the bot. We can  also see that once we submitted that adaptive   card response to the bot, we do get a dump of  that JSON data back in here. So we can see that   there was a callback to the bot, and it contains  the message that we typed and asked the bot to   echo back to us. So this output can be pretty  helpful in case you need to troubleshoot,   something's not working right, or didn't get a  message, or that type of thing. So in order to   make our bot a little bit more exciting - let's go  ahead and figure out how to add our own commands.   So next what we're going to do is, we will  create a new Python file for every command that   we want to add to the bot - just to keep the code  separate for each command that's going to be run.   So in this case, since our primary command  is going to be checking the weather,   I created a new file called "weather.py". To get  started - first we're going to go ahead and from   the webex_bot module, we're going to import the  command model. Next we're going to go ahead and   create a new class for our command. So since the  purpose of this command is going to be providing   the current weather by US Zip Code, we'll name  our class "WeatherByZIP" - and that's going to   inherit the command model from the webex_bot. So  the first function we'll do is the "__init__" and   under here we'll do "super().__init__" - and we'll  configure first the command keyword, which we'll   go ahead and set to "weather". This is going to  be the keyword that is registered with the bot.   Anytime the user sends a message to our bot that  contains this keyword - that's how the bot knows   that this is the code that we want to execute.  Next we'll also provide a help message. And we'll   set that to "Get current weather by ZIP Code". So  anytime a user types "help" to the bot - the bot's   going to go ahead and check through every command  that's registered to it, and look for this help   message, and that's going to be the text that's  provided back to our user. Last but not least,   we also have the ability to provide an adaptive  card. Now we saw this with both the help and   echo commands, where when we just gave the blank  text, we were provided with a card response back.   Now in this case, I don't want to do that, so  I'm going to go ahead and just set card to none.   And we'll go ahead and move on. So next, we'll go  ahead and create a function called execute - and   this is going to be the function that gets called  anytime our command is requested by the user. And   this is going to take two inputs - the first of  which being the actual text message from the user,   and the second being attachments. Now obviously we  saw earlier with that echo command - when the card   was submitted, there was a JSON payload attachment  that included what that message text was that   was being sent back. In this case, we don't  intend on doing that so we won't be using that.   But if you were to create a bot  command that uses adaptive cards,   and there was any type of user submission,  we would get that data back through the   attachments. Now one thing to keep in mind, is  that the message here that is going to be sent   to your code is actually going to be pre-stripped  from the command keyword. So what I mean by that   is, that if we say "weather" and then a zip code  like "12345" - when the bot receives that message,   it's gonna trigger the this command because it  knows the keyword is "weather". And then the   execute function is actually only gonna be passed  that five digit zip code - so the "12345". So that   the "weather" command itself will be pre-stripped  out of the message. So we can demonstrate this,   just to make sure that our code is working  and show how it works by returning just a   string of text that says "Got message" - and then  returning the stripped message that we get back. And so before we test our command, we will need  to go back over to the main bot file, the bot.py.   And first thing that we'll need to do, is we  will need to import our weather command module.   And so we'll just do "from weather import  WeatherByZIP". And then after that, right   before our "bot.run()" - we'll go ahead and add in  our new command. So we'll do "bot.add_command()"   and then our "WeatherByZIP". And once we  save this, we can go ahead and go back over   to our Linux terminal, kill our bot real quick,  restart it, and this should have our new command. So we'll open Webex teams one more time...  and we'll try to ask the bot for help.   And sure enough the weather bot does automatically  pick up the new command that we had configured.   And shows that there's now the ability to ask  the bot for weather. And it does show our help   text. So as a demonstration we'll go ahead and do  "weather 12345" - and our bot should respond back   "Got the message: 12345". Okay so at this  point we have our bot running, we've created   a new weather command, and we've tested it to make  sure that we know that the bot is receiving that,   has the command registered, and then is  able to just return a message back to us. So next let's go ahead and add the ability  for our bot to actually check the weather,   and format that response, and give it back to  us. So for this aspect of the project, I'm using   the weather APIs from openweathermap.org. For  development purposes, they do have a free tier   for their API - and so if we go to their API  page real quick... we can see that they have   a whole bunch of different things that we can  choose from. For the purposes of this project,   we're just going to go ahead and use the "Current  Weather Data" API. And so if we click on the API   documentation - on the right-hand side, we can  see "get current weather by zip code". And so   here's what we're going to be using. So in this,  we're just going to make a HTTP GET request to   https://api.openweathermap.org/data/2.5/weather  - and then we're going to provide a couple of   parameters to it. First off being the  zip code - the country code is optional,   if it's not provided by default it will assume US.  And then we provide an "appid" parameter which is   going to be our API key. Optionally as well, we  can provide a language and units if we want to. With that, let's go ahead and start writing  this into our bot. So we'll go back over   to VSCode - and we'll go back over to  our weather.py... The first thing is,   I'm going to need both the requests module and the  JSON module. So let's go ahead and import those.   Next I will go ahead and remove our existing  return. First we'll go ahead and start off by   defining our API key from openweathermap.org.  Next, because our message that's returned to   our function just has the command stripped out,  sometimes that means it can include extra spaces.   So we'll go ahead and assign our ZIP code  variable to "message.strip()" to remove any   additional white space. Then we'll go ahead  and define our HTTP URL that we're going to   be querying from. Again that's going to  be the https://api.openweathermap.org   with our parameters. Now in the URL, I am  providing variables for ZIP code and our   API key. You can also see that I am specifying  units as imperial, because I live in the United   States - whereas the default is standard or you  can define metric. Next we'll make a simple HTTP   GET request using "request.get()" and passing  our URL - we'll assign that to the response   variable. And then we'll create a new variable  called weather, and we'll print out the JSON   response from our HTTP request to that. Once  we have that JSON data loaded, it's going to   be as easy as just navigating through that data  structure and pulling out the information we want. So first we'll go ahead and pull out the city,  then we'll go ahead and pull out a description for   the weather conditions, then we'll also pull out  the current temperature, humidity, and wind speed. Last but not least, we'll create a new text  response message - that says "In whatever city,   the current temperature is whatever with some  conditions" and then printing out the wind speed   and the humidity - and we'll return that response  message. Seems easy enough, so let's go ahead and   test our bot and see if this works. So we'll  kill this bot one more time - and restart..   So if we go ahead and open up Webex teams, we  should be able to send a command to our bot asking   for the weather in a particular ZIP code. So I'll  go ahead and provide the zip code 44286, which is   for Richfield, Ohio. And our bot should respond  back with the weather. So sure enough - pretty   quickly, bot responds back - saying that "In  Richfield, it's currently 42.3 degrees with   scattered clouds. Wind is just over 10 and a  half miles an hour, humidity is 62 percent". So with that we've spent just a couple of minutes  and showed how to create a quick Webex bot using   python and websockets. Now obviously this bot  is pretty simplistic - it's only taking in one   command and returning some static text... we're  not doing any sort of adaptive cards or fancy   displays or any other sort of exciting features.  But my intent with this video is just to show how   easy it can be to get started with building a  Webex bot - and how using websockets for this   actually makes the process a lot easier. So with  that being said, I hope that you take this example   and are able to go start building a Webex bot  that does something that you think is exciting. And with that, I hope that this video  was helpful and thanks for watching!!!
Info
Channel: 0x2142 - Networking Nonsense
Views: 219
Rating: undefined out of 5
Keywords: cisco, webex, webex teams, webex messanger, chatbot, webex bot, openweather, openweathermap, openweathermap.org, python, webhook, websocket, flask, webex_bot
Id: yZQjoe5XUYE
Channel Id: undefined
Length: 18min 18sec (1098 seconds)
Published: Thu Nov 18 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.