Let's go with Watson Assistant (formerly Conversation) ④ How to link with Java logic

Target

Even with zero knowledge, we will bring you to the point where you can create Slack Bot and Line Bot using Watson.

[Updated on June 6, 2019] This post was written during the Watson Conversation era, the predecessor of Watson Assistant, and although screen captures are still old, Watson Assitant's basic ideas and operations Does not change, so please read it as the latest environment. </ font>

■ I would like to touch on the following.

(1) Introduction to thinking, creating an account ② Design method of dialogue flow using "Hotel reservation" as an example ③ Utilization of context, practical usage of various functions not mentioned in Tutorial ** ④ How to link with Java logic ** ← This article ⑤ Create a chatbot with Watson + Java + Slack

This time, in Part 4, I will explain ** ④ How to link with Java logic **.

Click here for the last time → ③ Utilization of context, practical usage of various functions not mentioned in Tutorial.


This time, we will link Java logic and Watson Conversation.

Preparation of workspace for operation check

First, create a simple workspace to check the operation of the program.

You can download the ** workspace file (JSON) ** for operation check from the following. https://riversun.github.io/wcs/org.riversun.WcsContextTestJa.zip

If you import this, you will have a workspace with only two nodes as shown below.

qt_04_001.png

  • Welcome_node
    The first ** Welcome_node ** is the first node to be executed, I have set multiple Context variables here.

qt_04_002.png

{
  "context": {
    "myParam01": "banana",
    "myParam02": "apple",
    "myParam03": 7777,
    "myParam04": true,
    "myParam05": {
      "subParam01": "orange",
      "subParam02": "lemon"
    }
  },
 ...
}

  • Show_Context_node
    The second ** Show_Context_node ** will be executed after user input immediately after executing Welcome_node.

qt_04_003.png

The response of this node is

** You said "". The value of the context variable myRemoteParam is "". ** **

Returns the user's input text and the Context variable ** myRemoteParam **.

Cooperation with Java programs

Check Workspace Ceredentials

In order to execute the Watson Conversation dialogue flow from a Java program, you need the workspace's ** WorkspaceId **, ** Username **, and ** Password **.

To see these, click the ** deploy icon ** on the left side of the dialog editor as shown below to open the ** deploy ** pane and select the ** Credentials ** tab. Make a note of ** WorkspaceId **, ** Username **, and ** Password **, respectively. You will use these later in your Java program.

qt_04_004b.png

Sample code

The sample code introduced below can be obtained from the following public repositories. https://github.com/riversun/watson-conversation-java-examples-ja

Example01: Set Context variable to send a message from Java logic to Watson Conversation and execute workspace

Below is the code that sends a text message to Watson. Also, set the Context variable from Java to Watson Conversation.

WcsExample01.java



package org.example.wcs;

import org.riversun.wcs.WcsClient;

import com.ibm.watson.developer_cloud.conversation.v1.model.MessageResponse;

public class WcsExample01 {

	private static final String WCS_USERNAME = "EDIT_ME_USERNAME_HERE";
	private static final String WCS_PASSWORD = "EDIT_ME_PASSWORD_HERE";
	private static final String WCS_WORKSPACE_ID = "EDIT_ME_WORKSPACE_ID_HERE";

	public static void main(String[] args)
	{

		String wcsClientId = "dummy_user_id";
		WcsClient watson = new WcsClient(WCS_USERNAME, WCS_PASSWORD, WCS_WORKSPACE_ID);

		MessageResponse wcsWelcomeRes = watson.startConversation(wcsClientId);

		System.out.println("FROM WATSON:" + wcsWelcomeRes.getTextConcatenated(""));

		final String ctxKey = "myRemoteParam";
		final String ctxValue = "I need you!";
		watson.put(wcsClientId, ctxKey, ctxValue);

		final String myMessage01 = "Hi! Watson";
		MessageResponse wcsRes01 = watson.sendMessage(wcsClientId, myMessage01);
		System.out.println("FROM WATSON:" + wcsRes01.getTextConcatenated(""));

	}
}


Code description


private static final String WCS_USERNAME = "EDIT_ME_USERNAME_HERE";//username
private static final String WCS_PASSWORD = "EDIT_ME_PASSWORD_HERE";//password
private static final String WCS_WORKSPACE_ID = "EDIT_ME_WORKSPACE_ID_HERE";//workspaceId

First, set the credentials to access Watson. Edit the following part of the code and replace it with the ** workspaceId, username, password ** you saw earlier in the ** deploy ** pane.


 String wcsClientId = "dummy_user_id";

When working with Watson Conversation using the helper library Give a unique user ID to identify the user (here, the variable name is wcsClientId. Note that it is completely different from the workspace username).

User ID is not a concept unique to Watson Conversation, but when multiple users interact with the bot at the same time with a chatbot as shown below, the interaction state between the user and the chatbot is maintained for each user (as a matter of course). Must be.

qt_04_005.png

Therefore, as in this sample, even one user can access Watson by assigning a user ID for convenience. (By the way, in Watson's internal processing, an ID called conversationId is assigned for each conversation session rather than for each user.)


 WcsClient watson = new WcsClient(username,password,workspaceId);

New the WcsClient class. This class communicates with watson conversation


MessageResponse wcsWelcomeRes = watson.startConversation(wcsClientId);
System.out.println("FROM WATSON:" + wcsWelcomeRes.getTextConcatenated(""));

The first call uses the ** # startConversation ** method. I think that the node of Watson Conversation is often a ** welcome node **, but ** #startConversation ** executes this ** welcome node **. Receive the response from Watson as ** MessageResponse **.

** # getTextConcatenated ** is for getting the response from Watson as a String. (Since it may go through multiple nodes before returning the response, the actual response from Watson is JSON String array type (= List in Java), but this String array type response Are combined and obtained as one String.)


final String ctxKey = "myRemoteParam";
final String ctxValue = "I need you!";
watson.put(wcsClientId, ctxKey, ctxValue);

Using ** watson.put (user ID, context variable name, context variable value) **, the ** Context variable ** of Watson Conversation is set from the Java logic side.

Here, I set the value "** I need you! **" to the Context variable named ** myRemoteParam **.

At this stage, the Context is held only in the Java logic, and it will be reflected on the Watson side the next time Watson is accessed from the Java logic.


final String myMessage01 = "Hi! Watson";
MessageResponse wcsRes01 = watson.sendMessage(wcsClientId, myMessage01);
System.out.println("FROM WATSON:" + wcsRes01.getTextConcatenated(""));

Send a text message to Watson with ** #sendMessage (user ID, message) **. At this timing, the Context variable set earlier is reflected on the Watson side.

Here, the message "** Hi! Watson **" is sent from Java logic.

By the way, the response of the ** Show_Context_node ** node on the Watson Conversation side is You said "**" ". The value of the context variable myRemoteParam is "". ** ”

Therefore, the response from Watson received on the Java logic side is as follows.

response


「Hi!You said "Watson". The value of the context variable myRemoteParam is "I need you!"is.


 final String myMessage02 = "Hello! Watson";
        String wcsResText = watson.sendMessageForText(wcsClientId, myMessage02);
        System.out.println("FROM WATSON:" + wcsResText);

** # sendMessageForText ** sends a text message to Watson like ** # sendMessage **, but since it also receives the response from Watson as text, this method is the simplest for sending and receiving text.

Also, if you use ** # sendMessageForText **, you can omit ** # startConversation ** (that is, execute *** startConversation ** in the first ** # sendMessageForText **). ), If you want to create a chatbot that just sends and receives text, the ** # sendMessageForText ** method is all you need.

Program execution result

When you run WcsExample01.java, it will be output to the console as below

Execution result


FROM WATSON:Hello, I'm Watson
FROM WATSON:「Hi!You said "Watson". The value of the context variable myRemoteParam is "I need you!"is.
FROM WATSON:「Hello!You said "Watson". The value of the context variable myRemoteParam is "I need you!"is.

Library dependencies

To execute the above code, set the dependent libraries as follows

maven


<dependency>
    <groupId>org.riversun</groupId>
    <artifactId>wcs</artifactId>
    <version>1.0.2</version>
</dependency>

gradle


compile 'org.riversun:wcs:1.0.2'

We have prepared watson-conversation-service-for-java as a helper library for executing Watson Conversation from Java. This library is a thin wrapping of the well-made Basic Library (https://github.com/watson-developer-cloud/java-sdk) and extended for multi-user chatbots.

Example02: Get Watson's Context variable from Java logic

The following is an example of getting the Context variable set on the Watson Conversation side.

WcsExample02.java


package org.example.wcs;

import java.util.Map;

import org.riversun.wcs.WcsClient;

public class WcsExample02 {

	private static final String WCS_USERNAME = "EDIT_ME_USERNAME_HERE";
	private static final String WCS_PASSWORD = "EDIT_ME_PASSWORD_HERE";
	private static final String WCS_WORKSPACE_ID = "EDIT_ME_WORKSPACE_ID_HERE";

	public static void main(String[] args)
	{

		String wcsClientId = "dummy_user_id";

		WcsClient watson = new WcsClient(WCS_USERNAME, WCS_PASSWORD, WCS_WORKSPACE_ID);

		watson.startConversation(wcsClientId);

		String myParam01 = watson.getAsString(wcsClientId, "myParam01");
		System.out.println("myParam01=" + myParam01);

		String myParam02 = watson.getAsString(wcsClientId, "myParam02");
		System.out.println("myParam02=" + myParam02);

		Integer myParam03 = watson.getAsInteger(wcsClientId, "myParam03");
		System.out.println("myParam03=" + myParam03);

		Boolean myParam04 = watson.getAsBoolean(wcsClientId, "myParam04");
		System.out.println("myParam04=" + myParam04);

		Map<String, Object> myParam05 = watson.getAsMap(wcsClientId, "myParam05");

		String subParam01 = (String) myParam05.get("subParam01");
		System.out.println("myParam05.subParam01=" + subParam01);

		String subParam02 = (String) myParam05.get("subParam02");
		System.out.println("myParam05.subParam02=" + subParam02);

	}
}

Code description

As seen above, the Context variables set in the ** Welcome_node ** node on the Watson Conversation side are as follows.

{
  "context": {
    "myParam01": "banana",
    "myParam02": "apple",
    "myParam03": 7777,
    "myParam04": true,
    "myParam05": {
      "subParam01": "orange",
      "subParam02": "lemon"
    }
  }
}

For example, to get the above Context variable "** myParam01 **" on the Java side, do as follows.

String myParam01 = watson.getAsString(User ID, "myParam01");

Also, in the case of a (nested) composite object such as the Context variable "** myParam05 **", get it as ** Map ** as shown below. Data is stored nested under ** Map **.

**Map<String, Object> myParam05 = watson.getAsMap(wcsClientId, "myParam05");**

The table below also shows how to access other types.

** Method to get Watson Conversation Context variable from Java logic **

Context variable type Method definition Return type
String type #getAsString(User ID,Context variable name) String
Numeric type(Integer type) #getAsInteger(User ID,Context variable name) Integer
Numeric type(Double type) #getAsDouble(User ID,Context variable name) Double
Boolean type #getAsBoolean(User ID,Context variable name) Boolean
Complex type(If the JSON is nested) #getAsMap(User ID,Context variable name) Map

Example03: Handle Watson response details from Java program

In the above two examples, we mainly looked at sending and receiving text (String) and exchanging Context variables, but you can actually get various information between Watson and Java logic.

** Information that can be obtained **

information Description
Input User input information
Output Output information from Watson. Information other than text can be flexibly included in Output
Context Context variable information
Intents Intent determined by Watson based on user input text(Multiple)
Entities Entity extracted by Watson based on user input text(Multiple)

The following is an example of actually accessing various information included in the response from Watson from Java logic.

public class WcsExample03 {

	private static final String WCS_USERNAME = "EDIT_ME_USERNAME_HERE";
	private static final String WCS_PASSWORD = "EDIT_ME_PASSWORD_HERE";
	private static final String WCS_WORKSPACE_ID = "EDIT_ME_WORKSPACE_ID_HERE";

	public static void main(String[] args)
	{

		String wcsClientId = "dummy_user_id";
		WcsClient watson = new WcsClient(WCS_USERNAME, WCS_PASSWORD, WCS_WORKSPACE_ID);

		MessageResponse res = watson.startConversation(wcsClientId);

		Map<String, Object> context = res.getContext();

		Map<String, Object> input = res.getInput();

		String inputText = res.getInputText();

		List<Intent> intents = res.getIntents();

		List<Entity> entities = res.getEntities();

		Map<String, Object> output = res.getOutput();

		List<String> text = res.getText();

		String textConcatenated = res.getTextConcatenated("");

		System.out.println("Response JSON from Watson=\n" + res.toString());

	}
}

Actual response from Watson (JSON)

Since Java has a helper library, there aren't many scenes where JSON is parsed directly by Java logic, but the actual response from Watson Conversation is as follows.

Response from Watson Conversation



{
  "context": {
    "system": {
      "dialog_stack": [
        {
          "dialog_node": "root"
        }
      ],
      "dialog_turn_counter": 2.0,
      "dialog_request_counter": 2.0,
      "_node_output_map": {
        "Welcome_Node": [
          0.0
        ],
        "Show_Context_Node": [
          0.0
        ]
      },
      "branch_exited": true,
      "branch_exited_reason": "completed"
    },
    "conversation_id": "xxxx-xxxxxx-xxxxx-xxxx",
    "myParam05": {
      "subParam01": "orange",
      "subParam02": "lemon"
    },
    "myRemoteParam": "I need you!",
    "myParam03": 7777.0,
    "myParam04": true,
    "myParam01": "banana",
    "myParam02": "apple"
  },
  "entities": [],
  "intents": [],
  "output": {
    "text": [
      "「Hi!You said "Watson". The value of the context variable myRemoteParam is "I need you!"is."
    ],
    "nodes_visited": [
      "Show_Context_Node"
    ],
    "log_messages": []
  },
  "input": {
    "text": "Hi!Watson"
  }
}

Example04: Create a GUI in Java to make it look like a chatbot

This section is a little extra.

It's a little difficult to try Watson Conversation interactions with just a Java console app, so I created a simple GUI.

java_gui_chat_watson.gif

・ All source code is in the following repository https://github.com/riversun/watson-examples-java-chatbot

・ The dialogue flow is the ** hotel reservation chatbot (enhanced version) ** introduced previous. You can download the workspace file (JSON) from the following. https://riversun.github.io/wcs/org.riversun.HotelReservationV2.zip

Code example

@SuppressWarnings("serial")
public class WatsonChat extends JFrame {

    private static final String WATSON_CONVERSATION_USERNAME = "EDIT HERE";
    private static final String WATSON_CONVERSATION_PASSWORD = "EDIT HERE";
    private static final String WATCON_CONVERSATION_WORKSPACE_ID = "EDIT HERE";
    private static final String WCS_CLIENT_ID = "dummy_user_id";

    private static final int WIDTH_PX = 640;
    private static final int HEIGHT_PX = 480;

    private final WcsClient mWatson = new WcsClient(WATSON_CONVERSATION_USERNAME, WATSON_CONVERSATION_PASSWORD, WATCON_CONVERSATION_WORKSPACE_ID);

    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
    private final StringBuilder mSb = new StringBuilder();

    private final JTextArea mTextArea = new JTextArea();
    private final JTextField mTextBox = new JTextField("");

    public static void main(String args[]) {

        EDTHandler.post(new Runnable() {
            public void run() {

                System.setProperty("jsse.enableSNIExtension", "false");
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException |
                        IllegalAccessException | UnsupportedLookAndFeelException e) {
                }

                final WatsonChat frame = new WatsonChat();
                frame.setVisible(true);
            }
        });
    }

    public WatsonChat() {
        EDTHandler.post(new Runnable() {
            @Override
            public void run() {
                buildGUI();
                sendMessageOnFirst();
            }
        });
    }

    boolean onUserInputText(String userInputText) {

        addTextIntoHistory("YOU:" + userInputText + "\n");

        sendMessageToWatson(WCS_CLIENT_ID, userInputText);

        return true;
    }

    void onClearButtonPressed() {
        mSb.setLength(0);
        EDTHandler.post(new Runnable() {
            @Override
            public void run() {
                mTextArea.setText(mSb.toString());
            }
        });
        mWatson.clearConversation(WCS_CLIENT_ID);
        sendMessageOnFirst();
    }

    void sendMessageOnFirst() {

        mExecutor.submit(new Runnable() {
            @Override
            public void run() {
                MessageResponse welcomeRes = mWatson.startConversation(WCS_CLIENT_ID);
                addTextIntoHistory("WATSON:" + welcomeRes.getTextConcatenated("") + "\n");
                unlockTextBox();
            }
        });
    }

    void sendMessageToWatson(String wcsClientId, String userInputText) {

        mExecutor.submit(new Runnable() {
            @Override
            public void run() {

                final String watsonOutputText = mWatson.sendMessageForText(wcsClientId, userInputText);
                addTextIntoHistory("WATSON:" + watsonOutputText);

                unlockTextBox();
            }
        });
    }

    void addTextIntoHistory(String text) {

        mSb.append(text);
        EDTHandler.post(new Runnable() {
            @Override
            public void run() {
                mTextArea.setText(mSb.toString());
            }
        });

    }

    void unlockTextBox() {

        EDTHandler.post(new Runnable() {
            @Override
            public void run() {

                mTextBox.setEditable(true);
                mTextBox.requestFocus();
                mTextBox.getCaret().setVisible(true);
                mTextBox.setCaretPosition(0);

            }
        });
    }

    void buildGUI() {

        setTitle("Chat with Watson");
        setSize(WIDTH_PX, HEIGHT_PX);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JLinearLayout layoutParent = new JLinearLayout().setChildOrientation(Orientation.VERTICAL).setPadding(5);
        final JLinearLayout layoutHeader = new JLinearLayout().setChildOrientation(Orientation.HORIZONTAL).setPadding(5, 0, 5, 0);
        final JLinearLayout layoutCenter = new JLinearLayout().setChildOrientation(Orientation.VERTICAL).setPadding(5, 0, 5, 0);
        final JLinearLayout layoutFooter = new JLinearLayout().setChildOrientation(Orientation.VERTICAL).setPadding(5);

        JLabel lbChatHistory = new JLabel("Chat History:");

        JButton btClear = new JButton("Clear");
        btClear.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                onClearButtonPressed();
            }
        });

        mTextArea.setLineWrap(true);
        mTextArea.setMargin(new Insets(4, 4, 4, 4));
        mTextArea.setEditable(false);

        JScrollPane textAreaScroll = new JScrollPane(mTextArea);
        textAreaScroll.setBorder(new LineBorder(Color.black, 1, true));

        JLabel lbInputText = new JLabel("Input Text:  (press ENTER-KEY to send)");

        mTextBox.setBorder(new LineBorder(Color.black, 1, true));
        mTextBox.setEditable(false);
        Font font = mTextBox.getFont().deriveFont(Font.PLAIN, 20f);
        mTextBox.setFont(font);
        mTextBox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                final String userInputText = mTextBox.getText();

                if ("".equals(userInputText)) {
                    return;
                }

                mTextBox.setEditable(false);

                final boolean consumed = onUserInputText(userInputText);

                if (consumed) {
                    mTextBox.setText("");
                }

            }
        });

        addWindowListener(new WindowAdapter() {
            public void windowOpened(WindowEvent e) {
                mTextBox.requestFocus();
            }
        });

        layoutHeader.addView(lbChatHistory, 1.0d);
        layoutHeader.addView(btClear, 0d);
        layoutCenter.addView(textAreaScroll);
        layoutFooter.addView(lbInputText);
        layoutFooter.addView(mTextBox);
        layoutParent.addView(layoutHeader, 0.0d);
        layoutParent.addView(layoutCenter, 1.0d);
        layoutParent.addView(layoutFooter, 0.0d);
        JPanel mainPanel = layoutParent.getAsPanel();
        Container contentPane = getContentPane();
        contentPane.add(mainPanel, BorderLayout.CENTER);

    }
}

Code description

 void sendMessageToWatson(String wcsClientId, String userInputText) {

        mExecutor.submit(new Runnable() {
            @Override
            public void run() {

                final String watsonOutputText = mWatson.sendMessageForText(wcsClientId, userInputText);
                addTextIntoHistory("WATSON:" + watsonOutputText);

                unlockTextBox();
            }
        });
    }

The key to this code is mostly summarized here.

The text entered from the text field (bottom) is sent to Watson with ** # sendMessageForText **. The result is received as text and displayed in the text area (top) of the history requirement.

The ** unlockTextBox ** part unlocks the text field. If you don't lock the text field while communicating with Watson, the next text will be sent before the result is returned.

The rest is a part that is often found in GUI processing, but the ** mExecutor.submit ** part uses Thread Executor to communicate with Watson in a separate thread. If you synchronize here, the GUI will be locked while communicating with Watson.

Summary

This time, I introduced how to link Java logic and Watson Conversation and execute the dialogue flow of Watson Conversation from Java.

--Sample code repository https://github.com/riversun/watson-conversation-java-examples-ja

--Helper library repository https://github.com/riversun/watson-conversation-service-for-java

Next time wants to connect with frontends such as Slack and LINE to create chatbot apps such as Slack Bot and LINE Bot.

Recommended Posts

Let's go with Watson Assistant (formerly Conversation) ④ How to link with Java logic
Let's go with Watson Assistant (formerly Conversation) ⑤ Create a chatbot with Watson + Java + Slack
Let's go with Watson Assistant (formerly Conversation) ② Make a hotel reservation chatbot
Let's go with Watson Assistant (formerly Conversation) ① Introduction What is the idea and intention understanding of interactive apps?
Investigated how to call services with Watson SDK for Java
Watson Assistant (formerly Conversation) on Android
[Java] How to compare with equals method
Try to link Ruby and Java with Dapr
How to use Java framework with AWS Lambda! ??
[Swift] How to link the app with Firebase
How to use Java API with lambda expression
[Java] How to omit spring constructor injection with Lombok
How to deploy Java to AWS Lambda with Serverless Framework
[Java] How to encrypt with AES encryption with standard library
How to build Java development environment with VS Code
[Java] How to start a new line with StringBuilder
Let's scrape with Java! !!
Let's write how to make API with SpringBoot + Docker from 0
How to use trained model of tensorflow2.0 with Kotlin / Java
How to handle exceptions coolly with Java 8 Stream or Optional
[Java] How to use Map
How to lower java version
[Java] How to use Map
Let's experiment with Java inlining
How to uninstall Java 8 (Mac)
Java to play with Function
Java --How to make JTable
How to use java Optional
How to minimize Java images
How to write java comments
Let's operate Excel with Java! !!
How to use java class
[Java] How to use Optional ②
[Java] How to use removeAll ()
[Java] How to display Wingdings
[Java] How to use string.format
How to number (number) with html.erb
How to use Java Map
How to update with activerecord-import
How to set Java constants
Connect to DB with Java
Connect to MySQL 8 with Java
How to use Java variables
How to convert Java radix
[Java] How to implement multithreading
[Java] How to use Optional ①
How to initialize Java array
How to execute Postgresql copy command with column information on Java
Android: How to deal with "Could not determine java version from '10 .0.1'"
How to switch Java version with direnv in terminal on Mac
Project facet Java version 13 is not supported. How to deal with
How to call with One Touch (without confirmation) on Android (Java)
How to encrypt and decrypt with RSA public key in Java