aws-lex-conversation 0.5.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 +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
|