[Aiml-programr-developers] Tests and Architecture

Nicholas H.Tollervey ntoll at ntoll.org
Sat Sep 15 18:07:27 EDT 2007


Hi Mauro,

Thanks for the quick email, just so you know how my thoughts are moving...

Re notation: to clear up the web-development analogy I'll try and
explain how I see the concepts mapped between the two domains (bots ->
web). Obviously analogies of these sorts are very much subjective,
imprecise (that's why they're an analogy), open to (mis)-interpretation
and (most importantly) depend on how "abstract" the people doing the
analogy are willing to go.

Anyway, here goes and please feel free to shoot this all down in flames,
I have a tough skin and positively welcome people telling me that I'm
wrong. To be honest, if we're to make this project easy to understand
for others we definitely need to make sure we're clear about how we
explain, conceptualise and define how it works! :-) Once again, I'm
thinking out loud here...

Put simply, I reckon the "Bot" class is like an add-on module for Apache
or some other web-server (e.g. PHP, modPython or ASP.NET) - or that's
how it should appear to developers: a plug-in client/server architecture
for natural language. The AIML set is like the HTML (static or
dynamically created) served by Apache/{PHP, Python, ASP.NET etc}. We
agree that the concepts of session, http request and http response map
onto our own conversation, request and response. If I understand you
correctly, our concept of "user" means the same as a "user" of a web
application - an encapsulation of all the appropriate information about
*ME* identified by a unique id - e.g. the id ntoll is my username at
del.icio.us (you'll see I've been bookmarking lots about Rake :-)... and
del.icio.us also store my email, password, real-name, tags, bundles and
friends... etc... etc... as part of my "user" profile in much the same
way that a bot instance will have to store a user's predicate list.

If the above is the case then I think we agree! If not, it'll be
interesting to discover the differences, find the reasons behind the
differences and move forward to a consensus.

Also, as I pointed out in my first email in this thread, the Ruby I was
writing was (literally) made up on the spot. I'm painfully aware that I
speak Ruby with a heavy C like accent (specifically C# at the moment) so
any style guidance would be most welcome. Having re-read it I think I'd
change the sample session so that the Bot implemented a method called
something like ReplyTo:

req= Request.new("Hi there", c)
response = myBot.ReplyTo(req)

Where obviously, "c" is the conversation instance, "myBot" is a bot
instance and the user is referenced within "c". Actually, my wife has
just been looking over my shoulder as I write this. She wanted me to
explain what it meant :-). I explained the above two lines of code in
plain English as, "I want the computer to create a new request called
"req" that contains the words "Hi there" as part of a conversation
called "c". Now give me a response from "myBot" to the request called
"req" (and obviously "c" has a user associated with it so the software
knows who to deliver it to)".

Anyway, its late and I have an appointment in the gym at 8am tomorrow...
:-)

Looking forward to hearing from and discussing this with you,

Nicholas

mauro at cicio.org wrote:
> Hi,
>
> Nicholas: thanks for the long mail!
>
> Sorry for not answering as it deserves I am very busy at the moment.
> This is just an ack to say that I am receiving and reading.
>
> Just   a short note on the notation:
> Bot -> Website
> User -> Client
> Conversation -> Session
> Request -> HTTP Request
> Response -> HTML served back
>
> Is probably more precise to say:
>
> Bot -> Webservice (which is what we can use to wrap pR)
> User -> Webapplication
> Conversation -> Session
> Request -> HTTP Request
> Response -> HTTP Response
>
> The  Webapplication is a proxy for the WebClient (EndUser) and it can
> be a Rails application or something like that.
>
> I'll write more tomorrow I hope,
>
> Ciao,
> Mauro
>
> On 12/09/2007, Nicholas H.Tollervey <ntoll at ntoll.org> wrote:
>   
>> Guys,
>>
>> What follows is a summary of my thoughts on testing prior to sitting
>> down and writing them.
>>
>> We're writing a library and as a result I'll define two sets of tests:
>>
>> * UAT - that define the expected behaviour of the classes that we expect
>> other developers to have to use to write their applications
>> * Unit Tests - that additionally encompass the expected behaviour of the
>> wider classes / methods / areas of the library that we hope other
>> developers will not have to use.
>>
>> As a result I'll do two things:
>>
>> 1. Specify our "public" classes that third party developers should use
>> to implement our library by means of example "use" cases written in code
>> 2. Define the architecture behind these public classes so we can start
>> to write unit tests.
>>
>> It is important to remember that I intend to unit test as locally to the
>> implementation of a method / class as possible. By this I mean that
>> there will not be any tests against the high-level "bot" class for the
>> "lower level" functionality of interpreting AIML tags (I'll test this
>> against the appropriate class(es)).
>>
>> So onto some example use cases (I'll formalise these into proper Ruby
>> unit tests - the purpose of this email is to make public my testing
>> strategy so you guys can shout if you disagree and we can then modify as
>> needs be)...
>>
>> I imagine a developer using our library should only have to deal with
>> five classes:
>>
>> 1. Bot - that encapsulates an instance of a particular bot.
>> 2. User - that encapsulates all the information about a particular user
>> who is interacting with a "Bot"
>> 3. Conversation - encapsulates and exchange between a particular "User"
>> and a "Bot"
>> 4. Request - encapsulates an single item of raw input from a "User" to a
>> "Bot" as part of a "Conversation"
>> 5 Response - encapsulates an item of output from a "Bot" to a "User" as
>> part of a "Conversation".
>>
>> If I were to make a comparison with web-development our classes would
>> map like this:
>>
>> Bot -> Website
>> User -> Client
>> Conversation -> Session
>> Request -> HTTP Request
>> Response -> HTML served back
>>
>> I've done this on purpose as we intend to target Ruby on Rails as a
>> potential platform. We could also piggy back on-top of other ruby
>> enabled web technology (lighttp, apache etc) to provide a Bot server.
>> Having such an easy mapping from the world of www to bots will make this
>> simpler to carry out and easier for others to understand.
>>
>> I'll UMLify these relationships when I get some time later this week.
>>
>> Now onto a quick example of how I hope a developer might use these
>> classes, an improvisation in Ruby :-)
>>
>> <code>
>>
>> myBot = Bot.new() # for default settings or:
>> myBot = Bot.new(path) # where path is to a config.yaml file setting up
>> the bot to non default settings
>> myBot.ToYAML # bot's predicate list as YAML
>>
>> # Attributes might include
>> myBot.Name # name of the bot
>> myBot.Botmaster # who the bot-master is
>> myBot.Size # number of categories in the graphmaster
>>
>> # loading AIML
>> myBot.Learn(SomeRawAIML) # well formed obviously
>> myBot.Load("pathToAIMLFile(s)") # if an individual AIML file is
>> specified the file is loaded, if a directory all AIML files within it.
>>
>> # User class:
>>
>> myUser = User.new("Unique id") # where Unique id might be something like
>> a PK in a database so information can be retrieved.
>> myUser = User.new("Unique id", userconfig.yaml) # as above but with some
>> yaml passed that includes user predicate table and / or conversation history
>> myUser["Name"] # how to reference the user's predicates
>> myUser.Conversations[0] # most recent conversation
>> myUser.ToYAML # predicate list etc as YAML
>>
>> # Conversation:
>>
>> c = Conversation.new(myUser, myBot) # create a new conversation session
>> with the specified user and bot
>> c.Request[0] # the first thing said to the bot in this conversation
>> c.Response[0] # the first thing said to the user
>> c.StartedOn # Timestamp
>> c.TimeOut # a session timeout setting (any activity after this mount of
>> time results in the session closing)
>> c.Close # close the session
>> c.Open # re-open a session
>> c.Open? # is the session open?
>>
>> # Request
>> req = Request.new("Some raw input") # ctor
>> req.StartedOn # timestamp
>> req.Response # either nil or the response object that was returned
>> req.User # who made the request (or nil)
>> req.Bot # "who" made the response (or nil)
>> req.Conversation # the session context for the request (or nil)
>>
>> # Response
>> res = Response.new(req) # ctor
>> res.to_s # the output from the bot
>> res.FinishedOn # Timestamp. res.FinishedOn - req.StartedOn = Duration of
>> the request
>> res.Sentences[0] # First sentence of a multi-sentence response
>> res.User # User for whom the response is for
>> res.Bot # the Bot who created the response
>> res.Converstaion # the session context for the response
>>
>> # sample session
>>
>> myBot = Bot.new("config.yaml")
>>
>> myUser = User.new("Default",someconfigYAML)
>>
>> c = Conversation.new(myUser, myBot)
>>
>> req = Request.new("Hi there!")
>> response = c.Speak(req)
>>
>> return response.to_s
>> </code>
>>
>> Nota Bene, the above code examples are off the top of my head and I'm
>> not sure how Rubyesque they are... Comments and suggestions would be
>> most welcome. :-)
>>
>> Best wishes,
>>
>> Nicholas
>> _______________________________________________
>> Aiml-programr-developers mailing list
>> Aiml-programr-developers at rubyforge.org
>> http://rubyforge.org/mailman/listinfo/aiml-programr-developers
>>
>>     
>
>   



More information about the Aiml-programr-developers mailing list