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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +35 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +29 -0
  6. data/.simplecov +5 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +12 -0
  9. data/LICENSE.md +21 -0
  10. data/README.md +160 -0
  11. data/Rakefile +11 -0
  12. data/aws-lex-conversation.gemspec +38 -0
  13. data/bin/console +15 -0
  14. data/bin/setup +8 -0
  15. data/lib/aws-lex-conversation.rb +3 -0
  16. data/lib/aws/lex/conversation.rb +58 -0
  17. data/lib/aws/lex/conversation/base.rb +40 -0
  18. data/lib/aws/lex/conversation/handler/base.rb +34 -0
  19. data/lib/aws/lex/conversation/handler/delegate.rb +17 -0
  20. data/lib/aws/lex/conversation/handler/echo.rb +24 -0
  21. data/lib/aws/lex/conversation/response/base.rb +30 -0
  22. data/lib/aws/lex/conversation/response/close.rb +29 -0
  23. data/lib/aws/lex/conversation/response/confirm_intent.rb +31 -0
  24. data/lib/aws/lex/conversation/response/delegate.rb +29 -0
  25. data/lib/aws/lex/conversation/response/elicit_intent.rb +27 -0
  26. data/lib/aws/lex/conversation/response/elicit_slot.rb +33 -0
  27. data/lib/aws/lex/conversation/support/inflector.rb +43 -0
  28. data/lib/aws/lex/conversation/support/responses.rb +56 -0
  29. data/lib/aws/lex/conversation/type/base.rb +95 -0
  30. data/lib/aws/lex/conversation/type/bot.rb +17 -0
  31. data/lib/aws/lex/conversation/type/confirmation_status.rb +17 -0
  32. data/lib/aws/lex/conversation/type/current_intent.rb +34 -0
  33. data/lib/aws/lex/conversation/type/dialog_action_type.rb +19 -0
  34. data/lib/aws/lex/conversation/type/enumeration.rb +44 -0
  35. data/lib/aws/lex/conversation/type/event.rb +37 -0
  36. data/lib/aws/lex/conversation/type/fulfillment_state.rb +16 -0
  37. data/lib/aws/lex/conversation/type/invocation_source.rb +16 -0
  38. data/lib/aws/lex/conversation/type/message.rb +20 -0
  39. data/lib/aws/lex/conversation/type/message/content_type.rb +19 -0
  40. data/lib/aws/lex/conversation/type/output_dialog_mode.rb +16 -0
  41. data/lib/aws/lex/conversation/type/recent_intent_summary_view.rb +29 -0
  42. data/lib/aws/lex/conversation/type/response.rb +17 -0
  43. data/lib/aws/lex/conversation/type/response_card.rb +23 -0
  44. data/lib/aws/lex/conversation/type/response_card/button.rb +18 -0
  45. data/lib/aws/lex/conversation/type/response_card/content_type.rb +17 -0
  46. data/lib/aws/lex/conversation/type/response_card/generic_attachment.rb +26 -0
  47. data/lib/aws/lex/conversation/type/sentiment_label.rb +18 -0
  48. data/lib/aws/lex/conversation/type/sentiment_response.rb +21 -0
  49. data/lib/aws/lex/conversation/type/sentiment_score.rb +35 -0
  50. data/lib/aws/lex/conversation/type/slot_detail.rb +20 -0
  51. data/lib/aws/lex/conversation/type/slot_resolution.rb +15 -0
  52. data/lib/aws/lex/conversation/version.rb +9 -0
  53. metadata +117 -0
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'aws/lex/conversation'
@@ -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