programr 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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