Skip to main content

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.

  1. Configuration file setup
  2. HTTP request to OpenWeatherMap API
  3. Script development (you are here)
  4. Testing

In this step, we will create a script that will report the current weather in the requested city.

Script steps:

  1. The bot sends a welcome message and asks the client to enter the city name.
  2. The client enters the city name. For example, London or What is the weather in London today?.
  3. 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.
  4. 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.
tip
Learn more about .sc script files

Script 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.

Server logs

Answer processing

Now we will use the data we need from the received response:

  • res.weather[0].description — displaying the message few clouds;
  • Math.round(res.main.temp) — displaying the current temperature rounded by Math.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 the Rain, Clouds or Drizzle 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.
caution
Note that the result of an external call is not available outside of the handler function passed to 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.