-
Notifications
You must be signed in to change notification settings - Fork 154
Expand file tree
/
Copy pathChatScript-Memorization.html
More file actions
318 lines (306 loc) · 11.3 KB
/
ChatScript-Memorization.html
File metadata and controls
318 lines (306 loc) · 11.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>ChatScript-Memorization</title>
<style>
html {
color: #1a1a1a;
background-color: #fdfdfd;
}
body {
margin: 0 auto;
max-width: 36em;
padding-left: 50px;
padding-right: 50px;
padding-top: 50px;
padding-bottom: 50px;
hyphens: auto;
overflow-wrap: break-word;
text-rendering: optimizeLegibility;
font-kerning: normal;
}
@media (max-width: 600px) {
body {
font-size: 0.9em;
padding: 12px;
}
h1 {
font-size: 1.8em;
}
}
@media print {
html {
background-color: white;
}
body {
background-color: transparent;
color: black;
font-size: 12pt;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3, h4 {
page-break-after: avoid;
}
}
p {
margin: 1em 0;
}
a {
color: #1a1a1a;
}
a:visited {
color: #1a1a1a;
}
img {
max-width: 100%;
}
svg {
height; auto;
max-width: 100%;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.4em;
}
h5, h6 {
font-size: 1em;
font-style: italic;
}
h6 {
font-weight: normal;
}
ol, ul {
padding-left: 1.7em;
margin-top: 1em;
}
li > ol, li > ul {
margin-top: 0;
}
blockquote {
margin: 1em 0 1em 1.7em;
padding-left: 1em;
border-left: 2px solid #e6e6e6;
color: #606060;
}
code {
font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
font-size: 85%;
margin: 0;
hyphens: manual;
}
pre {
margin: 1em 0;
overflow: auto;
}
pre code {
padding: 0;
overflow: visible;
overflow-wrap: normal;
}
.sourceCode {
background-color: transparent;
overflow: visible;
}
hr {
background-color: #1a1a1a;
border: none;
height: 1px;
margin: 1em 0;
}
table {
margin: 1em 0;
border-collapse: collapse;
width: 100%;
overflow-x: auto;
display: block;
font-variant-numeric: lining-nums tabular-nums;
}
table caption {
margin-bottom: 0.75em;
}
tbody {
margin-top: 0.5em;
border-top: 1px solid #1a1a1a;
border-bottom: 1px solid #1a1a1a;
}
th {
border-top: 1px solid #1a1a1a;
padding: 0.25em 0.5em 0.25em 0.5em;
}
td {
padding: 0.125em 0.5em 0.25em 0.5em;
}
header {
margin-bottom: 4em;
text-align: center;
}
#TOC li {
list-style: none;
}
#TOC ul {
padding-left: 1.3em;
}
#TOC > ul {
padding-left: 0;
}
#TOC a:not(:hover) {
text-decoration: none;
}
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<h1 id="user-memorization-in-conversation">User Memorization in
Conversation</h1>
<blockquote>
<p>Copyright Bruce Wilcox, gowilcox@gmail.com brilligunderstanding.com
Revision 8-5-2013 CS 3.52</p>
</blockquote>
<p>An initial impression of the bot hearing and understanding the user
comes from a gambit asking the user a question, and a rejoinder replying
specifically to what the user said. E.g.</p>
<pre><code>t: Do you have any pets?
#! dog
a: (dog) Dogs make great pets.
#! cat
a: (cat) I prefer cats.</code></pre>
<p>Or it comes from a responder able to answer the user’s question.
E.g.</p>
<pre><code>#! do you have any pets
?: ( << you ~own pet >>) I have two chickens.</code></pre>
<p>The next level of creating an impression is to remember some of the
information the user has given, and drop it back into conversation
later. This will create a vivid impression on the user.</p>
<p>This is easiest done by memorizing certain kinds of information and
having a use for them later. Things like what pet they have, whether
they like coffee or not, their age, etc. There are two places one can
store longer term data variables and facts. Variables are the cheapest
and most efficient thing to use. Here is an example of memorizing
pets:</p>
<pre><code>t: Do you have any pets?
#! dog
a: (%tense!=past dog) Dogs make great pets. $pet = dog
#! cat
a: (%tense!=past cat) I prefer cats. $pet = cat
#! elephant
a: (_~animals) $pet = _0
s: ( %tense!=past << I ~own _~animal >>) $pet = _0</code></pre>
<p>The above will either catch an unprovoked statement by the user that
he owns some animal (not owned in the past) or will catch a reference to
some animal in response to the bot’s question while commenting at the
same time. We now have a value for <code>$pet</code>. This can be used
later in the same topic/conversation as follows:</p>
<pre><code>t: do you have any pets?
t: I have two chickens.
t: I love having chickens
t: ($pet) refine()
a: ($pet=dog) Have you always preferred dogs as pets?
a: (*) What do you feed your $pet ?</code></pre>
<p>The pet gambit will not fire until it knows of a user’s pet. Control
would skip past it if the user has never named an animal. Someday in the
future when it learns of a pet, it might issue this gambit if it ever
randomly selected the pet topic again.</p>
<p>An even more impressive bot will bring up the pet again in a future
conversation. How to write such script will be explained in a moment.
But imagine at the start of some future conversation, the bot, after
saying hello, says “I was walking by a pet store the other day and saw
the cutest dog in the window, which reminded me of your dog. Has it
learned any new tricks?”</p>
<p>There are two parts to the code for this. First, you have to detect
you are in a new conversation. Then you have to decide when to bring
forth the memory. The simple place to do this is in the introduction
topic, when issuing and responding to “hello” and “how are you”. You are
only in this topic at the start of a conversation, so any knowledge you
have memorized about pets clearly has to have been from a prior
conversation. So you can try to find a moment when the user has issued a
statement (not a question). So the topic might have a bunch of rules
like this:</p>
<pre><code>s: ($pet) I remember you have a $pet.
s: ($coffee) I know you like coffee.</code></pre>
<p>Obviously the sentence output should be more sophisticated. Once this
rule has fired, it automatically erases itself and will not fire again.
Then again, maybe you want to initiate a subconversation on this by
calling a topic to handle it. The topic might look like this:</p>
<pre><code>topic: ~yourpet []
t: (!$pet) keep() end(TOPIC)
t: I was passing a pet shop yesterday and it reminded me of your $pet. Do you buy toys for it?
t: What do you feed your $pet?</code></pre>
<p>This topic has several special characteristics. First, it has no
keywords, so it will not be launched accidentally by something the user
says. Second, its first gambit will make the topic exit if no pet has
been learned about (and stays available for future use). This is because
if the system is trying to find a random topic to gambit at some point
in the future, we don’t want this topic to do anything if we don’t know
a pet. The call to the topic from inside introductions can remain the
same, or it can be changed to this:</p>
<pre><code>s: ($pet) gambit(~yourpet) disable(rule ~)</code></pre>
<p>The reason for disabling the rule is that when this rule is first
called, it will generate output from ~yourpet, so this rule does not
disable itself. That means during the next startup it will try to call
~yourpet again. That’s not awful, because only new gambits will be
issued. But maybe the topic is not written to be started from anywhere
within it. Or maybe you don’t want to start two conversations with
references to their pet. So if you explicitly disable this rule when it
fires, then all this is avoided.</p>
<p>An alternative to the above mechanism of sticking it in the
introductions, is to have a topic you can initiate later from somewhere
(presumably the control script) which goes and looks at memorized stuff
and initiates conversations about them. If you absolutely want it to do
this only in new conversations and not the same one where you learned
the data, then you need to memorize when you learned the data as well as
what. So your memorization might be:</p>
<pre><code>$pet = _0 $pethwhen = %input</code></pre>
<p>This means we could write script that can tell if this is a new
conversation or not.</p>
<pre><code>s: ($pet $petwhen<%userfirstline) I remember you have a $pet</code></pre>
<p>$petwhen will have been set at volley 20, for example. %userfirstline
is always the starting volley id of the current conversation. If the
first conversation lasted for 50 volleys, then the start will be at 51
in this new conversation and at 0 in the old conversation. So the
relation test fails as long as we are in the old conversation.</p>
<p>The most difficult part of bringing up remembered data is deciding
when to do it. Finding a natural segway into the memory at the start of
the conversation is best. It is perhaps more awkward if you try to find
a break in the conversation to suddenly ramble about what you remember
of the user. Which leads to yet another way of dealing with remembered
data. Finding an excuse in normal topics to make reference to it. The
problem is that the special code for that might get extensive.</p>
<p>Consider that we know they own a dog and the conversation is
currently on food. You might have a gambit inside ~food like this:</p>
<pre><code>t: ($pet=dog) Do you ever feed your dog table scraps during dinner?</code></pre>
<p>This gambit will never execute unless they own a dog, so it’s pretty
specialized. But you wouldn’t ask it for any pet, either:</p>
<pre><code>t: ($pet) Do you ever feed your $pet table scraps during dinner?</code></pre>
<p>Just imagine asking that about a canary or a goldfish. Of course you
could have a set of animals that would eat scraps like this;</p>
<pre><code>concept: ~table_pets (dog cat lion goat elephant)
t: ($pet?~table_pets) Do you ever feed your $pet table scraps during dinner?</code></pre>
<p>Note that $pet is a variable that, once set, lives forever with the
user data unless you explicitly erase it. Therefore it can be used all
over the place, and only gambits and responders using it that generate
output will get erased, the variable remains for other rules to trigger
on.</p>
</body>
</html>