kamigo 0.16.0 → 0.21.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a082803e8394a9239e446ce0e09ff99a09f160d11806d5c11b63f02ce563f0d
4
- data.tar.gz: 396410d5226e1879b1007aea8454b86169dee9c6f14206d795f87fcf8c9af244
3
+ metadata.gz: 603369132a555eac9c1006ef6c72942613f949a7969062cbb6a1113082cdfa01
4
+ data.tar.gz: 1723ac2a6317728974b8f8605e244490277851e652732524637ac41ba208bc1a
5
5
  SHA512:
6
- metadata.gz: fd383becc048eb21156fe66ffa59834b0f77b2e14403bbd972fa1fb9b62fd5be94d5a07b9adb5a9fad3c93f176bff12a0620006ea5c2ca845c6a81e5dcdf361e
7
- data.tar.gz: 395a3807def72c42bb2d9f34f8ddb2298b0e22e93d61e4c66b1bd6c6bbcb0f7f5b227127ad27e3ea537bbe6a1b765fb722f4fb8bbed593628faddc23c7701e3a
6
+ metadata.gz: 12a69d80119b1b44d96c65aa917c4df52cf7103b6588938d1004bc7c110d022bd6d1dc749c88539d93fe734c2916cca73e53bc0d4966dc7997c79331f5778583
7
+ data.tar.gz: 51e23e962faafa4abd7a7fd153c3187147d1a9bb7f1905f32fda1efeb91ad63db00e1a26d70f41703317423fdf229f0e24f468eeceaeed734dac537c9e574645
data/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 詳細的說明文件
2
+
3
+ [Kamigo 詳細說明](https://etrex.tw/kamigo/)
4
+
1
5
  # Kamigo 簡介
2
6
  Kamigo 是一個基於 Rails 的 Chatbot MVC Framework。
3
7
 
@@ -18,6 +22,8 @@ cd kamigo_demo
18
22
  # 安裝套件
19
23
  bundle add kamigo
20
24
  bundle add dotenv-rails
25
+ # 建立設定檔
26
+ rails g kamigo:install
21
27
  # 新增 resource controller
22
28
  rails g scaffold todo name desc
23
29
  rails db:create
@@ -137,19 +143,17 @@ Kamigo 預設使用基本的語意理解模型,會將使用者輸入視為在
137
143
  - 守護寵物機器人
138
144
  <p><img width="100" height="100" src="/doc/images/pet_loved_qrcode.png"></p>
139
145
 
140
- # 詳細的說明文件
141
- - [Kamigo 架構概觀](/doc/01_intro.md)
142
- - [Route 的使用說明](/doc/02_route.md)
143
- - [Controller 的使用說明](/doc/03_controller.md)
144
- - [View 的使用說明](/doc/04_view.md)
145
- - [Form 的使用說明](/doc/05_form.md)
146
- - [Kamigo 相關設定與 QA](/doc/06_setting.md)
147
-
148
146
  # 計畫
149
147
  - 提供多種語意理解模型串接
148
+ - DialogFlow
149
+ - LUIS
150
150
  - 網站使用者與聊天機器人使用者綁定
151
- - 支援 Telegram
152
- - 支援 Facebook Messenger
151
+ - Devise
152
+ - Log / 錯誤追蹤
153
+ - 支援其他平台
154
+ - Telegram
155
+ - Facebook Messenger
156
+ - Slack
153
157
 
154
158
  ## License
155
159
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,83 +1,11 @@
1
1
  require 'uri'
2
2
 
3
3
  class LineController < ApplicationController
4
- include ReverseRoute
5
4
  protect_from_forgery with: :null_session
6
5
 
7
6
  def entry
8
- parser = Kamigo::EventParsers::LineEventParser.new
9
- events = parser.parse_events(request)
10
- events.each do |event|
11
- process_event(event)
12
- end
7
+ request_handler = Kamigo::RequestHandlers::LineRequestHandler.new(request, form_authenticity_token)
8
+ request_handler.handle
13
9
  head :ok
14
10
  end
15
-
16
- private
17
-
18
- def process_event(event)
19
- http_method, path, request_params = slot_filling(event)
20
- http_method, path, request_params = language_understanding(event.message) if http_method.nil?
21
- encoded_path = URI.encode(path)
22
- request_params = event.platform_params.merge(request_params)
23
- output = reserve_route(encoded_path, http_method: http_method, request_params: request_params, format: :line)
24
- responser = Kamigo::EventResponsers::LineEventResponser.new
25
- response = responser.response_event(event, output)
26
- puts response&.body
27
- rescue NoMethodError => e
28
- puts e.full_message
29
- responser = Kamigo::EventResponsers::LineEventResponser.new
30
- response = responser.response_event(event, {
31
- type: "text",
32
- text: "404 not found"
33
- })
34
- end
35
-
36
- def slot_filling(event)
37
- begin
38
- Kamiform
39
- rescue StandardError
40
- return [nil, nil, nil]
41
- end
42
-
43
- form = Kamiform.find_by(
44
- platform_type: event.platform_type,
45
- source_group_id: event.source_group_id
46
- )
47
- return [nil, nil, nil] if form.nil?
48
-
49
- http_method = form.http_method
50
- path = form.path
51
- request_params = form.params
52
-
53
- # fill
54
- if form.field['.'].nil?
55
- request_params[form.field] = event.message
56
- else
57
- *head, tail = form.field.split('.')
58
- request_params.dig(*head)[tail] = event.message
59
- end
60
- form.destroy
61
- [http_method.upcase, path, request_params]
62
- end
63
-
64
- def language_understanding(text)
65
- http_method = %w[GET POST PUT PATCH DELETE].find do |http_method|
66
- text.start_with? http_method
67
- end
68
- text = text[http_method.size..-1] if http_method.present?
69
- text = text.strip
70
- lines = text.split("\n").compact
71
- path = lines.shift
72
- request_params = parse_json(lines.join(""))
73
- request_params[:authenticity_token] = form_authenticity_token
74
- http_method = request_params["_method"]&.upcase || http_method || "GET"
75
- [http_method, path, request_params]
76
- end
77
-
78
- def parse_json(string)
79
- return {} if string.strip.empty?
80
- JSON.parse(string)
81
- end
82
-
83
11
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/base'
4
+
5
+ module Kamigo
6
+ module Generators
7
+ class InstallGenerator < Rails::Generators::Base
8
+ source_root File.expand_path("../../templates", __FILE__)
9
+
10
+ desc "Creates a Kamigo initializer and copy locale files to your application."
11
+
12
+ def copy_initializer
13
+ template "kamigo.rb", "config/initializers/kamigo.rb"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,56 @@
1
+ require 'rails/generators/named_base'
2
+ require 'rails/generators/resource_helpers'
3
+
4
+ module Rails
5
+ module Generators
6
+ class CreateStateGenerator < NamedBase
7
+ include Rails::Generators::ResourceHelpers
8
+ namespace "devise"
9
+ argument :attributes, type: :string, default: 'kamigo_state'
10
+
11
+ class_option :timestamps, type: :boolean, default: true
12
+
13
+ def create_root_folder
14
+ path = File.join('app/views', controller_file_path)
15
+ empty_directory path unless File.directory?(path)
16
+ end
17
+
18
+ def copy_view_files
19
+ filenames.each do |filename|
20
+ template filename, File.join('app/views', controller_file_path, filename)
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ def attributes_names
27
+ [:id] + super
28
+ end
29
+
30
+ def filenames
31
+ [
32
+ "index.line.erb",
33
+ "show.line.erb",
34
+ "edit.liff.erb",
35
+ "new.liff.erb",
36
+ ]
37
+ end
38
+
39
+ def full_attributes_list
40
+ if options[:timestamps]
41
+ attributes_list(attributes_names + %w(created_at updated_at))
42
+ else
43
+ attributes_list(attributes_names)
44
+ end
45
+ end
46
+
47
+ def attributes_list(attributes = attributes_names)
48
+ if self.attributes.any? {|attr| attr.name == 'password' && attr.type == :digest}
49
+ attributes = attributes.reject {|name| %w(password password_confirmation).include? name}
50
+ end
51
+
52
+ attributes.map { |a| ":#{a}"} * ', '
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,14 @@
1
+ Kamigo.setup do |config|
2
+ # When user input doesn't match the route, Kamigo will pass the reuqest to default_path with default_http_method.
3
+ # config.default_path = "/"
4
+ # config.default_http_method = "GET"
5
+
6
+ # When Kamigo don't know what message to reply, then Kamigo reply the line_default_message.
7
+ # config.line_default_message = {
8
+ # type: "text",
9
+ # text: "Sorry, I don't understand your message."
10
+ # }
11
+
12
+ # When line_default_message is nil, then Kamigo don't reply message.
13
+ # config.line_default_message = nil
14
+ end
data/lib/kamigo.rb CHANGED
@@ -7,6 +7,26 @@ require "kamigo/events/basic_event"
7
7
  require "kamigo/events/line_event"
8
8
  require "kamigo/event_parsers/line_event_parser"
9
9
  require "kamigo/event_responsers/line_event_responser"
10
+ require "kamigo/event_processors/rails_router_processor"
11
+ require "kamigo/request_handlers/line_request_handler"
12
+
10
13
  module Kamigo
11
- # Your code goes here...
14
+ mattr_accessor :line_default_message
15
+ @@line_default_message = {
16
+ type: "text",
17
+ text: "Sorry, I don't understand your message."
18
+ }
19
+
20
+ mattr_accessor :default_path
21
+ @@default_path = nil
22
+
23
+ mattr_accessor :default_http_method
24
+ @@default_http_method = "GET"
25
+
26
+ mattr_accessor :line_event_processors
27
+ @@line_event_processors = [EventProcessors::RailsRouterProcessor.new]
28
+
29
+ def self.setup
30
+ yield self
31
+ end
12
32
  end
@@ -12,19 +12,37 @@ module Kamigo
12
12
  end
13
13
 
14
14
  def parse(event)
15
- payload = JSON.parse(event.to_json, symbolize_names: true)[:src]
16
- response = client.get_profile(payload[:source][:userId])
15
+ event_hash = JSON.parse(event.to_json, symbolize_names: true)
16
+ payload = event_hash[:src] || event_hash
17
17
  line_event = Kamigo::Events::LineEvent.new
18
18
  line_event.payload = payload
19
19
  line_event.reply_token = event['replyToken']
20
- line_event.profile = JSON.parse(response.body)
21
20
  line_event.source_type = payload.dig(:source, :type)
22
21
  line_event.source_group_id = payload.dig(:source, :groupId) || payload.dig(:source, :roomId) || payload.dig(:source, :userId)
23
22
  line_event.source_user_id = payload.dig(:source, :userId) || payload.dig(:source, :groupId) || payload.dig(:source, :roomId)
24
23
  line_event.message_type = payload.dig(:message, :type) || payload.dig(:type)
25
24
  line_event.message = payload.dig(:message, :text) || payload.dig(:postback, :data) || payload.dig(:message, :address) || line_event.message_type
25
+ line_event.profile = get_profile(line_event)
26
26
  line_event
27
27
  end
28
+
29
+ def get_profile(line_event)
30
+ case line_event.source_type
31
+ when 'group'
32
+ response = client.get_group_member_profile(
33
+ line_event.source_group_id,
34
+ line_event.source_user_id
35
+ )
36
+ when 'room'
37
+ response = client.get_room_member_profile(
38
+ line_event.source_group_id,
39
+ line_event.source_user_id
40
+ )
41
+ else
42
+ response = client.get_profile(line_event.source_user_id)
43
+ end
44
+ JSON.parse(response.body)
45
+ end
28
46
  end
29
47
  end
30
48
  end
@@ -0,0 +1,87 @@
1
+ module Kamigo
2
+ module EventProcessors
3
+ class RailsRouterProcessor
4
+ attr_accessor :request
5
+ attr_accessor :form_authenticity_token
6
+
7
+ def initialize
8
+ end
9
+
10
+ def process(event)
11
+ http_method, path, request_params = kamiform_context(event)
12
+ http_method, path, request_params = language_understanding(event.message) if http_method.nil?
13
+ encoded_path = URI.encode(path)
14
+ request_params = event.platform_params.merge(request_params)
15
+ output = reserve_route(encoded_path, http_method: http_method, request_params: request_params, format: :line)
16
+ return output if output.present?
17
+
18
+ return nil if Kamigo.default_path.nil?
19
+ reserve_route(URI.encode(Kamigo.default_path), http_method: Kamigo.default_http_method, request_params: request_params, format: :line)
20
+ end
21
+
22
+ private
23
+
24
+ def kamiform_context(event)
25
+ begin
26
+ Kamiform
27
+ rescue StandardError
28
+ return [nil, nil, nil]
29
+ end
30
+
31
+ form = Kamiform.find_by(
32
+ platform_type: event.platform_type,
33
+ source_group_id: event.source_group_id
34
+ )
35
+ return [nil, nil, nil] if form.nil?
36
+
37
+ http_method = form.http_method
38
+ path = form.path
39
+ request_params = form.params
40
+
41
+ # fill
42
+ if form.field['.'].nil?
43
+ request_params[form.field] = event.message
44
+ else
45
+ *head, tail = form.field.split('.')
46
+ request_params.dig(*head)[tail] = event.message
47
+ end
48
+ form.destroy
49
+ [http_method.upcase, path, request_params]
50
+ end
51
+
52
+ def language_understanding(text)
53
+ http_method = %w[GET POST PUT PATCH DELETE].find do |http_method|
54
+ text.start_with? http_method
55
+ end
56
+ text = text[http_method.size..-1] if http_method.present?
57
+ text = text.strip
58
+ lines = text.split("\n").compact
59
+ path = lines.shift
60
+ request_params = parse_json(lines.join(""))
61
+ request_params[:authenticity_token] = @form_authenticity_token
62
+ http_method = request_params["_method"]&.upcase || http_method || "GET"
63
+ [http_method, path, request_params]
64
+ end
65
+
66
+ def parse_json(string)
67
+ return {} if string.strip.empty?
68
+ JSON.parse(string)
69
+ end
70
+
71
+ def reserve_route(path, http_method: "GET", request_params: nil, format: nil)
72
+ path = "/#{path}" unless path.start_with? "/"
73
+
74
+ @request.request_method = http_method
75
+ @request.path_info = path
76
+ @request.format = format if format.present?
77
+ @request.request_parameters = request_params if request_params.present?
78
+
79
+ # req = Rack::Request.new
80
+ # env = {Rack::RACK_INPUT => StringIO.new}
81
+
82
+ res = Rails.application.routes.router.serve(@request)
83
+ res[2].body if res[2].respond_to?(:body)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -5,7 +5,7 @@ module Kamigo
5
5
 
6
6
  def response_event(event, message)
7
7
  return nil if message.blank?
8
- message = JSON.parse(message) if message.is_a?(String) && message.start_with?("{")
8
+ message = JSON.parse(message) if message.is_a?(String) && (message.start_with?("{") || message.start_with?("["))
9
9
  return nil if message.blank?
10
10
  response = client.reply_message(event.reply_token, message)
11
11
  response
@@ -0,0 +1,32 @@
1
+ module Kamigo
2
+ module RequestHandlers
3
+ class LineRequestHandler
4
+ def initialize(request, form_authenticity_token)
5
+ @request = request
6
+ @form_authenticity_token = form_authenticity_token
7
+ end
8
+
9
+ def handle
10
+ parser = EventParsers::LineEventParser.new
11
+ events = parser.parse_events(@request)
12
+ events.each do |event|
13
+ output = process_event(event) || Kamigo.line_default_message
14
+ responser = EventResponsers::LineEventResponser.new
15
+ response = responser.response_event(event, output)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def process_event(event)
22
+ Kamigo.line_event_processors.each do |processor|
23
+ processor.request = @request
24
+ processor.form_authenticity_token = @form_authenticity_token
25
+ output = processor.process(event)
26
+ return output if output.present?
27
+ end
28
+ nil
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,3 +1,3 @@
1
1
  module Kamigo
2
- VERSION = '0.16.0'.freeze
2
+ VERSION = '0.21.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kamigo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - etrex
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-22 00:00:00.000000000 Z
11
+ date: 2021-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -30,20 +30,20 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.24'
33
+ version: '0.25'
34
34
  - - ">="
35
35
  - !ruby/object:Gem::Version
36
- version: 0.24.0
36
+ version: 0.25.0
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - "~>"
42
42
  - !ruby/object:Gem::Version
43
- version: '0.24'
43
+ version: '0.25'
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 0.24.0
46
+ version: 0.25.0
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: kamiflex
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -103,26 +103,30 @@ files:
103
103
  - README.md
104
104
  - Rakefile
105
105
  - app/assets/config/kamigo_manifest.js
106
- - app/controllers/concerns/reverse_route.rb
107
106
  - app/controllers/kamigo_controller.rb
108
107
  - app/controllers/line_controller.rb
109
108
  - config/routes.rb
109
+ - lib/generators/kamigo/install_generator.rb
110
110
  - lib/generators/rails/kamigo/USAGE
111
111
  - lib/generators/rails/kamigo/kamigo_generator.rb
112
+ - lib/generators/rails/kamigo/state_generator.rb
112
113
  - lib/generators/rails/kamigo/templates/edit.liff.erb
113
114
  - lib/generators/rails/kamigo/templates/index.line.erb
114
115
  - lib/generators/rails/kamigo/templates/new.liff.erb
115
116
  - lib/generators/rails/kamigo/templates/show.line.erb
116
117
  - lib/generators/rails/scaffold_controller_generator.rb
117
118
  - lib/generators/rails/templates/controller.rb
119
+ - lib/generators/templates/kamigo.rb
118
120
  - lib/kamigo.rb
119
121
  - lib/kamigo/clients/line_client.rb
120
122
  - lib/kamigo/engine.rb
121
123
  - lib/kamigo/event_parsers/line_event_parser.rb
124
+ - lib/kamigo/event_processors/rails_router_processor.rb
122
125
  - lib/kamigo/event_responsers/line_event_responser.rb
123
126
  - lib/kamigo/events/basic_event.rb
124
127
  - lib/kamigo/events/line_event.rb
125
128
  - lib/kamigo/railtie.rb
129
+ - lib/kamigo/request_handlers/line_request_handler.rb
126
130
  - lib/kamigo/version.rb
127
131
  homepage: https://github.com/etrex/kamigo
128
132
  licenses:
@@ -1,16 +0,0 @@
1
- module ReverseRoute
2
- def reserve_route(path, http_method: "GET", request_params: nil, format: nil)
3
- path = "/#{path}" unless path.start_with? "/"
4
-
5
- request.request_method = http_method
6
- request.path_info = path
7
- request.format = format if format.present?
8
- request.request_parameters = request_params if request_params.present?
9
-
10
- # req = Rack::Request.new
11
- # env = {Rack::RACK_INPUT => StringIO.new}
12
-
13
- res = Rails.application.routes.router.serve(request)
14
- res[2].body
15
- end
16
- end