Monday, May 5, 2014

A Swig of ChatBot - Making Unity Chatter Part 1.


Unity3d is an amazing Game Engine that is revolutionizing the game industry by providing a simple to use game assembly, engine and publishing workflow that allows even very small (think 1 person) game companies to write once and publish their games to Windows, Mac, Linux, Android and iOS simultaneously on a stable performant platform.  If you game at all, chances are you've played on unity.

ChatScript is a innovative Natural Language Processing (NLP) engine written and open sourced by Bruce Wilcox which can be used to create believable ChatBots and can also act as a HTN Planner, search engine and undoubtably a number of other arcane thingys.  I'm playing around with it as part of my latest hobby project having to do with Unity3d and my secret love of RPGs (oops).
I want these two to work together.  I don't want much, right?

ChatScript is mostly expected to run as a stand alone server listening for TCP requests.  It's pretty easy to hook that up in Unity3d - you just write some C# that connects to the socket, have the expected conversation and voila.
Chat with Rose

But...  I'm planning on making my multiplayer game _without_ a central server architecture.  I don't have that kinda money to blow on a side hobby project in a niche market that is unlikely to gain much of a following and probably couldn't survive with a subscription model.  So...

I need to embed ChatScript _inside_ Unity so I don't have to run a central server or do something hokey like secretly launch a local server on the gamer's machine.   Unity allows C# and Javascript for coding ( which runs on mono for cross platform goodness ).   Chatscript is written in C++.  Problem.

SWIG to the rescue!  Swig wraps C/C++ code up to be called by your high level language of choice ( 19 currently supported ).  It has C# support, so theoretically this should work.

I'm going to just skip all the failure. That is more a story to be told quietly over a good scotch and some 70s punk turned down real low until it's just gibberish screaming in the background like a pair of someone else's headphones.  I'll get right to the solution.  That's what you want right?  Well, I'm not tapping my scotch cabinet for the whole internet, so give that up right now.

Swig works by creating a C wrapper around your C whatever given a definition file.  This gets compiled into the needed dynamically loaded library for whatever language you want.  I'm going to talk about C#, but I got it to work with Java and Perl as well before I felt I had mastered the process and moved on. ( I'll include those code samples too at the end ).

ChatScript.i
%module ChatScript %{ 
#include <time.h>
#include <stdint.h>
#include "common.h"
#include "mainSystem.h"
%}

That starts us off on what's needed to make a dynamic library out of chat script source. Next we have to tell it how to map the methods we want and the datatypes those methods use.

%include <typemaps.i>

%typemap(ctype) char * output "char *" 
%typemap(imtype) char * output  "System.Text.StringBuilder" 
%typemap(cstype) char * output "System.Text.StringBuilder" 

%typemap(in) char * ppString (char *tmp = 0) %{ 
$1=&tmp; 
%} 

%typemap(argout) char * ppString %{ 
strcpy($input, *$1); 
free(*$1); 
%} 

This swig magic does that. It essentially maps the char* into regular C#s strings and the output buffer char* into a StringBuilder. In C it's common to pass in a pointer to a method, then read from that pointer as a way of returning either complex data types or for other reasons. C# of course doesn't really do that so you have to wave your hands a bit to make the translation. All this is fairly standard stuff you get by reading the docs and looking at the great examples that are provided with the swig source code.

%apply char * output { char *OUTPUT }

int InitSystem(int argc, char * argv[],char* unchangedPath = NULL,
                         char* readonlyPath = NULL, char* writablePath = NULL);
void PerformChat(char* user, char* usee, char* incoming,char* ip, char* output);

The two lines at the bottom are telling swig what method signatures to wrap, the line above those is mapping the last input to the PerformChat method as an output variable.
Now that we have a swig .i file we go to ChatScript's src directory and tell swig to do it's magic.

'swig -c++ -csharp -namespace ChatScript ../swig/mac/csharp/ChatScript.i'

This creates the wrapper files in the same directory as the .i file. Handy. Now just to compile them into a dynamic library. I'm going to leave this part out mostly - I've included a sample Xcode project at the end of this but the basic swig instructions should work fine on your system. Besides, I wouldn't claim to be able to create a DLL on windows, then somebody might make me do it and I'm allergic to windows ( gives me Tourettes ).

ExampleClient.cs
// snip snip

  void InitServer ()
  {
   GCHandle gch = StringArray2Ptr (args);
   IntPtr argv = gch.AddrOfPinnedObject ();

   Console.WriteLine ("Started Chat Server : " 
           + ChatScript.ChatScript.InitSystem (args.Length, 
               new SWIGTYPE_p_p_char (argv, false), chatRoot, chatRoot, chatRoot));
   gch.Free ();
  }

  public string SendChat (string input)
  {
   System.Text.StringBuilder output = new System.Text.StringBuilder (1024);
   ChatScript.ChatScript.PerformChat (playerName, botName, input, null, output);
   return output.ToString ();
  }
// snip snip


full code in example swig and Xcode project below

 My next post will deal with getting this all into Unity and packaging it up.

For now check out the GitHub Project with all the example files you need.


Enjoy!

references:
http://www.chatbots.org/ai_zone/viewthread/1552/

Thursday, January 26, 2012

Vinterstitial Objects and Spaces - A proposal.


The shift to living in virtual reality a large portion of our day has been gradually taking place over the last 20 years or so as the Internet has grown in size and scope.

Bifurcation is our first response.   That is Inelegant.

How we currently deal with this bifurcation:
 - augmented reality
 - Internet of things
 - qrc/tags
 - away status
 - bridges/translation/transformation/portals, etc

Ill-effect of bifurcation:
 - fragmented vision of reality
 - difficulties keeping VR and RL in sync
 - conferencing and telepresence simple visual bridges
 - collaborative spaces only in either VR or physical

Proposal - We treat virtual reality dimensions as first class dimensions rather than second class ones.   We create a new classification of objects that inhabit all dimensions, VR and RL, as Vinterstitial.

(read Flatland for inspiration)

Interstitial Icon - for use on both Real and Virtual Objects:


Interactivity is either uni-directional or bi-directional, and is indicated by the binary existence of the internal dots. 

The Internet Doorbell Mk I


VR doobell with recursive doodad thingy picture
I like things simple.

That's just how it is.  Things most people have no problem with bother me. 

For example:

I have a house in Second Life that my online friends occasionally visit. I also have a house in real life that my real life friends occasionally visit. It bothers me that I have to treat these two houses separately, that I have to constantly context switch between them. It seems inelegant. Primitive. So I've decided to overlap the two using vinterstitial objects and spacial techniques.

I'm trying to merge my real and virtual lives, become a whole person again.  Is that so wrong?

To accomplish this I am going to start with the front door. The plan is to have my doorbell in VR ring my doorbell in RL and visa versa.

technical architecture diagram
Platform: 

WiFly Xbee module
I needed a relatively inexpensive stand alone solution that combined a programmable controller with wifi wireless capability.  I intend for this platform to eventually include other functionality to support my project so it needed to have decent digital and analog i/o capability.   I was also interested in having battery backup and/or power.   I chose the Arduino Fio and WiFly Xbee module.   The Fio is a great little arduino, it is inexpensive, has a xbee socket on the back already and a built in charger and battery connector, so minimal work is needed to meet my goals. The WiFly Xbee module is an inexpensive drop in wifi replacement for the popular 802.15.4 xBee radios. This means that I can program my Fio wirelessly via the xbee radios, test the code via the serial port, then simply switch in the WiFly module and the fio for standalone wifi. For comparision consider an Uno and wifi sheild ($30 + $90 = $120).  The Fio and WiFly xbee I use costs ($25 + $35 = $60) and has a battery connector, wireless programming and charger circuit.   I have a feeling I'll be using the Fio + wifly xbee quite a lot.

My RL doorbell guts and diagram
Doorbells:

Most doorbells are simple buttons that power a selenoid striker that hits the chime plate(s) when the circuit is closed.  They generally have support for two different chimes so that the front and back doors have different rings.  This is usually accomplished by having two selenoid strikers, one that rebounds from the first chime plate strike and hits the second chime plate, creating the classic doorbell 'ding dong'.  That is also why the dong can be delayed by holding down the doorbell button.  "Ding.........Dong..Ding.Dong...Ding......." The second striker is blocked from strike plate two so it only chimes once "Ding".

Hand Crafted Project Harness



Ringing the Doorbell from the Internet:

The Fio/Wifly connects to my home network automatically on powerup and runs a simple web server listening on the (newly dubbed) standard internet doorbell port of 33301.   My home router forwards any requests from the internet on that port to my home's public ip address to the fio. When the fio gets a http request it rings the doorbell "Ding" and sends a message back to the requestor.  Easy peasy.
Solid state relay
Relay Hardware:

I used a solid state relay kit from sparkfun although any sort of relay with the proper characteristics should work fine.  Basically doorbells are ~15-25V AC, so solid state relays are a really good solution (they generally can't switch DC on/off).  Most solid state relays are also opti-coupled.  This means there is no current path between the 24V AC and your arduino, which is a good thing in case your arch enemy's robot tries to fry it via the doorbell.  I suppose your doorbell is also protected from cyber threats as well.  Doorbells can be dangerous in the wrong hands so be careful.

Planned Improvements:

  • Bi-Directional - ie add a RL doorbell detector circuit and ring my internet doorbell
  • Add a text display to tell me who rang the internet doorbell
  • Add a video camera capture to tell me who rang the RL doorbell
  • Power the circuit off of the doorbell AC.
  • Add mobile device notification.

Do It Yourself: