Index - abcaccount2015/Main GitHub Wiki
SuperScript is a dialog system + bot engine for creating human-like conversation chat bots. It exposes an expressive script for crafting dialogue and features text-expansion using WordNet and information retrieval and extraction using ConceptNet.
- Dialog engine
- Multi-user platform for easy intergration with group chat systems
- Message pipeline with POS tagging, sentence analysys and question tagging
- Extensible plugin architecture
- A built in graph database using LevelDB and each user has their own SubLevelDB.
- ConceptNet, a feneral purpose database for knowledge extraction.
- WordNet, a database for word and concept expansion.
The message pipeline contains many steps, and varies from other implementations. When input comes into the system we convert the input into a message object. The message object contains multiple permutations of the original object and has been analyzed for parts of speech and question classification. The message is first handled by the reasoning system, before being sent to the dialog engine for processing.
## Terminology
- Topic: the main entry point into your application. All your conversations start within a topic depending on what exactly was said the first topic could vary. SuperScript will continue to search topics until it finds a matching gambit, then replies. A topic includes one or more gambits, and each gambit includes at least one reply.
- Gambit: a set of rules that tells the bot how to reply to a specific user action. In SuperScript, the gambit includes two parts: the input (the basis of the trigger that we match on) and one or more replies that the bot offers, either randomly or under specific conditions.
- Trigger: a rule that analyzes the user input and tries to match specific conditions.
- Input: the message sent by the user to the bot.
- Reply: a specific reply given by the bot under certain conditions, and is part of a gambit. A reply can also have a series of gambits attached to them thus creating a thread of conversation.
## Triggers
Triggers form the basis of all chat conversation and create a regular expression to match input on. In SuperScript, triggers are identified by +
in front of them, and replies by -
. The example below is a simple gambit and includes a trigger and a reply:
+ hello bot
- Hello, human!
If the user input is hello bot, the system will reply with Hello, human!.
Triggers are cleaned and normalized prior to being exposed to the engine. Extra whitespaces and punctuation are removed, as well matches are always case insensitive. The following rules are all identical.
+ hello bot
+ HELLO BOT
+ Hello, bot
+ hello BOT!
Inputs are processed by the system to make them easy to understand for a bot:
- cleaning and normalization
- spelling corrections for common spelling errors (or British spelling)
- idiom conversion
- junk word removal
- abbreviation expansion and more.
Examples:
- It’s a nice day becomes it is a nice day.
- Greetings such as hi, hello, hola, yo, hey become ~emohello.
Warning: normalization might remove some words from the input (like “really?” or “quite”), which might make rule triggering awkward sometimes.
Also, inputs coming into the system are burst into separate message objects and handled separately. Multiple phrases are broken based on ending punctuation AND commas following WH words. The reply of each gambit is concatenated back together to form the final message returned by the bot.
+ my name is john
- Hi John!
+ what is your name
- My name is Ava.
- An input like My name is John, what's your name? is split into two separate inputs and normalized: my name is john and what is your name. Then the bot looks for matches for both inputs, and then concatenates the replies, before replying to the user with Hi John! My name is Ava.
We use wildcards to allow for more natural and expressive rules. A wildcard will match one or more characters, words or tokens. Depending on the type of wildcard, the input may or may NOT be captured or saved by the system.
Will match zero to unlimited characters, words or tokens. The input is NOT captured or saved by the system.
+ * hello *
- That is crazy.
- Matches The dog said hello to the cat.
- Matches Hello world.
- Matches While hello.
If you want to only allow a few words though, you might consider using a variable length wildcard. The syntax for variable length wildcards is *~n
, where n
is the maximum number of words you want to let through.
+ hello *~2
- That is crazy!
- Matches Hello!
- Matches Hello John!
- Matches Hello John Doe
- Does not match Hello John George Doe
Variable length wildcards are great for capturing input where an adjective might be slipped in before a noun.
If you know exactly how many words you want to accept, but don't want to list what the words are, then an exact length wildcard might be what you're after.
The syntax is ***n **, where n is the exact number of words you want to let through.
+ hello *2
The above will now match Hello John Doe but fail to match hello or hello John. The wildcards will be captured by the system and can be used in replies.
+ hello *(2-4)
These are useful if you want to capture, let’s say, at least 2 words but no more than four words. The syntax is ** *(min-max) **. The above example will match hello John Doe, hello John and Mary Doe, but will fail to match hello John or hello John, Joe and Mary Doe.
If you use ** *(n) **, this is the equivalent of ** *n ** (exact length wildcards). The wildcards are captured by the system and can be used in replies.
Alternates are used when you have a range of words that could fit into the rule, but one is required.
+ I go by (bus|train|car)
The above will match I go by bus, I go by train or I go by car. The alternate in the input is captured by the system and can be used in replies.
Optionals can be used to add an extra optional word:
+ my [big] red balloon [is awesome]
The above will match all these inputs:
- my red balloon
- my big red balloon
- my red balloon is awesome
- my big red balloon is awesome
Optionals are not captured by the system.
WordNet is a database of words and ontology including hypernym, synonyms and lots of other neat relationships between words. SuperScript is using the raw WordNet library, as well it has expanded it to include fact tuples and provide even more relationships, through its scripted fact graph database. These terms are expanded by using a tilde ~ before the word you want to expand.
+ I ~like ~sport
This example will match any of these:
- I like hockey
- I love baseball
- I care for soccer
- I prefer lacrosse
When input comes into the system, we tag it and analyze it to help make sense of what is being said. SuperScript has a few tagged keywords you can use in triggers. These tags can also have a numeric value attached to them to get even more specific
<noun>, <nounN>, <nouns>
<adjective>, <adjectiveN>, <adjectives>
<verb>, <verbN>, <verbs>
<adverb>, <adverbN>, <adverbs>
<pronoun>, <pronounN> <pronouns>
<name>, <nameN>, <names>
+ <name1> is [more|less] <adjectives> than <name2>
will match Tom is taller than Mary or John is less disciplined than Jack.
Note that pronouns are a subclass of nouns, so “I”, “you”, “her” will match both <noun>
and <pronoun>
.
For an input like I’m an engineer, the system will normalize it to ** I am an engineer** then tag it:
taggedWords:
[ [ 'I', 'NN' ],
[ 'am', 'VBP' ],
[ 'an', 'DT' ],
[ 'engineer', 'NN' ],
The only matches the first noun in the lookup, where matches all nouns, therefore
- I am a will match **I am a I **
- I am a Will match I am a I or** I am an engineer**
- I am a Will match I am a cow or I am an engineer
We can identify questions (with or without the ending question mark) in the input, so you can create specific rules (by using ? to begin your trigger pattern in SuperScript, or selecting from the droplist in the editor.
+ Will you do * | All question types ▾
- Hmmm, let me get back to you on that.
SuperScript can go one step further and disseminate between different question types:
- Question word (who, what, where, when, why).
- Choice questions (this or that)
- Yes/No questions
- Tag questions (He is bald, isn’t he?)
Examples
+ *store | Question word ▾
matches Who went to the store? and also Why did you go to the store? but will fail to match Is this your store?
+ Is your car * | Choice question ▾
matches Is your car green or blue? but will fail to match Is your car green?
We can also match based on the type of input. In the future, we may look at other types of classification that follow more linguistic types like speech acts (http://www.wikiwand.com/en/Speech_act) and adjacency pairs.
SuperScript supports 8 broad categories and over 40 sub-categories with 80% accuracy:
**ABBR abbreviation**
abb abbreviation
exp expression abbreviated
**ENTY entities**
animal animals
body organs of body
color colors
creative inventions, books and other creative pieces
currency currency names
event events
food food
instrument musical instrument
lang languages
letter letters like a-z
other other entities
plant plants
product products
religion religions
sport sports
substance elements and substances
symbol symbols and signs
technique techniques and methods
term equivalent terms
vehicle vehicles
word words with a special property
**DESC description and abstract concepts**
def definition of sth.
desc description of sth.
manner manner of an action
reason reasons
**HUM human beings**
group a group or organization of persons
ind an individual
title title of a person
desc description of a person
**LOC locations**
city cities
country countries
mountain mountains
other other locations
state states
**NUM numeric values**
code postcodes, phone number or other codes
count number of sth.
expression numeric mathematical expression
date dates
distance linear measures
money prices
order ranks
other other numbers
period the lasting time of sth.
percent fractions
speed speed
temp temperature
size size, area and volume
weight weight
Here are some examples:
+ * phone * |?:NUM:code ▾
will match My phone is 415-315 9862.
Input types are different from concepts or parts of speech because they are made up of more than one word. LOC, for example, usually starts with “Where” then drills into a region or other complementary word.
For conversation to really flow you need to have more than one exchange. can recall the previous thing said and continue to build off of that:
+ *
- What is your favorite color? ```
+ *1
- This is my favorite color, too!
```
In SuperScript syntax, it looks like this:
+ *
- What is your favorite color?
+ *1
% What is your favorite color?
- This is my favorite color, too!
Let's walk though this example. Some input comes into the system and the open wildcard matches and replies with What is your favorite color?. When the next input comes into the system, we first check the history and see if the previous reply has more dialogue. This is noted by the % What is your favorite color? line in SuperScript. We pull the next trigger, in this case it is *1 meaning one word. The bot then replies with This is my favorite color, too!.
In conversations like this, we always try to match forward, but once there is no more matches we don't walk back up the tree, we reset back to the Random Topic. Also, * in conversation threads have the same weight as topic level * wildcards.
We have seen examples of replies in some of the above examples. Replies appear exactly as they are written–grammar, mistakes and all.
+ Hello *
- Hi, good to see you!
If you write more replies, the system will choose a random one, deliver it to the user and then discard it, so it is never used again. If the user asks the same question again, he will be delivered one of the remaining answers and that answer is discarded, too, and the process repeats until there are no more answers. So it is a good idea to have a few replies for every trigger. This will also keep your dialogue less robotic and more natural.
+ Hello *
- Hi, good to see you!
- Hey, welcome back!
- Hello to you too!
If we don’t want an answer to be discarded from a set of replies, we can add {keep} in front of it. This is especially useful in conversations, or to make sure the user gets a reply anytime.
+ Hello *
- {keep} Hi, good to see you!
- Hey, welcome back!
- Hello to you too!
Longer replies can be split on more lines manually, in the SuperScript editor reply text area (or by using \n in SuperScript):
+ Hello *
- Hi, good to see you!
- How are you today?
You can use alternates in replies, same as in inputs:
- Hi, (good|great) to see you!
will reply with Hi, good to see you! or Hi, great to see you!. This allows you to be more diverse in replies, without writing separate replies.
Sometimes you want to return the result of what was said back to the user in the reply. This is easily done by using the <cap>
tag in replies.
+ my name is *2
- Nice to meet you, <cap>!
In the above example, the input My name is John Doe will trigger a reply Nice to meet you, John Doe!
If you have more than one thing you want to capture, just add a number to the <cap>
:
+ *1 is taller than *2
- Are you sure that <cap1> is taller than <cap2>?
- Generic wildcards and optionals are not captured.
- Variable length, precise length, min-max wildcards, alternates, wordnet keywords and parts of speech are captured.
Sometimes you want to reuse the same reply/set of replies in more than one gambit. Instead of duplicating, you can define this set of replies in a new gambit, then redirect to it (we use double underscore to delimit it rather to avoid confusing it with regular gambits, it’s not a technical requirement):
+ hello my friend
- {@__greeting__} How are you today?
+ __greeting__
- Hi there!
- Hello to you too!
- Howdy!
will match Hello my friend! and reply with one of these three replies:
- Hi there! How are you today?
- Hello to you too! How are you today?
- Howdy! How are you today?
Unlike regular replies, these are truly random (not a random sequence), meaning you can get the same reply even three times in a row. When using a redirect, it should be a NxM random combination, providing each N has a redirect to M.
This is where things get interesting. Replies can execute a custom function where they have access to the entire message object, the user object and other resources like the fact databases. You can also pass parameters to the functions from captured input parts.
+ * weather in <name>?
- ^getWeather(<cap1>)
Functions are imported from the plugin folder at load time and are async Node.js functions.
exports.getWeather = function(city, cb) {
cb(null, "It is probably sunny in " + city);
}
You can have more than one function in a reply, so this is also valid:
+ It is ^callFunction1() and ^callFunction2()
The results of the callback will replace the function name. You can even nest functions within callback replies, so this is valid too.
+ ^nestedAFunction()
exports.nestedAFunction = function(cb) {
cb(null, "We ^nestedBFunction()");
}
exports.nestedBFunction = function(cb) {
cb(null, "are done");
}
The final reply will be We are done. The above example is contrived, remember you can also require the module and call the function directly from within the plugin code. This is also true for other NPM modules.
Custom functions are called in their own scope. This is done to give you control over most of the important bits of the system.
this.message
We expose the entire message object which is broken down 12 different ways and includes all the words in raw and lemma form, all the parts-of-speech and even compound 'things' like entities and dates.
this.user
The user who sent the message as we know them. This will allow us to see the past messages in their history, how many conversation replies we have had, and when the conversation started.
We also have direct access to the user’s memory.
this.user.memory
this.user.memory.db
Also, the entire message and reply history from the user (an array of past utterances and replies can accessed using
this.user.__history__
From the user memory you can query a sub-level graph DB for known facts the user may have shared or save new ones.
this.botfacts
this.botfacts.db
This is identical to the sub-level graph for the user except it contains only things about the bot and can be loaded on init.
this.facts
this.facts.db
This is similar to the users sub-level graph except it contains all the global facts.
this.topicSystem
We expose the topic system to the plugins in case you want to create a new topic reply or trigger dynamically.
Because you are in the fun wild world of Node.js you can also install any library from NPM and use it, and since the plugs are async, you can even make calls to Databases, API's or other remote web services.
There will be an entire doc on custom functions, but for now, explore this inside the plugins and review the test suite to get a better picture of some of the things possible.
These functions are shipped with SuperScript:
- ^getWeather(location) will do this
- time.js plugin has these functions for today’s date:
-
- ^getSeason() returns season (spring, summer, fall, winter)
-
- ^getDate() returns date (3, January 2015)
-
- ^getDateTomorrow() returns tommorrow's date (4, January 2015)
-
- ^getTime() returns "The time is 9:00"
-
- ^getTimeOfDay() returns "morning", "afternoon" or "night"
-
- ^getDayOfWeek() returns day of week (Monday, Tuesday)
-
- ^getMonth() returns month (January)
- math.js plugin allows performing math functions
-
- ^evaluateExpression(parameter) returns "I think it is (answer)" or "What do I look like, a computer?" if not valid.
-
- ^numToRoman(parameter) returns "I think it is (the roman number)"
-
- ^numToHex(parameter) returns "I think it is (hex equivalent)"
-
- ^numToBinary(parameter) returns "I think it is (binary equivalent)"
-
- ^numMissing(parameters) returns "I think it is (number)" for a trigger like "what number is missing from 1, 3, 5, 7"
-
- ^numSequence(parameters) returns "I think it is N" to find a number missing from an arithmetic or geometric sequence
Filters are used to filter out replies or triggers from being used. They are like using conditional logic in your app, and are actually functions (plugins) which return a TRUE or FALSE value. In the SuperScript Editor, filters have their own text box with an auto complete.
+ i am *1
- Yes, you are <cap>. | ^functionX(true)
- You’re lying, you’re not <cap>! | ^functionX(false)
In this example the ^function() is evaluated when we are making the decision to pick a reply. Lets see a real example based on one of the Loebner questions.
+ my name is <name>
- ^save(name,<cap1>)Nice to meet you, <cap1>! | ^hasName(false)
- I know, you already told me your name! | ^hasName(true)
^hasName checks to see if we know the user’s name, and if we don’t, (false) then we save the name using the ^save function, then say Nice to meet you, Name!. Then when we hit this trigger again, ^hasName(true) will be filtered in, and reply with a cheeky remark, I know, you already told me your name!.
Filter functions are not just for replies, and they can be applied to triggers too:
+ I like * | ^not(fish)
- I like <cap1>, too!
The syntax is identical to filters in replies, this function ^not(fish) will return false if the message contains the word fish.
We can pass extra metadata back to the client, using a specific function, ^addMessageProp(key,value). The reply object can have extra properties added on from any reply.
+ can you (text/sms) me the name of the place
- ^addMessageProp(medium,txt) The Canteen | ^hasNumber(true)
- Can I have your phone number, please? | ^hasNumber(false)
In the above example, if the user asks Can you text me the name of the place?, the system will check if the system has the user’s phone number (using the ^hasNumber filter).
- If the user has a phone number, the generated reply object looks like this:
{
string: "34345 Old Yale Rd.",
medium: "txt",
createdAt: "..."
}
And is sent to user’s mobile phone number as text (if the system has this defined).
- If the user does not have a phone number, the reply will be Can I have your phone number, please?
The function can be used from any reply, or you can augment the message props variable directly from within any custom function:
this.message.props['key'] = value;
Another example can be found here, and returns the color as a HEX RGB value, updating the page background color. You can think of this channel as anything non-text or non-verbal (perhaps an avatar emoji or something else to represent mood etc.).
Another frequent case can be injecting HTML content in the reply:
+ show * car
- Here’s my car: ^addMessageProp(img,http://www.exoticspotter.com/images/19/18281.jpg)
Rendering these props should be addressed by the client layer (web interface, mobile app, SMS etc.)
A topic is way to group triggers and replies together in some arbitrary, or logical way. There are no limit to how many topics you create. SuperScript will continue to try to find matches for your input outside of your current topic.
All dialogue belongs to a topic and even if you do not select any topics, those triggers and replies will be stored in the random topic.
You can create new topics using the editor, and the topic has these properties:
- topic name (unique, no spaces)
- keywords (optional) help with the topic flow
- system flag (explained later)
- keep flag (explained later)
Unlike in RiveScript, in SuperScript topics cannot be nested.
A topic can include any number of gambits, and the system will try to match them in order. You can sort the gambits in the editor automatically (the greediest trigger will be sorted last), or by drag & drop:
In SuperScript syntax, the default sorting can be overridden by using {weight=XX} in the input (note that this is different from Rivescript, where weight is used in replies):
+ * {weight=100}
- Hello there
+ hello * {weight=90}
- Who are you?
In the above example, Hello John will be matched by the first rule, because of the weighting.
To switch to a new topic, you can use {topic=topic_name} in the reply:
+ I like animals
- Me too! {topic=animals}
If you are in a custom plugin you can also change topics directly by accessing the user object method setTopic(...).
exports.somefunction = function(cb) {
this.user.setTopic("newTopic")
cb(null, "")
}
Topic changing only sets the recommended next topic on the next reply but does not guarantee a match. You could also get false positive matches out of context. When the user quits the conversation, the last topic he was in is saved, so next time the user logins, he starts in the same topic.
Everytime the system tries to match an input, there are two special topics that run, one before your current topic, and one after. We call them pre and post hooks or topics. If you need some trigger to be tested on every pass either before or after the regular triggers, this is where you would put it. Pre and Post topics have a slightly different behavior, but function the same as normal topics.
Topics can have a flag attached to them that modifies its behaviour. keep, system and nostay.
Keep is designed to disable to default behavior of exhausting triggers, if you want the bot to say things over and over again, and apply keep just after the topic definition.
System topics do not appear in the normal topic flow and you must provide your own way to access them, usually the ^respond(topic_name) function works great for that.
Nostay can be used to bounce from one topic, but return back to the previous topic right after. It might be a good way to break the flow up and allow the possibility to change the topic, but not do so forcefully.
As noted earlier, the topic logic has improved to allow for easier scripting, and your bot should have access to more gambits. It is important that your topics have well defined keywords, this will help when trying to figure out what topic to check next.
The basic flow for each message cycle is as follows (keep in mind that system topics will never appear in the normal flow):
- Pre topic
- Current topic
- Next best matched topic(s)
- Any remaining topics
- Post topic
You can match more than once. Providing your match does not produce any output, the system will keep looking for matches. This is extra helpful when you have plugins or functions that try to do extra parsing on the message or make assumptions that may be false. Note that the goal of SuperScript is to create human-like chatbots, and this is why the topic flow is not as deterministic as RiveScript or Hubot. The lack of keep and arbitrary feeling rules for picking or switching topics makes creating deterministic bots more difficult, but it is better for simulating how real people act (“Hey, I got bored and changed the topic to something else, maybe”).
^respond() The ^respond(topic_name) function is used in the reply it takes the current input and check it against the selected topic more matches. Once it gets to the end of the topic it will unwind its way back and continue checking in the normal path.
**Topic: random**
+ * i *
- ^respond(i_topic)
+ * you *
- ^respond(you_topic)
**Topic: i_topic**
+ i am not *
- No, you aren’t!
+ i am *1
- Yes, you are!
**Topic: you_topic**
+ you are not *
- No, I am not!
+ you are *1
- Yes, I am!
When the user says I am not a robot! the system will match it with the *** i *** rule and look first for a reply in gambits in i_topic.
^topicRedirect(topic_name,trigger)
^topicRedirect(topic,trigger) is used in the reply and is very similar to reply redirects except they redirect you to a reply in a specific topic.
**Topic: random**
+ say something random
- ^topicRedirect(something_random,__say__)
**Topic: something_random**
+ __say__
- Wind on the face is not good for you.
- I watched Mr. Dressup as a kid.
This introduces a new element called facts. Facts are triples aiming to provide common knowledge to your bot. They can be also used in generating part of a reply, by replacing a word in the reply.
+ I like ~sport
- Really? Wow, I like ~sport, too!
In this example ~sport is expanded in both the gambit and reply, and resolved to a sport defined either in wordnet or the fact DB. (For more technical details see sfacts).
Conceptnet is used differently than facts, and can provided actual replies. This lays in plugins at the moment (reason.js). This can be used to to address questions like What is a X? and What is X used for? or Where would I put a X?. It can also be used to resolve information too, like What color is the sky?.
This is general shared or common knowledge. Needs documentation
This table represents things the bot knows about itself. Needs documentation
This table is filled by though conversation and using ^save(key,value) and ^createUserFact(s,p,o) Needs documentation.
SuperScript is quite different from other chatbot scripts, despite being inspired by RiveScript and Chatscript
- SuperScript is JavaScript only and runs only on Node.js
- It is Asynchronous top to bottom
- It has handles input differently, the input is converted into a message Object and processed a little differently. The message object contains various other things like parts of speech and words broken down by nouns, adverbs etc.
- The system is well tested
- The parsing is broken out into a completely separate step to speed up boot time and allow for other systems to plugin.
- wildcards are not captured
- added variable and exact length wildcards (from chatscript)
- triggers will try to match both raw input and lemmatized input (like chatscript)
- topics have flags for keeping gambits
- replies are exhausted by default but can be kept with a keep flag.
- Wordnet and concept expansion is built in.
Learning has been reimagined as well. The system supports fact triples, and their is a global database as well as a per user memory. The best place to see some examples of the scripting and how the features work is in the tests.
Making sure everything is working can be time consuming and frustrating. Start with the basics, check for warnings and error messages. All of SuperScript uses debug and should make finding the problem much easier.
$ DEBUG=*,-Utils node_modules/superscript/bin/parse.js
This says, lets see everything except things from the Util library. During the parse setup, we will load Normalizer, Parse each line, then sort the results prior to saving them.
Once you are confident all files, have been properly parsed you will have a data.json file. Or some other file if you choose to output to a different name.
Make sure the file is not empty, null or incomplete. It should have a few sections and each trigger you entered will be in their along with extra metadata.
Start the bot in debug mode.
$ DEBUG=*,-Utils node server.js
Assuming you copied over the telnet server example. Here is output from my example bot Brit.
DEBUG=*,-Utils node server.js
Script Loading Plugin +0ms ./plugins oppisite
Script Loading Plugin +3ms ./plugins rhymes
Script Loading Plugin +0ms ./plugins syllable
Script Loading Plugin +0ms ./plugins letterLookup
Script Loading Plugin +0ms ./plugins wordLength
Script Loading Plugin +0ms ./plugins nextNumber
Script Loading Plugin +1ms ./plugins createFact
Script Loading Plugin +0ms ./plugins resolveAdjective
Script Loading Plugin +0ms ./plugins evaluateExpression
Script Loading Plugin +0ms ./plugins numToRoman
Script Loading Plugin +0ms ./plugins numToHex
Script Loading Plugin +0ms ./plugins numToBinary
Script Loading Plugin +0ms ./plugins numMissing
Script Loading Plugin +0ms ./plugins numSequence
Script Loading Plugin +0ms ./plugins num
Script Loading Plugin +0ms ./plugins changetopic
Script Loading Plugin +0ms ./plugins changefunctionreply
Script Loading Plugin +0ms ./plugins getDOW
Script Loading Plugin +0ms ./plugins getDate
Script Loading Plugin +0ms ./plugins getDateTomorrow
Script Loading Plugin +0ms ./plugins getSeason
Script Loading Plugin +0ms ./plugins getTime
Script Loading Plugin +0ms ./plugins getTimeOfDay
Script Loading Plugin +0ms ./plugins getDayOfWeek
Script Loading Plugin +0ms ./plugins getMonth
Script Loading Plugin +0ms ./plugins save
Script Loading Plugin +0ms ./plugins wordnetDefine
Script Loading Plugin +0ms ./plugins plural
Script Loading Plugin +224ms /Users/robellis/projects/bot/brit/plugins aGender
Script Loading Plugin +0ms /Users/robellis/projects/bot/brit/plugins aBaby
Script Loading Plugin +0ms /Users/robellis/projects/bot/brit/plugins aLocation
Script Loading Plugin +0ms /Users/robellis/projects/bot/brit/plugins aGroup
Script Loading Plugin +0ms /Users/robellis/projects/bot/brit/plugins weather
Normalizer Loaded File +0ms { key: '_sys', file: 'systemessentials.txt' }
Normalizer Loaded File +4ms { key: '_extra', file: 'substitutes.txt' }
Normalizer Loaded File +116ms { key: '_contractions', file: 'contractions.txt' }
Normalizer Loaded File +14ms { key: '_interjections', file: 'interjections.txt' }
Normalizer Loaded File +65ms { key: '_britsh', file: 'british.txt' }
Normalizer Loaded File +198ms { key: '_spellfix', file: 'spellfix.txt' }
Normalizer Loaded File +314ms { key: '_texting', file: 'texting.txt' }
Normalizer Done Reading Subs +7ms
Normalizer Done Loading files +1ms
Script Questions Loaded +751ms
Script System Loaded, waiting for replies +0ms
TCP server running on port 2000.
This walks through the entire initialization process, showing various plugins loaded and is waiting to start chatting. Once I open a telnet connection, we get much more output.
The message will walk through every piece of the framework showing how it gets to the final output. Usually the most important part of this process is to see what the message object looks like given your input, and how GetReply tries to match it with a given trigger.
GetReply Searching their topic 'random' for a match... +2ms
GetReply itorTopic +0ms __pre__
GetReply itorTopic +0ms random
GetReply Try to match 'test' against 9b9265b ((?:.*?)) +1ms
GetReply Try to match 'test' against 9b9265b ((?:.*?)) +0ms
GetReply Found a match! +0ms
GetReply Match found in Topic +0ms random
GetReply itorTopic +0ms __post__
GetReply Did we match? +0ms { trigger: '(?:.*?)',
options: { isQuestion: false, qType: false, qSubType: false },
reply: { '37c53b58': 'okay ~somethingmadeup {topic=car}' } }
GetReply Looking at choices: +1ms [ 'okay ~somethingmadeup {topic=car}' ]
GetReply We like this choice +0ms okay ~somethingmadeup {topic=car}
If you recall, the system will process pre topics, than your current topic, followed by the post topics, in our case the default random topic.
If you notice for each trigger, we will have two
GetReply Try to match 'test' against 9b9265b ((?:.*?)) +1ms
This is because we will try to match against the given input as well as the input lemmatized.
Finally, we see we do indeed have a match, and the system will show us what reply it choose, providing we had more than one.