kogno 1.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.
- checksums.yaml +7 -0
- data/bin/kogno +92 -0
- data/lib/boot.rb +9 -0
- data/lib/core/bin_helpers/messenger_ctl.rb +48 -0
- data/lib/core/bin_helpers/scaffolding.rb +203 -0
- data/lib/core/bin_helpers/scheduled_messages_ctl.rb +95 -0
- data/lib/core/bin_helpers/sequences_ctl.rb +95 -0
- data/lib/core/bin_helpers/server_ctl.rb +127 -0
- data/lib/core/bin_helpers/telegram_ctl.rb +48 -0
- data/lib/core/bin_helpers/webhook_ctl.rb +96 -0
- data/lib/core/db.rb +8 -0
- data/lib/core/extensions/array.rb +28 -0
- data/lib/core/extensions/hash.rb +12 -0
- data/lib/core/extensions/logger.rb +70 -0
- data/lib/core/extensions/string.rb +6 -0
- data/lib/core/extensions/wit.rb +60 -0
- data/lib/core/global_methods.rb +67 -0
- data/lib/core/helpers/string.rb +105 -0
- data/lib/core/lib/base_config.rb +17 -0
- data/lib/core/lib/block_params.rb +4 -0
- data/lib/core/lib/context.rb +1573 -0
- data/lib/core/lib/error_handler.rb +36 -0
- data/lib/core/lib/message.rb +182 -0
- data/lib/core/lib/messenger/api.rb +281 -0
- data/lib/core/lib/messenger/facebook_graph.rb +32 -0
- data/lib/core/lib/messenger/message.rb +202 -0
- data/lib/core/lib/messenger/notification.rb +351 -0
- data/lib/core/lib/messenger/post_comment.rb +104 -0
- data/lib/core/lib/messenger/recurring_notification.rb +81 -0
- data/lib/core/lib/nlp.rb +191 -0
- data/lib/core/lib/notification.rb +371 -0
- data/lib/core/lib/spelling.rb +13 -0
- data/lib/core/lib/telegram/api.rb +197 -0
- data/lib/core/lib/telegram/chat_activity.rb +111 -0
- data/lib/core/lib/telegram/inline_query.rb +112 -0
- data/lib/core/lib/telegram/message.rb +327 -0
- data/lib/core/lib/telegram/notification.rb +507 -0
- data/lib/core/lib/whatsapp/api.rb +153 -0
- data/lib/core/lib/whatsapp/message.rb +132 -0
- data/lib/core/lib/whatsapp/notification.rb +206 -0
- data/lib/core/lib/whatsapp/status_message.rb +58 -0
- data/lib/core/loaders/config_files.rb +15 -0
- data/lib/core/models/chat_log.rb +4 -0
- data/lib/core/models/long_payload.rb +25 -0
- data/lib/core/models/matched_message.rb +5 -0
- data/lib/core/models/messenger_recurring_notification.rb +16 -0
- data/lib/core/models/scheduled_message.rb +40 -0
- data/lib/core/models/sequence.rb +29 -0
- data/lib/core/models/telegram_chat_group.rb +26 -0
- data/lib/core/models/user.rb +285 -0
- data/lib/core/web/webhook.rb +198 -0
- data/lib/kogno.rb +130 -0
- data/scaffolding/new_project/Gemfile +3 -0
- data/scaffolding/new_project/application.rb +5 -0
- data/scaffolding/new_project/bot/contexts/main_context.rb +10 -0
- data/scaffolding/new_project/bot/conversation.rb +14 -0
- data/scaffolding/new_project/bot/models/user.rb +3 -0
- data/scaffolding/new_project/config/application.rb +28 -0
- data/scaffolding/new_project/config/database.yml +8 -0
- data/scaffolding/new_project/config/locales/en.yml +4 -0
- data/scaffolding/new_project/config/locales/es.yml +3 -0
- data/scaffolding/new_project/config/nlp.rb +23 -0
- data/scaffolding/new_project/config/platforms/messenger.rb +74 -0
- data/scaffolding/new_project/config/platforms/telegram.rb +45 -0
- data/scaffolding/new_project/config/platforms/whatsapp.rb +13 -0
- data/scaffolding/new_project/web/routes.rb +10 -0
- metadata +220 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module Kogno
|
2
|
+
class TelegramCtl
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def options(a)
|
6
|
+
error = false
|
7
|
+
case (a[1].to_sym rescue nil)
|
8
|
+
when :webhook
|
9
|
+
if a[2] == 'start'
|
10
|
+
Kogno::Telegram::Api.set_webhook("#{Kogno::Application.config.telegram.webhook_https_server}#{Kogno::Application.config.telegram.webhook_route}", Kogno::Application.config.telegram.webhook_drop_pending_updates)
|
11
|
+
elsif a[2] == 'stop'
|
12
|
+
Kogno::Telegram::Api.delete_webhook(Kogno::Application.config.telegram.webhook_drop_pending_updates)
|
13
|
+
else
|
14
|
+
error = true
|
15
|
+
end
|
16
|
+
when :set_commands
|
17
|
+
puts a[2]
|
18
|
+
scope = a[2]
|
19
|
+
if scope == "all"
|
20
|
+
puts "Aca222"
|
21
|
+
Kogno::Telegram::Api.set_all_commands
|
22
|
+
elsif Kogno::Telegram::Api.command_valid_scopes.include?(scope.to_sym)
|
23
|
+
Kogno::Telegram::Api.set_scope_commands(scope.to_sym)
|
24
|
+
else
|
25
|
+
error = true
|
26
|
+
end
|
27
|
+
when :delete_commands
|
28
|
+
scope = a[2]
|
29
|
+
if Kogno::Telegram::Api.command_valid_scopes.include?(scope.to_sym)
|
30
|
+
Kogno::Telegram::Api.delete_commands(scope)
|
31
|
+
else
|
32
|
+
error = true
|
33
|
+
end
|
34
|
+
else
|
35
|
+
error = true
|
36
|
+
end
|
37
|
+
|
38
|
+
puts %{Usage:
|
39
|
+
kogno telegram
|
40
|
+
webhook start|stop
|
41
|
+
set_commands #{Kogno::Telegram::Api.command_valid_scopes.join("|")}|all
|
42
|
+
delete_commands #{Kogno::Telegram::Api.command_valid_scopes.join("|")}
|
43
|
+
} if error
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Kogno
|
2
|
+
class WebhookCtl
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def pid_file
|
6
|
+
Application.file_path(File.join(Application.project_path,"tmp","webhook.pid"))
|
7
|
+
end
|
8
|
+
|
9
|
+
def log_environment_info
|
10
|
+
logger.write "Kogno #{Gem.loaded_specs["kogno"].version.version} http server starting in #{Kogno::Application.config.environment}", :bright
|
11
|
+
end
|
12
|
+
|
13
|
+
def server_file
|
14
|
+
File.join(Application.core_path,"lib/core/web/webhook.rb")
|
15
|
+
end
|
16
|
+
|
17
|
+
def save_pid(pid)
|
18
|
+
File.write(self.pid_file, pid)
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete_pid
|
22
|
+
save_pid("")
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_pid
|
26
|
+
File.read(File.join(self.pid_file)).to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def kill_process(pid)
|
30
|
+
return false if pid.to_i == 0
|
31
|
+
Process.kill("KILL",pid) rescue nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def alive?
|
35
|
+
pid = get_pid
|
36
|
+
return false if pid == 0
|
37
|
+
Process.getpgid(pid) rescue false
|
38
|
+
end
|
39
|
+
|
40
|
+
def start
|
41
|
+
log_environment_info()
|
42
|
+
if get_pid > 0 && alive?
|
43
|
+
logger.write "Error: It has already started..", :red
|
44
|
+
else
|
45
|
+
system(%{
|
46
|
+
RACK_ENV=#{Kogno::Application.config.environment} ruby #{self.server_file} daemon > /dev/null&
|
47
|
+
echo $! > "#{self.pid_file}"
|
48
|
+
})
|
49
|
+
logger.write "START", :green
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def fg
|
54
|
+
log_environment_info()
|
55
|
+
if get_pid > 0 && alive?
|
56
|
+
logger.write "Error: It has already started..", :red
|
57
|
+
else
|
58
|
+
system("RACK_ENV=#{Kogno::Application.config.environment} ruby #{self.server_file}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def stop
|
63
|
+
pid = self.get_pid
|
64
|
+
self.kill_process(pid)
|
65
|
+
self.delete_pid
|
66
|
+
logger.write "STOP", :red
|
67
|
+
end
|
68
|
+
|
69
|
+
def status
|
70
|
+
if alive?
|
71
|
+
logger.write "Running | Pid: #{self.get_pid}..", :green
|
72
|
+
else
|
73
|
+
logger.write "Stopped", :red
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def options(option)
|
78
|
+
case option.to_s.to_sym
|
79
|
+
when :start
|
80
|
+
self.start
|
81
|
+
when :stop
|
82
|
+
self.stop
|
83
|
+
when :restart
|
84
|
+
self.stop
|
85
|
+
self.start
|
86
|
+
when :status
|
87
|
+
self.status
|
88
|
+
when :fg
|
89
|
+
self.fg
|
90
|
+
else
|
91
|
+
puts "usage: http stop|start|restart|status|fg"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/core/db.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
db_configuration_file = File.join(Kogno::Application.project_path,'config', 'database.yml')
|
2
|
+
db_configuration = YAML.load(File.read(db_configuration_file))
|
3
|
+
|
4
|
+
def db_connect(db_configuration)
|
5
|
+
ActiveRecord::Base.establish_connection(db_configuration)
|
6
|
+
end
|
7
|
+
|
8
|
+
db_connect(db_configuration)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
class Array
|
3
|
+
|
4
|
+
def replace_keys(defaults)
|
5
|
+
new_a = []
|
6
|
+
self.each do |v|
|
7
|
+
if v.class == Array
|
8
|
+
new_a << v.replace_keys(defaults)
|
9
|
+
elsif v.class == Hash
|
10
|
+
new_h = v
|
11
|
+
defaults.each do |find,replace|
|
12
|
+
# logger.debug "#{find} => #{replace}"
|
13
|
+
# logger.debug "v:#{v}"
|
14
|
+
new_h = new_h.transform_keys{|k| k == find ? replace : k}
|
15
|
+
end
|
16
|
+
new_a << new_h
|
17
|
+
else
|
18
|
+
new_a << v
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return(new_a)
|
22
|
+
end
|
23
|
+
|
24
|
+
def deep_symbolize_keys!
|
25
|
+
self.map{|h| h.deep_symbolize_keys!}
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class Logger
|
2
|
+
|
3
|
+
def write(str, color=nil)
|
4
|
+
if color.nil?
|
5
|
+
self.info(str)
|
6
|
+
else
|
7
|
+
self.info(Logger::colorize(str, color.to_sym))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def write_json(json,color=nil)
|
12
|
+
write(JSON.pretty_generate(json),color)
|
13
|
+
end
|
14
|
+
|
15
|
+
def debug(str,color=nil)
|
16
|
+
write(str,color) if Kogno::Application.config.environment == :development
|
17
|
+
end
|
18
|
+
|
19
|
+
def debug_json(json,color=nil)
|
20
|
+
write(JSON.pretty_generate(json),color) if Kogno::Application.config.environment == :development
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
class << self
|
25
|
+
|
26
|
+
def set(daemon)
|
27
|
+
case daemon
|
28
|
+
when :webhook
|
29
|
+
$logger = Logger.new(File.join(Kogno::Application.project_path,'logs','http.log'))
|
30
|
+
when :sequences
|
31
|
+
$logger = Logger.new(File.join(Kogno::Application.project_path,'logs','sequences.log'))
|
32
|
+
when :scheduled_messages
|
33
|
+
$logger = Logger.new(File.join(Kogno::Application.project_path,'logs','scheduled_messages.log'))
|
34
|
+
else
|
35
|
+
$logger = Logger.new(STDOUT)
|
36
|
+
end
|
37
|
+
|
38
|
+
# logger.datetime_format = ""
|
39
|
+
$logger.formatter = proc do |severity, datetime, progname, msg|
|
40
|
+
"#{msg}\n"
|
41
|
+
end
|
42
|
+
|
43
|
+
ActiveRecord::Base.logger = $logger
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def colors
|
48
|
+
@colors ||= {
|
49
|
+
bright: 1,
|
50
|
+
blue: 34,
|
51
|
+
green: 32,
|
52
|
+
light_blue: 36,
|
53
|
+
pink: 35,
|
54
|
+
red: 31,
|
55
|
+
white: 256,
|
56
|
+
yellow: 33
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def colorize(str, color_code)
|
61
|
+
"\e[#{colors[color_code]}m#{str}\e[0m"
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
def logger
|
69
|
+
$logger
|
70
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'wit'
|
2
|
+
class Wit
|
3
|
+
|
4
|
+
|
5
|
+
def initialize(opts = {})
|
6
|
+
@access_token = opts[:access_token]
|
7
|
+
@api_version = opts[:api_version] || "20210928"
|
8
|
+
|
9
|
+
if opts[:logger]
|
10
|
+
@logger = opts[:logger]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def message_with_context(msg, context=nil)
|
15
|
+
params = {}
|
16
|
+
params[:q] = msg unless msg.nil?
|
17
|
+
params[:context] = context.to_json unless context.nil?
|
18
|
+
res = req(logger, @access_token, Net::HTTP::Get, '/message', params)
|
19
|
+
return res
|
20
|
+
end
|
21
|
+
|
22
|
+
def entity_create(params) # extras = {roles: [], keywords: [], lookups: []}
|
23
|
+
res = req(logger, @access_token, Net::HTTP::Post, "/entities", {}, params)
|
24
|
+
return res
|
25
|
+
end
|
26
|
+
|
27
|
+
def entity_keyword_add(name, role, keyword, synonyms)
|
28
|
+
res = req(logger, @access_token, Net::HTTP::Post, "/entities/#{name}/keywords", {}, {keyword: keyword, synonyms: synonyms})
|
29
|
+
return res
|
30
|
+
end
|
31
|
+
|
32
|
+
def entity_keyword_remove(name, keyword)
|
33
|
+
res = req(logger, @access_token, Net::HTTP::Delete, "/entities/#{name}/keywords/#{keyword}")
|
34
|
+
return res
|
35
|
+
end
|
36
|
+
|
37
|
+
def req(logger, access_token, meth_class, path, params={}, payload={})
|
38
|
+
uri = URI(WIT_API_HOST + path)
|
39
|
+
uri.query = URI.encode_www_form(params)
|
40
|
+
# logger.debug uri, :green
|
41
|
+
request = meth_class.new(uri)
|
42
|
+
request['authorization'] = 'Bearer ' + access_token
|
43
|
+
request['accept'] = 'application/vnd.wit.' + @api_version + '+json'
|
44
|
+
request.add_field 'Content-Type', 'application/json'
|
45
|
+
request.body = payload.to_json
|
46
|
+
# logger.debug request, :yellow
|
47
|
+
Net::HTTP.start(uri.host, uri.port, {:use_ssl => uri.scheme == 'https'}) do |http|
|
48
|
+
rsp = http.request(request)
|
49
|
+
json = JSON.parse(rsp.body)
|
50
|
+
if rsp.code.to_i != 200
|
51
|
+
error_msg = (json.is_a?(Hash) and json.has_key?('error')) ? json['error'] : json
|
52
|
+
logger.write "Wit.ai responded with an error: #{error_msg}", :red
|
53
|
+
raise Error.new("Wit.ai responded with an error: #{error_msg}")
|
54
|
+
end
|
55
|
+
# logger.debug("#{meth_class} #{uri} #{json}")
|
56
|
+
json
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
def t(key, **interpolation)
|
2
|
+
translation = I18n.t(key, **interpolation)
|
3
|
+
if translation.class == Array
|
4
|
+
return translation[rand(translation.count)]
|
5
|
+
else
|
6
|
+
return translation
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def l(value, **format)
|
11
|
+
I18n.l(value, **format)
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_payload(payload,params=nil)
|
15
|
+
unless params.nil?
|
16
|
+
output_payload = "#{payload}:#{params.to_json}"
|
17
|
+
else
|
18
|
+
output_payload = payload
|
19
|
+
end
|
20
|
+
return output_payload
|
21
|
+
end
|
22
|
+
|
23
|
+
def reload!(print = true)
|
24
|
+
puts 'Reloading ...' if print
|
25
|
+
Kogno::Application.load_locales
|
26
|
+
Kogno::Application.load_app
|
27
|
+
return true
|
28
|
+
end
|
29
|
+
|
30
|
+
def sql_query(query)
|
31
|
+
# logger.debug "sql_query = > #{query}", :green
|
32
|
+
results = ActiveRecord::Base.connection.select_all(query)
|
33
|
+
{
|
34
|
+
columns: results.columns,
|
35
|
+
rows: results.rows
|
36
|
+
}
|
37
|
+
results
|
38
|
+
end
|
39
|
+
|
40
|
+
def html_template(route, params={})
|
41
|
+
|
42
|
+
route_array = route.to_s.split("/")
|
43
|
+
if route_array.count == 2
|
44
|
+
action_group = route_array[0]
|
45
|
+
action = route_array[1]
|
46
|
+
elsif route_array.count == 1
|
47
|
+
if self.type == :context
|
48
|
+
action_group = self.name
|
49
|
+
action = route_array[0]
|
50
|
+
else
|
51
|
+
raise "Can't determine the context for template #{route}"
|
52
|
+
return false
|
53
|
+
end
|
54
|
+
else
|
55
|
+
raise "Wrong format on route. Expected:'context_name/template_name'"
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
template = $context_html_templates[action_group.to_sym][action.to_sym]
|
60
|
+
if template.nil?
|
61
|
+
logger.write "Template bot/templates/#{action_group}/#{action}.rhtml not found.", :red
|
62
|
+
return ""
|
63
|
+
else
|
64
|
+
return template.render(self, params)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
def tabulate(text, divider, max_chars, orientation = "left")
|
2
|
+
amount = text.count(divider)
|
3
|
+
amount = amount + 1
|
4
|
+
spacing = max_chars / amount
|
5
|
+
text = text.split(divider)
|
6
|
+
text.each do |str|
|
7
|
+
str = str.strip
|
8
|
+
index = text.find_index(str)
|
9
|
+
if str[0] == " "
|
10
|
+
text[index] = str[1..-1]
|
11
|
+
elsif str[str.length - 1] == " "
|
12
|
+
text[index] = str.chop
|
13
|
+
end
|
14
|
+
end
|
15
|
+
new_text = []
|
16
|
+
#even_space = 0
|
17
|
+
|
18
|
+
case orientation
|
19
|
+
when "left"
|
20
|
+
new_text = tabulateLeft(text, spacing)
|
21
|
+
when "right"
|
22
|
+
new_text = tabulateRight(text, spacing)
|
23
|
+
when "middle"
|
24
|
+
new_text = tabulateMiddle(text, spacing)
|
25
|
+
end
|
26
|
+
|
27
|
+
return new_text.join(divider)
|
28
|
+
end
|
29
|
+
|
30
|
+
def tabulateLeft(text, spacing)
|
31
|
+
new_text = []
|
32
|
+
text.each do |str|
|
33
|
+
tab_str = str
|
34
|
+
spaces = spacing - str.length
|
35
|
+
|
36
|
+
if text.find_index(tab_str).even?
|
37
|
+
if spacing > tab_str.length && text.find_index(tab_str) != 0
|
38
|
+
tab_str.prepend(" ")
|
39
|
+
spaces -= 1
|
40
|
+
end
|
41
|
+
while spaces > 0 do
|
42
|
+
tab_str.concat(" ")
|
43
|
+
spaces -= 1
|
44
|
+
end
|
45
|
+
else
|
46
|
+
if spacing > tab_str.length
|
47
|
+
tab_str.prepend(" ")
|
48
|
+
spaces -= 1
|
49
|
+
end
|
50
|
+
while spaces > 0 do
|
51
|
+
tab_str.concat(" ")
|
52
|
+
spaces -= 1
|
53
|
+
end
|
54
|
+
end
|
55
|
+
new_text << tab_str
|
56
|
+
end
|
57
|
+
return new_text
|
58
|
+
end
|
59
|
+
|
60
|
+
def tabulateRight(text, spacing)
|
61
|
+
new_text = []
|
62
|
+
text.each do |str|
|
63
|
+
tab_str = str
|
64
|
+
spaces = spacing - str.length
|
65
|
+
|
66
|
+
if text.find_index(tab_str).even?
|
67
|
+
if spacing > tab_str.length
|
68
|
+
tab_str.concat(" ")
|
69
|
+
spaces -= 1
|
70
|
+
end
|
71
|
+
while spaces > 0 do
|
72
|
+
tab_str.prepend(" ")
|
73
|
+
spaces -= 1
|
74
|
+
end
|
75
|
+
else
|
76
|
+
while spaces > 0 do
|
77
|
+
tab_str.prepend(" ")
|
78
|
+
spaces -= 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
new_text << tab_str
|
82
|
+
end
|
83
|
+
return new_text
|
84
|
+
end
|
85
|
+
|
86
|
+
def tabulateMiddle(text, spacing)
|
87
|
+
new_text = []
|
88
|
+
text.each do |str|
|
89
|
+
tab_str = str
|
90
|
+
spaces = spacing - str.length
|
91
|
+
divided = spaces / 2
|
92
|
+
concat = false
|
93
|
+
|
94
|
+
while spaces > divided do
|
95
|
+
tab_str.prepend(" ")
|
96
|
+
spaces -= 1
|
97
|
+
end
|
98
|
+
while spaces > 0 do
|
99
|
+
tab_str.concat(" ")
|
100
|
+
spaces -= 1
|
101
|
+
end
|
102
|
+
new_text << tab_str
|
103
|
+
end
|
104
|
+
return new_text
|
105
|
+
end
|