aws-lex-conversation 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +35 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.rubocop.yml +29 -0
- data/.simplecov +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +12 -0
- data/LICENSE.md +21 -0
- data/README.md +160 -0
- data/Rakefile +11 -0
- data/aws-lex-conversation.gemspec +38 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/aws-lex-conversation.rb +3 -0
- data/lib/aws/lex/conversation.rb +58 -0
- data/lib/aws/lex/conversation/base.rb +40 -0
- data/lib/aws/lex/conversation/handler/base.rb +34 -0
- data/lib/aws/lex/conversation/handler/delegate.rb +17 -0
- data/lib/aws/lex/conversation/handler/echo.rb +24 -0
- data/lib/aws/lex/conversation/response/base.rb +30 -0
- data/lib/aws/lex/conversation/response/close.rb +29 -0
- data/lib/aws/lex/conversation/response/confirm_intent.rb +31 -0
- data/lib/aws/lex/conversation/response/delegate.rb +29 -0
- data/lib/aws/lex/conversation/response/elicit_intent.rb +27 -0
- data/lib/aws/lex/conversation/response/elicit_slot.rb +33 -0
- data/lib/aws/lex/conversation/support/inflector.rb +43 -0
- data/lib/aws/lex/conversation/support/responses.rb +56 -0
- data/lib/aws/lex/conversation/type/base.rb +95 -0
- data/lib/aws/lex/conversation/type/bot.rb +17 -0
- data/lib/aws/lex/conversation/type/confirmation_status.rb +17 -0
- data/lib/aws/lex/conversation/type/current_intent.rb +34 -0
- data/lib/aws/lex/conversation/type/dialog_action_type.rb +19 -0
- data/lib/aws/lex/conversation/type/enumeration.rb +44 -0
- data/lib/aws/lex/conversation/type/event.rb +37 -0
- data/lib/aws/lex/conversation/type/fulfillment_state.rb +16 -0
- data/lib/aws/lex/conversation/type/invocation_source.rb +16 -0
- data/lib/aws/lex/conversation/type/message.rb +20 -0
- data/lib/aws/lex/conversation/type/message/content_type.rb +19 -0
- data/lib/aws/lex/conversation/type/output_dialog_mode.rb +16 -0
- data/lib/aws/lex/conversation/type/recent_intent_summary_view.rb +29 -0
- data/lib/aws/lex/conversation/type/response.rb +17 -0
- data/lib/aws/lex/conversation/type/response_card.rb +23 -0
- data/lib/aws/lex/conversation/type/response_card/button.rb +18 -0
- data/lib/aws/lex/conversation/type/response_card/content_type.rb +17 -0
- data/lib/aws/lex/conversation/type/response_card/generic_attachment.rb +26 -0
- data/lib/aws/lex/conversation/type/sentiment_label.rb +18 -0
- data/lib/aws/lex/conversation/type/sentiment_response.rb +21 -0
- data/lib/aws/lex/conversation/type/sentiment_score.rb +35 -0
- data/lib/aws/lex/conversation/type/slot_detail.rb +20 -0
- data/lib/aws/lex/conversation/type/slot_resolution.rb +15 -0
- data/lib/aws/lex/conversation/version.rb +9 -0
- metadata +117 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'conversation/base'
|
4
|
+
|
5
|
+
module Aws
|
6
|
+
module Lex
|
7
|
+
class Conversation
|
8
|
+
include Support::Responses
|
9
|
+
|
10
|
+
attr_accessor :event, :context, :lex
|
11
|
+
|
12
|
+
def initialize(opts = {})
|
13
|
+
self.event = opts.fetch(:event)
|
14
|
+
self.context = opts.fetch(:context)
|
15
|
+
self.lex = Type::Event.shrink_wrap(event)
|
16
|
+
end
|
17
|
+
|
18
|
+
def chain
|
19
|
+
@chain ||= []
|
20
|
+
end
|
21
|
+
|
22
|
+
def handlers=(list)
|
23
|
+
last = nil
|
24
|
+
|
25
|
+
reversed = list.reverse.map do |element|
|
26
|
+
handler = element.fetch(:handler).new(
|
27
|
+
options: element.fetch(:options) { {} },
|
28
|
+
successor: last
|
29
|
+
)
|
30
|
+
last = handler
|
31
|
+
handler
|
32
|
+
end
|
33
|
+
|
34
|
+
@chain = reversed.reverse
|
35
|
+
end
|
36
|
+
|
37
|
+
def handlers
|
38
|
+
chain.map(&:class)
|
39
|
+
end
|
40
|
+
|
41
|
+
def respond
|
42
|
+
chain.first.handle(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
def intent_name
|
46
|
+
lex.current_intent.name
|
47
|
+
end
|
48
|
+
|
49
|
+
def slots
|
50
|
+
lex.current_intent.slots
|
51
|
+
end
|
52
|
+
|
53
|
+
def session
|
54
|
+
lex.session_attributes
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'shrink/wrap'
|
5
|
+
|
6
|
+
require_relative 'version'
|
7
|
+
require_relative 'response/base'
|
8
|
+
require_relative 'response/close'
|
9
|
+
require_relative 'response/confirm_intent'
|
10
|
+
require_relative 'response/delegate'
|
11
|
+
require_relative 'response/elicit_intent'
|
12
|
+
require_relative 'response/elicit_slot'
|
13
|
+
require_relative 'support/responses'
|
14
|
+
require_relative 'support/inflector'
|
15
|
+
require_relative 'type/base'
|
16
|
+
require_relative 'type/enumeration'
|
17
|
+
require_relative 'type/sentiment_label'
|
18
|
+
require_relative 'type/sentiment_score'
|
19
|
+
require_relative 'type/sentiment_response'
|
20
|
+
require_relative 'type/invocation_source'
|
21
|
+
require_relative 'type/dialog_action_type'
|
22
|
+
require_relative 'type/confirmation_status'
|
23
|
+
require_relative 'type/fulfillment_state'
|
24
|
+
require_relative 'type/recent_intent_summary_view'
|
25
|
+
require_relative 'type/slot_resolution'
|
26
|
+
require_relative 'type/slot_detail'
|
27
|
+
require_relative 'type/current_intent'
|
28
|
+
require_relative 'type/output_dialog_mode'
|
29
|
+
require_relative 'type/bot'
|
30
|
+
require_relative 'type/message/content_type'
|
31
|
+
require_relative 'type/message'
|
32
|
+
require_relative 'type/response_card/content_type'
|
33
|
+
require_relative 'type/response_card/button'
|
34
|
+
require_relative 'type/response_card/generic_attachment'
|
35
|
+
require_relative 'type/response_card'
|
36
|
+
require_relative 'type/response'
|
37
|
+
require_relative 'type/event'
|
38
|
+
require_relative 'handler/base'
|
39
|
+
require_relative 'handler/echo'
|
40
|
+
require_relative 'handler/delegate'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Handler
|
7
|
+
class Base
|
8
|
+
attr_accessor :successor, :options
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
self.successor = opts[:successor]
|
12
|
+
self.options = opts[:options]
|
13
|
+
end
|
14
|
+
|
15
|
+
def will_respond?(conversation)
|
16
|
+
callable = options.fetch(:respond_on) { ->(_c) { false } }
|
17
|
+
callable.call(conversation)
|
18
|
+
end
|
19
|
+
|
20
|
+
def response(_conversation)
|
21
|
+
raise NotImplementedError, 'define #response in a subclass'
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle(conversation)
|
25
|
+
return response(conversation) if will_respond?(conversation)
|
26
|
+
return unless successor # end of chain - return nil
|
27
|
+
|
28
|
+
successor.handle(conversation)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Handler
|
7
|
+
class Delegate < Base
|
8
|
+
def response(conversation)
|
9
|
+
conversation.delegate(
|
10
|
+
slots: conversation.lex.current_intent.slots
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Handler
|
7
|
+
class Echo < Base
|
8
|
+
def response(conversation)
|
9
|
+
content = options.fetch(:content) { conversation.lex.input_transcript }
|
10
|
+
content_type = options.fetch(:content_type) { Type::Message::ContentType.new('PlainText') }
|
11
|
+
fulfillment_state = options.fetch(:fulfillment_state) { Type::FulfillmentState.new('Fulfilled') }
|
12
|
+
conversation.close(
|
13
|
+
fulfillment_state: fulfillment_state,
|
14
|
+
message: Type::Message.new(
|
15
|
+
content: content,
|
16
|
+
content_type: content_type
|
17
|
+
)
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Response
|
7
|
+
class Base
|
8
|
+
attr_accessor :session_attributes, :recent_intent_summary_view
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
self.session_attributes = opts[:session_attributes]
|
12
|
+
self.recent_intent_summary_view = opts[:recent_intent_summary_view]
|
13
|
+
end
|
14
|
+
|
15
|
+
def dialog_action
|
16
|
+
raise NotImplementedError, 'define dialog_action in a subclass'
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_lex
|
20
|
+
Type::Response.new(
|
21
|
+
session_attributes: session_attributes,
|
22
|
+
recent_intent_summary_view: recent_intent_summary_view,
|
23
|
+
dialog_action: dialog_action
|
24
|
+
).to_lex
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Response
|
7
|
+
class Close < Base
|
8
|
+
attr_accessor :fulfillment_state, :message, :response_card
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
super
|
12
|
+
self.fulfillment_state = opts.fetch(:fulfillment_state)
|
13
|
+
self.message = opts[:message]
|
14
|
+
self.response_card = opts[:response_card]
|
15
|
+
end
|
16
|
+
|
17
|
+
def dialog_action
|
18
|
+
{
|
19
|
+
type: 'Close',
|
20
|
+
fulfillmentState: fulfillment_state,
|
21
|
+
message: message,
|
22
|
+
responseCard: response_card
|
23
|
+
}.reject { |_, v| v.nil? }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Response
|
7
|
+
class ConfirmIntent < Base
|
8
|
+
attr_accessor :intent_name, :message, :response_card, :slots
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
super
|
12
|
+
self.intent_name = opts.fetch(:intent_name)
|
13
|
+
self.slots = opts[:slots]
|
14
|
+
self.message = opts[:message]
|
15
|
+
self.response_card = opts[:response_card]
|
16
|
+
end
|
17
|
+
|
18
|
+
def dialog_action
|
19
|
+
{
|
20
|
+
type: 'ConfirmIntent',
|
21
|
+
intentName: intent_name,
|
22
|
+
slots: slots,
|
23
|
+
message: message,
|
24
|
+
responseCard: response_card
|
25
|
+
}.reject { |_, v| v.nil? }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Response
|
7
|
+
class Delegate < Base
|
8
|
+
attr_accessor :slots, :kendra_query_request_payload, :kendra_query_filter_string
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
super
|
12
|
+
self.slots = opts[:slots]
|
13
|
+
self.kendra_query_request_payload = opts[:kendra_query_request_payload]
|
14
|
+
self.kendra_query_filter_string = opts[:kendra_query_filter_string]
|
15
|
+
end
|
16
|
+
|
17
|
+
def dialog_action
|
18
|
+
{
|
19
|
+
type: 'Delegate',
|
20
|
+
slots: slots,
|
21
|
+
kendraQueryRequestPayload: kendra_query_request_payload,
|
22
|
+
kendraQueryFilterString: kendra_query_filter_string
|
23
|
+
}.reject { |_, v| v.nil? }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Response
|
7
|
+
class ElicitIntent < Base
|
8
|
+
attr_accessor :message, :response_card
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
super
|
12
|
+
self.message = opts[:message]
|
13
|
+
self.response_card = opts[:response_card]
|
14
|
+
end
|
15
|
+
|
16
|
+
def dialog_action
|
17
|
+
{
|
18
|
+
type: 'ElicitIntent',
|
19
|
+
message: message,
|
20
|
+
responseCard: response_card
|
21
|
+
}.reject { |_, v| v.nil? }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Response
|
7
|
+
class ElicitSlot < Base
|
8
|
+
attr_accessor :intent_name, :message, :response_card, :slots, :slot_to_elicit
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
super
|
12
|
+
self.intent_name = opts.fetch(:intent_name)
|
13
|
+
self.slot_to_elicit = opts.fetch(:slot_to_elicit)
|
14
|
+
self.slots = opts.fetch(:slots)
|
15
|
+
self.message = opts[:message]
|
16
|
+
self.response_card = opts[:response_card]
|
17
|
+
end
|
18
|
+
|
19
|
+
def dialog_action
|
20
|
+
{
|
21
|
+
type: 'ElicitSlot',
|
22
|
+
intentName: intent_name,
|
23
|
+
slots: slots,
|
24
|
+
slotToElicit: slot_to_elicit,
|
25
|
+
message: message,
|
26
|
+
responseCard: response_card
|
27
|
+
}.reject { |_, v| v.nil? }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Support
|
7
|
+
class Inflector
|
8
|
+
attr_accessor :input
|
9
|
+
|
10
|
+
def initialize(input)
|
11
|
+
self.input = input.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_snake_case
|
15
|
+
# shamelessly borrowed from ActiveSupport
|
16
|
+
input
|
17
|
+
.gsub(/::/, '/')
|
18
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
19
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
20
|
+
.tr('-', '_')
|
21
|
+
.gsub(/\W/, '_')
|
22
|
+
.downcase
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_camel_case(style = :lower)
|
26
|
+
parts = input.split('_')
|
27
|
+
first = parts.shift
|
28
|
+
rest = parts.map(&:capitalize)
|
29
|
+
|
30
|
+
case style
|
31
|
+
when :lower
|
32
|
+
rest.unshift(first).join
|
33
|
+
when :upper
|
34
|
+
rest.unshift(first.capitalize).join
|
35
|
+
else
|
36
|
+
raise ArgumentError, "invalid option: `#{style.inspect}`"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Lex
|
5
|
+
class Conversation
|
6
|
+
module Support
|
7
|
+
module Responses
|
8
|
+
def close(opts = {})
|
9
|
+
params = {
|
10
|
+
session_attributes: lex.session_attributes,
|
11
|
+
recent_intent_summary_view: lex.recent_intent_summary_view
|
12
|
+
}.merge(opts)
|
13
|
+
Response::Close.new(params).to_lex
|
14
|
+
end
|
15
|
+
|
16
|
+
def confirm_intent(opts = {})
|
17
|
+
params = {
|
18
|
+
session_attributes: lex.session_attributes,
|
19
|
+
recent_intent_summary_view: lex.recent_intent_summary_view,
|
20
|
+
intent_name: lex.current_intent.name,
|
21
|
+
slots: lex.current_intent.slots
|
22
|
+
}.merge(opts)
|
23
|
+
Response::ConfirmIntent.new(params).to_lex
|
24
|
+
end
|
25
|
+
|
26
|
+
def delegate(opts = {})
|
27
|
+
params = {
|
28
|
+
session_attributes: lex.session_attributes,
|
29
|
+
recent_intent_summary_view: lex.recent_intent_summary_view,
|
30
|
+
slots: lex.current_intent.slots
|
31
|
+
}.merge(opts)
|
32
|
+
Response::Delegate.new(params).to_lex
|
33
|
+
end
|
34
|
+
|
35
|
+
def elicit_intent(opts = {})
|
36
|
+
params = {
|
37
|
+
session_attributes: lex.session_attributes,
|
38
|
+
recent_intent_summary_view: lex.recent_intent_summary_view
|
39
|
+
}.merge(opts)
|
40
|
+
Response::ElicitIntent.new(params).to_lex
|
41
|
+
end
|
42
|
+
|
43
|
+
def elicit_slot(opts = {})
|
44
|
+
params = {
|
45
|
+
session_attributes: lex.session_attributes,
|
46
|
+
recent_intent_summary_view: lex.recent_intent_summary_view,
|
47
|
+
slots: lex.current_intent.slots,
|
48
|
+
intent_name: lex.current_intent.name
|
49
|
+
}.merge(opts)
|
50
|
+
Response::ElicitSlot.new(params).to_lex
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|