Train Assistant Guide

Steps to integrate the train assistant into your app

Slang’s Android train assistant (aka SlangTrainAssistant) is a fully trained voice assistant specialized for Android apps in the train travel domain. By integrating with this assistant, apps can help their users perform the following types of tasks through voice:

  • Search for trains between specified cities, within a specified date range, along with filters such as travel class, ticket type, etc.

  • Sort listings of trains by parameters such as price, departure date/time, etc.

  • Track status of trains, by name or number

  • Look up PNR details

The following guide describes the steps that apps need to take in order to integrate with the assistant.

Integration Details

Step 1: Update Gradle dependencies

Update the app’s build.gradle files to include the following repository

top-level build.gradle
allprojects {
  repositories {
    maven { url "http://maven.slanglabs.in:8080/artifactory/gradle-release" }
  }
}

Then, add the following library to your app’s dependencies:

app's build.gradle
dependencies {
  implementation 'in.slanglabs.assistants:slang-train-assistant:4.0.1'
}

Step 2: Add UI elements to your activities

In your app’s activities where you’d like to show the assistant, you will need to add the assistant’s UI elements into the appropriate XML layouts like this:

activity_main.xml
<LinearLayout … >
  <in.slanglabs.assistants.train.SlangTrainAssistantButton
    android:clickable="true"
    android:src="@drawable/mic_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

</LinearLayout>

Step 3: Initialize the assistant

If your app has an Application class, then initialize the assistant in the onCreate() method of the Application. You’d need <API_KEY> and <BUDDY_ID> for this. You should’ve received this from the Slang team. If not, please ask :)

MyApplication.java
public void onCreate() {

  AssistantConfiguration configuration = new AssistantConfiguration.Builder()
    .setAPIKey(<API_KEY>)
    .setBuddyId(<BUDDY_ID>)
    .build();
  SlangTrainAssistant.initialize(this, configuration);
}

If your app does not have an Application class, then you can initialize the assistant in the MainActivity instead.

MainActivity.java
protected void onCreate(Bundle savedInstance) {

  AssistantConfiguration configuration = new AssistantConfiguration.Builder()
    .setAPIKey(<API_KEY>)
    .setBuddyId(<BUDDY_ID>)
    .build();
  SlangTrainAssistant.initialize(this, configuration);
}

Step 4: Register actions to be performed

Finally, you will need to register action methods that will be called by the assistant on behalf of the end-users to service their requirements.

MainActivity.java
SlangTrainAssistant.setAction(new SlangTrainAssistant.Action() {
    @Override
    public Status onSearch(TrainSearchQuery query, AssistantSession session, Bundle b) {
        // handle train search
        Date departureDate = query.getDepartureDate();
        String sourceCity = query.getSource().getCity();
        String destinationCity = query.getDestination().getCity();
        TrainTicketType type = query.getTicketType();
        
        return Status.UNSUPPORTED; // Refer below for possible return status.
    }

    @Override
    public Status onSort(TrainSortQuery query, AssistantSession session, Bundle b) {
        // handle sorting of listings
        return Status.UNSUPPORTED; // Refer below for possible return status.
    }

    @Override
    public Status onTrackStatus(Train train, AssistantSession session, Bundle b) {
        // handle train status tracking
        String trainNumber = train.getNumber();
        
        return Status.UNSUPPORTED; // Refer below for possible return status.
    }

    @Override
    public Status onPNRLookUp(PNR pnr, AssistantSession session, Bundle b) {
        // handle PNR lookup
        long pnrNumber = pnr.getNumber();
        
        return Status.UNSUPPORTED; // Refer below for possible return status.
    }

    @Override
    void onAssistantError(AssistantError error) {
        // handle assistant errors.
    }
 });

Possible return values of SlangTrainAssistant.Status is:

  • Status.UNSUPPORTED: This indicates to the assistant that the app doesn’t support this action, and the assistant can inform the user accordingly.

  • Status.SUCCESS: This indicates that the action is handled successfully and the assistant should let the user know about it with the success statement.

  • Status.FAILURE: This indicates that the app has failed to take action for some reason and the assistant should treat this as a failure, and speak out the appropriate failure statement.

  • Status.WAIT: This indicates that, the app will be processing the action asynchronously and the assistant should wait until the app notifies through the callback. Refer to the asynchronous action handling section below.

  • Status.NO_RESULTS_RETRY: This a search action specific status code indicating that search operation resulted in 'no data' and the user should be prompted to retry with valid inputs.

  • Status.NO_RESULTS_STOP: This a search action specific status code indicating that search operation resulted in 'no data' and assistant should end the conversation without retrying.

Error Handling

The onAssistantError() method is a very important method through which the Slang assistant communicates with the app whenever it detects an error. Apps must ensure that they implement this method and handle the various types of errors.

The most important types of errors, and how to handle them are described below. You can get the type of the error by calling the AssistantError.getType() method.

  • AssistantError.Type.FATAL_ERROR: This error type indicates that the Slang assistant encountered a fatal error and cannot continue. Upon receiving this error, the app must ensure that the app UI indicates that the Slang assistant is not available.

  • AssistantError.Type.ASSISTANT_DISABLED: This error type indicates that the Slang assistant is disabled for the current device. Upon receiving this error, the app must ensure that the app UI indicates that the Slang assistant is not available.

  • AssistantError.Type.MISSING_CREDENTIALS: This error type indicates that either or both of the required credentials (buddy id, API key) were not supplied during initialization

  • AssistantError.Type.INVALID_CREDNTIALS: This error type indicates that invalid credentials (buddy id, API key) were supplied during initialization.

  • AssistantError.Type.SYSTEM_ERROR: This error type usually indicates that a non-fatal system error occurred. The error is informational and the app should be able to continue execution despite receiving this error.

Asynchronous action handling

In the scenario where the app cannot complete the processing of the action synchronously inside the action method, it can do so by asking the assistant to wait and notify it once the action handling is done. This need can be achieved using the 'AssistantSession' passed in the action methods. Refer to the below example code snippet to understand how to achieve this.

@Override
public Status onSearch(TrainSearchQuery query, AssistantSession session, Bundle b) {
    session.waitForActionCompletion(); //Indicates assistant to wait for processing the action status.
    //Launch your asynchronous processing here.
    processTrainSearch(query, session)
    return Status.WAIT;
}

//Below method mimicks the asynchronous processing of train search.
private void processTrainSearch(TrainSearchQuery query, final AssistantSession session) {
  new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            //Notify assistant about the status of the action.
            session.notifyActionCompleted(Status.NO_RESULTS_RETRY);
        }
    }, 1000);
}

Basically, call "session.waitForActionCompletion()" and return Status.WAIT to tell the assistant to wait to be notified about the completion of the action. Once the app completes handling the action, it should call "session.notifyActionCompleted()" with appropriate action status. The assistant surface will be in the processing state until the app notifies it.

Step 5: Notify the assistant on the non-voice train search

This will help understand user behavior of using touch vs voice while searching for trains.

// build and pass the TrainSearchQuery object using the data from UI.
TrainSearchQuery nonVoiceQuery = new TrainSearchQuery.Builder()....build();
SlanTrainAssistant.notifyNonVoiceSearch(nonVoiceQuery);

Step 6 (optional): Passing the known/default search details to the assistant through search context.

You can use the assistant’s search context to pass any data that you might’ve known from user preference or from the partial data entered in the UI or from booking history. This will help avoid prompting users for available data unnecessarily.

For example, if the app knows the user’s location and wants to use it as a default source city, you can set that in search context and pass it to the assistant. This will help the assistant from explicitly prompting for the source of the travel.

TrainSearchContext searchContext = SlangTrainAssistant.getSearchContext();
searchContext.setSource(<default_source_city>);

Step 7 (optional): Passing any user-specific properties to the assistant for a deeper understanding of voice analytics.

The app has knowledge about the user in terms of demography or any application-specific details such as user id, name, etc. This information can be optionally passed to the assistant so that we can generate deeper user behavior analytics.

String userId =<USER_ID>”;

Map<String, String> userDetails;
SlangTrainAssistant.setUserProperties(userId, userDetails);

Last updated