From d8d232077ea07852f6e627a78c1139d90c37b97a Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Thu, 6 Aug 2020 17:09:50 +0100 Subject: [PATCH] Converted to use json for rules instead of yaml --- eliza.ipynb | 318 +++++++++++++++++++----------------------------- eliza.py | 23 +++- rules.json | 342 ++++++++++++++++++++++++++++++++++++++++++++++++++++ rules.yaml | 2 +- 4 files changed, 488 insertions(+), 197 deletions(-) create mode 100644 rules.json diff --git a/eliza.ipynb b/eliza.ipynb index 7a6da3c..312bc8a 100644 --- a/eliza.ipynb +++ b/eliza.ipynb @@ -2,23 +2,20 @@ "cells": [ { "cell_type": "code", - "execution_count": 100, - "metadata": { - "collapsed": true - }, + "execution_count": 51, + "metadata": {}, "outputs": [], "source": [ - "import yaml\n", + "# import yaml\n", + "import json\n", "import collections\n", "import random" ] }, { "cell_type": "code", - "execution_count": 84, - "metadata": { - "collapsed": false - }, + "execution_count": 52, + "metadata": {}, "outputs": [], "source": [ "Match = collections.namedtuple('Match', 'text, rule, bindings')" @@ -26,10 +23,25 @@ }, { "cell_type": "code", - "execution_count": 169, - "metadata": { - "collapsed": false - }, + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "# def read_rules_y(rules_file):\n", + "# with open(rules_file) as f:\n", + "# rules = [{'pattern': r['pattern'].split(),\n", + "# 'responses': [t.split() for t in r['responses']]}\n", + "# for r in yaml.safe_load(f)]\n", + "# return rules\n", + "\n", + "# all_rules_y = read_rules_y('rules.yaml')\n", + "# all_rules_y" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, "outputs": [ { "data": { @@ -173,7 +185,7 @@ " [\"i'm\", 'sure', \"it's\", 'not', 'pleasant', 'to', 'be', 'unhappy']]},\n", " {'pattern': ['?X', 'are', 'like', '?Y'],\n", " 'responses': [['what',\n", - " 'resemblence',\n", + " 'resemblance',\n", " 'do',\n", " 'you',\n", " 'see',\n", @@ -310,7 +322,7 @@ " 'things']]}]" ] }, - "execution_count": 169, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } @@ -320,34 +332,32 @@ " with open(rules_file) as f:\n", " rules = [{'pattern': r['pattern'].split(),\n", " 'responses': [t.split() for t in r['responses']]}\n", - " for r in yaml.load(f)]\n", + " for r in json.load(f)]\n", " return rules\n", "\n", - "all_rules = read_rules('rules.yaml')\n", + "all_rules = read_rules('rules.json')\n", "all_rules" ] }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, + "execution_count": 55, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "> tom dick harry\n" + "> hello there\n" ] }, { "data": { "text/plain": [ - "['tom', 'dick', 'harry']" + "['hello', 'there']" ] }, - "execution_count": 4, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } @@ -359,10 +369,8 @@ }, { "cell_type": "code", - "execution_count": 102, - "metadata": { - "collapsed": true - }, + "execution_count": 56, + "metadata": {}, "outputs": [], "source": [ "def match(text, rule):\n", @@ -371,10 +379,8 @@ }, { "cell_type": "code", - "execution_count": 240, - "metadata": { - "collapsed": true - }, + "execution_count": 57, + "metadata": {}, "outputs": [], "source": [ "def all_matches(matches):\n", @@ -393,10 +399,8 @@ }, { "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": true - }, + "execution_count": 58, + "metadata": {}, "outputs": [], "source": [ "def is_var(word):\n", @@ -405,10 +409,8 @@ }, { "cell_type": "code", - "execution_count": 23, - "metadata": { - "collapsed": true - }, + "execution_count": 59, + "metadata": {}, "outputs": [], "source": [ "def successful_match(match):\n", @@ -417,10 +419,8 @@ }, { "cell_type": "code", - "execution_count": 24, - "metadata": { - "collapsed": true - }, + "execution_count": 60, + "metadata": {}, "outputs": [], "source": [ "def splits(item):\n", @@ -429,10 +429,8 @@ }, { "cell_type": "code", - "execution_count": 25, - "metadata": { - "collapsed": false - }, + "execution_count": 61, + "metadata": {}, "outputs": [ { "data": { @@ -445,7 +443,7 @@ " ('harry', '')]" ] }, - "execution_count": 25, + "execution_count": 61, "metadata": {}, "output_type": "execute_result" } @@ -456,10 +454,8 @@ }, { "cell_type": "code", - "execution_count": 236, - "metadata": { - "collapsed": true - }, + "execution_count": 62, + "metadata": {}, "outputs": [], "source": [ "def match_item(text, rule, bindings):\n", @@ -487,10 +483,8 @@ }, { "cell_type": "code", - "execution_count": 213, - "metadata": { - "collapsed": false - }, + "execution_count": 63, + "metadata": {}, "outputs": [ { "data": { @@ -498,7 +492,7 @@ "[{'?X': ['fred'], '?Y': ['jane']}]" ] }, - "execution_count": 213, + "execution_count": 63, "metadata": {}, "output_type": "execute_result" } @@ -509,10 +503,8 @@ }, { "cell_type": "code", - "execution_count": 214, - "metadata": { - "collapsed": false - }, + "execution_count": 64, + "metadata": {}, "outputs": [ { "data": { @@ -520,7 +512,7 @@ "[{'?X': [], '?Y': ['jane']}]" ] }, - "execution_count": 214, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" } @@ -531,10 +523,8 @@ }, { "cell_type": "code", - "execution_count": 215, - "metadata": { - "collapsed": false - }, + "execution_count": 65, + "metadata": {}, "outputs": [ { "data": { @@ -542,7 +532,7 @@ "[{'?X': ['fred'], '?Y': []}]" ] }, - "execution_count": 215, + "execution_count": 65, "metadata": {}, "output_type": "execute_result" } @@ -553,10 +543,8 @@ }, { "cell_type": "code", - "execution_count": 216, - "metadata": { - "collapsed": false - }, + "execution_count": 66, + "metadata": {}, "outputs": [ { "data": { @@ -564,7 +552,7 @@ "[{'?X': [], '?Y': []}]" ] }, - "execution_count": 216, + "execution_count": 66, "metadata": {}, "output_type": "execute_result" } @@ -575,10 +563,8 @@ }, { "cell_type": "code", - "execution_count": 217, - "metadata": { - "collapsed": false - }, + "execution_count": 67, + "metadata": {}, "outputs": [ { "data": { @@ -586,7 +572,7 @@ "[]" ] }, - "execution_count": 217, + "execution_count": 67, "metadata": {}, "output_type": "execute_result" } @@ -597,10 +583,8 @@ }, { "cell_type": "code", - "execution_count": 218, - "metadata": { - "collapsed": false - }, + "execution_count": 68, + "metadata": {}, "outputs": [ { "data": { @@ -608,7 +592,7 @@ "[{'?X': ['fred']}]" ] }, - "execution_count": 218, + "execution_count": 68, "metadata": {}, "output_type": "execute_result" } @@ -619,10 +603,8 @@ }, { "cell_type": "code", - "execution_count": 219, - "metadata": { - "collapsed": false - }, + "execution_count": 69, + "metadata": {}, "outputs": [ { "data": { @@ -630,7 +612,7 @@ "[]" ] }, - "execution_count": 219, + "execution_count": 69, "metadata": {}, "output_type": "execute_result" } @@ -641,10 +623,8 @@ }, { "cell_type": "code", - "execution_count": 220, - "metadata": { - "collapsed": false - }, + "execution_count": 70, + "metadata": {}, "outputs": [ { "data": { @@ -652,7 +632,7 @@ "[{'?X': ['yes'], '?Y': ['rain']}]" ] }, - "execution_count": 220, + "execution_count": 70, "metadata": {}, "output_type": "execute_result" } @@ -663,10 +643,8 @@ }, { "cell_type": "code", - "execution_count": 221, - "metadata": { - "collapsed": false - }, + "execution_count": 71, + "metadata": {}, "outputs": [ { "data": { @@ -674,7 +652,7 @@ "[{'?X': ['no'], '?Y': ['rain']}]" ] }, - "execution_count": 221, + "execution_count": 71, "metadata": {}, "output_type": "execute_result" } @@ -685,10 +663,8 @@ }, { "cell_type": "code", - "execution_count": 222, - "metadata": { - "collapsed": false - }, + "execution_count": 72, + "metadata": {}, "outputs": [ { "data": { @@ -696,7 +672,7 @@ "[]" ] }, - "execution_count": 222, + "execution_count": 72, "metadata": {}, "output_type": "execute_result" } @@ -707,10 +683,8 @@ }, { "cell_type": "code", - "execution_count": 223, - "metadata": { - "collapsed": false - }, + "execution_count": 73, + "metadata": {}, "outputs": [ { "data": { @@ -718,7 +692,7 @@ "[{'?X': [], '?Y': ['rain']}]" ] }, - "execution_count": 223, + "execution_count": 73, "metadata": {}, "output_type": "execute_result" } @@ -729,9 +703,8 @@ }, { "cell_type": "code", - "execution_count": 241, + "execution_count": 74, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -742,7 +715,7 @@ " {'?X': ['hello'], '?Y': ['there']}]" ] }, - "execution_count": 241, + "execution_count": 74, "metadata": {}, "output_type": "execute_result" } @@ -753,9 +726,8 @@ }, { "cell_type": "code", - "execution_count": 242, + "execution_count": 75, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -765,7 +737,7 @@ "[{'?X': ['hello']}]" ] }, - "execution_count": 242, + "execution_count": 75, "metadata": {}, "output_type": "execute_result" } @@ -776,10 +748,8 @@ }, { "cell_type": "code", - "execution_count": 244, - "metadata": { - "collapsed": false - }, + "execution_count": 76, + "metadata": {}, "outputs": [ { "data": { @@ -790,7 +760,7 @@ " {'?X': ['hello', 'hello', 'hello'], '?Y': []}]" ] }, - "execution_count": 244, + "execution_count": 76, "metadata": {}, "output_type": "execute_result" } @@ -801,10 +771,8 @@ }, { "cell_type": "code", - "execution_count": 245, - "metadata": { - "collapsed": false - }, + "execution_count": 77, + "metadata": {}, "outputs": [ { "data": { @@ -813,7 +781,7 @@ " {'?X': ['hello'], '?Y': ['hello']}]" ] }, - "execution_count": 245, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } @@ -824,10 +792,8 @@ }, { "cell_type": "code", - "execution_count": 196, - "metadata": { - "collapsed": true - }, + "execution_count": 78, + "metadata": {}, "outputs": [], "source": [ "def candidate_rules(rules, comment):\n", @@ -838,9 +804,8 @@ }, { "cell_type": "code", - "execution_count": 197, + "execution_count": 79, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -888,7 +853,7 @@ " {'?X': ['i', 'remember', 'rain']})]" ] }, - "execution_count": 197, + "execution_count": 79, "metadata": {}, "output_type": "execute_result" } @@ -899,10 +864,8 @@ }, { "cell_type": "code", - "execution_count": 198, - "metadata": { - "collapsed": true - }, + "execution_count": 80, + "metadata": {}, "outputs": [], "source": [ "def fill(response, bindings):\n", @@ -920,10 +883,8 @@ }, { "cell_type": "code", - "execution_count": 202, - "metadata": { - "collapsed": false - }, + "execution_count": 81, + "metadata": {}, "outputs": [ { "data": { @@ -931,7 +892,7 @@ "'do you often think of rain'" ] }, - "execution_count": 202, + "execution_count": 81, "metadata": {}, "output_type": "execute_result" } @@ -944,10 +905,8 @@ }, { "cell_type": "code", - "execution_count": 165, - "metadata": { - "collapsed": true - }, + "execution_count": 82, + "metadata": {}, "outputs": [], "source": [ "pronoun_swaps = {\n", @@ -973,10 +932,8 @@ }, { "cell_type": "code", - "execution_count": 166, - "metadata": { - "collapsed": false - }, + "execution_count": 83, + "metadata": {}, "outputs": [ { "data": { @@ -984,7 +941,7 @@ "{'?X': ['your', 'father'], '?Y': ['you', 'are', 'your', 'brother', 'keeper']}" ] }, - "execution_count": 166, + "execution_count": 83, "metadata": {}, "output_type": "execute_result" } @@ -995,10 +952,8 @@ }, { "cell_type": "code", - "execution_count": 101, - "metadata": { - "collapsed": true - }, + "execution_count": 84, + "metadata": {}, "outputs": [], "source": [ "def respond(rule, bindings):\n", @@ -1007,18 +962,16 @@ }, { "cell_type": "code", - "execution_count": 231, - "metadata": { - "collapsed": false - }, + "execution_count": 85, + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "['why', 'do', 'you', 'recall', 'rain', 'right', 'now']" + "['what', 'is', 'the', 'connection', 'between', 'me', 'and', 'rain']" ] }, - "execution_count": 231, + "execution_count": 85, "metadata": {}, "output_type": "execute_result" } @@ -1030,10 +983,8 @@ }, { "cell_type": "code", - "execution_count": 167, - "metadata": { - "collapsed": false - }, + "execution_count": 86, + "metadata": {}, "outputs": [], "source": [ "def eliza_loop():\n", @@ -1049,9 +1000,8 @@ }, { "cell_type": "code", - "execution_count": 168, + "execution_count": 87, "metadata": { - "collapsed": false, "scrolled": true }, "outputs": [ @@ -1060,27 +1010,15 @@ "output_type": "stream", "text": [ "Hello. I'm Eliza. What seems to be the problem?\n", - "> this is weird\n", - "i am not sure i understand you fully\n", - "> i love my father\n", - "your father\n", - "> yes, my father\n", - "what else comes to mind when you think of your father\n", - "> i remember my father\n", - "does thinking of your father bring anything else to mind\n", - "> i remember i am a saint\n", - "does thinking of you are a saint bring anything else to mind\n", - "> saints are always happy\n", - "really -- always\n", - "> yes, always\n", - "can you think of a specific example\n", - "> saint george was happy when he killed the dragon\n", - "go on\n", - "> i don't think you understand me\n", - "perhaps in your fantasies we don't think each other\n", - "> i aardvark you understand me\n", - "perhaps in your fantasies we aardvark each other\n", - "> exit\n" + "> hello\n", + "how do you do. please state your problem\n", + "> i am sad about life\n", + "i'm sure it's not pleasant to be sad\n", + "> it isn't\n", + "very interesting\n", + "> are you happy\n", + "perhaps i am happy in your fantasies\n", + "> quit\n" ] } ], @@ -1091,9 +1029,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [] } @@ -1114,9 +1050,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.2+" + "version": "3.7.4" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/eliza.py b/eliza.py index 2a3e04c..c86f3f3 100644 --- a/eliza.py +++ b/eliza.py @@ -1,6 +1,7 @@ # coding: utf-8 -import yaml +#import yaml +import json import collections import random @@ -11,14 +12,26 @@ pronoun_swaps = { 'me': 'you', 'my': 'your', 'mine': 'yours', - 'am': 'are' + 'am': 'are', + 'you': 'i', + 'your': 'my', + 'yours': 'mine' } +halt_words = 'quit halt exit stop'.split() + +# def read_rules(rules_file): +# with open(rules_file) as f: +# rules = [{'pattern': r['pattern'].split(), +# 'responses': [t.split() for t in r['responses']]} +# for r in yaml.safe_load(f)] +# return rules + def read_rules(rules_file): with open(rules_file) as f: rules = [{'pattern': r['pattern'].split(), 'responses': [t.split() for t in r['responses']]} - for r in yaml.load(f)] + for r in json.load(f)] return rules def is_var(word): @@ -108,14 +121,14 @@ def eliza_loop(rules): print("Hello. I'm Eliza. What seems to be the problem?") while True: c = input("> ") - if c.strip() in 'quit halt exit stop'.split(): break + if c.strip() in halt_words: break comment = c.split() rule, bindings = candidate_rules(rules, comment)[0] swapped_bindings = pronoun_person_swap(bindings) print(' '.join(respond(rule, swapped_bindings))) -all_rules = read_rules('rules.yaml') +all_rules = read_rules('rules.json') eliza_loop(all_rules) diff --git a/rules.json b/rules.json new file mode 100644 index 0000000..6a893fb --- /dev/null +++ b/rules.json @@ -0,0 +1,342 @@ +[ + { + "pattern": "?X hello ?Y", + "responses": [ + "how do you do. please state your problem" + ] + }, + { + "pattern": "?X computer ?Y", + "responses": [ + "do computers worry you", + "what do you think about machines", + "why do you mention computers", + "what do you think machines have to do with your problem" + ] + }, + { + "pattern": "?X name ?Y", + "responses": [ + "i am not interested in names" + ] + }, + { + "pattern": "?X sorry ?Y", + "responses": [ + "please don't apologize", + "apologies are not necessary", + "what feelings do you have when you apologize" + ] + }, + { + "pattern": "?X i remember ?Y", + "responses": [ + "do you often think of ?Y", + "does thinking of ?Y bring anything else to mind", + "what else do you remember?", + "why do you recall ?Y right now", + "what in this present situation reminds you of ?Y", + "what is the connection between me and ?Y" + ] + }, + { + "pattern": "?X do you remember ?Y", + "responses": [ + "did you think i would forget ?Y", + "why do you think i should recall ?Y", + "what about ?Y", + "you mentioned ?Y" + ] + }, + { + "pattern": "?X if ?Y", + "responses": [ + "do you really think it is likely that ?Y", + "do you wish that ?Y", + "what do you think about ?Y", + "really -- if ?Y" + ] + }, + { + "pattern": "?X i dreamt ?Y", + "responses": [ + "really -- ?Y", + "have you ever fantasized ?Y while you were awake", + "have you dreamt ?Y before" + ] + }, + { + "pattern": "?X i dreamed ?Y", + "responses": [ + "really -- ?Y", + "have you ever fantasized ?Y while you were awake", + "have you dreamed ?Y before" + ] + }, + { + "pattern": "?X dream ?Y", + "responses": [ + "what does this dream suggest to you", + "do you dream often", + "what persons appear in your dreams", + "don't you believe that dream has to do with your problem" + ] + }, + { + "pattern": "?X my mother ?Y", + "responses": [ + "who else is in your family ?Y", + "tell me more about your family" + ] + }, + { + "pattern": "?X my father ?Y", + "responses": [ + "your father", + "does he influence you strongly", + "what else comes to mind when you think of your father" + ] + }, + { + "pattern": "?X i want ?Y", + "responses": [ + "what would it mean if you got ?Y", + "why do you want ?Y", + "suppose you got ?Y soon" + ] + }, + { + "pattern": "?X i am glad ?Y", + "responses": [ + "how have i helped you to be ?Y", + "what makes you happy just now", + "can you explain why you are suddenly ?Y" + ] + }, + { + "pattern": "?X i am happy ?Y", + "responses": [ + "how have i helped you to be ?Y", + "what makes you glad just now", + "can you explain why you are suddenly ?Y" + ] + }, + { + "pattern": "?X i am sad ?Y", + "responses": [ + "i am sorry to hear you are depressed", + "i'm sure it's not pleasant to be sad" + ] + }, + { + "pattern": "?X i am unhappy ?Y", + "responses": [ + "i am sorry to hear you are depressed", + "i'm sure it's not pleasant to be unhappy" + ] + }, + { + "pattern": "?X are like ?Y", + "responses": [ + "what resemblance do you see between ?X and ?Y" + ] + }, + { + "pattern": "?X is like ?Y", + "responses": [ + "in what way is it that ?X is like ?Y", + "what resemblence do you see", + "could there really be some connection", + "how" + ] + }, + { + "pattern": "?X alike ?Y", + "responses": [ + "in what way", + "what similarities are there" + ] + }, + { + "pattern": "?X same ?Y", + "responses": [ + "what other connections do you see" + ] + }, + { + "pattern": "?X i was ?Y", + "responses": [ + "were you really", + "perhaps i already knew you were ?Y", + "why do you tell me you were ?Y now" + ] + }, + { + "pattern": "?X was i ?Y", + "responses": [ + "what if you were ?Y", + "do you think you were ?Y", + "what would it mean if you were ?Y" + ] + }, + { + "pattern": "?X i am ?Y", + "responses": [ + "in what way are you ?Y", + "do you want to be ?Y" + ] + }, + { + "pattern": "?X am i ?Y", + "responses": [ + "do you believe you are ?Y", + "would you want to be ?Y", + "you wish i would tell you you are ?Y", + "what would it mean if you were ?Y" + ] + }, + { + "pattern": "?X am ?Y", + "responses": [ + "why do you say \"am\"", + "i don't understand that" + ] + }, + { + "pattern": "?X are you ?Y", + "responses": [ + "why are you interested in whether i am ?Y or not", + "would you prefer it if i weren't ?Y", + "perhaps i am ?Y in your fantasies" + ] + }, + { + "pattern": "?X you are ?Y", + "responses": [ + "what makes you think i am ?Y" + ] + }, + { + "pattern": "?X because ?Y", + "responses": [ + "is that the real reason", + "what other reason might there be", + "does that reason seem to explain anything else" + ] + }, + { + "pattern": "?X were you ?Y", + "responses": [ + "perhaps i was ?Y", + "what do you think", + "what if i had been ?Y" + ] + }, + { + "pattern": "?X i can't ?Y", + "responses": [ + "maybe you could ?Y now", + "what if you could ?Y" + ] + }, + { + "pattern": "?X i feel ?Y", + "responses": [ + "do you often feel ?Y" + ] + }, + { + "pattern": "?X i felt ?Y", + "responses": [ + "what other feelings do you have" + ] + }, + { + "pattern": "?X i ?Y you ?Z", + "responses": [ + "perhaps in your fantasies we ?Y each other" + ] + }, + { + "pattern": "?X why don't you ?Y", + "responses": [ + "should you ?Y yourself", + "do you believe i don't ?Y", + "perhaps i will ?Y in good time" + ] + }, + { + "pattern": "?X yes ?Y", + "responses": [ + "you seem quite positive", + "you are sure", + "i understand" + ] + }, + { + "pattern": "?X no ?Y", + "responses": [ + "why not", + "you are being a bit negative", + "are you saying \"no\" just to be negative" + ] + }, + { + "pattern": "?X someone ?Y", + "responses": [ + "can you be more specific" + ] + }, + { + "pattern": "?X everyone ?Y", + "responses": [ + "surely not everyone", + "can you think of anyone in particular", + "who for example", + "you are thinking of a special person" + ] + }, + { + "pattern": "?X always ?Y", + "responses": [ + "can you think of a specific example", + "when", + "what incident are you thinking of", + "really -- always" + ] + }, + { + "pattern": "?X what ?Y", + "responses": [ + "why do you ask", + "does that question interest you", + "what is it you really want to know", + "what do you think", + "what comes to your mind when you ask that" + ] + }, + { + "pattern": "?X perhaps ?Y", + "responses": [ + "you do not seem quite certain" + ] + }, + { + "pattern": "?X are ?Y", + "responses": [ + "do you think they might not be ?Y", + "possibly they are ?Y" + ] + }, + { + "pattern": "?X", + "responses": [ + "very interesting", + "i am not sure i understand you fully", + "what does that suggest to you", + "please continue", + "go on", + "do you feel strongly about discussing such things" + ] + } +] \ No newline at end of file diff --git a/rules.yaml b/rules.yaml index 5cdeb5e..8883195 100644 --- a/rules.yaml +++ b/rules.yaml @@ -102,7 +102,7 @@ - pattern: ?X are like ?Y responses: - - what resemblence do you see between ?X and ?Y + - what resemblance do you see between ?X and ?Y - pattern: ?X is like ?Y responses: -- 2.34.1