kamigo 0.16.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
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