Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Add a Chatbot to a C# Application using SIML (Synthetic Intelligence Markup Language)

0.00/5 (No votes)
9 Oct 2017 2  
Integration of a Chatbot in a C# application using SIML (Synthetic Intelligence Markup Language)

Introduction

In a nutshell, Chatbots are software entities that engage in a conversation with a human user by textual or auditory means. For many years (decades), developers and researchers have been working over Chatbot architectures trying to implement and improve over existing ones to further the research over intelligent machines.

SIML or Synthetic Intelligence Markup Language is one such architecture that allows developers to write simple as well as complex knowledge bases for Chatbots. The best part is that SIML offers complex pattern recognition along with conditional patterns and even JavaScript ensuring that we are no longer bound by the simple pattern recognition system used by many of the existing architectures.

Those of you who are familiar with AIML will find SIML's XML construct easier to grasp and implement as SIML is a superset of AIML and is quite well thought and powerful. It also comes with its own IDE for the sole purpose of creating intelligent SIML knowledge bases and offers auto-completion, code analysis, JavaScript editor, Regular Expression tester and also a Script Evaluator.

  • For those who are new to Chatbots or XML, I highly recommend that you stay patient throughout the tutorial and give yourself more time to experiment.
  • Explaining a specification is a major undertaking but I will try my best to keep the tutorial as simple as possible.

If you've already referred to this article, you may proceed to the next article - Part 2.

If you prefer building an intelligent bot that is powered by Machine Learning, you can take a look at my other article Database Bot using Oscova.

Prerequisites

  • Good knowledge of XML and its syntax
  • Beginner level experience with XAML and WPF for GUI
  • A fairly average experience with C# development
  • Basic knowledge of SIML (which can be acquired from the SIML Quick Start document)

Getting Started

Firstly, fireup Visual Studio to create a new project. I am currently using Visual Studio Community Edition 2013 with Update 4. The class library that we are going use in this tutorial is Syn.Bot which is available as a NuGet package.

Setting Up the GUI

Now let's start the game of imitation. Firstly let's create a (very) simple WPF application in C# to interact with our Chatbot. Click File->New->Project.. and under Visual C# template, select WPF Application and make sure you target .NET 4.5 or above for the project. Name your project SIML Chatbot Demo for the sake of simplicity.

To interact with our Chatbot, we will need the following components to be added to our WPF Application.

  • An Input box to send the message we type.
  • A Send button (obviously) to submit our text message.
  • And an Output box to display the response generated by our Chatbot.

I could have gone with WinForms to help beginner C# developers but working with WPF isn't that hard either and quite frankly is preferred over WinForms these days. Double click MainWindow.xaml and replace the code with the following XAML code. You may have to make your own changes if you didn't name your Project as aforementioned.

<Window x:Class="SIML_Chatbot_Demo.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="SIML Chatbot Demo" Height="350" Width="600">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="260*"/>
            <RowDefinition Height="5*"/>
            <RowDefinition Height="40*"/>
        </Grid.RowDefinitions>
        <TextBox Name="OutputBox" IsReadOnly="True" />
        <DockPanel Grid.Row="2">
            <TextBox Width="450" Name="InputBox" />
            <Button Content="Send" 

            Name="SendButton" Click="SendButton_OnClick"/>
        </DockPanel>
    </Grid>
</Window>

When you paste the above code Click="SendButton_OnClick" will appear in RED as the event handler is not present in our C# code. So right click MainWindow.xaml, select View Code and add the following event handler for the click event of our SendButton.

private void SendButton_OnClick(object sender, RoutedEventArgs e)
{
    //Our code will go here
}

Fantastic! So now, we have our GUI ready.

Importing the Syn.Bot NuGet Package

To import the portable class library from NuGet, click Tools->NuGet Package Manager->Package Manager Console and type Install-Package Syn.Bot. The class library will now be added to your project and will be referenced properly. Syn.Bot is the official interpreter for SIML and is updated on a regular basis.
Great! Now that we have our library with us, we will move towards writing our knowledge base for the Bot which we will later import into our C# application.

Getting the IDE for SIML Development

To create an SIML knowledge base, we will make use of Syn Chatbot Studio which is a freely available IDE for SIML development. To download Syn Chatbot Studio, type "Download Syn Chatbot Studio" in Google and follow the link. In this tutorial, we will create a very simple knowledge base but if you prefer to hone some SIML skills, try the SIML Quick Start tutorial available in the official SIML website.

Once you have installed and launched the Chatbot Studio, click on File->New->Project and fill in the details but make sure that you select the Empty template under the Template section.

Save your SIML Project to any directory you prefer (at this point, the Project directory is irrelevant). Once your project is created, you will be presented with your Project Overview. The Overview panel gives a quick peek to your project statistics.

SIML Basics

Before I start diving deep into SIML, I have to be honest that SIML is extremely powerful but for better comprehension in this tutorial, I'll try to just scratch the surface for the readers.

Your SIML Project consists of 2 main parts:

  • Settings
  • Concepts

These are grouped under the Files Explorer, towards the right, under the Settings and Files category respectively.

SIML in its bare metal consists of Concepts and Models. A Concept in SIML is the subject or topic under which the respective Models are declared. A Model in SIML is the basic unit of knowledge and comprises a unique Pattern and a Response.

For the sake of this tutorial, we will write some simple SIML Models with some patterns and on the way, learn some of the basics. Click on the Console tab, type hello bot and press Send.

You will get the response "hello user!"

Now click on Stats under the Console tab. What you are looking at is the speed of the response generated by the Bot and the time in milliseconds it took for doing so. For now, this ain't important so let's move on.

Click on the Hello Bot file in the Files category under the Files Explorer. You will be presented with an entry point Model.

In the above image that you are looking at is a simple SIML Concept file with just 1 Model.

  • Concept - Every SIML knowledge base should start with a subject or a topic. Concepts allow you to group Models under a specific name. In the example code above, the name of the Concept is Hello Bot.
  • Model - Is the basic unit of knowledge in SIML and contains Patterns and Responses. A single Concept may contain 1000s of Models but a Model contains 1 Response element, unlimited number of Patterns and optionally a <Previous> element.
  • Pattern - A Pattern is a set of tokens/words that are inspected at runtime against the user input to see if the User input matches the specified sequence of tokens/words.
  • Response - Once a Pattern is inspected and satisfies every condition specified, the Response part is evaluated and is sent back to the user.

All of the above elements are placed within an <Siml> element (which is always the root element of any SIML document). The names of these elements are case-sensitive.

There are 2 types of Concepts in SIML - Public and Private. A Public concept subsumes all Models and are publicly accessible at runtime whereas a Private concept has to be activated by some other SIML code. You may stop wondering about public and private concepts for now as we will be working only with Public concepts in this tutorial.

A Simple Atomic Pattern

Delete the existing Model (XML Element) and type the following SIML Code in the Editor.

<Model>
  <Pattern>
    <Item>HELLO THERE</Item>
    <Item>HI</Item>
    <Item>HOLA</Item>
    <Item>HI</Item>
  </Pattern>
  <Response>Hi there!</Response>
</Model>

Press F5 and click on the Console tab and type "Hello there" you'll receive the response "Hi there!" Well, that was easy. In the above SIML code, we added an SIML Model with a Pattern element within which we declared multiple atomic patterns using the <Item> element and finally added a Response element with a simple text.

  • To define multiple patterns, always make use of the <Item> element within the <Pattern>
  • Always refresh your project before using the Console to load the changes you made into the Bot memory.
  • The pattern we used are called "Atomic" Patterns because they contain no symbols/wildcards.

From the above example, we learn that to declare an SIML Model, we use the <Model> element which in-turn takes a <Pattern> and a <Response> element as its children. To declare multiple patterns, all we got to do is use an <Item> element within the <Pattern> itself.

Using Real-Time Sets

We shall now try some non-atomic patterns. Add the following SIML Model within the Concept element.

<Model>
  <Pattern>DO YOU LIKE (BACON|PANCAKE)</Pattern>
  <Response>Yes I love <Match /></Response>
</Model>

Press F5 and type "do you like bacon?". The response will be "Yes I love bacon". In our new SIML Model's Pattern, we have used what is called a real-time set that consists of 2 items namely bacon and pancake. So if the user types do you like bacon or do you like pancake, our SIML Model gets evaluated.

To create a realtime set, we use round brackets and separate each word with the | character. The Response element we declared consists of a new element the <Match> element. This element captures the value of any wildcard, regular expression or SIML set we use in our SIML Model's pattern. In our case, the realtime set (bacon|pancake) matched the word bacon when we input do you like bacon.

  • A Match element <Match/> can be used to capture the value of wildcards, sets (in our example above the 2 words bacon and pancake) or regular expressions in patterns.
  • A Match element also has the Index attribute that is used to specify the index of the item in our pattern.

Using Static Sets

Let's try to push ourselves a bit further by creating an SIML Set that will help us match a number of colors within the user input. Suppose we wanted to detect the color the user mentions in his/her input. Say "I like the color red".

To create a set, click on the Sets file in the Settings category under Files Explorer and add the following SIML code:

<Set Name="COLOR">
  <Item>Red</Item>
  <Item>Green</Item>
  <Item>Blue</Item>
</Set>

In the above SIML Code, we create an SIML Set using the <Set> tag and use the "Name" Attribute to give the Set a unique name which can later be used in our SIML Code. Press Ctrl+S to save the SIML code we just wrote within our Project and click on the Hello Bot file under the Files Explorer and add the following SIML Code.

<Model>
  <Pattern>MY FAVOURITE COLOR IS [COLOR]</Pattern>
  <Response>I see so you like the color <Match />.</Response>
</Model>

In the above SIML Code, we enclose the name of the required Set within square brackets and to get the value of captured Set, we of course use the <Match> element. I will come back to this element later in the tutorial. Refresh your project by pressing F5 and type "My favourite color is Green" in the Console the response will be "I see so you like the color Green".

  • Sets save a lot of time by allowing us to use a collection of items grouped in our Pattern thereby eliminating redundancy and help in maintenance of large knowledge bases.
  • SIML Sets are extremely fast and larger sets will have no impact in your project. Except for the fact that storing of larger sets requires more physical memory.

Using Regular Expressions

Since embedding of Regex directly into our Pattern element is not allowed, for obvious reasons, we'll have to create a regular expression in a separate file, give the pattern a unique name and then use the Regex within a pattern element using the unique name we specified for our regular expression. To do so, under the Settings category, click on the Regular Expressions file and add the following SIML Code.

<Regex Name="number" Pattern="\b(\d+)\b" />

In the above code, we create a simple Regex element, then we specify a unique name for the Regular Expression using the Name attribute and inside the Pattern attribute, we write a simple Regex pattern for capturing integer numbers. Press Ctrl+S to save the code to file and move to our Hello Bot file and type the following SIML Code.

<Model>
  <Pattern>I AM @NUMBER YEARS OLD</Pattern>
  <Response>
    <Match /> years is good enough.</Response>
</Model>

The code above is self explanatory except for the part that instead of using a Square bracket like we did with Sets, we've used an @ symbol before the name of our regular expression and this is exactly how you can use a previously declared regular expression within your SIML Pattern.

To test the Code, press F5 ( to refresh the project ) and click on the Console tab and type "I am 26 years old" and the desired response will be generated.

Using Wildcards

There are a number of wildcards in SIML. These wildcards are like containers for words you wish to capture. Making it possible to use loose-patterns. Let me take you through an example.

There are 4 wildcard symbols in SIML:

  • % Matches zero or more words
  • _ Matches one or more words
  • $ Matches zero or more words but ranks lower than %
  • * Matches one or more words but ranks lower than _

One may ask as to why is it that 2 or more symbols for the same function exist in SIML. The simplest answer to that is a Pattern in SIML is stored within a Hybrid Graph Structure so that every pattern you write is actually stored in a tree-like-fashion. I won't go into that for now. But if you are still scratching your head over this, all I would advice is that over time, you will realize that sometimes we need to override existing patterns using higher ranking wildcards.

Now let's use 2 wildcards, one for zero or more words and the other for one or more words. Firstly, let's try the one or more words wildcard, the * symbol. Type the following SIML Code within your Hello Bot concept.

<Model>
  <Pattern>ARE YOU *</Pattern>
  <Response>I am not sure if I am <Match /></Response>
</Model>

Press F5 in Chatbot Studio and within the Console Tab, type "Are you a human"? The bot will reply "I am not sure if I am a human" and later type "are you", there will be no response. This is because the * wildcard matches "1" or more words and the input "are you" has no words left for the * symbol to match

Now let's try the zero or more words wildcard. To do so, type the following SIML code.

<Model>
  <Pattern>HOW ARE YOU $</Pattern>
  <Response>I am fine thank you!</Response>
</Model>

The $ symbol in the pattern makes sure that the Model is evaluated even if a word is not present in the place of the $ symbol in the user input. So press F5 and type "How are you my friend" or just "How are you?" and the response will always be the same.

Using Keywords as Pattern

Keywords based patterns, IMHO, are the layman's patterns. They consists of a collection of words that should exist in a user input for the underlying Response to be accepted. Say for example, you wish to respond to the user whenever and however he wrote the words "play music" .

<Model>
  <Pattern>{PLAY MUSIC}</Pattern>
  <Response>Playing music.</Response>
</Model>

In the above code (within the Pattern element), we specify 2 words "play" and "music" and enclose them within curly brackets. This tells the SIML interpreter that whenever the user submits a chat request that consists of the 2 words (play and music), the underlying response should be generated.

So if you type "play music" or "can you play music" or even "play some rock music for me", the response will always be "Playing Music". This tells us that if we use the keywords based patterns anything before, in between and after the specified keywords have absolutely no effect on our pattern.

  • Keyword based patterns should always be used as the last resort for pattern recognition.

Using JavaScript in Patterns and Responses

JavaScript can also be used as patterns inside the Pattern element and for generation of complex strings inside the Response element. The way it's done is that a JavaScript function is mentioned within the Pattern element and if the specified Js function, on evaluation, returns True then the Model gets activated. Similarly, JavaScripts within a Response element are evaluated by the JavaScript interpreter and the returned value is added to the response string.

Example Code to Use JavaScript Inside a Response Element

Select Scripts file under the Settings category and type in the following code:

<Script Type="JavaScript">
  function test(){return "Js string response";}
</Script>

The above JavaScript returns "Js string response" whenever the function, test(); is called. Now we'll have to move back to our Hello Bot file and type the following SIML Code.

<Model>
  <Pattern>TEST JAVASCRIPT</Pattern>
  <Response>
    <Js>test();</Js>
  </Response>
</Model>

Note that we have used a new <Js> element in our Response. This is to tell the SIML interpreter to treat the inner value of this element as a JavaScript. Type "Test JavaScript" and you will get the returned value from our JavaScript function as a string.

Scripts in SIML are for hardcore and experienced developers. So for now, I will leave it to the developers to experiment with this feature.

  • SIML Interpreter (Syn.Bot) has an in-built Js interpreter and therefore requires no external library to be referenced for your SIML Code to work.

Working with Bot and User Variables

Now that we have exercised with Patterns, it's time to learn about Variables in SIML. Every Chatbot you develop will certainly have some properties or attributes unique to the Bot. These properties can be set during the development phase and can be retrieved during a chat session.

Variables in SIML can either be single-valued or can be a collection of values. Here, we will see how we can Get and Set Bot related variables. For this, select the file Bot-Settings under the Settings category. You will see dozens of Bot variables declared by default under the <BotSettings> element. Scroll to the variable with the value for the Name attribute being "Name". This is the variable that assigns a name to your Bot. To get the name during runtime, let's try an SIML Code.

Inside the Hello Bot file, type

<Model>
  <Pattern>WHAT IS YOUR NAME</Pattern>
  <Response>My name is <Bot Get="NAME" /></Response>
</Model>

In the above code, we use the <Bot> tag to get the value of a previously stored Bot variable. To do so, we use the Get attribute and specify the name of the variable. The Bot element should always be used whenever you wish to work with Bot related variables.

Refresh the project and in the Console Tab, type "what is your name" and voila, the name of the Bot is extracted from the Bot Variable and is mentioned in the response.

Now to Set a variable, let's use an SIML Code.

<Model>
  <Pattern>CHANGE YOUR NAME TO *</Pattern>
  <Response>Alright my name is now <Bot Set="NAME"><Match /></Bot></Response>
</Model>

To set a variable for the Bot, we use the Set attribute and specify the name of the variable we wish to modify. The inner value of the <Bot> element is now used to set the value for the variable "name".

To test the above code, type "what is your name" in the Console Tab and after that type "Change your name to Juliet" and then try asking "what is your name" again. You will notice that the name of the Bot has now changed to Juliet but the content of the Bot-Settings file is left untouched.

Similarly, you can set or get a variable for the user using the <User> element and the Get/Set attributes.

For example, you can set the name of the user using the following SIML Code:

<Model>
  <Pattern>MY NAME IS *</Pattern>
  <Response>Alright I will remember your name 
  <User Set="NAME"><Match /></User></Response>
</Model>

Likewise, you can retrieve the user name using the Get attribute.

Normalizing User Input

Not every user who interacts with your Chatbot is going to be an English Professor. To combat some internet/sms slang and to filter out junk words, there is always the need of normalization.

Normalization consists of 2 easy-to-comprehend steps. The first is to split the user input by detecting some characters like the "dot" or "period" symbol in a sentence that indicates that the sentence has ended and the second step is to replace words and texts to their simplest recognizable forms.

Splitting the user input is the simplest form of normalization. This sort of normalization is performed over user input to detect multiple sentences and to generate separate responses for each sentence. Assume that the user types "How are you today. What are you upto". It would be more humanly to generate a response for both the sentences. This requires that we detach the 2 sentences and to do so, we make use of an SIML Splitter.

For simplicity, I recommend that you leave the Splitter intact if you are working with an English Chatbot Project. However, if you are curious enough, a Splitter is declared using a <Splitter> element and its children elements specify the character or word to detect for splitting the user input. A typical Splitter may look like the following:

<Splitter>
  <Text>.</Text>
  <Text>?</Text>
  <Text>!</Text>
  <Text>;</Text>
</Splitter>

In the above SIML code, a Splitter element is declared and within it multiple children <Text> elements are specified. These elements force the SIML interpreter to split the user input wherever the symbol . ? ! or ; is detected.

But can we split the sentence whenever we encounter a particular word ? Yes we can.

Let's see an example:

<Splitter>
  <Text>.</Text>
  <Text>?</Text>
  <Text>!</Text>
  <Text>;</Text>
  <Word>and</Word>
</Splitter>

Now according to our new Splitter setup, whenever the word and is encountered in the user input, the input will be split. So for example, if the user says "play music and make it loud", the user input will be split into 2 sentences "play music" and "make it loud" respectively. These 2 sentences will be processed separately and a combined output will be sent back to the user. Do note that the word and doesn't get included in the second sentence.

Apart from the <Word> element, there is one more element that you can make use of in a splitter for advanced regular expression based splitting of user input. But I cannot come up with any genuine example where you would actually want to do just that.

Anyways, if I were to replace the <Word> example above using a <Regex> element, I would do that using the following SIML code.

<Splitter>
  <Text>.</Text>
  <Text>?</Text>
  <Text>!</Text>
  <Text>;</Text>
  <Regex>\b(and)\b</Regex>
</Splitter>

The <Regex> element tells the interpreter to treat its inner value as a regular expression. This setup will split the user input at the position defined by the regular expression.

Coming to Filters...

SIML offers a lot of filtration techniques that target the user input and the Bot's own output. We will (in this tutorial) try to filter a word and convert it into its normalized form before passing it to the SIML interpreter. Click and select Normalizations under the Settings category. The normalization file must contain all of your, of course, normalizations like filters and splitters. Say that you wish to filter (transform) out the word "whats" to "what is".

Example SIML Filter Code
<Filter Value="what is">
  <Word>whats</Word>
</Filter>

The syntax for creating a Filter in SIML is not that hard to grasp. You use a <Filter> element within which you include children elements like <Word>, <Text> or <Regex> (each with its own behavior) and finally use the Value attribute to specify a replacement value.

Mapping User Input

Mapping in SIML transforms the specified text to a different value using a pre-defined Map. Maps are useful when you wish to change a piece of text to some other desired value at run-time. An example would be a pronoun substitution from 1st person to 2nd person. Let's say that the user types "I think you are awesome" or "I think I am awesome" and our desired response is supposed to be something like "Yes I am awesome" or "Yes you are awesome" respectively.

We'll go ahead and create a Map which we will call "2ndPerson" and use the Map within our SIML Model.

<Map Name="2ndPerson">
  <MapItem Content="you are" Value="i am" />
  <MapItem Content="i am" Value="you are" />
  <MapItem Content="you" Value="me" />
  <MapItem Content="me" Value="you" />
  <MapItem Content="your" Value="my" />
</Map>

As shown in the above SIML Code, declaring an SIML Map involves using a <Map> element with a Name attribute that gives our Map a unique identifier and then we create individual SIML MapItem(s). The Content attribute of these items specify the value you wish to change and the Value portion is self-explanatory.

To test our new Map, we'll create an SIML Model with a Pattern that will extract the desired portion from the user input which we will map to a different value in our Response.

Type the following SIML Code with the Hello Bot file.

<Model>
  <Pattern>I THINK * AWESOME</Pattern>
  <Response>Yes <Map Get="2ndPerson"><Match /></Map> awesome.</Response>
</Model>

Apparently, all we are doing here is capturing the value of the * wildcard and using a Map element within our response by specifying the name of the transformation we wish to perform on the extracted value. Now if you save and refresh the project, you can test the output of the bot for the input "I think you are awesome" which will be "yes I am awesome".

Random Responses

It's obvious that sometimes random responses maybe best suited for certain types of user inputs. In SIML, the <Random> tag is used to define a collection of random responses. The interpreter selects 1 item from the collection and sends it back to the user.

Let's peek at an example.

<Model>
  <Pattern>BYE</Pattern>
  <Response>
    <Random>
      <Item>See Ya</Item>
      <Item>Adios amigo!</Item>
      <Item>Talk to you later</Item>
      <Item>Nice talking to you.</Item>
    </Random>
  </Response>
</Model>

In the above example, all I did is that I added a <Random> element, within this element, I grouped together 4 <Item> elements, the values of which contain different ways of saying good bye.

Press F5 and type in the Console Bye repeatedly and you should be presented with random answers.

Predictive Responses

So now that we are accustomed with random responses, how about some random responses that try to match the output to user input. For this, we will have to add the following SIML Code into the Editor.

<Model>
  <Pattern>
    <Item>DO YOU LIKE CUPCAKES</Item>
    <Item>DO YOU LOVE CUPCAKES</Item>
    <Item>DO YOU WANT CUPCAKES</Item>
  </Pattern>
  <Response>
    <Phrase>
      <Item>I do like cupcakes</Item>
      <Item>Yes I love cupcakes</Item>
      <Item>I do want cupcakes</Item>
    </Phrase>
  </Response>
</Model>

Boy o boy, that is the largest SIML code we've confronted. Let me take you through this one. In the above SIML code, we have a Pattern with multiple choices and then there's our Response element which consists of a <Phrase> element with a number of <Item> elements.

A Phrase element is just like a<Random> element except for the fact that whenever the Model is evaluated (after any of the specified Pattern is matched), the output is going to match the user input.

Now if you type do you love cupcakes?, the answer from the bot would be Yes I love cupcakes and if you type do you want cupcakes? the answer would be I do want cupcakes.

  • Phrase elements should only be used with atomic patterns and responses. In many cases, if no concrete similarity with the user input is found, then the same answer gets repeated.

Previous Utterance - That's What She Said

A dialog based system requires that the previous utterance of the Bot is kept in check while processing the user input. Think of a scenario where you tell your computer to close a critical application and the bot is supposed to confirm the command.

<Model>
  <Pattern>Close Application</Pattern>
  <Response>Are you sure?</Response>
<Model>

<Model>
  <Pattern>YES</Pattern>
  <Previous>are you sure</Previous>
  <Response>Application closed</Response>
</Model>

Now if you type Close application, the bot will respond Are you sure? and if you say Yes, then the response will be application closed.

The scenario is made possible using the <Previous> element within the latter Model. The Previous element tells the interpreter that apart from the Pattern Yes the previous utterance of the Bot should be are you sure. And if and only if the previous output of the Bot was are you sure, the underlying Response is accepted.

Nested Modeling

Another thing about SIML, when I tried to figure out the actual meaning of a "Model", is that every Model can magically be nested inside another Model and doing so has some behavioral impact on how your code is interpreted by the Syn.Bot class library. I will use the above example here to show how you can reduce redundancy by using the nested Modeling technique.

The above SIML code can be re-written using nested modeling as..

<Model>
  <Pattern>CLOSE APPLICATION</Pattern>
  <Response>Are you sure?</Response>
  
  <Model>
	<Pattern>Yes</Pattern>
	<Response>Application closed.</Response>
  </Model>

  <Model>
	<Pattern>No</Pattern>
	<Response>Application shut-down cancelled.</Response>
  </Model>
</Model>

The code above is self-explanatory or maybe not. What I did in the above SIML code is that I added a Model within another Model, i.e., I nested them. So now if the user says "Close application", the bot will reply "Are you sure?" and if the user says "no", then the output will be "Application shut-down cancelled". Note that I didn't use any <Previous> element this time and for obvious reasons because nested Models behave as if they are linked by some hidden <Previous> element. The only caveat with this technique, I noticed, is that your code slightly loses its readability but it's sort of a tradeoff to avoid redundancy.

Random Answers and Previous Utterances

One strange question (that I asked myself) when I used the first technique of addressing the previous utterance of the Bot, in a dialog based scenario, was that What if the previous utterance involved a random answer? Will I have to write a Model for every item in the Random response. If that would have been the case, then I would be better off counting stars in the sky. Fortunately, there is the God-gifted <Label> element.

A <Label> element overrides the string value of the Previous element for the Model with a unique value which can later be referenced inside the <Previous> element of any succeeding Model.

Boy! I don't think I can further explain what I just wrote but maybe an example would help.

<Model>
  <Pattern>RESTART COMPUTER</Pattern>
  <Response>
    <Random>
      <Item>Are you sure Sir?</Item>
      <Item>Shall I restart the Computer now?</Item>
      <Item>Say yes if you wish to restart your computer now.</Item>
      <Item>Please confirm that you intend to restart your computer</Item>
    </Random>
    <Label>computer-restart:</Label>
  </Response>
</Model>

<Model>
  <Pattern>Yes</Pattern>
  <Previous>computer-restart:</Previous>
  <Response>Restarting computer. Please Standby..</Response>
</Model>

Let me scratch your head for you! It's simple to understand from the code above that since I used a random response in the former Model I can no longer assume what the actual output would be at run-time. So instead of writing multiple Models for every item in my random response, I added a <Label> to the response. This Label ensures that I can reference any response by the Model using a unique label, i.e., "computer-restart:". And voila, I have saved myself from bloating my code.

  • When creating labels, try to separate individual words using the hyphen symbol and end your label with a colon.
  • Avoid ambiguous labels and make sure your label speaks for itself.

Mathematical Expressions

I can hardly imagine writing a textual pattern for every possible mathematical expression out there just to amuse the user. This is where the <Math> tag comes in handy as it provides a set of useful functionalities found typically in modern day calculators.

Say you want to evaluate a mathematical expression. Example "What is the sine of 1".

<Model>
  <Pattern>what is the sine of *</Pattern>
  <Response>It's <Math Get="sin"><Match /></Math></Response>
</Model>

To achieve what I just mentioned, all we got to do is use a <Math> element and in the Get attribute, specify the math function we wish to call. SIML's Math element has a lot of in-built functions like sin, cos, acos, tan, tanh, pi, random, floor and so on. You'll have to refer the specification for more information on this. Links of which have been provided below.

Another great news about the <Math> element is that it acts much like a Mathematical Expression Evaluator when the Get attribute is skipped.

<Model>
  <Pattern>CALCULATE *</Pattern>
  <Response>The answer is <Math><Match /></Math></Response>
</Model>

In the above code, I have used the <Match/> element to extract the value of the * wildcard and specified it as a value for the <Math> element.

So now if you Press F5 and type Calculate 1+2+7 in the console, the bot will respond The answer is 10 or if you type calculate sin(1), the bot will respond The answer is 0.841470984807897.

Textual Manipulation

At some point, you would definitely be required to manipulate a corpora of text. For instance, changing text to upper or lower case or even splitting the text into properly spaced characters.

To accomplish such text related tasks, there is the <Text> element that can be used within our Response element. Do remember that the Text element you use within Splitters and Filters behave entirely different from the one that is used within a <Response> element.

Example:

<Model>
  <Pattern>CHANGE * TO UPPERCASE</Pattern>
  <Response><Text Get="Uppercase"><Match /></Text></Response>
</Model>

So now, if you type Change this to uppercase, the response would be THIS. Likewise there's the Lowercase, Titlecase, Explode, Join, Sentence, Length, WordCount, and so on.

Say for example, you want to find the number of letters in a word. The following SIML code would suffice.

<Model>
  <Pattern>HOW MANY LETTERS ARE THERE IN THE WORD *</Pattern>
  <Response>There are <Text Get="Length"><Match /></Text> letters in the word <Match /></Response>
</Model>

Now if you ask how many letters are there in the word Bacon, the response will be There are 5 letters in the word bacon.

Date and Time

Your users can take your bot by surprise by asking date and time related questions. For both date and time retrieval, SIML offers the <Date> element. The Get attribute of this element is used to retrieve a particular date and time related value. Say for instance, a user asks "what day is it?" or "what year is it?". Though JavaScript may be suited for this, I recommended that you stick with the SIML's in-built elements because they have been heavily optimized for such tasks (atleast that is what the specification tells us).

Example SIML code for retrieving the day of the week:

<Model>
  <Pattern>WHAT DAY IS IT</Pattern>
  <Response>It's <Date Get="weekday" /></Response>
</Model>

Example SIML code for retrieving the year:

<Model>
  <Pattern>WHAT YEAR IS IT</Pattern>
  <Response>It's <Date Get="year" /></Response>
</Model>

Some acceptable values for the Get attribute within a Date element are:

  • weekday
  • month
  • year
  • hour
  • minute
  • second
  • meridiem
  • timezone
  • time
  • format

Another value for the Get attribute (my personal favorite) is format. As I went through the specification, it became apparent that it acts like the C# Date.ToString("format") function. For example, in C#, the custom format specifier "dddd" gives you the day of the week.

So a pretty easy example would be..

<Model>
  <Pattern>WHAT ERA IS IT</Pattern>
  <Response>It's <Date Format="gg"/></Response>
</Model>

Which according to .NET Custom Date and Time Format Strings returns the era or the period. If we were to test the above example by saying "what era is it?", the answer would be "It's A.D".

EmotionML - Emotions in your Chatbot

Emotions in SIML are created using the W3C standard Emotion Markup Language. I recommend that you go through the EmotionML specification by W3C before even trying to work with it in SIML.

But... Click on the EmotionML item under the Settings category. It's under this file that all EmotionML's emotions are created. SIML requires that you use the Siml namespace and give every detailed emotion a unique identifier so that you can later use the emotion in your SIML Project or most importantly inside your SIML Model.

These emotions are actually meant for hardcore developers to simulate genuine humanly expressions either through a 3D avatar or via voice synthesis. Going into EmotionML is beyond the scope of this tutorial but I will definitely try to expand this section later on.

Exporting to SIML Package

Alright, now that we have gone though some SIML basics (yes, they were still the basics), we'll export our first knowledge base package. Click on Project->Export to Package. Name your package "Knowledge" and save it within the Bin directory (found within the Debug or Release folder) of your C# WPF project and close the studio.

Back to Our C# Application (Phew!)

We did get caught up with the SIML basics but now for the final touch. Replace the MainWindow.xaml.cs code with the following:

using System.IO;
using System.Windows;
using Syn.Bot;

namespace SIML_Chatbot_Demo
{
    public partial class MainWindow
    {
        public SynBot Chatbot;
        public MainWindow()
        {
            InitializeComponent();
            Chatbot = new SynBot();
            Chatbot.PackageManager.LoadFromString(File.ReadAllText("Knowledge.simlpk"));
        }

        private void SendButton_OnClick(object sender, RoutedEventArgs e)
        {
            var result = Chatbot.Chat(InputBox.Text);
            OutputBox.Text = string.Format("User: {0}\nBot: {1}\n{2}", 
                                            InputBox.Text, result.BotMessage, OutputBox.Text);
            InputBox.Text = string.Empty;
        }
    }
}

Time to run the WPF C# application, so press Start (in Visual Studio) and you should be presented with a Window that looks something like the following image:

Try some of the SIML code you just wrote like What is your name or How are you? and the desired response will be presented to you.

Resources

History

  • Monday, 19th of January 2015 - Initial release
  • Wednesday, 21st of January 2015 - Added the following topics (updated project files accordingly)
    • Date and Time (above EmotionML)
    • Nested Modeling (under Previous Utterance)
    • Labels (under Previous Utterance)
    • <Word> and <Regex> (under Normalization)
  • Monday, 9th of October 2017 - Minor edit

Points of Interest

Though I've covered only a small portion of SIML in this tutorial, there's a lot to learn but what you've learnt so far should be sufficient enough to get you started with your Chatbot venture. The SIML specification has dozens of functional elements that one can make use of throughout development and therefore if at some point you feel lost, you know exactly where to look. Also, on a side note, SIML 2.0 specification (with Machine Learning features) has been released.

If you are hungry for more, you may refer the next article - Part 2.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here