programr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,269 @@
1
+ require 'rexml/parsers/sax2parser'
2
+ require 'programr/aiml_elements'
3
+
4
+ # gli accenti nel file di input vengono trasformati in ' !!!
5
+ #
6
+ module ProgramR
7
+ class AimlParser
8
+ def initialize(learner); @learner = learner end
9
+
10
+ def parse(aiml)
11
+ @parser = REXML::Parsers::SAX2Parser.new(aiml)
12
+ category = nil
13
+ openLabels = []
14
+ patternIsOpen = false
15
+ thatIsOpen = false
16
+ currentSetLabel = nil
17
+ currentCondition = nil
18
+ currentSrai = nil
19
+ currentGender = nil
20
+ currentPerson = nil
21
+ currentPerson2 = nil
22
+ currentTopic = nil
23
+
24
+ @parser.listen(%w{ category }){|uri,localname,qname,attributes|
25
+ category = Category.new
26
+ category.topic = currentTopic if(currentTopic)
27
+ }
28
+
29
+ @parser.listen(['topicstar','thatstar','star']){|u,localname,qn,attributes|
30
+ openLabels[-1].add(Star.new(localname,attributes))
31
+ }
32
+
33
+ ### condition -- random
34
+ @parser.listen(%w{ condition }){|uri,localname,qname,attributes|
35
+ if(attributes.key?('value'))
36
+ currentCondition = Condition.new(attributes)
37
+ else
38
+ currentCondition = ListCondition.new(attributes)
39
+ end
40
+ openLabels[-1].add(currentCondition)
41
+ openLabels.push(currentCondition)
42
+ }
43
+
44
+ @parser.listen(%w{ random }){|uri,localname,qname,attributes|
45
+ currentCondition = Random.new
46
+ openLabels[-1].add(currentCondition)
47
+ openLabels.push(currentCondition)
48
+ }
49
+
50
+ @parser.listen(:characters, %w{ condition }){|text|
51
+ next if(text =~ /^\s+$/)
52
+ currentCondition.add(text)
53
+ }
54
+
55
+ @parser.listen(%w{ li }){|uri,localname,qname,attributes|
56
+ next unless currentCondition
57
+ currentCondition.setListElement(attributes)
58
+ }
59
+
60
+ @parser.listen(:characters,%w{ li }){|text|
61
+ next unless currentCondition
62
+ currentCondition.add(text)
63
+ }
64
+
65
+ @parser.listen(:end_element, ['condition','random']){
66
+ currentCondition = nil
67
+ openLabels.pop
68
+ }
69
+ ### end condition -- random
70
+
71
+ @parser.listen([/^get.*/,/^bot_*/,'for_fun',/that$/, 'question']){
72
+ |uri,localname,qname,attributes|
73
+ unless(openLabels.empty?)
74
+ openLabels[-1].add(ReadOnlyTag.new(localname, attributes))
75
+ end
76
+ }
77
+
78
+ @parser.listen(['bot','name']){|uri,localname,qname,attributes|
79
+ if(localname == 'bot')
80
+ localname = 'bot_'+attributes['name']
81
+ else
82
+ localname = 'bot_name'
83
+ end
84
+ if(patternIsOpen)
85
+ category.add_pattern(ReadOnlyTag.new(localname, {}))
86
+ elsif(thatIsOpen)
87
+ category.add_that(ReadOnlyTag.new(localname, {}))
88
+ else
89
+ openLabels[-1].add(ReadOnlyTag.new(localname, {}))
90
+ end
91
+ }
92
+
93
+ ### set
94
+ @parser.listen([/^set_*/,'set']){|uri,localname,qname,attributes|
95
+ setObj = SetTag.new(localname,attributes)
96
+ openLabels[-1].add(setObj)
97
+ openLabels.push(setObj)
98
+ }
99
+
100
+ @parser.listen(:characters,[/^set_*/]){|text|
101
+ openLabels[-1].add(text)
102
+ }
103
+
104
+ @parser.listen(:end_element, [/^set_*/,'set']){
105
+ openLabels.pop
106
+ }
107
+ ### end set
108
+
109
+ ### pattern
110
+ @parser.listen(%w{ pattern }){patternIsOpen = true}
111
+ @parser.listen(:characters,%w{ pattern }){|text|
112
+ #TODO verify if case insensitive. Cross check with facade
113
+ category.add_pattern(text.upcase)
114
+ }
115
+ @parser.listen(:end_element, %w{ pattern }){patternIsOpen = false}
116
+ #end pattern
117
+
118
+ #### that
119
+ @parser.listen(%w{ that }){thatIsOpen = true}
120
+ @parser.listen(:characters,%w{ that }){|text| category.add_that(text)}
121
+ @parser.listen(:end_element, %w{ that }){thatIsOpen = false}
122
+ ### end that
123
+
124
+ ### template
125
+ @parser.listen(%w{ template }){
126
+ category.template = Template.new
127
+ openLabels.push(category.template)
128
+ }
129
+
130
+ @parser.listen(:characters, %w{ template }){|text|
131
+ category.template.append(text)
132
+ }
133
+
134
+ @parser.listen(:end_element, %w{ template }){
135
+ openLabels.pop
136
+ }
137
+ ### end template
138
+
139
+ @parser.listen(%w{ input }){|uri,localname,qname,attributes|
140
+ category.template.add(Input.new(attributes))
141
+ }
142
+
143
+ ### think
144
+ @parser.listen(:start_element, %w{ think }){
145
+ openLabels[-1].add(Think.new('start'))
146
+ }
147
+
148
+ @parser.listen(:end_element, %w{ think }){
149
+ openLabels[-1].add(Think.new('end'))
150
+ }
151
+ ###end think
152
+
153
+ @parser.listen(:characters, %w{ uppercase }){|text|
154
+ openLabels[-1].add(text.upcase.gsub(/\s+/, ' '))
155
+ }
156
+
157
+ @parser.listen(:characters, %w{ lowercase }){|text|
158
+ openLabels[-1].add(text.downcase.gsub(/\s+/, ' '))
159
+ }
160
+
161
+ @parser.listen(:characters, %w{ formal }){|text|
162
+ text.gsub!(/(\w+)/){$1.capitalize}
163
+ openLabels[-1].add(text.gsub(/\s+/, ' '))
164
+ }
165
+
166
+ @parser.listen(:characters, %w{ sentence }){|text|
167
+ openLabels[-1].add(text.capitalize.gsub(/\s+/, ' '))
168
+ }
169
+
170
+ @parser.listen(%w{ date }){
171
+ openLabels[-1].add(Sys_Date.new)
172
+ }
173
+
174
+ @parser.listen(:characters, %w{ system }){|text|
175
+ openLabels[-1].add(Command.new(text))
176
+ }
177
+
178
+ @parser.listen(%w{ size }){
179
+ openLabels[-1].add(Size.new)
180
+ }
181
+
182
+ @parser.listen(%w{ sr }){|uri,localname,qname,attributes|
183
+ openLabels[-1].add(Srai.new(Star.new('star',{})))
184
+ }
185
+ ### srai
186
+ @parser.listen(%w{ srai }){|uri,localname,qname,attributes|
187
+ currentSrai = Srai.new
188
+ openLabels[-1].add(currentSrai)
189
+ openLabels.push(currentSrai)
190
+ }
191
+
192
+ @parser.listen(:characters, %w{ srai }){|text|
193
+ currentSrai = Srai.new
194
+ currentSrai.add(text)
195
+ }
196
+
197
+ @parser.listen(:end_element, %w{ srai }){
198
+ currentSrai = nil
199
+ openLabels.pop
200
+ }
201
+ ### end srai
202
+
203
+ ### gender
204
+ @parser.listen(%w{ gender }){|uri,localname,qname,attributes|
205
+ currentGender = Gender.new
206
+ openLabels[-1].add(currentGender)
207
+ openLabels.push(currentGender)
208
+ }
209
+
210
+ @parser.listen(:characters, %w{ gender }){|text|
211
+ currentGender.add(text)
212
+ }
213
+
214
+ @parser.listen(:end_element, %w{ gender }){
215
+ currentGender = nil
216
+ openLabels.pop
217
+ }
218
+ ### end gender
219
+
220
+ ### person
221
+ @parser.listen(%w{ person }){|uri,localname,qname,attributes|
222
+ currentPerson = Person.new
223
+ openLabels[-1].add(currentPerson)
224
+ openLabels.push(currentPerson)
225
+ }
226
+
227
+ @parser.listen(:characters, %w{ person }){|text|
228
+ currentPerson.add(text)
229
+ }
230
+
231
+ @parser.listen(:end_element, %w{ person }){
232
+ currentPerson = nil
233
+ openLabels.pop
234
+ }
235
+ ### end person
236
+
237
+ ### person2
238
+ @parser.listen(%w{ person2 }){|uri,localname,qname,attributes|
239
+ currentPerson2 = Person2.new
240
+ openLabels[-1].add(currentPerson2)
241
+ openLabels.push(currentPerson2)
242
+ }
243
+
244
+ @parser.listen(:characters, %w{ person2 }){|text|
245
+ currentPerson2.add(text)
246
+ }
247
+
248
+ @parser.listen(:end_element, %w{ person2 }){
249
+ currentPerson2 = nil
250
+ openLabels.pop
251
+ }
252
+ ### end perso2
253
+
254
+ @parser.listen(:end_element, %w{ category }){ @learner.learn(category) }
255
+
256
+ ### topic
257
+ @parser.listen(%w{ topic }){|uri,localname,qname,attributes|
258
+ currentTopic = attributes['name']
259
+ }
260
+
261
+ @parser.listen(:end_element, %w{ topic }){
262
+ currentTopic = nil
263
+ }
264
+ ### end topic
265
+
266
+ @parser.parse
267
+ end
268
+ end #Aiml@parser
269
+ end
@@ -0,0 +1,75 @@
1
+ require 'yaml'
2
+ require 'programr/history'
3
+
4
+ module ProgramR
5
+ class Environment
6
+ @@readOnlyTags = nil
7
+ @@history = nil
8
+
9
+ def initialize
10
+ return self unless(@@readOnlyTags == nil)
11
+ @@readOnlyTags = YAML::load(
12
+ File.open(
13
+ File.dirname(__FILE__) +
14
+ "/../../conf/readOnlyTags.yaml"))
15
+ @@history = History.new
16
+ srand(1)
17
+ end
18
+
19
+ def get(aTag)
20
+ send(aTag)
21
+ end
22
+
23
+ def set(aTag,aValue)
24
+ @@history.updateTopic(aValue) if(aTag == 'topic')
25
+ @@readOnlyTags[aTag] = aValue
26
+ end
27
+
28
+ def method_missing(methId)
29
+ tag = methId.id2name
30
+ return @@history.send(tag) if(tag =~ /that$/)
31
+ return @@readOnlyTags[tag] if(@@readOnlyTags.key?(tag))
32
+ ''
33
+ end
34
+
35
+ def test
36
+ #should overwrite test ....
37
+ return @@readOnlyTags[tag] if(@@readOnlyTags.key?(tag))
38
+ ''
39
+ end
40
+
41
+ def star(anIndex)
42
+ @@history.getStar(anIndex)
43
+ end
44
+
45
+ def thatstar(anIndex)
46
+ @@history.getThatStar(anIndex)
47
+ end
48
+
49
+ def topicstar(anIndex)
50
+ @@history.getTopicStar(anIndex)
51
+ end
52
+
53
+ def male
54
+ @@readOnlyTags['gender'] = 'male'
55
+ return 'male'
56
+ end
57
+
58
+ def female
59
+ @@readOnlyTags['gender'] = 'female'
60
+ return 'female'
61
+ end
62
+
63
+ def question
64
+ @@readOnlyTags['question'][rand(@@readOnlyTags['question'].length-1)]
65
+ end
66
+
67
+ def getRandom(anArrayofChoices)
68
+ anArrayofChoices[rand(anArrayofChoices.length-1)]
69
+ end
70
+
71
+ def getStimula(anIndex)
72
+ @@history.getStimula(anIndex)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,65 @@
1
+ require 'programr/graph_master'
2
+ require 'programr/aiml_parser'
3
+ require 'programr/history'
4
+ require 'programr/utils'
5
+
6
+ module ProgramR
7
+ class Facade
8
+ def initialize(cache = nil)
9
+ @graph_master = GraphMaster.new
10
+ @parser = AimlParser.new(@graph_master)
11
+ @history = History.new
12
+ end
13
+
14
+ def learn(files)
15
+ AimlFinder::find(files).each{|f| File.open(f,'r'){|f| @parser.parse f} }
16
+ end
17
+
18
+ def loading(theCacheFilename='cache')
19
+ cache = Cache::loading(theCacheFilename)
20
+ @graph_master = cache if cache
21
+ end
22
+
23
+ def merging(theCacheFilename='cache')
24
+ cache = Cache::loading(theCacheFilename)
25
+ @graph_master.merge(cache) if cache
26
+ end
27
+
28
+ def dumping(theCacheFilename='cache')
29
+ Cache::dumping(theCacheFilename,@graph_master)
30
+ end
31
+
32
+ def get_reaction(stimula,firstStimula=true)
33
+ starGreedy = []
34
+ #TODO verify if case insensitive. Cross check with parser
35
+ #@history.updateStimula(stimula.upcase) if(firstStimula)
36
+ @history.updateStimula(stimula.upcase) if(firstStimula)
37
+ thinkIsActive = false
38
+ reaction = @graph_master.get_reaction(stimula.upcase, @history.that,
39
+ @history.topic,starGreedy)
40
+ @history.updateStarMatches(starGreedy)
41
+ res = ''
42
+ reaction.each{|tocken|
43
+ if(tocken.class == Srai)
44
+ tocken = get_reaction(tocken.pattern,false)
45
+ @history.updateStarMatches(starGreedy)
46
+ end
47
+ if tocken.class == Think
48
+ thinkIsActive = ! thinkIsActive
49
+ next
50
+ end
51
+ value = tocken.to_s
52
+ res += value unless(thinkIsActive)
53
+ }
54
+ #TODO verify if case insensitive. Cross check with main program & parser
55
+ @history.updateResponse(res.strip.upcase) if(firstStimula)
56
+ return res.strip
57
+ end
58
+
59
+ def to_s
60
+ @graph_master.to_s
61
+ end
62
+
63
+ # def getBotName()end
64
+ end
65
+ end
@@ -0,0 +1,110 @@
1
+ require 'programr/aiml_elements'
2
+
3
+ module ProgramR
4
+ THAT = '<that>'
5
+ TOPIC = '<topic>'
6
+ class GraphMaster
7
+ attr_reader :graph
8
+ def initialize
9
+ @graph = Node.new
10
+ end
11
+
12
+ def merge(aCache)
13
+ @graph.merge(aCache.graph)
14
+ end
15
+
16
+ def learn(category)
17
+ path = category.get_pattern
18
+ path += [THAT] + category.get_that unless (category.get_that).empty?
19
+ path += [TOPIC] + category.topic.split(/\s+/) if category.topic
20
+ @graph.learn(category, path)
21
+ end
22
+
23
+ def to_s
24
+ @graph.inspectNode()
25
+ end
26
+
27
+ def get_reaction(stimula, last_said,cur_topic,starGreedy)
28
+ path = "#{stimula} #{THAT} #{last_said} #{TOPIC} #{cur_topic}"
29
+ template = @graph.get_template(path.split(/\s+/),starGreedy)
30
+ return template.value unless(template == nil)
31
+ return []
32
+ end
33
+ end
34
+
35
+ class Node
36
+ attr_reader :children
37
+ def initialize
38
+ @template = nil
39
+ @children = {}
40
+ end
41
+
42
+ def merge(aCache)
43
+ aCache.children.keys.each do |key|
44
+ if(@children.key?(key))
45
+ @children[key].merge(aCache.children[key])
46
+ next
47
+ end
48
+ @children[key] = aCache.children[key]
49
+ end
50
+ end
51
+
52
+ def learn(category, path)
53
+ branch = path.shift
54
+ return @template = category.template unless branch
55
+ @children[branch] = Node.new unless @children[branch]
56
+ @children[branch].learn(category, path)
57
+ end
58
+
59
+ def get_template(pattern,starGreedy,isGreedy=false)
60
+ currentTemplate = nil
61
+ gotValue = nil
62
+ curGreedy = []
63
+ if(@template)
64
+ if(isGreedy)
65
+ starGreedy.push(pattern.shift) until(pattern.empty?||pattern[0]==THAT ||
66
+ pattern[0] == TOPIC)
67
+ end
68
+ return @template if(pattern.empty?)
69
+ currentTemplate = @template if(pattern[0] == THAT || pattern[0] == TOPIC)
70
+ end
71
+ branch = pattern.shift
72
+ isGreedy = false if(branch == THAT || branch == TOPIC)
73
+ unless(branch != THAT || @children.key?(THAT))
74
+ branch = pattern.shift until (branch == nil or branch == TOPIC)
75
+ end
76
+ return nil unless(branch)
77
+ if(@children[branch])
78
+ gotValue = @children[branch].get_template(pattern.clone,curGreedy)
79
+ elsif(isGreedy)
80
+ curGreedy.push(branch)
81
+ gotValue = get_template(pattern.clone,curGreedy,true)
82
+ end
83
+ if(gotValue)
84
+ starGreedy.push(branch) if(branch == THAT || branch == TOPIC)
85
+ starGreedy.concat(curGreedy)
86
+ return gotValue
87
+ end
88
+ return currentTemplate if currentTemplate
89
+ ["_","*"].each do |star|
90
+ next unless(@children.key?(star))
91
+ next unless(gotValue=@children[star].get_template(pattern.clone,
92
+ curGreedy,true))
93
+ starGreedy.push(branch) if(branch == THAT || branch == TOPIC)
94
+ starGreedy.concat(['<newMatch>',branch].concat(curGreedy))
95
+ return gotValue
96
+ end
97
+ return nil
98
+ end
99
+
100
+ def inspectNode(nodeId = nil, ind = 0)
101
+ str = ''
102
+ str += '| '*(ind - 1) + "|_#{nodeId}" unless ind == 0
103
+ str += ": [#{@template.inspect}]" if @template
104
+ str += "\n" unless ind == 0
105
+ @children.each_key{|c| str += @children[c].inspectNode(c, ind+1)}
106
+ str
107
+ end
108
+ end
109
+
110
+ end #ProgramR