eliza in js following charles hayden's classic java implementation
commit
d1d5eca12e
@ -0,0 +1,360 @@
|
|||||||
|
initial: How do you do. Please tell me your problem.
|
||||||
|
final: Goodbye. Thank you for talking to me.
|
||||||
|
quit: bye
|
||||||
|
quit: goodbye
|
||||||
|
quit: quit
|
||||||
|
pre: dont don't
|
||||||
|
pre: cant can't
|
||||||
|
pre: wont won't
|
||||||
|
pre: recollect remember
|
||||||
|
pre: dreamt dreamed
|
||||||
|
pre: dreams dream
|
||||||
|
pre: maybe perhaps
|
||||||
|
pre: how what
|
||||||
|
pre: when what
|
||||||
|
pre: certainly yes
|
||||||
|
pre: machine computer
|
||||||
|
pre: computers computer
|
||||||
|
pre: were was
|
||||||
|
pre: you're you are
|
||||||
|
pre: i'm i am
|
||||||
|
pre: same alike
|
||||||
|
post: am are
|
||||||
|
post: your my
|
||||||
|
post: me you
|
||||||
|
post: myself yourself
|
||||||
|
post: yourself myself
|
||||||
|
post: i you
|
||||||
|
post: you I
|
||||||
|
post: my your
|
||||||
|
post: i'm you are
|
||||||
|
synon: belief feel think believe wish
|
||||||
|
synon: family mother mom father dad sister brother wife children child
|
||||||
|
synon: desire want need
|
||||||
|
synon: sad unhappy depressed sick
|
||||||
|
synon: happy elated glad better
|
||||||
|
synon: cannot can't
|
||||||
|
synon: everyone everybody nobody noone
|
||||||
|
synon: be am is are was
|
||||||
|
key: xnone
|
||||||
|
decomp: *
|
||||||
|
reasmb: I'm not sure I understand you fully.
|
||||||
|
reasmb: Please go on.
|
||||||
|
reasmb: What does that suggest to you ?
|
||||||
|
reasmb: Do you feel strongly about discussing such things ?
|
||||||
|
key: sorry
|
||||||
|
decomp: *
|
||||||
|
reasmb: Please don't apologise.
|
||||||
|
reasmb: Apologies are not necessary.
|
||||||
|
reasmb: I've told you that apologies are not required.
|
||||||
|
key: apologise
|
||||||
|
decomp: *
|
||||||
|
reasmb: goto sorry
|
||||||
|
key: remember 5
|
||||||
|
decomp: * i remember *
|
||||||
|
reasmb: Do you often think of (2) ?
|
||||||
|
reasmb: Does thinking of (2) bring anything else to mind ?
|
||||||
|
reasmb: What else do you recollect ?
|
||||||
|
reasmb: Why do you recollect (2) just now ?
|
||||||
|
reasmb: What in the present situation reminds you of (2) ?
|
||||||
|
reasmb: What is the connection between me and (2) ?
|
||||||
|
decomp: * do you remember *
|
||||||
|
reasmb: Did you think I would forget (2) ?
|
||||||
|
reasmb: Why do you think I should recall (2) now ?
|
||||||
|
reasmb: What about (2) ?
|
||||||
|
reasmb: goto what
|
||||||
|
reasmb: You mentioned (2) ?
|
||||||
|
key: if 3
|
||||||
|
decomp: * if *
|
||||||
|
reasmb: Do you think its likely that (2) ?
|
||||||
|
reasmb: Do you wish that (2) ?
|
||||||
|
reasmb: What do you know about (2) ?
|
||||||
|
reasmb: Really, if (2) ?
|
||||||
|
key: dreamed 4
|
||||||
|
decomp: * i dreamed *
|
||||||
|
reasmb: Really, (2) ?
|
||||||
|
reasmb: Have you ever fantasized (2) while you were awake ?
|
||||||
|
reasmb: Have you ever dreamed (2) before ?
|
||||||
|
reasmb: goto dream
|
||||||
|
key: dream 3
|
||||||
|
decomp: *
|
||||||
|
reasmb: What does that dream suggest to you ?
|
||||||
|
reasmb: Do you dream often ?
|
||||||
|
reasmb: What persons appear in your dreams ?
|
||||||
|
reasmb: Do you believe that dreams have something to do with your problems ?
|
||||||
|
key: perhaps
|
||||||
|
decomp: *
|
||||||
|
reasmb: You don't seem quite certain.
|
||||||
|
reasmb: Why the uncertain tone ?
|
||||||
|
reasmb: Can't you be more positive ?
|
||||||
|
reasmb: You aren't sure ?
|
||||||
|
reasmb: Don't you know ?
|
||||||
|
key: name 15
|
||||||
|
decomp: *
|
||||||
|
reasmb: I am not interested in names.
|
||||||
|
reasmb: I've told you before, I don't care about names -- please continue.
|
||||||
|
key: deutsch
|
||||||
|
decomp: *
|
||||||
|
reasmb: goto xforeign
|
||||||
|
reasmb: I told you before, I don't understand German.
|
||||||
|
key: francais
|
||||||
|
decomp: *
|
||||||
|
reasmb: goto xforeign
|
||||||
|
reasmb: I told you before, I don't understand French.
|
||||||
|
key: italiano
|
||||||
|
decomp: *
|
||||||
|
reasmb: goto xforeign
|
||||||
|
reasmb: I told you before, I don't understand Italian.
|
||||||
|
key: espanol
|
||||||
|
decomp: *
|
||||||
|
reasmb: goto xforeign
|
||||||
|
reasmb: I told you before, I don't understand Spanish.
|
||||||
|
key: xforeign
|
||||||
|
decomp: *
|
||||||
|
reasmb: I speak only English.
|
||||||
|
key: hello
|
||||||
|
decomp: *
|
||||||
|
reasmb: How do you do. Please state your problem.
|
||||||
|
reasmb: Hi. What seems to be your problem ?
|
||||||
|
key: computer 50
|
||||||
|
decomp: *
|
||||||
|
reasmb: Do computers worry you ?
|
||||||
|
reasmb: Why do you mention computers ?
|
||||||
|
reasmb: What do you think machines have to do with your problem ?
|
||||||
|
reasmb: Don't you think computers can help people ?
|
||||||
|
reasmb: What about machines worrys you ?
|
||||||
|
reasmb: What do you think about machines ?
|
||||||
|
key: am
|
||||||
|
decomp: * am i *
|
||||||
|
reasmb: Do you believe you are (2) ?
|
||||||
|
reasmb: Would you want to be (2) ?
|
||||||
|
reasmb: Do you wish I would tell you you are (2) ?
|
||||||
|
reasmb: What would it mean if you were (2) ?
|
||||||
|
reasmb: goto what
|
||||||
|
decomp: *
|
||||||
|
reasmb: Why do you say 'am' ?
|
||||||
|
reasmb: I don't understand that.
|
||||||
|
key: are
|
||||||
|
decomp: * are you *
|
||||||
|
reasmb: Why are you interested in whether I am (2) or not ?
|
||||||
|
reasmb: Would you prefer if I weren't (2) ?
|
||||||
|
reasmb: Perhaps I am (2) in your fantasies.
|
||||||
|
reasmb: Do you sometimes think I am (2) ?
|
||||||
|
reasmb: goto what
|
||||||
|
decomp: * are *
|
||||||
|
reasmb: Did you think they might not be (2) ?
|
||||||
|
reasmb: Would you like it if they were not (2) ?
|
||||||
|
reasmb: What if they were not (2) ?
|
||||||
|
reasmb: Possibly they are (2).
|
||||||
|
key: your
|
||||||
|
decomp: * your *
|
||||||
|
reasmb: Why are you concerned over my (2) ?
|
||||||
|
reasmb: What about your own (2) ?
|
||||||
|
reasmb: Are you worried about someone else's (2) ?
|
||||||
|
reasmb: Really, my (2) ?
|
||||||
|
key: was 2
|
||||||
|
decomp: * was i *
|
||||||
|
reasmb: What if you were (2) ?
|
||||||
|
reasmb: Do you think you were (2) ?
|
||||||
|
reasmb: Were you (2) ?
|
||||||
|
reasmb: What would it mean if you were (2) ?
|
||||||
|
reasmb: What does (2) suggest to you ?
|
||||||
|
reasmb: goto what
|
||||||
|
decomp: * i was *
|
||||||
|
reasmb: Were you really ?
|
||||||
|
reasmb: Why do you tell me you were (2) now ?
|
||||||
|
reasmb: Perhaps I already know you were (2).
|
||||||
|
decomp: * was you *
|
||||||
|
reasmb: Would you like to believe I was (2) ?
|
||||||
|
reasmb: What suggests that I was (2) ?
|
||||||
|
reasmb: What do you think ?
|
||||||
|
reasmb: Perhaps I was (2).
|
||||||
|
reasmb: What if I had been (2) ?
|
||||||
|
key: i
|
||||||
|
decomp: * i @desire *
|
||||||
|
reasmb: What would it mean to you if you got (3) ?
|
||||||
|
reasmb: Why do you want (3) ?
|
||||||
|
reasmb: Suppose you got (3) soon ?
|
||||||
|
reasmb: What if you never got (3) ?
|
||||||
|
reasmb: What would getting (3) mean to you ?
|
||||||
|
reasmb: What does wanting (3) have to do with this discussion ?
|
||||||
|
decomp: * i am* @sad *
|
||||||
|
reasmb: I am sorry to hear that you are (3).
|
||||||
|
reasmb: Do you think that coming here will help you not to be (3) ?
|
||||||
|
reasmb: I'm sure it's not pleasant to be (3).
|
||||||
|
reasmb: Can you explain what made you (3) ?
|
||||||
|
decomp: * i am* @happy *
|
||||||
|
reasmb: How have I helped you to be (3) ?
|
||||||
|
reasmb: Has your treatment made you (3) ?
|
||||||
|
reasmb: What makes you (3) just now ?
|
||||||
|
reasmb: Can you explan why you are suddenly (3) ?
|
||||||
|
decomp: * i was *
|
||||||
|
reasmb: goto was
|
||||||
|
decomp: * i @belief * i *
|
||||||
|
reasmb: Do you really think so ?
|
||||||
|
reasmb: But you are not sure you (3).
|
||||||
|
reasmb: Do you really doubt you (3) ?
|
||||||
|
decomp: * i* @belief *you *
|
||||||
|
reasmb: goto you
|
||||||
|
decomp: * i am *
|
||||||
|
reasmb: Is it because you are (2) that you came to me ?
|
||||||
|
reasmb: How long have you been (2) ?
|
||||||
|
reasmb: Do you believe it is normal to be (2) ?
|
||||||
|
reasmb: Do you enjoy being (2) ?
|
||||||
|
decomp: * i @cannot *
|
||||||
|
reasmb: How do you think that you can't (3) ?
|
||||||
|
reasmb: Have you tried ?
|
||||||
|
reasmb: Perhaps you could (3) now.
|
||||||
|
reasmb: Do you really want to be able to (3) ?
|
||||||
|
decomp: * i don't *
|
||||||
|
reasmb: Don't you really (2) ?
|
||||||
|
reasmb: Why don't you (2) ?
|
||||||
|
reasmb: Do you wish to be able to (2) ?
|
||||||
|
reasmb: Does that trouble you ?
|
||||||
|
decomp: * do i feel *
|
||||||
|
reasmb: Tell me more about such feelings.
|
||||||
|
reasmb: Do you often feel (2) ?
|
||||||
|
reasmb: Do you enjoy feeling (2) ?
|
||||||
|
reasmb: Of what does feeling (2) remind you ?
|
||||||
|
decomp: * i * you *
|
||||||
|
reasmb: Perhaps in your fantasies we (2) each other.
|
||||||
|
reasmb: Do you wish to (2) me ?
|
||||||
|
reasmb: You seem to need to (2) me.
|
||||||
|
reasmb: Do you (2) anyone else ?
|
||||||
|
decomp: *
|
||||||
|
reasmb: You say (1) ?
|
||||||
|
reasmb: Can you elaborate on that ?
|
||||||
|
reasmb: Do you say (1) for some special reason ?
|
||||||
|
reasmb: That's quite interesting.
|
||||||
|
key: you
|
||||||
|
decomp: * you remind me of *
|
||||||
|
reasmb: goto alike
|
||||||
|
decomp: * you are *
|
||||||
|
reasmb: What makes you think I am (2) ?
|
||||||
|
reasmb: Does it please you to believe I am (2) ?
|
||||||
|
reasmb: Do you sometimes wish you were (2) ?
|
||||||
|
reasmb: Perhaps you would like to be (2).
|
||||||
|
decomp: * you* me *
|
||||||
|
reasmb: Why do you think I (2) you ?
|
||||||
|
reasmb: You like to think I (2) you -- don't you ?
|
||||||
|
reasmb: What makes you think I (2) you ?
|
||||||
|
reasmb: Really, I (2) you ?
|
||||||
|
reasmb: Do you wish to believe I (2) you ?
|
||||||
|
reasmb: Suppose I did (2) you -- what would that mean ?
|
||||||
|
reasmb: Does someone else believe I (2) you ?
|
||||||
|
decomp: * you *
|
||||||
|
reasmb: We were discussing you -- not me.
|
||||||
|
reasmb: Oh, I (2) ?
|
||||||
|
reasmb: You're not really talking about me -- are you ?
|
||||||
|
reasmb: What are your feelings now ?
|
||||||
|
key: yes
|
||||||
|
decomp: *
|
||||||
|
reasmb: You seem to be quite positive.
|
||||||
|
reasmb: You are sure.
|
||||||
|
reasmb: I see.
|
||||||
|
reasmb: I understand.
|
||||||
|
key: no
|
||||||
|
decomp: *
|
||||||
|
reasmb: Are you saying no just to be negative?
|
||||||
|
reasmb: You are being a bit negative.
|
||||||
|
reasmb: Why not ?
|
||||||
|
reasmb: Why 'no' ?
|
||||||
|
key: my 2
|
||||||
|
decomp: $ * my *
|
||||||
|
reasmb: Lets discuss further why your (2).
|
||||||
|
reasmb: Earlier you said your (2).
|
||||||
|
reasmb: But your (2).
|
||||||
|
reasmb: Does that have anything to do with the fact that your (2) ?
|
||||||
|
decomp: * my* @family *
|
||||||
|
reasmb: Tell me more about your family.
|
||||||
|
reasmb: Who else in your family (4) ?
|
||||||
|
reasmb: Your (3) ?
|
||||||
|
reasmb: What else comes to mind when you think of your (3) ?
|
||||||
|
decomp: * my *
|
||||||
|
reasmb: Your (2) ?
|
||||||
|
reasmb: Why do you say your (2) ?
|
||||||
|
reasmb: Does that suggest anything else which belongs to you ?
|
||||||
|
reasmb: Is it important that your (2) ?
|
||||||
|
key: can
|
||||||
|
decomp: * can you *
|
||||||
|
reasmb: You believe I can (2) don't you ?
|
||||||
|
reasmb: goto what
|
||||||
|
reasmb: You want me to be able to (2).
|
||||||
|
reasmb: Perhaps you would like to be able to (2) yourself.
|
||||||
|
decomp: * can i *
|
||||||
|
reasmb: Whether or not you can (2) depends on you more than me.
|
||||||
|
reasmb: Do you want to be able to (2) ?
|
||||||
|
reasmb: Perhaps you don't want to (2).
|
||||||
|
reasmb: goto what
|
||||||
|
key: what
|
||||||
|
decomp: *
|
||||||
|
reasmb: Why do you ask ?
|
||||||
|
reasmb: Does that question interest you ?
|
||||||
|
reasmb: What is it you really wanted to know ?
|
||||||
|
reasmb: Are such questions much on your mind ?
|
||||||
|
reasmb: What answer would please you most ?
|
||||||
|
reasmb: What do you think ?
|
||||||
|
reasmb: What comes to mind when you ask that ?
|
||||||
|
reasmb: Have you asked such questions before ?
|
||||||
|
reasmb: Have you asked anyone else ?
|
||||||
|
key: because
|
||||||
|
decomp: *
|
||||||
|
reasmb: Is that the real reason ?
|
||||||
|
reasmb: Don't any other reasons come to mind ?
|
||||||
|
reasmb: Does that reason seem to explain anything else ?
|
||||||
|
reasmb: What other reasons might there be ?
|
||||||
|
key: why
|
||||||
|
decomp: * why don't you *
|
||||||
|
reasmb: Do you believe I don't (2) ?
|
||||||
|
reasmb: Perhaps I will (2) in good time.
|
||||||
|
reasmb: Should you (2) yourself ?
|
||||||
|
reasmb: You want me to (2) ?
|
||||||
|
reasmb: goto what
|
||||||
|
decomp: * why can't i *
|
||||||
|
reasmb: Do you think you should be able to (2) ?
|
||||||
|
reasmb: Do you want to be able to (2) ?
|
||||||
|
reasmb: Do you believe this will help you to (2) ?
|
||||||
|
reasmb: Have you any idea why you can't (2) ?
|
||||||
|
reasmb: goto what
|
||||||
|
decomp: *
|
||||||
|
reasmb: goto what
|
||||||
|
key: everyone 2
|
||||||
|
decomp: * @everyone *
|
||||||
|
reasmb: Realy, (2) ?
|
||||||
|
reasmb: Surely not (2).
|
||||||
|
reasmb: Can you think of anyone in particular ?
|
||||||
|
reasmb: Who, for example?
|
||||||
|
reasmb: Are you thinking of a very special person ?
|
||||||
|
reasmb: Who, may I ask ?
|
||||||
|
reasmb: Someone special perhaps ?
|
||||||
|
reasmb: You have a particular person in mind, don't you ?
|
||||||
|
reasmb: Who do you think you're talking about ?
|
||||||
|
key: everybody 2
|
||||||
|
decomp: *
|
||||||
|
reasmb: goto everyone
|
||||||
|
key: nobody 2
|
||||||
|
decomp: *
|
||||||
|
reasmb: goto everyone
|
||||||
|
key: noone 2
|
||||||
|
decomp: *
|
||||||
|
reasmb: goto everyone
|
||||||
|
key: always 1
|
||||||
|
decomp: *
|
||||||
|
reasmb: Can you think of a specific example ?
|
||||||
|
reasmb: When ?
|
||||||
|
reasmb: What incident are you thinking of ?
|
||||||
|
reasmb: Really, always ?
|
||||||
|
key: alike 10
|
||||||
|
decomp: *
|
||||||
|
reasmb: In what way ?
|
||||||
|
reasmb: What resemblence do you see ?
|
||||||
|
reasmb: What does that similarity suggest to you ?
|
||||||
|
reasmb: What other connections do you see ?
|
||||||
|
reasmb: What do you suppose that resemblence means ?
|
||||||
|
reasmb: What is the connection, do you suppose ?
|
||||||
|
reasmb: Could here really be some connection ?
|
||||||
|
reasmb: How ?
|
||||||
|
key: like 10
|
||||||
|
decomp: * @be *like *
|
||||||
|
reasmb: goto alike
|
||||||
|
|
@ -0,0 +1,191 @@
|
|||||||
|
function chatbot (rules, textarea, display, debug) {
|
||||||
|
function process_rules (rules) {
|
||||||
|
function looping_iterator (l) {
|
||||||
|
var next = function () {
|
||||||
|
var ret = l[next.i];
|
||||||
|
if (++next.i >= l.length) { next.i = 0 };
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
next.length = l.length;
|
||||||
|
next.i = 0;
|
||||||
|
next.items = l;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
// index pre + post and tokenize results
|
||||||
|
function _index (name) {
|
||||||
|
var new_value = {};
|
||||||
|
rules[name].forEach(function (x) {
|
||||||
|
var words = tokenize(x),
|
||||||
|
word = words.shift();
|
||||||
|
new_value[word] = words;
|
||||||
|
})
|
||||||
|
rules[name] = new_value;
|
||||||
|
}
|
||||||
|
_index("pre");
|
||||||
|
_index("post");
|
||||||
|
// index synonmys by first word
|
||||||
|
var new_synon = {};
|
||||||
|
rules.synon.forEach(function (x) {
|
||||||
|
var words = tokenize(x);
|
||||||
|
new_synon[words[0]] = words;
|
||||||
|
})
|
||||||
|
rules.synon = new_synon;
|
||||||
|
// index keywords by name
|
||||||
|
rules.keywords_by_token = {};
|
||||||
|
rules.keywords.forEach(function (x) {
|
||||||
|
// console.log("token", x.token);
|
||||||
|
rules.keywords_by_token[x.token] = x;
|
||||||
|
// wrap the rules
|
||||||
|
x.rules.forEach(function (r) {
|
||||||
|
// ensure list
|
||||||
|
if (!Array.isArray(r.reasmb)) { r.reasmb = [r.reasmb]; }
|
||||||
|
// wrap the reasmb list in a looping iterator that perserves its state
|
||||||
|
r.reasmb = looping_iterator(r.reasmb);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// console.log("keywords_by_token", rules.keywords_by_token)
|
||||||
|
}
|
||||||
|
// function trim (text) { return text.replace(/\s+$/, "").replace(/\s+/, ""); }
|
||||||
|
function trimword (text) {
|
||||||
|
return text
|
||||||
|
.replace(/[^a-zA-Zéèàöùç]+$/, "")
|
||||||
|
.replace(/^[^a-zA-Zéèàöùç]+/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function tokenize (text) {
|
||||||
|
return (trimword(text).split(/\s+/).map(trimword));
|
||||||
|
}
|
||||||
|
|
||||||
|
function sub (tokens, subst) {
|
||||||
|
for (var i=0, l=tokens.length; i<l; i++) {
|
||||||
|
var sub = subst[tokens[i].toLowerCase()];
|
||||||
|
if (sub) {
|
||||||
|
if (Array.isArray(sub)) {
|
||||||
|
Array.prototype.splice.apply(tokens, [i, 1].concat(sub));
|
||||||
|
i += (sub.length - 1);
|
||||||
|
} else {
|
||||||
|
tokens[i] = sub;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
function select_keywords (tokens) {
|
||||||
|
var ret = [];
|
||||||
|
for (var i=0, l=tokens.length; i<l; i++) {
|
||||||
|
var w = tokens[i].toLowerCase(),
|
||||||
|
rule = rules.keywords_by_token[w];
|
||||||
|
if (rule) { ret.push(rule); }
|
||||||
|
}
|
||||||
|
if (rules.keywords_by_token.xnone && rules.keywords_by_token.xnone.weight != 0) {
|
||||||
|
// append xnone rule pre-sort
|
||||||
|
ret.push(rules.keywords_by_token.xnone);
|
||||||
|
}
|
||||||
|
ret.sort(function (a, b) { return b.weight - a.weight });
|
||||||
|
if (rules.keywords_by_token.xnone && rules.keywords_by_token.xnone.weight == 0) {
|
||||||
|
// append xnone rule post-sort (ensuring it's last)
|
||||||
|
ret.push(rules.keywords_by_token.xnone);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
function compile_pattern (pattern) {
|
||||||
|
// compile a decomposition pattern
|
||||||
|
// * i @cannot * ==> i(cannot|cant|...)(.+)
|
||||||
|
// * i* @belief *you * ==> (belief|feel|think|believe|wish)
|
||||||
|
// * i @belief i *
|
||||||
|
var ret = pattern
|
||||||
|
.replace(/ *\* */g, "*") // compact spaces around stars
|
||||||
|
.replace(/\*/g, "(.*?)")
|
||||||
|
.replace(/@(\w+)/, function (match, word) {
|
||||||
|
var syn = rules.synon[word.toLowerCase()];
|
||||||
|
if (syn) {
|
||||||
|
return "("+syn.join("|")+")";
|
||||||
|
} else {
|
||||||
|
console.log("Missing @synonym", word);
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return "^"+ret+"$";
|
||||||
|
}
|
||||||
|
function match_decomp (pattern, tokens) {
|
||||||
|
var ppat = compile_pattern(pattern);
|
||||||
|
// console.log("compile_pattern.in", pattern);
|
||||||
|
// console.log("compile_pattern.out", ppat);
|
||||||
|
var ppat = new RegExp(ppat, "i");
|
||||||
|
return ppat.exec(tokens.join(" "));
|
||||||
|
}
|
||||||
|
function do_post (txt) {
|
||||||
|
var tokens = tokenize(txt);
|
||||||
|
tokens = sub(tokens, rules.post);
|
||||||
|
return tokens.join(" ");
|
||||||
|
}
|
||||||
|
function do_reasmb (reasmb, match, tokens) {
|
||||||
|
if (Array.isArray(match)) {
|
||||||
|
return reasmb.replace(/\((\d+)\)/, function (m, n) {
|
||||||
|
// console.log("replace", m, n);
|
||||||
|
var ret = match[parseInt(n)];
|
||||||
|
return do_post(ret); // apply POST substitutions here to matching input
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return reasmb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function apply_keywords (keywords, tokens) {
|
||||||
|
for (var i=0, l=keywords.length; i<l; i++) {
|
||||||
|
var keyword = keywords[i];
|
||||||
|
while (true) {
|
||||||
|
console.log("trying keyword", keyword.token);
|
||||||
|
for (var ri=0, rl = keyword.rules.length; ri<rl; ri++) {
|
||||||
|
var rule = keyword.rules[ri];
|
||||||
|
console.log("trying rule", rule.decomp, "("+(ri+1)+"/"+rl+")");
|
||||||
|
var match = match_decomp(rule.decomp, tokens);
|
||||||
|
if (match) {
|
||||||
|
var ra = rule.reasmb();
|
||||||
|
if (ra.indexOf("goto ") == 0) {
|
||||||
|
var goto_name = ra.substr(5);
|
||||||
|
console.log("goto", goto_name);
|
||||||
|
keyword = rules.keywords_by_token[goto_name]
|
||||||
|
} else {
|
||||||
|
console.log("match", match, ra);
|
||||||
|
return do_reasmb(ra, match, tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function log (msg, kls) {
|
||||||
|
var d = document.createElement("div");
|
||||||
|
d.setAttribute("class", kls);
|
||||||
|
d.innerHTML = msg;
|
||||||
|
display.appendChild(d);
|
||||||
|
}
|
||||||
|
function say (msg) {
|
||||||
|
log(msg, "bot");
|
||||||
|
}
|
||||||
|
|
||||||
|
function process (text) {
|
||||||
|
if (debug) { console.log("input", text); }
|
||||||
|
var tokens = tokenize(text);
|
||||||
|
if (debug) { console.log("tokens", tokens); }
|
||||||
|
tokens = sub(tokens, rules.pre);
|
||||||
|
if (debug) { console.log("pre", tokens); }
|
||||||
|
var keywords = select_keywords(tokens);
|
||||||
|
if (debug) { console.log("keywords", keywords.map(function (x) { return x.token })); }
|
||||||
|
var output = apply_keywords(keywords, tokens);
|
||||||
|
if (debug) { console.log("output", output); }
|
||||||
|
say(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
process_rules(rules);
|
||||||
|
textarea.addEventListener("keypress", function (event) {
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
var text = textarea.value;
|
||||||
|
log(text, "user");
|
||||||
|
process(text);
|
||||||
|
textarea.value = "";
|
||||||
|
textarea.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
say(rules.initial);
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
"""
|
||||||
|
key: remember 5
|
||||||
|
decomp: * i remember *
|
||||||
|
reasmb: Do you often think of (2) ?
|
||||||
|
reasmb: Does thinking of (2) bring anything else to mind ?
|
||||||
|
reasmb: What else do you recollect ?
|
||||||
|
reasmb: Why do you remember (2) just now ?
|
||||||
|
reasmb: What in the present situation reminds you of (2) ?
|
||||||
|
reasmb: What is the connection between me and (2) ?
|
||||||
|
reasmb: What else does (2) remind you of ?
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
output = {}
|
||||||
|
output['pre'] = pre = []
|
||||||
|
output['post'] = post = []
|
||||||
|
output['synon'] = synon = []
|
||||||
|
output['quit'] = quit = []
|
||||||
|
output['keywords'] = keys = []
|
||||||
|
for line in sys.stdin:
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("#") or not line:
|
||||||
|
continue
|
||||||
|
cmd, rest = line.split(" ", 1)
|
||||||
|
cmd = cmd.strip()
|
||||||
|
rest = rest.strip()
|
||||||
|
if cmd == "initial:":
|
||||||
|
output['initial'] = rest
|
||||||
|
elif cmd == "final:":
|
||||||
|
output['final'] = rest
|
||||||
|
elif cmd == "pre:":
|
||||||
|
pre.append(rest)
|
||||||
|
elif cmd == "post:":
|
||||||
|
post.append(rest)
|
||||||
|
elif cmd == "synon:":
|
||||||
|
synon.append(rest)
|
||||||
|
elif cmd == "key:":
|
||||||
|
try:
|
||||||
|
token, weight = rest.split()
|
||||||
|
except ValueError:
|
||||||
|
token = rest.strip()
|
||||||
|
weight = 0
|
||||||
|
print ("key", token, int(weight), file=sys.stderr)
|
||||||
|
keys.append({"token": token.strip(), "weight": int(weight), "rules": []})
|
||||||
|
elif line.startswith("decomp:"):
|
||||||
|
_, pattern = line.split(" ", 1)
|
||||||
|
print ("decomp", pattern, file=sys.stderr)
|
||||||
|
keys[-1]['rules'].append({"decomp": pattern.strip(), "reasmb": []})
|
||||||
|
elif line.startswith("reasmb:"):
|
||||||
|
_, pattern = line.split(" ", 1)
|
||||||
|
print ("reasmb", pattern, file=sys.stderr)
|
||||||
|
keys[-1]['rules'][-1]['reasmb'].append(pattern.strip())
|
||||||
|
# out = {}
|
||||||
|
# keywords = out['keywords'] = {}
|
||||||
|
# for obj in keys:
|
||||||
|
# keyname = obj.get("token")
|
||||||
|
# del obj['token']
|
||||||
|
# keywords[keyname] = obj
|
||||||
|
import json
|
||||||
|
print (json.dumps(output, indent=2))
|
@ -0,0 +1,64 @@
|
|||||||
|
How Eliza Works
|
||||||
|
|
||||||
|
All the behavior of Eliza is controlled by a script file.
|
||||||
|
The standard script is attached to the end of this explanation.
|
||||||
|
|
||||||
|
Eliza starts by reading the script file. Because of Java security, it
|
||||||
|
must be on the same server as the class files. Eliza then reads a line at
|
||||||
|
a time from the user, processes it, and formulates a reply.
|
||||||
|
|
||||||
|
Processing consists of the following steps.
|
||||||
|
First the sentence broken down into words, separated by spaces. All further
|
||||||
|
processing takes place on these words as a whole, not on the individual
|
||||||
|
characters in them.
|
||||||
|
Second, a set of pre-substitutions takes place.
|
||||||
|
Third, Eliza takes all the words in the sentence and makes a list of all
|
||||||
|
keywords it finds. It sorts this keyword list in descending weight. It
|
||||||
|
process these keywords until it produces an output.
|
||||||
|
Fourth, for the given keyword, a list of decomposition patterns is searched.
|
||||||
|
The first one that matches is selected. If no match is found, the next keyword
|
||||||
|
is selected instead.
|
||||||
|
Fifth, for the matching decomposition pattern, a reassembly pattern is
|
||||||
|
selected. There may be several reassembly patterns, but only one is used
|
||||||
|
for a given sentence. If a subsequent sentence selects the same decomposition
|
||||||
|
pattern, the next reassembly pattern in sequence is used, until they have all
|
||||||
|
been used, at which point Eliza starts over with the first reassembly pattern.
|
||||||
|
Sixth, a set of post-substitutions takes place.
|
||||||
|
Finally, the resulting sentence is displayed as output.
|
||||||
|
|
||||||
|
The script is used to construct the pre and post substitution lists, the
|
||||||
|
keyword lists, and the decomposition and reassembly patterns.
|
||||||
|
In addition, there is a synonym matching facility, which is explained below.
|
||||||
|
|
||||||
|
Every line of script is prefaced by a tag that tells what list it is
|
||||||
|
part of. Here is an explanation of the tags.
|
||||||
|
|
||||||
|
initial: Eliza says this when it starts.
|
||||||
|
final: Eliza says this when it quits.
|
||||||
|
quit: If the input is this, then Eliza quits. Any number permitted.
|
||||||
|
pre: Part of the pre-substitution list. If the first word appears in
|
||||||
|
the sentence, it is replaced by the rest of the words.
|
||||||
|
post: Part of the post-subsititution list. If the first word appears
|
||||||
|
in the sentence, it is replaced by the rest of the words.
|
||||||
|
key: A keyword. Keywords with greater weight are selected in
|
||||||
|
preference to ones with lesser weight.
|
||||||
|
If no weight is given, it is assumed to be 1.
|
||||||
|
decomp: A decomposition pattern. The character * stands for any
|
||||||
|
sequence of words.
|
||||||
|
reasmb: A reassembly pattern. A set of words matched by * in
|
||||||
|
the decomposition pattern can be used as part of the reassembly.
|
||||||
|
For instance, (2) inserts the words matched by the second *
|
||||||
|
in the decomposition pattern.
|
||||||
|
synon: A list of synonyms. In a decomposition rule, for instance, @be
|
||||||
|
matches any of the words "be am is are was" because of the line:
|
||||||
|
"synon: be am is are was". The match @be also counts as a *
|
||||||
|
in numbering the matches for use by reassembly rules.
|
||||||
|
|
||||||
|
Other Special Rules
|
||||||
|
If a $ appears first in a decomposition rule, then the output is formed as
|
||||||
|
normal, but is saved and Eliza goes on to the next keyword. If no keywords
|
||||||
|
match, and there are saved sentences, one of them is picked at random and
|
||||||
|
used as the output, then it is discarded.
|
||||||
|
If there are no saved sentences, and no keywords match, then it uses the
|
||||||
|
keyword "xnone".
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import print_function
|
||||||
|
import json, sys, argparse
|
||||||
|
|
||||||
|
ap = argparse.ArgumentParser("wrap JSON in either a variable declaration (hardcode) or a callback (JSONP).")
|
||||||
|
ap.add_argument("--variable", default="weft", help="define a variable")
|
||||||
|
ap.add_argument("--callback", help="use a named callback (JSONP) -- overrides --variable")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
if args.callback:
|
||||||
|
print ("{0}({1});".format(args.callback, json.dumps(d)))
|
||||||
|
else:
|
||||||
|
print ("{0} = {1};".format(args.variable, json.dumps(d)))
|
Loading…
Reference in New Issue