Symphony Developer - Building an interactive bot using BDK 2.0

Note: Before beginning the steps in this article, you must first complete the steps in Symphony Developer - Configure a Bot for BDK 2.0

BDK 2.0 is a library of tools and intelligent API bindings that provides a simplified configuration and authentication setup, intuitive message and room management, customizable message templating, and a new activities API that makes it easy to facilitate bot workflows. 

 

First, open up the code generated by the Symphony Bot Generator in an Integrated Development Environment (IDE) of your choice, and then navigate to the BotApplication.java file:

BotApplication.java
package com.symphony.java;

import com.symphony.bdk.core.SymphonyBdk;
import com.symphony.bdk.core.service.datafeed.RealTimeEventListener;
import com.symphony.bdk.core.service.message.model.Message;
import com.symphony.bdk.gen.api.model.V4Initiator;
import com.symphony.bdk.gen.api.model.V4UserJoinedRoom;
import com.symphony.bdk.template.api.Template;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.symphony.bdk.core.config.BdkConfigLoader.loadFromClasspath;
import static com.symphony.bdk.core.activity.command.SlashCommand.slash;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;

/**
* Simple Bot Application.
*/
public class BotApplication {

/** The Logger */
private static final Logger log = LoggerFactory.getLogger(BotApplication.class);

public static void main(String[] args) throws Exception {

// Initialize BDK entry point
final SymphonyBdk bdk = new SymphonyBdk(loadFromClasspath("/config.yaml"));

// Register a "slash" activity
bdk.activities().register(slash("/gif", false, context -> {
Template template = bdk.messages().templates().newTemplateFromClasspath("/templates/gif.ftl");
bdk.messages().send(context.getStreamId(), Message.builder().template(template).build());
}));

// Register a "formReply" activity that handles the Gif category form submission
bdk.activities().register(new GifFormActivity(bdk.messages()));

// Subscribe to 'onUserJoinedRoom' Real Time Event
bdk.datafeed().subscribe(new RealTimeEventListener() {

@Override
public void onUserJoinedRoom(V4Initiator initiator, V4UserJoinedRoom event) {
final String userDisplayName = event.getAffectedUser().getDisplayName();
Template template = bdk.messages().templates().newTemplateFromClasspath("/templates/welcome.ftl");
bdk.messages().send(event.getStream(),
Message.builder().template(template, singletonMap("name", userDisplayName)).build());
}
});

// finally, start the datafeed read loop
bdk.datafeed().start();
}
}


The highlighted code is responsible for sending Symphony Elements in the BotApplication.java.


This code leverages the Activities API to register a new slash command that listens to ("/gif"). If an incoming message contains ("/gif) the bot builds a new message template which is provided out of the box.

Note: See more information about creating slash commands and how to leverage the Activities API here

The freemarker template below contains messageML that represents a Symphony Element:
resources/templates/gif.ftl
v<messageML>
<h2>Gif Generator</h2>
<form id="gif-category-form">

<text-field name="category" placeholder="Enter a Gif category..."/>

<button name="submit" type="action">Submit</button>
<button name="test" type="action">Test</button>
<button type="reset">Reset Data</button>

</form>
</messageML>
Note: See more information on Symphony Elements here

 

When a message is sent to the bot containing "/gif", the following Symphony Element is sent to the user in the conversation or stream (Figure 1):

 

1.png

Figure 1 Symphony Element

 

Bots need a way to capture the data submitted on this form. This can be done by registering a new type of Activity class:

// Register a "formReply" activity that handles the Gif category form submission
bdk.activities().register(new GifFormActivity(bdk.messages()));


Open the GifFormActivity class and the user will see that GifFormActivity extends the FormReplyActivity class. A form activity is only triggered when an end user replies or submits an Elements form:

public class GifFormActivity extends FormReplyActivity<FormReplyContext> {

private final MessageService messageService;

public GifFormActivity(MessageService messageService) {
this.messageService = messageService;
}

@Override
public ActivityMatcher<FormReplyContext> matcher() {
return context -> "gif-category-form".equals(context.getFormId())
&& "submit".equals(context.getFormValue("action"));
}

@Override
public void onActivity(FormReplyContext context) {
final String category = context.getFormValue("category");
final String message = "<messageML>Received category '" + category + "'</messageML>";
this.messageService.send(context.getSourceEvent().getStream(), Message.builder().content(message).build());
}

@Override
protected ActivityInfo info() {
return new ActivityInfo().type(ActivityType.FORM)
.name("Gif Display category form command")
.description("\"Form handler for the Gif Category form\"");
}
}

Note: See more information on creating your own FormReplyActivity class here

 

Inside the GifFormActivity class, the user will see an ActivityMatcher matcher() method:

@Override
public ActivityMatcher<FormReplyContext> matcher() {
return context -> "gif-category-form".equals(context.getFormId())
&& "submit".equals(context.getFormValue("action"));
}

Using the context variable, a bot can access information about the context of the form submission including the form values and the form ID


Inside of the matcher() function, the bot is performing a validation check. If the formId of the submitted form is equal to "gif-category-form," then the bot calls the onActivity() trigger function and executes its business logic.

 

If there is not a match, the bot does nothing and continues to listen for incoming events. As seen in the gif.ftl template earlier in the article, the formId matches, so the following onActivity() trigger function is executed:

@Override
public void onActivity(FormReplyContext context) {
final String category = context.getFormValue("category");
final String message = "<messageML>Received category '" + category + "'</messageML>";
this.messageService.send(context.getSourceEvent().getStream(), Message.builder().content(message).build());
}

Finally, run the bot and execute the following example to ensure the functionality is working as expected (Figure 2):

 

2.png

Figure 2 Generator