AI Zone Admin Forum Add your forum

CX Company, chatbot market leader in the Netherlands since 2005, will speak on the Amsterdam Chatbots Meetup on Wednesday, Oct 18!

Using Chatscript Facts and inference to create a chatbot that learns
 
 

I am getting back into Chatscript facts and the query language and playing with using Chatscript facts and queries to create a chatbot that learns.  The problem that I had a couple of years ago and that I still have is that the matching of the object does not appear to work for me. 

I have created a query pattern called “infer”.  I would like it to scan up the hierarchy using the verb “is_a” and match the verb and the object passed in anywhere up the hierarchy.  This basic example ignores concepts and topics. 

I believe the commented line below should work without further coding.  I have had to add extra code to loop through the results and force a match on object that was passed in since the match o3 is not limiting the results to the object that was passed in but is tagging everything up the hierarchy.  But the extra code seems to be working fine.

Here is some simple code to add, delete and query facts:

queryinfer "4'is_a.t 1s<4q 2vt 3ot: queue s: match v2 o3"

outputmacro: ^IsInferred( ^^^)
## if ( ^query( infer ^s ^v ^o ) ) {TRUE} else {FALSE}

 
@= ^queryinfer ^^^)
 $
$RecordCount = ^length(@2)
 $
$InferredMatch FALSE
 loop
($$RecordCount
  
{
   
if ( ^first(@2Object) = ^$$InferredMatch TRUE end(loop}
  }
 
$$InferredMatch 

outputmacro
: ^deletefact( ^^^)
 @
= ^querydirect_svo ^^^)
 ^
delete(@2)

topic: ~reason keep repeat is a are infer can able to does have )

u: ( delete fact a _is a _* )
 ^
deletefact_0 is_a _1 )
 
OkFact_0 is_a _1 has been deleted.

u: ( a _is a _* ) 
 if ( ^
findfact_0 is_a _1 ) ) { I knew that already}
 
else ^createfact_0 is_a _1 OkI have learned that a _0 is a _1}

u
: ( is a _a _* )
 if ( ^
findfact_0 is_a _1 ) ) { YesA _0 is a _1
 
else if ( ^IsInferred_0 is_a _1 ) = TRUE ^IsInferreddebug_0 is_a _1 YesA _0 is a _1
 
else {NoA _0 is not a _1.

u
: ( a _can _* ) 
 if ( ^
findfact_0 can _1 ) ) { I knew that already}
 
else ^createfact_0 can _1 OkI have learned that a _0 can _1}

u
: ( is a _able to _* )
 if ( ^
findfact_0 can _1 ) ) { YesA _0 can _1
 
else if ( ^IsInferred_0 can _1 ) ) { YesA _0 can _1
 
else {NoA _0 can not _1.

u
: ( can a _~mainsubject _~mainverb )
 if ( ^
findfact_0 can _1 ) ) { YesA _0 can _1
 
else if ( ^IsInferred_0 can _1 ) ) { YesA _0 can _1
 
else {NoA _0 can not _1.}

u
: ( a _has {a} _* ) 
 if ( ^
findfact_0 has_part _1 ) ) { I knew that already}
 
else ^createfact_0 has_part _1 OkI have learned that a _0 has '_1. } 

u: ( does a _* have {a} _* )
 if ( ^findfact( _0 has_part _1 ) ) { Yes. A _0 has '
_1
 
else if ( ^IsInferred_0 has_part _1 ) ) { YesA _0 has '_1. } 
 else {No. A _0 does not have '
_1.

u
: ( a _is _* ) 
 if ( ^
findfact_0 has_attribute _1 ) ) { I knew that already}
 
else {  ^createfact_0 has_attribute _1 OkI have learned that a _0 is _1}

u
: ( is a _~mainsubject _* )
 if ( ^
findfact_0 has_attribute _1 ) ) { YesA _0 is _1
 
else if ( ^IsInferred_0 has_attribute _1 ) ) { YesA _0 is _1
 
else {NoA _0 is not _1.
 

 
  [ # 1 ]

Sample Output:

HARRY:  Welcome to ChatScript.
trainer: > a bird is a creature
HARRY:  Ok. I have learned that a bird is a creature.
trainer: > a mammal is a creature
HARRY:  Ok. I have learned that a mammal is a creature.
trainer: > an insect is a creature
HARRY:  Ok. I have learned that a insect is a creature.
trainer: > a fish is a creature
HARRY:  Ok. I have learned that a fish is a creature.
trainer: > a robin is a bird
HARRY:  Ok. I have learned that a robin is a bird.
trainer: > a crow is a bird
HARRY:  Ok. I have learned that a crow is a bird.
trainer: > a hawk is a bird
HARRY:  Ok. I have learned that a hawk is a bird.
trainer: > a bird has feathers
HARRY:  Ok. I have learned that a bird has feathers.
trainer: > a creature is alive
HARRY:  Ok. I have learned that a creature is alive.
trainer: > does a crow have feathers?
HARRY:  Yes. A crow has feathers.
trainer: > is an insect alive?
HARRY:  Yes. A insect is alive.
trainer: > a bird can fly
HARRY:  Ok. I have learned that a bird can fly.
trainer: > can a robin fly?
HARRY:  Yes. A robin can fly.
trainer: > a hammer is a tool
HARRY:  Ok. I have learned that a hammer is a tool.
trainer: > can a hammer fly
HARRY:  No. A hammer can not fly.
trainer: > does a hammer have feathers?
HARRY:  No. A hammer does not have feathers.
trainer: > is a hammer alive?
HARRY:  No. A hammer is not alive.
trainer: > a mammal can bear live young
HARRY:  Ok. I have learned that a mammal can bear live young.
trainer: > a dog is a mammal
HARRY:  Ok. I have learned that a dog is a mammal.
trainer: > can a dog bear live young?
HARRY:  No. A bear can not live.
trainer: >

Ok. So it is not perfect. smile The example needs to be expanded to handle different phrasing, word order, etc.  I need to add some functionality to handle multiple word subjects, verbs and object phrases.  This does show that this simple code can handle inheriting attributes, parts and abilities using inference and a hierarchy built using a custom “is_a” verb/predicate.  (isa is already in use by Chatscript).  The attributes and relations at higher levels in the hierarchy do not need to be physically expanded into new facts at all lower levels.  They can just be “reasoned” with in memory.

 

 
  [ # 2 ]

After training following code I have asked question that answers correctly but after rebuild it does not answer coorectly
query: infer “4’is_a.t 1s<4q 2vt 3ot: queue s: match v2 o3”

outputmacro: ^IsInferred( ^s ^v ^o )
## if ( ^query( infer ^s ^v ^o ) ) {TRUE} else {FALSE}

@2 = ^query( infer ^s ^v ^o )
$$RecordCount = ^length(@2)
$$InferredMatch = FALSE
loop($$RecordCount)
  {
if ( ^first(@2Object) = ^o ) { $$InferredMatch = TRUE end(loop) }
  }
$$InferredMatch

outputmacro: ^deletefact( ^s ^v ^o )
@2 = ^query( direct_svo ^s ^v ^o )
^delete(@2)

topic: ~reason keep repeat ( is a are infer can able to does have )

u: ( delete fact a _* is a _* )
^deletefact( _0 is_a _1 )
Ok. Fact: _0 is_a _1 has been deleted.

u: ( a _* is a _* )
if ( ^findfact( _0 is_a _1 ) ) { I knew that already. }
else { ^createfact( _0 is_a _1 ) Ok. I have learned that a _0 is a _1. }

u: ( is a _* a _* )
if ( ^findfact( _0 is_a _1 ) ) { Yes. A _0 is a _1. }
else if ( ^IsInferred( _0 is_a _1 ) = TRUE ) { ^IsInferreddebug( _0 is_a _1 ) Yes, A _0 is a _1. }
else {No. A _0 is not a _1.}

u: ( a _* can _* )
if ( ^findfact( _0 can _1 ) ) { I knew that already. }
else { ^createfact( _0 can _1 ) Ok. I have learned that a _0 can _1. }

u: ( is a _* able to _* )
if ( ^findfact( _0 can _1 ) ) { Yes. A _0 can _1. }
else if ( ^IsInferred( _0 can _1 ) ) { Yes. A _0 can _1. }
else {No. A _0 can not _1.}

u: ( can a * _~mainsubject * _~mainverb )
if ( ^findfact( _0 can _1 ) ) { Yes. A _0 can _1. }
else if ( ^IsInferred( _0 can _1 ) ) { Yes. A _0 can _1. }
else {No. A _0 can not _1.}

u: ( a _* has {a} _* )
if ( ^findfact( _0 has_part _1 ) ) { I knew that already. }
else { ^createfact( _0 has_part _1 ) Ok. I have learned that a _0 has '_1. }

u: ( does a _* have {a} _* )
if ( ^findfact( _0 has_part _1 ) ) { Yes. A _0 has '_1. }
else if ( ^IsInferred( _0 has_part _1 ) ) { Yes. A _0 has '_1. }
else {No. A _0 does not have '_1.}

u: ( a _* is _* )
if ( ^findfact( _0 has_attribute _1 ) ) { I knew that already. }
else { ^createfact( _0 has_attribute _1 ) Ok. I have learned that a _0 is _1. }

u: ( is a _~mainsubject _* )
if ( ^findfact( _0 has_attribute _1 ) ) { Yes. A _0 is _1. }
else if ( ^IsInferred( _0 has_attribute _1 ) ) { Yes. A _0 is _1. }
else {No. A _0 is not _1.}

 

 
  [ # 3 ]

Learning is unique to the user you logged in as originally. If you come in as a different user, you do not have that learning.

 

 
  [ # 4 ]

But you can have that learning by using a shared text file:

create aliases at the top of your file:

rename: @clearthoughts @8
rename
: @brain @

replace any calls to the createfact function with learnfact and add the outputmacro below:

outputmacro: ^learnfact( ^^^)
 $
$newfact = ^createfact( ^^^)
 @
brain = $$newfact
 
^exportcollectiveconsciousness.txt @brain append 

This will append all learned facts as they are learned to a common text file: collectiveconsciousness.txt

Teach your bot some facts while logged in as the first user then log off and log in as another user.  The second user will not know any of the first users facts until you load the collective consciousness.  You can do that by adding the pattern below and typing “load collective consciousness”

u: ( load collective consciousness 
 ^
importcollectiveconsciousness.txt @brain keep permanent )
 
OkI have loaded our collective consciousnessWowI feel smarterI know ^length( @brain facts

(You will need to add the words collective consciousness to your topic key words)

Ideally you would put the import command in your control topic file. 

Even though the fact learning code in this thread checks for known facts before adding new ones, now that multiple users can append to the same file it is possible to create duplicate facts.

Sleep rests and restores the brain in humans so use this pattern to tell your chatbot to sleep now and clean up the possible duplicated facts in the collective consciousness.

u: ( sleep now 
 ^
importcollectiveconsciousness.txt @brain keep permanent )
 @
clearthoughts = ^unduplicate( @brain )
 ^
exportcollectiveconsciousness.txt @clearthoughts )
 
OkI have taken a short nap.  My mind feels clearer now

If you want to know how many facts are in the collective consciousness:

u: ( how many facts 
 ^
importcollectiveconsciousness.txt @brain keep permanent )
 
I know ^length( @brain facts

Sample Output:

Enter user name: bob

HARRY:  Hi.
bob: > is a canary a bird
HARRY:  No. A canary is not a bird.
bob: > load collective consciousness
HARRY:  Ok. I have loaded our collective consciousness. Wow, I feel smarter. I know 10 facts.
bob: > is a canary a bird
HARRY:  Yes. A canary is a bird.
bob: > sleep now
HARRY:  Ok. I have taken a short nap. My mind feels clearer now.
bob: > how many facts
HARRY:  I know 9 facts.
bob: >

 

 

 
  [ # 5 ]

Alaric, this is excellent!!

 

 
  login or register to react