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!!!