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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/bin/kogno +92 -0
  3. data/lib/boot.rb +9 -0
  4. data/lib/core/bin_helpers/messenger_ctl.rb +48 -0
  5. data/lib/core/bin_helpers/scaffolding.rb +203 -0
  6. data/lib/core/bin_helpers/scheduled_messages_ctl.rb +95 -0
  7. data/lib/core/bin_helpers/sequences_ctl.rb +95 -0
  8. data/lib/core/bin_helpers/server_ctl.rb +127 -0
  9. data/lib/core/bin_helpers/telegram_ctl.rb +48 -0
  10. data/lib/core/bin_helpers/webhook_ctl.rb +96 -0
  11. data/lib/core/db.rb +8 -0
  12. data/lib/core/extensions/array.rb +28 -0
  13. data/lib/core/extensions/hash.rb +12 -0
  14. data/lib/core/extensions/logger.rb +70 -0
  15. data/lib/core/extensions/string.rb +6 -0
  16. data/lib/core/extensions/wit.rb +60 -0
  17. data/lib/core/global_methods.rb +67 -0
  18. data/lib/core/helpers/string.rb +105 -0
  19. data/lib/core/lib/base_config.rb +17 -0
  20. data/lib/core/lib/block_params.rb +4 -0
  21. data/lib/core/lib/context.rb +1573 -0
  22. data/lib/core/lib/error_handler.rb +36 -0
  23. data/lib/core/lib/message.rb +182 -0
  24. data/lib/core/lib/messenger/api.rb +281 -0
  25. data/lib/core/lib/messenger/facebook_graph.rb +32 -0
  26. data/lib/core/lib/messenger/message.rb +202 -0
  27. data/lib/core/lib/messenger/notification.rb +351 -0
  28. data/lib/core/lib/messenger/post_comment.rb +104 -0
  29. data/lib/core/lib/messenger/recurring_notification.rb +81 -0
  30. data/lib/core/lib/nlp.rb +191 -0
  31. data/lib/core/lib/notification.rb +371 -0
  32. data/lib/core/lib/spelling.rb +13 -0
  33. data/lib/core/lib/telegram/api.rb +197 -0
  34. data/lib/core/lib/telegram/chat_activity.rb +111 -0
  35. data/lib/core/lib/telegram/inline_query.rb +112 -0
  36. data/lib/core/lib/telegram/message.rb +327 -0
  37. data/lib/core/lib/telegram/notification.rb +507 -0
  38. data/lib/core/lib/whatsapp/api.rb +153 -0
  39. data/lib/core/lib/whatsapp/message.rb +132 -0
  40. data/lib/core/lib/whatsapp/notification.rb +206 -0
  41. data/lib/core/lib/whatsapp/status_message.rb +58 -0
  42. data/lib/core/loaders/config_files.rb +15 -0
  43. data/lib/core/models/chat_log.rb +4 -0
  44. data/lib/core/models/long_payload.rb +25 -0
  45. data/lib/core/models/matched_message.rb +5 -0
  46. data/lib/core/models/messenger_recurring_notification.rb +16 -0
  47. data/lib/core/models/scheduled_message.rb +40 -0
  48. data/lib/core/models/sequence.rb +29 -0
  49. data/lib/core/models/telegram_chat_group.rb +26 -0
  50. data/lib/core/models/user.rb +285 -0
  51. data/lib/core/web/webhook.rb +198 -0
  52. data/lib/kogno.rb +130 -0
  53. data/scaffolding/new_project/Gemfile +3 -0
  54. data/scaffolding/new_project/application.rb +5 -0
  55. data/scaffolding/new_project/bot/contexts/main_context.rb +10 -0
  56. data/scaffolding/new_project/bot/conversation.rb +14 -0
  57. data/scaffolding/new_project/bot/models/user.rb +3 -0
  58. data/scaffolding/new_project/config/application.rb +28 -0
  59. data/scaffolding/new_project/config/database.yml +8 -0
  60. data/scaffolding/new_project/config/locales/en.yml +4 -0
  61. data/scaffolding/new_project/config/locales/es.yml +3 -0
  62. data/scaffolding/new_project/config/nlp.rb +23 -0
  63. data/scaffolding/new_project/config/platforms/messenger.rb +74 -0
  64. data/scaffolding/new_project/config/platforms/telegram.rb +45 -0
  65. data/scaffolding/new_project/config/platforms/whatsapp.rb +13 -0
  66. data/scaffolding/new_project/web/routes.rb +10 -0
  67. 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,12 @@
1
+
2
+ class Hash
3
+
4
+ def replace_keys(defaults)
5
+ new_hash = self
6
+ defaults.each do |find,replace|
7
+ new_hash = new_hash.transform_keys{|k| k == find ? replace : k}
8
+ end
9
+ return(new_hash)
10
+ end
11
+
12
+ 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,6 @@
1
+ class String
2
+
3
+ def to_payload
4
+ self.downcase.gsub(" ","_").to_sym
5
+ end
6
+ 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
@@ -0,0 +1,17 @@
1
+ module Kogno
2
+
3
+ class BaseConfig
4
+
5
+ def initialize(*attr_accessors)
6
+ attr_accessors.each do |attr_accessor_name|
7
+ self.class.send(:attr_accessor, attr_accessor_name)
8
+ end
9
+ end
10
+
11
+ def to_h
12
+ self.as_json
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,4 @@
1
+ module Kogno
2
+ class BlockParams < Array
3
+ end
4
+ end