cogibara 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/bin/cogibara-local.rb +68 -0
- data/bin/cogibara-redis.rb +35 -0
- data/cogibara.gemspec +50 -0
- data/lib/cogibara/configuration.rb +84 -0
- data/lib/cogibara/confirmer.rb +30 -0
- data/lib/cogibara/default_config.rb +6 -0
- data/lib/cogibara/dispatcher.rb +125 -0
- data/lib/cogibara/file_handler.rb +44 -0
- data/lib/cogibara/message.rb +20 -0
- data/lib/cogibara/message_handler.rb +153 -0
- data/lib/cogibara/operator_base.rb +39 -0
- data/lib/cogibara/operators/calendar.rb +41 -0
- data/lib/cogibara/operators/chat.rb +22 -0
- data/lib/cogibara/operators/help.rb +13 -0
- data/lib/cogibara/operators/knowledge.rb +55 -0
- data/lib/cogibara/operators/reminder_setter.rb +8 -0
- data/lib/cogibara/operators/soft_parser.rb +48 -0
- data/lib/cogibara/operators/translate.rb +33 -0
- data/lib/cogibara/operators/weather.rb +89 -0
- data/lib/cogibara/operators/wiki/wiki_getter.rb +47 -0
- data/lib/cogibara/operators/wiki.rb +22 -0
- data/lib/cogibara/operators/wolfram_alpha.rb +27 -0
- data/lib/cogibara/responder.rb +24 -0
- data/lib/cogibara/speaker.rb +21 -0
- data/lib/cogibara/text_parser.rb +8 -0
- data/lib/cogibara/transcriber.rb +44 -0
- data/lib/cogibara/version.rb +3 -0
- data/lib/cogibara.rb +73 -0
- metadata +338 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
module Cogibara
|
2
|
+
class MessageHandler
|
3
|
+
|
4
|
+
def handle(message)
|
5
|
+
if(message.is_a? String)
|
6
|
+
message = Message.new(message, "local")
|
7
|
+
end
|
8
|
+
|
9
|
+
Responder.new.send_reply("@think",message.clientID)
|
10
|
+
|
11
|
+
if Cogibara::config.soft_parse
|
12
|
+
message.structure = derive_structure(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
msg = message.text
|
17
|
+
@verbose = Cogibara::config.verbose
|
18
|
+
@name = Cogibara::config.name
|
19
|
+
|
20
|
+
if msg
|
21
|
+
puts "core" if @verbose
|
22
|
+
reply = process_core(msg, message)
|
23
|
+
unless reply
|
24
|
+
reply = process_confirm_deny(msg, message)
|
25
|
+
unless reply
|
26
|
+
splitmsg = msg
|
27
|
+
splitmsg = splitmsg.split
|
28
|
+
puts "instruction #{splitmsg[0]}" if @verbose
|
29
|
+
if splitmsg[0]==@name
|
30
|
+
slicemessage = splitmsg
|
31
|
+
slicemessage.shift
|
32
|
+
slicemessage = slicemessage.join(' ')
|
33
|
+
# slicemessage.slice!(@name)
|
34
|
+
slicemessage = slicemessage.strip
|
35
|
+
puts "instructed #{slicemessage}" if @verbose
|
36
|
+
# if @soft_parse
|
37
|
+
|
38
|
+
reply = process_instruction(slicemessage, message)
|
39
|
+
unless reply
|
40
|
+
puts "defaults" if @verbose
|
41
|
+
reply = process_default(msg, message)
|
42
|
+
end
|
43
|
+
elsif Cogibara::config.active_mode
|
44
|
+
puts "active module #{Cogibara::config.active_mode} processing #{msg}" if @verbose
|
45
|
+
reply = process_instruction(Cogibara::config.active_mode + " " + msg, message)
|
46
|
+
unless reply
|
47
|
+
puts "defaultx" if @verbose
|
48
|
+
reply = process_default(msg, message)
|
49
|
+
end
|
50
|
+
elsif message.structure[:category]
|
51
|
+
reply = process_intent(msg, message)
|
52
|
+
unless reply
|
53
|
+
puts "defaulty" if @verbose
|
54
|
+
reply = process_default(msg, message)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
puts "defaultz" if @verbose
|
58
|
+
reply = process_default(msg, message)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
puts reply if @verbose
|
64
|
+
Responder.new.send_reply("@listen",message.clientID)
|
65
|
+
Cogibara::say Message.new("#{@name}: " + reply.to_s, message.clientID)
|
66
|
+
|
67
|
+
reply
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def process_core(message, obj)
|
72
|
+
@yourname = "person"
|
73
|
+
if message == "hey #{@name}"
|
74
|
+
"what's up #{@yourname}?"
|
75
|
+
elsif message == "reset mode"
|
76
|
+
Cogibara::config.active_mode = nil
|
77
|
+
Cogibara::config.active_file_mode = nil
|
78
|
+
"Disabling any active modules"
|
79
|
+
elsif /your name is now/ =~ message
|
80
|
+
message.slice!("your name is now ")
|
81
|
+
@name = message.chomp
|
82
|
+
"OK, you can call me #{@name}"
|
83
|
+
elsif /my name is/ =~ message
|
84
|
+
message.slice!("my name is ")
|
85
|
+
@yourname = message.chomp
|
86
|
+
"OK, I'll call you #{@yourname}"
|
87
|
+
elsif message == "what time is it"
|
88
|
+
"it is #{Time.now.hour} o'clock and #{Time.now.min} minutes"
|
89
|
+
else
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def process_default(msg, obj)
|
95
|
+
chatmsg = Message.new(msg, obj.clientID, obj.structure)
|
96
|
+
puts chatmsg.inspect if @verbose
|
97
|
+
Cogibara::dispatcher.call("chat", chatmsg)
|
98
|
+
end
|
99
|
+
|
100
|
+
def process_instruction(message, obj)
|
101
|
+
|
102
|
+
puts "instruction: #{message.split[0]} (#{Cogibara::dispatcher.registered?(message.split[0])})" if @verbose
|
103
|
+
if message =~ /\Aset mode/
|
104
|
+
message.slice!("set mode")
|
105
|
+
Cogibara::config.active_mode = message.chomp.strip
|
106
|
+
"Going into #{Cogibara::config.active_mode} mode"
|
107
|
+
elsif message =~ /\Aset file mode/
|
108
|
+
message.slice!("set file mode")
|
109
|
+
Cogibara::config.active_file_mode = message.chomp.strip
|
110
|
+
"Handling files with #{Cogibara::config.active_file_mode}"
|
111
|
+
elsif Cogibara::dispatcher.registered?(message.split[0])
|
112
|
+
splitmsg = message.split
|
113
|
+
Responder.new.send_reply("@search",obj.clientID)
|
114
|
+
puts "recognized instruction #{message.split[0]} (#{splitmsg})" if @verbose
|
115
|
+
mod = splitmsg[0]
|
116
|
+
splitmsg.shift
|
117
|
+
Cogibara::dispatcher.call(mod, Message.new(splitmsg.join(' '), obj.clientID, obj.structure))
|
118
|
+
else
|
119
|
+
puts "didn't understand instruction #{message.split[0]}" if @verbose
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def process_intent(message, obj)
|
125
|
+
if (obj.structure[:action] && Cogibara::dispatcher.registered?(obj.structure[:action].to_s))
|
126
|
+
puts "recognized instruction #{obj.structure[:action]}" if @verbose
|
127
|
+
Cogibara::dispatcher.call(obj.structure[:category].to_s,obj)
|
128
|
+
elsif (obj.structure[:category] && Cogibara::dispatcher.registered?(obj.structure[:category].to_s))
|
129
|
+
puts "recognized instruction #{obj.structure[:category]}" if @verbose
|
130
|
+
Cogibara::dispatcher.call(obj.structure[:category].to_s,obj)
|
131
|
+
else
|
132
|
+
puts "didn't understand instruction #{message.split[0]}" if @verbose
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def derive_structure(message)
|
138
|
+
response = Cogibara::dispatcher.call("maluuba",message)
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
def process_confirm_deny(message, obj)
|
143
|
+
if message == "yes"
|
144
|
+
if Cogibara::confirmer.waiting?
|
145
|
+
Cogibara::confirmer.confirm_action
|
146
|
+
"Confirmed!"
|
147
|
+
end
|
148
|
+
else
|
149
|
+
nil
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Cogibara
|
2
|
+
class OperatorBase
|
3
|
+
|
4
|
+
attr :clientID
|
5
|
+
attr :message_text
|
6
|
+
attr :message_structure
|
7
|
+
attr :operator_config
|
8
|
+
|
9
|
+
def initialize(config={})
|
10
|
+
@operator_config = config
|
11
|
+
initialize_operator if self.respond_to?(:initialize_operator)
|
12
|
+
end
|
13
|
+
|
14
|
+
def receive_message(message)
|
15
|
+
@clientID = message.clientID
|
16
|
+
@message_text = message.text
|
17
|
+
@message_structure = message.structure
|
18
|
+
process(message)
|
19
|
+
end
|
20
|
+
|
21
|
+
def process(message)
|
22
|
+
"!!!text processing not implemented for this operator!!!"
|
23
|
+
end
|
24
|
+
|
25
|
+
def process_file(file)
|
26
|
+
"!!!file processing not implemented for this operator!!!"
|
27
|
+
end
|
28
|
+
|
29
|
+
def say(message)
|
30
|
+
Cogibara::say Message.new("#{Cogibara::config.name}: " + message, @clientID)
|
31
|
+
end
|
32
|
+
|
33
|
+
def confirm(message, success=nil, failure=nil)
|
34
|
+
puts "new confirm"
|
35
|
+
Cogibara::confirmer.add_action(message, success)
|
36
|
+
message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'google_calendar'
|
2
|
+
|
3
|
+
class Calendar < Cogibara::OperatorBase
|
4
|
+
|
5
|
+
def initialize_operator
|
6
|
+
@calendar = Google::Calendar.new(username: self.operator_config["username"], password: self.operator_config["password"], app_name: 'cogibara-calendar-operator')
|
7
|
+
end
|
8
|
+
|
9
|
+
def process(message)
|
10
|
+
info = message.structure
|
11
|
+
puts info
|
12
|
+
case info[:action]
|
13
|
+
when :CALENDAR_CREATE_EVENT
|
14
|
+
# puts info
|
15
|
+
title = info[:entities][:title]? info[:entities][:title][0] : "Untitled event"
|
16
|
+
if info[:entities][:daterange]
|
17
|
+
start_t = Time.parse(info[:entities][:daterange][0][:start] + " " + info[:entities][:timerange][0][:start])
|
18
|
+
end_t = Time.parse(info[:entities][:daterange][0][:start] + " " + info[:entities][:timerange][0][:end]) # use same day because broken?
|
19
|
+
else
|
20
|
+
start_t = Time.parse(info[:entities][:timerange][0][:start])
|
21
|
+
end_t = Time.parse(info[:entities][:timerange][0][:end]) # use same day because broken?
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
create_event = lambda do
|
26
|
+
say "adding #{title} to your calendar"
|
27
|
+
@calendar.create_event do |e|
|
28
|
+
e.title = title
|
29
|
+
e.start_time = start_t
|
30
|
+
e.end_time = end_t
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# {code: :confirm, message: "create calendar event #{title} from #{start_t} to #{end_t}?", success: create_event}
|
34
|
+
puts "confirming event"
|
35
|
+
confirm("create calendar event #{title} from #{start_t} to #{end_t}?", create_event)
|
36
|
+
else
|
37
|
+
puts "unsupported calendar operation #{info[:action]}, returning nil"
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'cleverbot'
|
2
|
+
require 'curb'
|
3
|
+
|
4
|
+
class Chat < Cogibara::OperatorBase
|
5
|
+
def initialize_operator
|
6
|
+
@cleverbot_client = Cleverbot::Client.new
|
7
|
+
pf_ID = self.operator_config["Bot_ID"].to_i
|
8
|
+
if pf_ID > 0
|
9
|
+
@pf_ID = pf_ID
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def process(message)
|
14
|
+
if @pf_ID
|
15
|
+
reply = Curl.post("http://www.personalityforge.com/directchat.php?BotID=#{@pf_ID}&MID=8", {Message: message.text, action: "Send Message", UserID: @pf_ID})
|
16
|
+
reply.body_str.slice(/<\!-- Bot's reply -->.*?<\!-- end section -->/m).slice(/<span class="bigfont">.*<\/span>/m).gsub(/<.*>/,'').gsub("\n\t",'')
|
17
|
+
else
|
18
|
+
@cleverbot_client.write message.text
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# require_relative 'wolfram_alpha.rb'
|
2
|
+
|
3
|
+
class Help < Cogibara::OperatorBase
|
4
|
+
|
5
|
+
def process(message)
|
6
|
+
operators = Cogibara::dispatcher.operators.keys
|
7
|
+
|
8
|
+
soft_operators = operators.reject{ |o| o.upcase != o}
|
9
|
+
hard_operators = operators
|
10
|
+
|
11
|
+
"I understand the following categories of natural speech: #{soft_operators}, and keyword queries of the form <my name>: #{hard_operators}. Most natural speech categories implement a more natural response, so, for example, 'what is 18 dollars in rupees' activates the knowledge module, and returns 'rupee 968.31(Indian rupees)', while the 'ask' keyword sends the query to the knowledge engine and prints raw output, so 'cucumber ask what is 18 dollars in rupees' = 'Input Interpretation: convert $18 (US dollars) to Indian rupees, Result: rupee968.31 (Indian rupees), 1-year minimum | rupee931.42 (October 4, 2012 | 7 months ago) 1-year maximum | rupee1030.38 (June 24, 2012 | 10 months ago)"
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# require_relative 'wolfram_alpha.rb'
|
2
|
+
require 'cleverbot'
|
3
|
+
require 'wolfram'
|
4
|
+
|
5
|
+
class Knowledge < Cogibara::OperatorBase
|
6
|
+
|
7
|
+
def initialize_operator
|
8
|
+
Wolfram.appid = self.operator_config["WOLFRAM_KEY"]
|
9
|
+
# @wolfram = WolframAlpha.new
|
10
|
+
@cleverbot = Cleverbot::Client.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def is_question_word?(word)
|
14
|
+
qwords = %w{who what why where when how are can if}
|
15
|
+
qwords.include? word.downcase
|
16
|
+
end
|
17
|
+
|
18
|
+
def process(query)
|
19
|
+
word = query.text.split[0]
|
20
|
+
|
21
|
+
if is_question_word?(word)
|
22
|
+
result = Wolfram::HashPresenter.new(Wolfram.fetch(query.text)).to_hash
|
23
|
+
if result[:pods]["Result"] || result[:pods]["Exact result"] || result[:pods]["Basic information"]
|
24
|
+
valid_result = true
|
25
|
+
if result[:pods]["Result"]
|
26
|
+
msg = result[:pods]["Result"][0]
|
27
|
+
elsif result[:pods]["Exact result"]
|
28
|
+
msg = result[:pods]["Exact result"][0]
|
29
|
+
elsif result[:pods]["Basic information"]
|
30
|
+
msg = result[:pods]["Basic information"][0]
|
31
|
+
end
|
32
|
+
else
|
33
|
+
valid_result == false
|
34
|
+
end
|
35
|
+
# valid_result = !(!result[:pods]["Result"] || result[:pods]["Result"][0] == "(data not available)")
|
36
|
+
else
|
37
|
+
valid_result = false
|
38
|
+
end
|
39
|
+
|
40
|
+
if valid_result
|
41
|
+
if msg == "(data not available)"
|
42
|
+
# msg = @cleverbot.write(query.text) + " (dk)"
|
43
|
+
# # puts msg
|
44
|
+
# msg
|
45
|
+
nil
|
46
|
+
else
|
47
|
+
msg
|
48
|
+
end
|
49
|
+
else
|
50
|
+
# @cleverbot.write(query.text)
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
# valid_result ? result[:pods]["Result"][0] : @cleverbot.write(query.text)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'maluuba_napi'
|
2
|
+
|
3
|
+
class SoftParser < Cogibara::OperatorBase
|
4
|
+
def initialize_operator
|
5
|
+
@api_key = self.operator_config["API_KEY"]
|
6
|
+
@client = MaluubaNapi::Client.new(@api_key)
|
7
|
+
end
|
8
|
+
|
9
|
+
def normalize(message, type)
|
10
|
+
@client.normalize phrase: message, type: type, timezone:"CST"
|
11
|
+
end
|
12
|
+
|
13
|
+
def normalize_response!(msg, response)
|
14
|
+
if response[:entities]
|
15
|
+
if response[:entities][:daterange]
|
16
|
+
n = normalize(msg, "daterange")[:entities][:daterange]
|
17
|
+
response[:entities][:daterange] = n if n
|
18
|
+
end
|
19
|
+
if response[:entities][:timerange]
|
20
|
+
n = normalize(msg, "timerange")[:entities][:timerange]
|
21
|
+
response[:entities][:timerange] = n if n
|
22
|
+
end
|
23
|
+
if response[:entities][:time]
|
24
|
+
n = normalize(msg, "time")[:entities][:time]
|
25
|
+
response[:entities][:time] = n if n
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def process(message)
|
31
|
+
response = @client.interpret phrase: message.text
|
32
|
+
normalize_response!(message.text, response)
|
33
|
+
## Should normalize times and do something with them
|
34
|
+
# time_categories = [:REMINDER, :ALARM, :TIMER]
|
35
|
+
# timerange_categories = [:TIMER]
|
36
|
+
# date_categories = [:CALENDAR]
|
37
|
+
#
|
38
|
+
# if time_categories.includes? response[:category]
|
39
|
+
# normalized = @client.normalize phrase: message, type: 'time', timezone: 'CST'
|
40
|
+
# elsif timerange_categories.includes? response[:category]
|
41
|
+
# normalized = @client.normalize phrase: message, type: 'timerange', timezone: 'CST'
|
42
|
+
# elsif date_categories.includes? response[:category]
|
43
|
+
# normalized = @client.normalize phrase: message, type: 'daterange', timezone: 'CST'
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
response
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'bing_translator'
|
2
|
+
|
3
|
+
class Translate < Cogibara::OperatorBase
|
4
|
+
|
5
|
+
LANGUAGES = {'english' => 'en-US', 'English' => 'en-US', 'Japanese' => 'ja', 'japanese' => 'ja', 'en-US' => 'en-US', 'dutch' => 'nl-NL', 'Dutch' => 'nl-NL', 'German' => 'de-DE','german' => 'de-DE', 'Spanish' => 'es-US', 'spanish' => 'es-US'}
|
6
|
+
|
7
|
+
def initialize_operator
|
8
|
+
@bing = BingTranslator.new('wstrinz', 'aMAR9BHp6NxCml97/OjCaZDB/WRpCDCdmXNHXbCz83s=')
|
9
|
+
end
|
10
|
+
|
11
|
+
def translate(message)
|
12
|
+
in_language = @bing.detect message
|
13
|
+
@bing.translate message, :from => in_language, :to => "en"
|
14
|
+
end
|
15
|
+
|
16
|
+
def process(input)
|
17
|
+
message = input.text
|
18
|
+
if LANGUAGES.has_key? message
|
19
|
+
@language = LANGUAGES[message]
|
20
|
+
"Translating from #{message} (#{@language})"
|
21
|
+
elsif message =~ /\Aset language/
|
22
|
+
@language = LANGUAGES[message.split[2]]
|
23
|
+
"Translating from #{message.split[2]} (#{@language})"
|
24
|
+
else
|
25
|
+
"you said: " + translate(message)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def process_file(file)
|
30
|
+
message = Cogibara::Transcriber.new.transcribe_lang(file, @language)
|
31
|
+
"you said: " + translate(message)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'forecast_io'
|
2
|
+
require 'geocoder'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
class Weather < Cogibara::OperatorBase
|
6
|
+
def initialize_operator
|
7
|
+
Forecast::IO.api_key = self.operator_config["API_KEY"]
|
8
|
+
end
|
9
|
+
|
10
|
+
# def translate(message)
|
11
|
+
# in_language = @bing.detect message
|
12
|
+
# @bing.translate message, :from => in_language, :to => "en"
|
13
|
+
# end
|
14
|
+
|
15
|
+
def location_to_coordinates(location)
|
16
|
+
Geocoder.coordinates(location)
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_location(message)
|
20
|
+
info = message.structure
|
21
|
+
if info[:entities][:location]
|
22
|
+
location_to_coordinates(info[:entities][:location][0])
|
23
|
+
else
|
24
|
+
[43.092, -89.369]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_forecast_period(message)
|
29
|
+
info = message.structure[:entities]
|
30
|
+
|
31
|
+
if info[:daterange]
|
32
|
+
start_d = Date.parse(info[:daterange][0][:start])
|
33
|
+
end_d = Date.parse(info[:daterange][0][:end])
|
34
|
+
start_d..end_d
|
35
|
+
elsif info[:time]
|
36
|
+
info[:time]=="tomorrow" ? Date.today + 1 : Date.today
|
37
|
+
else
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def current_conditions
|
43
|
+
# if @forecast.minutely
|
44
|
+
# say "now: #{@forecast.minutely.summary}"
|
45
|
+
# end
|
46
|
+
curr_summary = " Currently " + @forecast.currently.summary + ", "
|
47
|
+
curr_cond = "#{@forecast.currently.temperature.round} degrees, cloud cover #{(@forecast.currently.cloudCover * 100).round}% "
|
48
|
+
next_cond = @forecast.minutely ? @forecast.minutely.summary : ""
|
49
|
+
# next_cond = @forecast.minutely ? "Then " + @forecast.minutely.summary : ""
|
50
|
+
curr_summary + curr_cond + "then, " + next_cond
|
51
|
+
end
|
52
|
+
|
53
|
+
def todays_forecast
|
54
|
+
temps = @forecast.hourly.data[0..18].map{|hr| hr.temperature}
|
55
|
+
max_t = temps.each_with_index.max
|
56
|
+
min_t = temps.each_with_index.min
|
57
|
+
@forecast.hourly.summary + " The high temperature will be #{max_t[0].round} degrees, in #{max_t[1]} hours, and the low will be #{min_t[0].round} degrees, in #{min_t[1]} hours"
|
58
|
+
end
|
59
|
+
|
60
|
+
def week_forecast
|
61
|
+
say @forecast.daily.summary
|
62
|
+
end
|
63
|
+
|
64
|
+
def process(message)
|
65
|
+
return nil if message.text.split.include?("cool")
|
66
|
+
|
67
|
+
@loc = get_location(message)
|
68
|
+
@date = get_forecast_period(message)
|
69
|
+
@forecast = Forecast::IO.forecast(@loc[0],@loc[1])
|
70
|
+
|
71
|
+
unless @date
|
72
|
+
current_conditions
|
73
|
+
else
|
74
|
+
if @date.is_a? Range
|
75
|
+
if @date.first == Date.today || @date.first == Date.today+1
|
76
|
+
todays_forecast
|
77
|
+
else
|
78
|
+
week_forecast
|
79
|
+
end
|
80
|
+
else
|
81
|
+
if @date == Date.today || @date == Date.today + 1
|
82
|
+
todays_forecast
|
83
|
+
else
|
84
|
+
week_forecast
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'wikipedia'
|
2
|
+
require 'wikicloth'
|
3
|
+
require 'json'
|
4
|
+
require 'sanitize'
|
5
|
+
|
6
|
+
class WikiGetter
|
7
|
+
|
8
|
+
def checkRedirect(article)
|
9
|
+
if(/\Aredirect/ =~ article.strip)
|
10
|
+
return article.strip.gsub(/\Aredirect/,'')
|
11
|
+
elsif(/\AREDIRECT/ =~ article.strip)
|
12
|
+
return article.strip.gsub(/\AREDIRECT/,'').strip
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def getArticle(title)
|
17
|
+
article = JSON.parse(Wikipedia.find(title).json)["query"]["pages"].to_a[0][1]["revisions"]
|
18
|
+
unless article
|
19
|
+
"Could not find article, sorry"
|
20
|
+
else
|
21
|
+
raw = article[0]["*"]
|
22
|
+
# parsed = Wikitext::Parser.new.parse(raw)
|
23
|
+
parsed = WikiCloth::Parser.new({:data => raw})
|
24
|
+
sanitized = Sanitize.clean(parsed.to_html)
|
25
|
+
redirect = checkRedirect(sanitized)
|
26
|
+
if redirect
|
27
|
+
puts "redirecting to #{redirect}"
|
28
|
+
getArticle(redirect)
|
29
|
+
else
|
30
|
+
ref_links = sanitized.gsub(/\[\d+\]/,'').gsub(/\[edit\]/,'')
|
31
|
+
http_links = ref_links.gsub(/\[http+\s?\]/m,'')
|
32
|
+
|
33
|
+
|
34
|
+
# leftover = sanitized.gsub(/\[\[.*\]\]/, '').gsub(/\{\{.*\}\}/, '')
|
35
|
+
# leftover = leftover.gsub(/\[\[.*?\]\]/m, '').gsub(/\{\{.*?\}\}/m, '').gsub(/<.*?>/m,'')
|
36
|
+
# leftover = leftover.gsub(/\'\'/,'').gsub(/\[http.*?\]/m,'').gsub(/\{\|.*?\|\}/m,'').gsub(/\}\}/,'')
|
37
|
+
# removeUgly = leftover.gsub(/\|/,' ').gsub(/\_/,'')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# leftover
|
42
|
+
# leftover
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# puts WikiGetter.new.getArticle("Cattle")
|
47
|
+
# puts WikiGetter.new.getArticle("Cat").length
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'wiki/wiki_getter.rb'
|
2
|
+
|
3
|
+
class Wiki < Cogibara::OperatorBase
|
4
|
+
|
5
|
+
def initialize_operator
|
6
|
+
@handler = WikiGetter.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def process(message)
|
10
|
+
search = message.text
|
11
|
+
article = WikiGetter.new.getArticle(search)
|
12
|
+
# splits = article.split
|
13
|
+
# (splits.count / 100).times do |n|
|
14
|
+
# if (n+1)*100 > splits.count
|
15
|
+
# chunk = splits[n*100..splits.count] * ' '
|
16
|
+
# else
|
17
|
+
# chunk = splits[n*100..((n+1)*100 - 1)] * ' '
|
18
|
+
# end
|
19
|
+
# yield chunk
|
20
|
+
# end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# require_relative 'wolfram_alpha/'
|
2
|
+
require 'wolfram'
|
3
|
+
class WolframAlpha < Cogibara::OperatorBase
|
4
|
+
|
5
|
+
def initialize_operator
|
6
|
+
Wolfram.appid = self.operator_config["API_KEY"]
|
7
|
+
end
|
8
|
+
|
9
|
+
def resultToString(result)
|
10
|
+
rhash = Wolfram::HashPresenter.new(result).to_hash
|
11
|
+
rarr = []
|
12
|
+
rhash[:pods].keys.each do |key|
|
13
|
+
value = rhash[:pods][key][0]
|
14
|
+
rarr << (key + ":\n\t" + value + "\n")
|
15
|
+
end
|
16
|
+
rarr.join
|
17
|
+
end
|
18
|
+
|
19
|
+
def process(message)
|
20
|
+
# puts "asking wolfram #{query}"
|
21
|
+
query = message.text
|
22
|
+
result = resultToString(Wolfram.fetch(query))
|
23
|
+
# puts result == "Result:\n"
|
24
|
+
# result == "Result:\n" ? nil : result
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
module Cogibara
|
4
|
+
class Responder
|
5
|
+
def redis
|
6
|
+
@redis ||= Redis.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def send_reply(message, client, options={type: "text"})
|
10
|
+
if(Cogibara::config.use_redis)
|
11
|
+
redis.multi do
|
12
|
+
redis.incr "sendMsgNum"
|
13
|
+
@msgid = redis.get "sendMsgNum"
|
14
|
+
end
|
15
|
+
|
16
|
+
redis.hmset("sendMsg:#{@msgid.value}",options[:type],message,"client",client)
|
17
|
+
redis.publish("fromCapy","sendMsg:#{@msgid.value}")
|
18
|
+
end
|
19
|
+
if(Cogibara::config.local)
|
20
|
+
puts message unless message[0] == "@"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Cogibara
|
2
|
+
class Speaker
|
3
|
+
def speak_to_local(message, voice="rab_diphone", engine=:festival)
|
4
|
+
if engine == :pico
|
5
|
+
`pico2wave -w out.wav "#{self}"`
|
6
|
+
`aplay out.wav`
|
7
|
+
`rm ./out.wav`
|
8
|
+
else
|
9
|
+
`echo "#{self}" | text2wave -eval "(voice_#{voice})" | aplay`
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def speak_to_file(message)
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|