bot_platform 0.1.0 → 0.2.3

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.idea/.gitignore +8 -0
  3. data/.idea/bot_platform.iml +317 -0
  4. data/.idea/misc.xml +4 -0
  5. data/.idea/modules.xml +8 -0
  6. data/.idea/vcs.xml +6 -0
  7. data/.ruby-version +1 -0
  8. data/CHANGELOG.md +25 -0
  9. data/Gemfile.lock +1 -1
  10. data/LICENSE +21 -0
  11. data/README.md +21 -9
  12. data/bin/cli +34 -0
  13. data/bot_platform.gemspec +3 -2
  14. data/docs/channels.md +13 -0
  15. data/lib/bot_platform/activity.rb +32 -0
  16. data/lib/bot_platform/adapter.rb +87 -0
  17. data/lib/bot_platform/asserts.rb +69 -0
  18. data/lib/bot_platform/boot.rb +12 -0
  19. data/lib/bot_platform/channels/base.rb +26 -0
  20. data/lib/bot_platform/channels/chatwork.rb +1 -0
  21. data/lib/bot_platform/channels/console.rb +60 -0
  22. data/lib/bot_platform/channels/facebook.rb +1 -0
  23. data/lib/bot_platform/channels/line.rb +1 -0
  24. data/lib/bot_platform/channels/lineworks.rb +102 -0
  25. data/lib/bot_platform/channels/skype.rb +1 -0
  26. data/lib/bot_platform/channels/skype_for_business.rb +1 -0
  27. data/lib/bot_platform/channels/slack.rb +15 -0
  28. data/lib/bot_platform/channels/teams.rb +15 -0
  29. data/lib/bot_platform/channels/web.rb +15 -0
  30. data/lib/bot_platform/channels/wechat.rb +1 -0
  31. data/lib/bot_platform/channels.rb +9 -0
  32. data/lib/bot_platform/cli.rb +97 -0
  33. data/lib/bot_platform/conversation_state.rb +32 -0
  34. data/lib/bot_platform/dialogs/dialog.rb +48 -0
  35. data/lib/bot_platform/dialogs/dialog_context.rb +104 -0
  36. data/lib/bot_platform/dialogs/dialog_instance.rb +15 -0
  37. data/lib/bot_platform/dialogs/dialog_result.rb +22 -0
  38. data/lib/bot_platform/dialogs/dialog_set.rb +38 -0
  39. data/lib/bot_platform/dialogs/dialog_state.rb +11 -0
  40. data/lib/bot_platform/dialogs/prompts/prompt.rb +84 -0
  41. data/lib/bot_platform/dialogs/prompts/prompt_options.rb +12 -0
  42. data/lib/bot_platform/dialogs/prompts/prompt_recognizer_result.rb +16 -0
  43. data/lib/bot_platform/dialogs/prompts/text_prompt.rb +36 -0
  44. data/lib/bot_platform/dialogs.rb +17 -0
  45. data/lib/bot_platform/message_factory.rb +9 -0
  46. data/lib/bot_platform/state/bot_state.rb +21 -0
  47. data/lib/bot_platform/state/conversation_state.rb +17 -0
  48. data/lib/bot_platform/state/user_state.rb +1 -0
  49. data/lib/bot_platform/storage/memory_storage.rb +51 -0
  50. data/lib/bot_platform/storage/mysql_storage.rb +1 -0
  51. data/lib/bot_platform/storage/redis_storage.rb +1 -0
  52. data/lib/bot_platform/storage/storageable.rb +33 -0
  53. data/lib/bot_platform/turn_context.rb +105 -0
  54. data/lib/bot_platform/version.rb +1 -1
  55. data/lib/bot_platform.rb +11 -0
  56. data/samples/dialogs/dialog_simple.rb +29 -0
  57. data/samples/echo.rb +5 -0
  58. metadata +56 -5
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BotPlatform
4
+ module Dialogs
5
+ module Prompts
6
+ class Prompt < Dialog
7
+ attr_reader :validator
8
+
9
+ def initialize(dialog_id, validtor=nil)
10
+ super(dialog_id)
11
+ @validator = validator
12
+ end
13
+
14
+ def start(dc, options)
15
+ assert_dialog_context_is_valid dc
16
+ assert_prompt_options_is_valid options
17
+
18
+ state = dc.active_dialog.state
19
+ state[:options] = options
20
+ state[:state] = {}
21
+
22
+ on_prompt(dc.turn_context, state[:state], state[:options], false)
23
+ return BotPlatform::Dialogs::DialogResult.new :complete
24
+ end
25
+
26
+ def continue(dc)
27
+ assert_dialog_context_is_valid dc
28
+
29
+ if dc.turn_context.activity.type != BotPlatform::Activity::TYPES[:message]
30
+ # do nothing
31
+ return BotPlatform::Dialogs::DialogResult.new :complete
32
+ end
33
+
34
+ instance = dc.active_dialog
35
+ state = instance.state[:state]
36
+ options = instance.state[:options]
37
+
38
+ recognized = on_recognize(dc.turn_context, state, options)
39
+
40
+ is_valid = false
41
+
42
+ if !@validator.nil?
43
+ prompt_validator_ctx = PromptValidatorContext.new dc.turn_context, recognized, state, options
44
+ is_valid = @validator.send(prompt_validator_ctx)
45
+ elsif recognized.succeeded
46
+ is_valid = true
47
+ end
48
+
49
+ if is_valid
50
+ return dc.stop_dialog(recognized.value)
51
+ else
52
+ return on_prompt(dc.turn_context, state, options, true)
53
+ end
54
+ end
55
+
56
+ def resume(dc, result=null)
57
+ assert_dialog_context_is_valid dc
58
+
59
+ reprompt(dc.turn_context, dc.active_dialog)
60
+ return BotPlatform::Dialogs::DialogResult.new :complete
61
+ end
62
+
63
+ def repromp(ttx, instance)
64
+ assert_turn_context_is_valid ttx
65
+ assert_dialog_instance_is_valid instance
66
+
67
+ state = instace.state[:state]
68
+ options = instance.state[:options]
69
+
70
+ on_prompt(ttx, state, options, false)
71
+ end
72
+
73
+ def on_prompt(turn_context, state, options, is_retry)
74
+ raise "not implemented(abstrct in super)"
75
+ end
76
+
77
+ def on_recognize(turn_context, state, options, is_retry)
78
+ raise "not implemented(abstrct in super)"
79
+ end
80
+
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BotPlatform
4
+ module Dialogs
5
+ module Prompts
6
+ class PromptOptions
7
+ attr_accessor :prompt, :retry_prompt, :choices, :validations
8
+
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BotPlatform
4
+ module Dialogs
5
+ module Prompts
6
+ class PromptRecognizerResult
7
+ attr_accessor :succeeded, :value
8
+
9
+ def initialize
10
+ @succeeded = false
11
+ @value = nil
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BotPlatform
4
+ module Dialogs
5
+ module Prompts
6
+ class TextPrompt < Prompt
7
+ def on_prompt(ctx, state, options, is_retry)
8
+ assert_turn_context_is_valid ctx
9
+ #assert_dialog_instance_state_is_valid state
10
+ assert_prompt_options_is_valid options
11
+
12
+ if is_retry && !options.retry_prompt.nil?
13
+ ctx.send_activity options.retry_prompt
14
+ else
15
+ ctx.send_activity options.prompt
16
+ end
17
+ end
18
+
19
+ def on_recognize(ctx, state, options)
20
+ assert_turn_context_is_valid ctx
21
+
22
+ result = PromptRecognizerResult.new
23
+ if ctx.activity.type == BotPlatform::Activity::TYPES[:message]
24
+ message = ctx.activity.text
25
+ unless message.nil? || message.empty?
26
+ result.succeeded = true
27
+ result.value = message
28
+ end
29
+ end
30
+
31
+ return result
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'dialogs/dialog'
2
+ require_relative 'dialogs/dialog_context'
3
+ require_relative 'dialogs/dialog_instance'
4
+ require_relative 'dialogs/dialog_result'
5
+ require_relative 'dialogs/dialog_set'
6
+ require_relative 'dialogs/dialog_state'
7
+
8
+ require_relative 'dialogs/prompts/prompt'
9
+ require_relative 'dialogs/prompts/prompt_options'
10
+ require_relative 'dialogs/prompts/text_prompt'
11
+ require_relative 'dialogs/prompts/prompt_recognizer_result'
12
+
13
+ module BotPlatform
14
+ module Dialogs
15
+
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BotPlatform
4
+ class MessageFactory
5
+ def self.Text(text)
6
+ return Activity.new Activity::TYPES[:message], {text: text}
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BotPlatform
4
+ module State
5
+ class BotState
6
+ include BotPlatform::Asserts
7
+
8
+ attr_accessor :storage, :service_key
9
+ def initialize(storage, service_key)
10
+ @storage = storage
11
+ @service_key = service_key
12
+ end
13
+
14
+ def save_changes(turn_context, force=false)
15
+ assert_turn_context_is_valid turn_context
16
+
17
+ #TODO:
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BotPlatform
4
+ module State
5
+ class ConversationState < BotState
6
+ def initialize(storage)
7
+ super(storage, "conversation_state")
8
+ end
9
+
10
+ def get_storage_key(turn_context)
11
+ channel_id = turn_context.activity.channel_id
12
+ conversation_id = turn_context.conversation.id
13
+ "#{channel_id}/conversations/#{conversation_id}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1 @@
1
+ # frozen_string_literal: true
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ module BotPlatform
6
+ module Storage
7
+ class MemoryStorage
8
+ include Singleton
9
+ include Storageable
10
+
11
+ attr_accessor :data, :locker
12
+
13
+ def initialize
14
+ @locker = Mutex::new
15
+ @data = {}
16
+ end
17
+
18
+ def read(keys)
19
+ new_hash = {}
20
+ @locker.synchronize do
21
+ keys.each do |key|
22
+ if @data.key?(key)
23
+ k = key.to_sym
24
+ new_hash[k] = @data[k]
25
+ end
26
+ end
27
+ end
28
+ return new_hash
29
+ end
30
+
31
+ def write(changes)
32
+ @locker.synchronize do
33
+ changes.each do |change|
34
+ @data[change.key.to_sym] = change.value
35
+ end
36
+ end
37
+ end
38
+
39
+ def getState(context)
40
+ user_id = context.from[:user_id]
41
+ room_id = context.from[:room_id] || ""
42
+ # FIXME: room_id appear and disappear
43
+ #key = "#{user_id}@#{room_id}"
44
+ key = "#{user_id}".intern
45
+ @data[key] = ConversationState.new(key) if @data[key].nil?
46
+ return @data[key]
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1 @@
1
+ # frozen_string_literal: true
@@ -0,0 +1 @@
1
+ # frozen_string_literal: true
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BotPlatform
4
+ module Storage
5
+ module Storageable
6
+ attr_accessor :data, :_user_state, :coversation_state, :dialog_state
7
+
8
+ def set(key, value, exipred=false)
9
+ end
10
+
11
+ def get(key)
12
+ end
13
+
14
+ def del(key)
15
+ end
16
+
17
+ def read(keys)
18
+ end
19
+
20
+ def write(changes)
21
+ end
22
+
23
+ def user_state
24
+ get(:_user_state)
25
+ end
26
+
27
+ def user_state=(state)
28
+ set(:_user_state, state)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BotPlatform
4
+ class TurnContext
5
+ include Asserts
6
+
7
+ attr_reader :adpter, #元のアダプター情報
8
+ :activity, # ユーザーからの要求(incoming)
9
+ :channel_id,
10
+ :from
11
+
12
+ attr_accessor :state, #コンテキストに登録されたサービスを保持
13
+ :responded, # 応答済フラグ
14
+ :locale,
15
+ :buffered_reply_activities,
16
+ :turn_state, # コンテキストに登録されたサービスを保持
17
+ :_on_send_activities,
18
+ :_on_update_activities,
19
+ :_on_delete_activities
20
+
21
+ def initialize(adapter, activity)
22
+ @adapter = adapter
23
+ @activity = activity # incoming activity
24
+ @from = activity.from
25
+ @channel_id = activity.channel_id
26
+ @responded = false
27
+ @locale = "ja"
28
+ @_on_send_activities = []
29
+ @_on_update_activities = []
30
+ @_on_delete_activities = []
31
+
32
+ end
33
+
34
+ def add_on_send_activities(activity_handler)
35
+ @_on_send_activities << activity_handler
36
+ self
37
+ end
38
+
39
+ def add_on_update_activities(activity_handler)
40
+ @_on_update_activities << activity_handler
41
+ self
42
+ end
43
+
44
+ def add_on_delete_activits(activity_handler)
45
+ @_on_delete_activities << activity_handler
46
+ self
47
+ end
48
+
49
+ def self.dup_context(context, activity)
50
+ ctx = TurnContext.new context.adapter, activity
51
+ ctx.state = context.state
52
+ ctx.responded = context.responded
53
+ if context.is_a?(TurnContext)
54
+ ctx.buffered_reply_activities = context.buffered_reply_activities
55
+ # keep private middleware pipeline hooks.
56
+ ctx._on_send_activities = context._on_send_activities
57
+ ctx._on_update_activity = context._on_update_activity
58
+ ctx._on_delete_activity = context._on_delete_activity
59
+ end
60
+ return ctx
61
+ end
62
+
63
+ def send_message(text)
64
+ activity_to_send = Activity.new(Activity::TYPES[:message], {text: text})
65
+ send_activity(activity_to_send)
66
+ end
67
+
68
+ def send_confirm(text,prefix="")
69
+ activity_to_send = Activity.new(Activity::TYPES[:confirm], {text: text, prefix: prefix})
70
+ send_activity(activity_to_send)
71
+ end
72
+
73
+ def send_options(caption, prefix, options)
74
+ activity_to_send = Activity.new(Activity::TYPES[:options], {text: caption, options: options, prefix: prefix})
75
+ send_activity(activity_to_send)
76
+ end
77
+
78
+ def send_image(preview_url, resource_url)
79
+ activity_to_send = Activity.new(Activity::TYPES[:image], {resource_url: resource_url, preview_url: preview_url})
80
+ send_activity(activity_to_send)
81
+ end
82
+
83
+ def send_content(content)
84
+ activity_to_send = Activity.new(Activity::TYPES[:carousel], {
85
+ content: content, to: @activity.from
86
+ })
87
+ send_activity(activity_to_send)
88
+ end
89
+
90
+ def send_activity(activity)
91
+ activity.to = @activity.from
92
+ send_activities([activity])
93
+ end
94
+
95
+ # Sends a set of activities to the sender of the incoming activity.
96
+ def send_activities(activities)
97
+ assert_activity_is_not_null activities
98
+ assert_activity_is_not_null activities[0]
99
+
100
+ @adapter.send_activities(self, activities)
101
+ end
102
+
103
+
104
+ end
105
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BotPlatform
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.3"
5
5
  end
data/lib/bot_platform.rb CHANGED
@@ -1,6 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "bot_platform/version"
4
+ require_relative "bot_platform/activity"
5
+ require_relative "bot_platform/adapter"
6
+ require_relative "bot_platform/asserts"
7
+ require_relative "bot_platform/message_factory"
8
+ require_relative "bot_platform/turn_context"
9
+ require_relative "bot_platform/channels"
10
+ require_relative "bot_platform/dialogs"
11
+ require_relative "bot_platform/storage/storageable"
12
+ require_relative "bot_platform/storage/memory_storage"
13
+ require_relative "bot_platform/state/bot_state"
14
+ require_relative "bot_platform/state/conversation_state"
4
15
 
5
16
  module BotPlatform
6
17
  class Error < StandardError; end