Script development
This article is a part of a tutorial about creating a bot which reports the current weather in any city of the world.
- Configuration file setup
- HTTP request to OpenWeatherMap API
- Script development (you are here)
- Testing
In this step, we will create a script that will report the current weather in the requested city.
Script steps:
- The bot sends a welcome message and asks the client to enter the city name.
- The client enters the city name. For example, London or What is the weather in London today?.
- The city will be picked from the message and used as an input parameter of an API request we’ve created during the previous step.
- The API service will return a response. The received data will be used to display a message about the current weather.
Creating the script
Create the main.sc
file in the src
folder. It will contain the script of the bot.
require: functions.js
require: city/cityEn.sc
module = sys.zb-common
require: city/cities-en.csv
name = Cities
var = $Cities
module = sys.zb-common
theme: /
state: Start
q!: $regex</start>
a: Hello! I am a virtual assistant. I can tell you the current weather in any city. Just type the city.
state: GetWeather
q: * $City *
script:
var city = $parseTree._City.name;
openWeatherMapCurrent("metric", "en", city).then(function (res) {
if (res && res.weather) {
$reactions.answer("Today in " + capitalize(city) + ": " + res.weather[0].description + ", " + Math.round(res.main.temp) + "°C" );
if(res.weather[0].main == 'Rain' || res.weather[0].main == 'Drizzle') {
$reactions.answer("I recommend you to bring an umbrella with you!")
} else if (Math.round(res.main.temp) < 0) {
$reactions.answer("Brrrr... It's so cold outside! Dress warm!")
}
} else {
$reactions.answer("Server problems. I can not find out the weather.");
}
}).catch(function (err) {
$reactions.answer("Server problems. I can not find out the weather.");
});
state: CatchAll || noContext=true
event!: noMatch
a: I'm sorry, I don't understand, but I can tell you about the weather.
go: /GetWeather
At the beginning of the script, we’ve added the additional modules city/cityEn.sc
and city/cities-en.csv
under the require
tag. Also, we’ve added the function that we wrote at the previous step from functions.js
to the script.
The first two modules are required for working with the city list. To use them in the script, specify the following parameters in the require: city/cities-en.csv
tag:
name
(string) — name of the pattern for named entities’ dictionary.var
(string) — name of js-variable with data from a dictionary.
The bot script consists of the following states:
Start
— getting started. The bot welcomes the user and tells them what it can do.GetWeather
— displays weather information in the requested city.CatchAll
— uses in cases when the user’s message does not fit any of the described stages.
.sc
script filesScript structure
Start
state: Start
q!: $regex</start>
a: Hello! I am a virtual assistant. I can tell you the current weather in any city. Just type the city.
The script starts with the Start
state. The bot sends a welcome message and asks the user to enter the city name for them to get the current weather forecast.
GetWeather
state: GetWeather
q: * $City *
script:
var city = $parseTree._City.name;
openWeatherMapCurrent("metric", "en", city).then(function (res) {
if (res && res.weather) {
$reactions.answer("Today in " + capitalize(city) + ": " + res.weather[0].description + ", " + Math.round(res.main.temp) + "°C" );
if(res.weather[0].main == 'Rain' || res.weather[0].main == 'Drizzle') {
$reactions.answer("I recommend you to bring an umbrella with you!")
} else if (Math.round(res.main.temp) < 0) {
$reactions.answer("Brrrr... It's so cold outside! Dress warm!")
}
} else {
$reactions.answer("Server problems. I can not find out the weather.");
}
}).catch(function (err) {
$reactions.answer("Server problems. I can not find out the weather.");
});
Calling API function
Let’s move on to request processing. The transition to GetWeather
state is based on the * $City *
pattern specified in the q
tag. We will store the entered city name in the city
variable using $parseTree._City.name
.
Let’s call the openWeatherMapCurrent
function that we created before. The function accepts the following arguments:
"metric"
— unit of temperature measurement in Celsius;"en"
— language parameter;city
— city name.
Now, let’s execute the HTTP request. The openWeatherMapCurrent
function returns a promise
object. To display the result, we need to process promise
using then(function (res) {})
. Here res
is a variable that contains a response to a request.
Response format
Let’s assume that the client wants to know the current weather in London. Then in $parseTree._City.name
will be stored London
. The function sends a request to the OpenWeatherMap server with the "metric"
, "en"
and "London"
parameters. If a request is successful, the server sends a response in JSON format.
Response example
{
"coord":{"lon":-0.13,"lat":51.51},
"weather":[{
"id":802,
"main":"Clouds",
"description":"scattered clouds",
"icon":"03d"}],
"base":"stations",
"main":{
"temp":14.32,
"feels_like":12.37,
"temp_min":13.89,
"temp_max":15,
"pressure":1023,
"humidity":72},
"visibility":10000,
"wind":{
"speed":2.6,
"deg":230},
"clouds":{"all":40},
"dt":1605023271,
"sys":{
"type":1,
"id":1414,
"country":"GB",
"sunrise":1604992232,
"sunset":1605025111},
"timezone":0,
"id":2643743,
"name":"London",
"cod":200}
Click Logs tab to view the sever response.
Answer processing
Now we will use the data we need from the received response:
res.weather[0].description
— displaying the messagefew clouds
;Math.round(res.main.temp)
— displaying the current temperature rounded byMath.round
function.
To convert the first letter of the city name into uppercase, use the capitalize
function.
Next, using the if
conditional operator, we check whether there’s a response that contains a weather
field. If true
, the client will receive information about the weather using $reactions.answer
function:
"Today in " + capitalize(city) + ": " + res.weather[0].description + ", " + Math.round(res.main.temp) + "°C"
Additional recommendations
Let’s make our bot send recommendations depending on the current weather conditions.
- The server response contains a parameter that stores the weather status
res.weather[0].main
. If this parameter is equal to theRain
,Clouds
orDrizzle
values, then the bot will display a message:
I recommend you to bring an umbrella with you!
- If the temperature is below zero
Math.round(res.main.temp) < 0
, the bot will send the following message:
Brrrr... It's so cold outside! Dress warm!
Thus, the bot will display the following message about the current temperature in London:
Today in London: few clouds, 14°C. I recommend you to bring an umbrella with you!
Processing errors
If the request returned no response or its weather
field is empty, we will display an error message in else
.
It may also happen that the server is unavailable. We have to provide for this option by preparing an error message. To do this, use the catch
function and display the following message:
Server problems. I can not find out the weather.
then
.CatchAll
People can make mistakes when typing commands and send the bot a text that differs from all the considered options. For this purpose, the CatchAll
state is used. It processes the end of the script in case the client message does not fit any of the described stages.
state: CatchAll || noContext=true
event!: noMatch
a: I'm sorry, I don't understand, but I can tell you about the weather.
go: /GetWeather
When the client enters a message, for example, It's sunny outside
, the noMatch
event is activated, which is specified under the event!
tag in the CatchAll
state. The bot will send the following message:
I'm sorry, I don't understand, but I can tell you about the weather.
Then, move to /GetWeather
state using the go
tag.
Next, move on to testing the bot script.