adhearsion 2.6.4 → 3.0.0.beta1
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 +4 -4
- data/.travis.yml +6 -9
- data/CHANGELOG.md +22 -7
- data/Gemfile +2 -0
- data/README.markdown +4 -5
- data/Rakefile +1 -2
- data/adhearsion.gemspec +19 -8
- data/features/cli_create.feature +19 -3
- data/features/step_definitions/cli_steps.rb +0 -11
- data/features/support/env.rb +3 -4
- data/lib/adhearsion.rb +48 -27
- data/lib/adhearsion/call.rb +34 -50
- data/lib/adhearsion/call_controller.rb +6 -12
- data/lib/adhearsion/call_controller/dial.rb +15 -53
- data/lib/adhearsion/call_controller/input.rb +39 -162
- data/lib/adhearsion/call_controller/input/ask_grammar_builder.rb +44 -0
- data/lib/adhearsion/call_controller/input/menu_builder.rb +136 -0
- data/lib/adhearsion/call_controller/input/prompt_builder.rb +78 -0
- data/lib/adhearsion/call_controller/input/result.rb +46 -0
- data/lib/adhearsion/call_controller/output.rb +48 -67
- data/lib/adhearsion/call_controller/output/abstract_player.rb +3 -3
- data/lib/adhearsion/call_controller/output/async_player.rb +3 -3
- data/lib/adhearsion/call_controller/output/player.rb +1 -1
- data/lib/adhearsion/call_controller/record.rb +23 -8
- data/lib/adhearsion/calls.rb +1 -1
- data/lib/adhearsion/cli_commands/ahn_command.rb +2 -65
- data/lib/adhearsion/cli_commands/thor_errors.rb +0 -6
- data/lib/adhearsion/configuration.rb +91 -39
- data/lib/adhearsion/core_ext/blather/stanza.rb +41 -0
- data/lib/adhearsion/core_ext/blather/stanza/presence.rb +13 -0
- data/lib/adhearsion/error.rb +5 -0
- data/lib/adhearsion/event.rb +21 -0
- data/lib/adhearsion/event/active_speaker.rb +11 -0
- data/lib/adhearsion/event/answered.rb +11 -0
- data/lib/adhearsion/event/asterisk.rb +10 -0
- data/lib/adhearsion/event/asterisk/ami.rb +34 -0
- data/lib/adhearsion/event/complete.rb +75 -0
- data/lib/adhearsion/event/dtmf.rb +11 -0
- data/lib/adhearsion/event/end.rb +22 -0
- data/lib/adhearsion/event/input_timers_started.rb +9 -0
- data/lib/adhearsion/event/joined.rb +17 -0
- data/lib/adhearsion/event/offer.rb +14 -0
- data/lib/adhearsion/event/ringing.rb +11 -0
- data/lib/adhearsion/event/started_speaking.rb +13 -0
- data/lib/adhearsion/event/stopped_speaking.rb +13 -0
- data/lib/adhearsion/event/unjoined.rb +17 -0
- data/lib/adhearsion/events.rb +47 -66
- data/lib/adhearsion/foundation.rb +0 -1
- data/lib/adhearsion/foundation/object.rb +0 -5
- data/lib/adhearsion/generators/app/app_generator.rb +4 -1
- data/lib/adhearsion/generators/app/templates/Gemfile.erb +2 -10
- data/lib/adhearsion/generators/app/templates/adhearsion.erb +9 -9
- data/lib/adhearsion/generators/app/templates/config.ru +7 -0
- data/lib/adhearsion/generators/app/templates/en.yml +4 -0
- data/lib/adhearsion/generators/app/templates/events.erb +2 -2
- data/lib/adhearsion/generators/app/templates/hello_world.wav +0 -0
- data/lib/adhearsion/generators/app/templates/simon_game.rb +2 -1
- data/lib/adhearsion/generators/app/templates/simon_game_spec.rb +2 -2
- data/lib/adhearsion/has_headers.rb +34 -0
- data/lib/adhearsion/http_server.rb +37 -0
- data/lib/adhearsion/initializer.rb +19 -153
- data/lib/adhearsion/logging.rb +6 -25
- data/lib/adhearsion/outbound_call.rb +5 -5
- data/lib/adhearsion/plugin.rb +1 -0
- data/lib/adhearsion/protocol_error.rb +26 -0
- data/lib/adhearsion/rayo.rb +30 -0
- data/lib/adhearsion/rayo/client.rb +62 -0
- data/lib/adhearsion/rayo/client/component_registry.rb +33 -0
- data/lib/adhearsion/rayo/command.rb +21 -0
- data/lib/adhearsion/rayo/command/accept.rb +16 -0
- data/lib/adhearsion/rayo/command/answer.rb +16 -0
- data/lib/adhearsion/rayo/command/dial.rb +57 -0
- data/lib/adhearsion/rayo/command/hangup.rb +16 -0
- data/lib/adhearsion/rayo/command/join.rb +43 -0
- data/lib/adhearsion/rayo/command/mute.rb +13 -0
- data/lib/adhearsion/rayo/command/redirect.rb +23 -0
- data/lib/adhearsion/rayo/command/reject.rb +40 -0
- data/lib/adhearsion/rayo/command/unjoin.rb +24 -0
- data/lib/adhearsion/rayo/command/unmute.rb +13 -0
- data/lib/adhearsion/rayo/command_node.rb +47 -0
- data/lib/adhearsion/rayo/component.rb +21 -0
- data/lib/adhearsion/rayo/component/asterisk.rb +13 -0
- data/lib/adhearsion/rayo/component/asterisk/agi.rb +14 -0
- data/lib/adhearsion/rayo/component/asterisk/agi/command.rb +46 -0
- data/lib/adhearsion/rayo/component/asterisk/ami.rb +14 -0
- data/lib/adhearsion/rayo/component/asterisk/ami/action.rb +61 -0
- data/lib/adhearsion/rayo/component/component_node.rb +90 -0
- data/lib/adhearsion/rayo/component/input.rb +186 -0
- data/lib/adhearsion/rayo/component/output.rb +471 -0
- data/lib/adhearsion/rayo/component/prompt.rb +53 -0
- data/lib/adhearsion/rayo/component/receive_fax.rb +26 -0
- data/lib/adhearsion/rayo/component/record.rb +165 -0
- data/lib/adhearsion/rayo/component/send_fax.rb +64 -0
- data/lib/adhearsion/rayo/component/stop.rb +11 -0
- data/lib/adhearsion/rayo/connection.rb +12 -0
- data/lib/adhearsion/rayo/connection/asterisk.rb +74 -0
- data/lib/adhearsion/rayo/connection/connected.rb +22 -0
- data/lib/adhearsion/rayo/connection/generic_connection.rb +22 -0
- data/lib/adhearsion/rayo/connection/xmpp.rb +198 -0
- data/lib/adhearsion/rayo/disconnected_error.rb +22 -0
- data/lib/adhearsion/{punchblock_plugin → rayo}/initializer.rb +19 -19
- data/lib/adhearsion/rayo/rayo_node.rb +127 -0
- data/lib/adhearsion/rayo/ref.rb +57 -0
- data/lib/adhearsion/statistics.rb +1 -1
- data/lib/adhearsion/tasks.rb +1 -2
- data/lib/adhearsion/tasks/configuration.rb +1 -1
- data/lib/adhearsion/tasks/environment.rb +0 -2
- data/lib/adhearsion/tasks/i18n.rb +49 -0
- data/lib/adhearsion/translator.rb +11 -0
- data/lib/adhearsion/translator/asterisk.rb +234 -0
- data/lib/adhearsion/translator/asterisk/agi_app.rb +17 -0
- data/lib/adhearsion/translator/asterisk/agi_command.rb +45 -0
- data/lib/adhearsion/translator/asterisk/ami_error_converter.rb +20 -0
- data/lib/adhearsion/translator/asterisk/call.rb +416 -0
- data/lib/adhearsion/translator/asterisk/channel.rb +43 -0
- data/lib/adhearsion/translator/asterisk/component.rb +88 -0
- data/lib/adhearsion/translator/asterisk/component/asterisk.rb +15 -0
- data/lib/adhearsion/translator/asterisk/component/asterisk/agi_command.rb +42 -0
- data/lib/adhearsion/translator/asterisk/component/asterisk/ami_action.rb +68 -0
- data/lib/adhearsion/translator/asterisk/component/composed_prompt.rb +76 -0
- data/lib/adhearsion/translator/asterisk/component/dtmf_recognizer.rb +137 -0
- data/lib/adhearsion/translator/asterisk/component/input.rb +34 -0
- data/lib/adhearsion/translator/asterisk/component/input_component.rb +90 -0
- data/lib/adhearsion/translator/asterisk/component/mrcp_native_prompt.rb +71 -0
- data/lib/adhearsion/translator/asterisk/component/mrcp_prompt.rb +55 -0
- data/lib/adhearsion/translator/asterisk/component/mrcp_recog_prompt.rb +165 -0
- data/lib/adhearsion/translator/asterisk/component/output.rb +233 -0
- data/lib/adhearsion/translator/asterisk/component/record.rb +101 -0
- data/lib/adhearsion/translator/asterisk/component/stop_by_redirect.rb +30 -0
- data/lib/adhearsion/translator/asterisk/unimrcp_app.rb +28 -0
- data/lib/adhearsion/uri_list.rb +21 -0
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +79 -1420
- data/spec/adhearsion/call_controller/input_spec.rb +1141 -237
- data/spec/adhearsion/call_controller/output/async_player_spec.rb +10 -10
- data/spec/adhearsion/call_controller/output/player_spec.rb +8 -8
- data/spec/adhearsion/call_controller/output_spec.rb +162 -215
- data/spec/adhearsion/call_controller/record_spec.rb +15 -16
- data/spec/adhearsion/call_controller_spec.rb +23 -40
- data/spec/adhearsion/call_spec.rb +123 -129
- data/spec/adhearsion/calls_spec.rb +3 -3
- data/spec/adhearsion/configuration_spec.rb +94 -108
- data/spec/adhearsion/event/answered_spec.rb +50 -0
- data/spec/adhearsion/event/asterisk/Find Results +402 -0
- data/spec/adhearsion/event/asterisk/ami_spec.rb +81 -0
- data/spec/adhearsion/event/complete_spec.rb +176 -0
- data/spec/adhearsion/event/dtmf_spec.rb +35 -0
- data/spec/adhearsion/event/end_spec.rb +85 -0
- data/spec/adhearsion/event/input_timers_started_spec.rb +19 -0
- data/spec/adhearsion/event/joined_spec.rb +53 -0
- data/spec/adhearsion/event/offer_spec.rb +106 -0
- data/spec/adhearsion/event/ringing_spec.rb +50 -0
- data/spec/adhearsion/event/started_speaking_spec.rb +37 -0
- data/spec/adhearsion/event/stopped_speaking_spec.rb +37 -0
- data/spec/adhearsion/event/unjoined_spec.rb +48 -0
- data/spec/adhearsion/event/untitled +0 -0
- data/spec/adhearsion/events_spec.rb +19 -45
- data/spec/adhearsion/initializer_spec.rb +12 -184
- data/spec/adhearsion/logging_spec.rb +5 -20
- data/spec/adhearsion/outbound_call_spec.rb +13 -13
- data/spec/adhearsion/plugin_spec.rb +3 -4
- data/spec/adhearsion/protocol_error_spec.rb +91 -0
- data/spec/adhearsion/rayo/client/component_registry_spec.rb +26 -0
- data/spec/adhearsion/rayo/client_spec.rb +134 -0
- data/spec/adhearsion/rayo/command/accept_spec.rb +63 -0
- data/spec/adhearsion/rayo/command/answer_spec.rb +73 -0
- data/spec/adhearsion/rayo/command/dial_spec.rb +156 -0
- data/spec/adhearsion/rayo/command/hangup_spec.rb +63 -0
- data/spec/adhearsion/rayo/command/join_spec.rb +158 -0
- data/spec/adhearsion/rayo/command/mute_spec.rb +32 -0
- data/spec/adhearsion/rayo/command/redirect_spec.rb +89 -0
- data/spec/adhearsion/rayo/command/reject_spec.rb +117 -0
- data/spec/adhearsion/rayo/command/unjoin_spec.rb +82 -0
- data/spec/adhearsion/rayo/command/unmute_spec.rb +32 -0
- data/spec/adhearsion/rayo/command_node_spec.rb +101 -0
- data/spec/adhearsion/rayo/component/asterisk/agi/command_spec.rb +111 -0
- data/spec/adhearsion/rayo/component/asterisk/ami/action_spec.rb +173 -0
- data/spec/adhearsion/rayo/component/component_node_spec.rb +110 -0
- data/spec/adhearsion/rayo/component/input_spec.rb +715 -0
- data/spec/adhearsion/rayo/component/output_spec.rb +1030 -0
- data/spec/adhearsion/rayo/component/prompt_spec.rb +171 -0
- data/spec/adhearsion/rayo/component/receive_fax_spec.rb +136 -0
- data/spec/adhearsion/rayo/component/record_spec.rb +497 -0
- data/spec/adhearsion/rayo/component/send_fax_spec.rb +144 -0
- data/spec/adhearsion/rayo/connection/asterisk_spec.rb +118 -0
- data/spec/adhearsion/rayo/connection/xmpp_spec.rb +449 -0
- data/spec/adhearsion/rayo/initializer_spec.rb +353 -0
- data/spec/adhearsion/rayo/ref_spec.rb +168 -0
- data/spec/adhearsion/rayo_spec.rb +7 -0
- data/spec/adhearsion/router/route_spec.rb +1 -1
- data/spec/adhearsion/statistics_spec.rb +2 -5
- data/spec/adhearsion/translator/asterisk/call_spec.rb +2047 -0
- data/spec/adhearsion/translator/asterisk/component/asterisk/agi_command_spec.rb +256 -0
- data/spec/adhearsion/translator/asterisk/component/asterisk/ami_action_spec.rb +151 -0
- data/spec/adhearsion/translator/asterisk/component/composed_prompt_spec.rb +257 -0
- data/spec/adhearsion/translator/asterisk/component/input_spec.rb +571 -0
- data/spec/adhearsion/translator/asterisk/component/mrcp_native_prompt_spec.rb +774 -0
- data/spec/adhearsion/translator/asterisk/component/mrcp_prompt_spec.rb +1244 -0
- data/spec/adhearsion/translator/asterisk/component/output_spec.rb +1850 -0
- data/spec/adhearsion/translator/asterisk/component/record_spec.rb +426 -0
- data/spec/adhearsion/translator/asterisk/component/stop_by_redirect_spec.rb +62 -0
- data/spec/adhearsion/translator/asterisk/component_spec.rb +83 -0
- data/spec/adhearsion/translator/asterisk_spec.rb +685 -0
- data/spec/adhearsion/uri_list_spec.rb +88 -0
- data/spec/adhearsion_spec.rb +89 -14
- data/spec/fixtures/locale/en.yml +13 -0
- data/spec/fixtures/locale/it.yml +13 -0
- data/spec/spec_helper.rb +18 -5
- data/spec/support/call_controller_test_helpers.rb +3 -2
- data/spec/support/initializer_stubs.rb +3 -1
- data/spec/support/punchblock_examples.rb +65 -0
- data/spec/support/punchblock_mocks.rb +12 -0
- metadata +412 -70
- data/features/cli_daemon.feature +0 -20
- data/features/cli_restart.feature +0 -52
- data/features/cli_stop.feature +0 -50
- data/lib/adhearsion/call_controller/menu_dsl.rb +0 -21
- data/lib/adhearsion/call_controller/menu_dsl/array_match_calculator.rb +0 -26
- data/lib/adhearsion/call_controller/menu_dsl/calculated_match.rb +0 -43
- data/lib/adhearsion/call_controller/menu_dsl/calculated_match_collection.rb +0 -45
- data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +0 -11
- data/lib/adhearsion/call_controller/menu_dsl/match_calculator.rb +0 -40
- data/lib/adhearsion/call_controller/menu_dsl/menu.rb +0 -207
- data/lib/adhearsion/call_controller/menu_dsl/menu_builder.rb +0 -92
- data/lib/adhearsion/call_controller/menu_dsl/range_match_calculator.rb +0 -60
- data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +0 -25
- data/lib/adhearsion/call_controller/utility.rb +0 -77
- data/lib/adhearsion/foundation/custom_daemonizer.rb +0 -52
- data/lib/adhearsion/punchblock_plugin.rb +0 -63
- data/scripts/cloc-1.64.pl +0 -10483
- data/spec/adhearsion/call_controller/menu_dsl/array_match_calculator_spec.rb +0 -76
- data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +0 -60
- data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +0 -61
- data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +0 -39
- data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +0 -17
- data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +0 -165
- data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +0 -420
- data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +0 -32
- data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +0 -40
- data/spec/adhearsion/call_controller/utility_spec.rb +0 -90
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +0 -356
- data/spec/adhearsion/punchblock_plugin_spec.rb +0 -59
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Adhearsion
|
|
4
|
+
class CallController
|
|
5
|
+
module Input
|
|
6
|
+
class AskGrammarBuilder
|
|
7
|
+
def initialize(options)
|
|
8
|
+
@options = options
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def grammars
|
|
12
|
+
@grammars ||= build_grammars
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def build_grammars
|
|
18
|
+
grammars = []
|
|
19
|
+
|
|
20
|
+
grammars.concat [@options[:grammar]].flatten.compact.map { |val| {value: val} } if @options[:grammar]
|
|
21
|
+
grammars.concat [@options[:grammar_url]].flatten.compact.map { |val| {url: val} } if @options[:grammar_url]
|
|
22
|
+
|
|
23
|
+
if grammars.empty?
|
|
24
|
+
limit = @options[:limit]
|
|
25
|
+
grammar = RubySpeech::GRXML.draw mode: :dtmf, root: 'digits' do
|
|
26
|
+
rule id: 'digits', scope: 'public' do
|
|
27
|
+
item repeat: "0-#{limit}" do
|
|
28
|
+
one_of do
|
|
29
|
+
0.upto(9) { |d| item { d.to_s } }
|
|
30
|
+
item { "#" }
|
|
31
|
+
item { "*" }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
grammars << {value: grammar}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
grammars
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'adhearsion/call_controller/input/prompt_builder'
|
|
4
|
+
|
|
5
|
+
module Adhearsion
|
|
6
|
+
class CallController
|
|
7
|
+
module Input
|
|
8
|
+
class MenuBuilder
|
|
9
|
+
def initialize(options, &block)
|
|
10
|
+
@options = options
|
|
11
|
+
@matchers = []
|
|
12
|
+
@callbacks = {}
|
|
13
|
+
build(&block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def match(*args, &block)
|
|
17
|
+
payload = block || args.pop
|
|
18
|
+
|
|
19
|
+
@matchers << Matcher.new(payload, args)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def invalid(&block)
|
|
23
|
+
register_user_supplied_callback :nomatch, &block
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def timeout(&block)
|
|
27
|
+
register_user_supplied_callback :noinput, &block
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def failure(&block)
|
|
31
|
+
register_user_supplied_callback :failure, &block
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def execute(output_document, controller)
|
|
35
|
+
catch :match do
|
|
36
|
+
(@options[:tries] || 1).times do
|
|
37
|
+
result = PromptBuilder.new(output_document, grammars, @options).execute(controller)
|
|
38
|
+
process_result result
|
|
39
|
+
end
|
|
40
|
+
execute_hook :failure
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def grammars
|
|
47
|
+
@grammar ||= [{value: build_grammar}]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def process_result(result)
|
|
51
|
+
if result.status == :match
|
|
52
|
+
handle_match result
|
|
53
|
+
else
|
|
54
|
+
execute_hook result.status
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def register_user_supplied_callback(name, &block)
|
|
59
|
+
@callbacks[name] = block
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def execute_hook(hook_name)
|
|
63
|
+
callback = @callbacks[hook_name]
|
|
64
|
+
return unless callback
|
|
65
|
+
@context.instance_exec(&callback)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def handle_match(result)
|
|
69
|
+
match = @matchers[result.interpretation.to_i]
|
|
70
|
+
match.dispatch @context, result.utterance
|
|
71
|
+
throw :match
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def build(&block)
|
|
75
|
+
@context = eval "self", block.binding
|
|
76
|
+
instance_eval(&block)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def method_missing(method_name, *args, &block)
|
|
80
|
+
if @context
|
|
81
|
+
@context.send method_name, *args, &block
|
|
82
|
+
else
|
|
83
|
+
super
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def build_grammar
|
|
88
|
+
raise ArgumentError, "You must specify one or more matches." if @matchers.count < 1
|
|
89
|
+
matchers = @matchers
|
|
90
|
+
|
|
91
|
+
RubySpeech::GRXML.draw mode: (@options[:mode] || :dtmf), root: 'options', tag_format: 'semantics/1.0-literals' do
|
|
92
|
+
rule id: 'options', scope: 'public' do
|
|
93
|
+
item do
|
|
94
|
+
one_of do
|
|
95
|
+
matchers.each_with_index do |matcher, index|
|
|
96
|
+
item do
|
|
97
|
+
tag { index.to_s }
|
|
98
|
+
matcher.apply_to_grammar self
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
Matcher = Struct.new(:payload, :keys) do
|
|
108
|
+
def dispatch(controller, utterance)
|
|
109
|
+
if payload.is_a?(Proc)
|
|
110
|
+
controller.instance_exec utterance, &payload
|
|
111
|
+
else
|
|
112
|
+
controller.invoke payload, extension: utterance
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def apply_to_grammar(grammar)
|
|
117
|
+
possible_options = calculate_possible_options
|
|
118
|
+
if possible_options.count > 1
|
|
119
|
+
grammar.one_of do
|
|
120
|
+
possible_options.each do |key|
|
|
121
|
+
item { key.to_s }
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
else
|
|
125
|
+
keys.first.to_s
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def calculate_possible_options
|
|
130
|
+
keys.map { |key| key.respond_to?(:to_a) ? key.to_a : key }.flatten
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'adhearsion/call_controller/input/result'
|
|
4
|
+
|
|
5
|
+
module Adhearsion
|
|
6
|
+
class CallController
|
|
7
|
+
module Input
|
|
8
|
+
class PromptBuilder
|
|
9
|
+
def initialize(output_document, grammars, options)
|
|
10
|
+
input_options = {
|
|
11
|
+
mode: options[:mode] || :dtmf,
|
|
12
|
+
initial_timeout: timeout(options[:timeout] || Adhearsion.config.core.media.timeout),
|
|
13
|
+
inter_digit_timeout: timeout(options[:inter_digit_timeout] || Adhearsion.config.core.media.inter_digit_timeout),
|
|
14
|
+
max_silence: timeout(options[:timeout] || Adhearsion.config.core.media.timeout),
|
|
15
|
+
min_confidence: Adhearsion.config.core.media.min_confidence,
|
|
16
|
+
grammars: grammars,
|
|
17
|
+
recognizer: Adhearsion.config.core.media.recognizer,
|
|
18
|
+
language: Adhearsion.config.core.media.input_language,
|
|
19
|
+
terminator: options[:terminator]
|
|
20
|
+
}.merge(options[:input_options] || {})
|
|
21
|
+
|
|
22
|
+
@prompt = if output_document || options[:render_document]
|
|
23
|
+
output_options = {
|
|
24
|
+
render_document: options[:render_document] || {value: output_document},
|
|
25
|
+
renderer: Adhearsion.config.core.media.default_renderer,
|
|
26
|
+
voice: Adhearsion.config.core.media.default_voice
|
|
27
|
+
}.merge(options[:output_options] || {})
|
|
28
|
+
|
|
29
|
+
Adhearsion::Rayo::Component::Prompt.new output_options, input_options, barge_in: options.has_key?(:interruptible) ? options[:interruptible] : true
|
|
30
|
+
else
|
|
31
|
+
Adhearsion::Rayo::Component::Input.new input_options
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def execute(controller)
|
|
36
|
+
controller.execute_component_and_await_completion @prompt
|
|
37
|
+
|
|
38
|
+
result @prompt.complete_event.reason
|
|
39
|
+
rescue Adhearsion::Call::ExpiredError
|
|
40
|
+
raise Adhearsion::Call::Hangup
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def result(reason)
|
|
46
|
+
Result.new.tap do |result|
|
|
47
|
+
case reason
|
|
48
|
+
when proc { |r| r.respond_to? :nlsml }
|
|
49
|
+
result.status = :match
|
|
50
|
+
result.mode = reason.mode
|
|
51
|
+
result.confidence = reason.confidence
|
|
52
|
+
result.utterance = reason.utterance
|
|
53
|
+
result.interpretation = reason.interpretation
|
|
54
|
+
result.nlsml = reason.nlsml
|
|
55
|
+
when Adhearsion::Event::Complete::Error
|
|
56
|
+
raise InputError, reason.details
|
|
57
|
+
when Adhearsion::Rayo::Component::Input::Complete::NoMatch
|
|
58
|
+
result.status = :nomatch
|
|
59
|
+
when Adhearsion::Rayo::Component::Input::Complete::NoInput
|
|
60
|
+
result.status = :noinput
|
|
61
|
+
when Adhearsion::Event::Complete::Hangup
|
|
62
|
+
result.status = :hangup
|
|
63
|
+
when Adhearsion::Event::Complete::Stop
|
|
64
|
+
result.status = :stop
|
|
65
|
+
else
|
|
66
|
+
raise "Unknown completion reason received: #{reason}"
|
|
67
|
+
end
|
|
68
|
+
logger.debug "Ask completed with result #{result.inspect}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def timeout(value)
|
|
73
|
+
value > 0 ? value * 1000 : value
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Adhearsion
|
|
4
|
+
class CallController
|
|
5
|
+
module Input
|
|
6
|
+
Result = Struct.new(:status, :mode, :confidence, :utterance, :interpretation, :nlsml) do
|
|
7
|
+
def to_s
|
|
8
|
+
utterance
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def inspect
|
|
12
|
+
"#<#{self.class} status=#{status.inspect}, confidence=#{confidence.inspect}, utterance=#{utterance.inspect}, interpretation=#{interpretation.inspect}, nlsml=#{nlsml.inspect}>"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def utterance=(other)
|
|
16
|
+
self[:utterance] = mode == :dtmf ? parse_dtmf(other) : other
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def match?
|
|
20
|
+
status == :match
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def parse_dtmf(dtmf)
|
|
26
|
+
return if dtmf.nil? || dtmf.empty?
|
|
27
|
+
dtmf.split(' ').inject '' do |final, digit|
|
|
28
|
+
final << parse_dtmf_digit(digit)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @private
|
|
33
|
+
def parse_dtmf_digit(digit)
|
|
34
|
+
case tone = digit.split('-').last
|
|
35
|
+
when 'star'
|
|
36
|
+
'*'
|
|
37
|
+
when 'pound'
|
|
38
|
+
'#'
|
|
39
|
+
else
|
|
40
|
+
tone
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
require 'uri'
|
|
3
|
+
require 'i18n'
|
|
3
4
|
|
|
4
5
|
%w(
|
|
5
6
|
abstract_player
|
|
@@ -18,7 +19,7 @@ module Adhearsion
|
|
|
18
19
|
# Speak output using text-to-speech (TTS)
|
|
19
20
|
#
|
|
20
21
|
# @param [String, #to_s] text The text to be rendered
|
|
21
|
-
# @param [Hash] options A set of options for output. Includes everything in
|
|
22
|
+
# @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
22
23
|
#
|
|
23
24
|
# @raise [PlaybackError] if the given argument could not be played
|
|
24
25
|
#
|
|
@@ -32,7 +33,7 @@ module Adhearsion
|
|
|
32
33
|
# Speak output using text-to-speech (TTS) and return as soon as it begins
|
|
33
34
|
#
|
|
34
35
|
# @param [String, #to_s] text The text to be rendered
|
|
35
|
-
# @param [Hash] options A set of options for output. Includes everything in
|
|
36
|
+
# @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
36
37
|
#
|
|
37
38
|
# @raise [PlaybackError] if the given argument could not be played
|
|
38
39
|
#
|
|
@@ -49,7 +50,7 @@ module Adhearsion
|
|
|
49
50
|
# say_characters('abc123')
|
|
50
51
|
#
|
|
51
52
|
# @param [String, #to_s] characters The string of characters to be spoken
|
|
52
|
-
# @param [Hash] options A set of options for output. Includes everything in
|
|
53
|
+
# @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
53
54
|
#
|
|
54
55
|
# @raise [PlaybackError] if the given argument could not be played
|
|
55
56
|
#
|
|
@@ -64,7 +65,7 @@ module Adhearsion
|
|
|
64
65
|
# say_characters!('abc123')
|
|
65
66
|
#
|
|
66
67
|
# @param [String, #to_s] characters The string of characters to be spoken
|
|
67
|
-
# @param [Hash] options A set of options for output. Includes everything in
|
|
68
|
+
# @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
68
69
|
#
|
|
69
70
|
# @raise [PlaybackError] if the given argument could not be played
|
|
70
71
|
#
|
|
@@ -79,7 +80,7 @@ module Adhearsion
|
|
|
79
80
|
# additional options. See play_time for more information.
|
|
80
81
|
#
|
|
81
82
|
# @param [Array<String, Fixnum, Time, Date>, String, Fixnum, Time, Date] outputs A collection of outputs to render.
|
|
82
|
-
# @param [Hash] options A set of options for output. Includes everything in
|
|
83
|
+
# @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
83
84
|
#
|
|
84
85
|
# @example Play file hello-world
|
|
85
86
|
# play 'http://www.example.com/hello-world.mp3'
|
|
@@ -113,7 +114,7 @@ module Adhearsion
|
|
|
113
114
|
# additional options. See play_time for more information.
|
|
114
115
|
#
|
|
115
116
|
# @param [Array<String, Fixnum, Time, Date>, String, Fixnum, Time, Date] outputs A collection of outputs to render.
|
|
116
|
-
# @param [Hash] options A set of options for output. Includes everything in
|
|
117
|
+
# @param [Hash] options A set of options for output. Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
117
118
|
#
|
|
118
119
|
# @example Play file hello-world
|
|
119
120
|
# play 'http://www.example.com/hello-world.mp3'
|
|
@@ -130,7 +131,7 @@ module Adhearsion
|
|
|
130
131
|
# play "/path/to/you-sound-cute.mp3", "/path/to/what-are-you-wearing.wav"
|
|
131
132
|
#
|
|
132
133
|
# @raise [PlaybackError] if (one of) the given argument(s) could not be played
|
|
133
|
-
# @return [
|
|
134
|
+
# @return [Adhearsion::Rayo::Component::Output]
|
|
134
135
|
#
|
|
135
136
|
def play!(*outputs, options)
|
|
136
137
|
options = process_output_options outputs, options
|
|
@@ -143,10 +144,9 @@ module Adhearsion
|
|
|
143
144
|
#
|
|
144
145
|
# Plays the given audio file.
|
|
145
146
|
# SSML supports http:// paths and full disk paths.
|
|
146
|
-
# The Punchblock backend will have to handle cases like Asterisk where there is a fixed sounds directory.
|
|
147
147
|
#
|
|
148
148
|
# @param [String] file http:// URL or full disk path to the sound file
|
|
149
|
-
# @param [Hash] options Additional options Includes everything in
|
|
149
|
+
# @param [Hash] options Additional options Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
150
150
|
# @option options [String] :fallback The text to play if the file is not available
|
|
151
151
|
#
|
|
152
152
|
# @raise [PlaybackError] if (one of) the given argument(s) could not be played
|
|
@@ -159,14 +159,13 @@ module Adhearsion
|
|
|
159
159
|
#
|
|
160
160
|
# Plays the given audio file and returns as soon as it begins.
|
|
161
161
|
# SSML supports http:// paths and full disk paths.
|
|
162
|
-
# The Punchblock backend will have to handle cases like Asterisk where there is a fixed sounds directory.
|
|
163
162
|
#
|
|
164
163
|
# @param [String] file http:// URL or full disk path to the sound file
|
|
165
|
-
# @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in
|
|
164
|
+
# @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
166
165
|
# @option options [String] :fallback The text to play if the file is not available
|
|
167
166
|
#
|
|
168
167
|
# @raise [PlaybackError] if (one of) the given argument(s) could not be played
|
|
169
|
-
# @return [
|
|
168
|
+
# @return [Adhearsion::Rayo::Component::Output]
|
|
170
169
|
#
|
|
171
170
|
def play_audio!(file, options = {})
|
|
172
171
|
async_player.play_ssml(output_formatter.ssml_for_audio(file, options), options)
|
|
@@ -177,7 +176,7 @@ module Adhearsion
|
|
|
177
176
|
# using the given timezone and format.
|
|
178
177
|
#
|
|
179
178
|
# @param [Date, Time, DateTime] time Time to be said.
|
|
180
|
-
# @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in
|
|
179
|
+
# @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
181
180
|
# @option options [String] :format This format is used only to disambiguate times that could be interpreted in different ways.
|
|
182
181
|
# For example, 01/06/2011 could mean either the 1st of June or the 6th of January.
|
|
183
182
|
# Please refer to the SSML specification.
|
|
@@ -198,7 +197,7 @@ module Adhearsion
|
|
|
198
197
|
# using the given timezone and format and returns as soon as it begins.
|
|
199
198
|
#
|
|
200
199
|
# @param [Date, Time, DateTime] time Time to be said.
|
|
201
|
-
# @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in
|
|
200
|
+
# @param [Hash] options Additional options to specify how exactly to say time specified. Includes everything in Adhearsion::Rayo::Component::Output.new.
|
|
202
201
|
# @option options [String] :format This format is used only to disambiguate times that could be interpreted in different ways.
|
|
203
202
|
# For example, 01/06/2011 could mean either the 1st of June or the 6th of January.
|
|
204
203
|
# Please refer to the SSML specification.
|
|
@@ -207,7 +206,7 @@ module Adhearsion
|
|
|
207
206
|
# It uses Time::strftime symbols.
|
|
208
207
|
#
|
|
209
208
|
# @raise [ArgumentError] if the given argument can not be played
|
|
210
|
-
# @return [
|
|
209
|
+
# @return [Adhearsion::Rayo::Component::Output]
|
|
211
210
|
#
|
|
212
211
|
def play_time!(time, options = {})
|
|
213
212
|
raise ArgumentError unless [Date, Time, DateTime].include?(time.class) && options.is_a?(Hash)
|
|
@@ -220,7 +219,7 @@ module Adhearsion
|
|
|
220
219
|
# is pronounced as "one hundred" instead of "one zero zero".
|
|
221
220
|
#
|
|
222
221
|
# @param [Numeric, String] number Numeric or String containing a valid Numeric, like "321".
|
|
223
|
-
# @param [Hash] options A set of options for output. See
|
|
222
|
+
# @param [Hash] options A set of options for output. See Adhearsion::Rayo::Component::Output.new for details.
|
|
224
223
|
#
|
|
225
224
|
# @raise [ArgumentError] if the given argument can not be played
|
|
226
225
|
#
|
|
@@ -236,10 +235,10 @@ module Adhearsion
|
|
|
236
235
|
# is pronounced as "one hundred" instead of "one zero zero".
|
|
237
236
|
#
|
|
238
237
|
# @param [Numeric, String] number Numeric or String containing a valid Numeric, like "321".
|
|
239
|
-
# @param [Hash] options A set of options for output. See
|
|
238
|
+
# @param [Hash] options A set of options for output. See Adhearsion::Rayo::Component::Output.new for details.
|
|
240
239
|
#
|
|
241
240
|
# @raise [ArgumentError] if the given argument can not be played
|
|
242
|
-
# @return [
|
|
241
|
+
# @return [Adhearsion::Rayo::Component::Output]
|
|
243
242
|
#
|
|
244
243
|
def play_numeric!(number, options = {})
|
|
245
244
|
raise ArgumentError unless number.kind_of?(Numeric) || number =~ /^\d+$/
|
|
@@ -250,7 +249,7 @@ module Adhearsion
|
|
|
250
249
|
# Plays the given SSML document from a URL.
|
|
251
250
|
#
|
|
252
251
|
# @param [String] url String containing a valid URL, like "http://example.com/document.ssml".
|
|
253
|
-
# @param [Hash] options A set of options for output. See
|
|
252
|
+
# @param [Hash] options A set of options for output. See Adhearsion::Rayo::Component::Output.new for details.
|
|
254
253
|
#
|
|
255
254
|
# @raise [ArgumentError] if the given argument can not be played
|
|
256
255
|
#
|
|
@@ -264,68 +263,50 @@ module Adhearsion
|
|
|
264
263
|
# Plays the given SSML document from a URL and returns as soon as it begins.
|
|
265
264
|
#
|
|
266
265
|
# @param [String] url String containing a valid URL, like "http://example.com/document.ssml".
|
|
267
|
-
# @param [Hash] options A set of options for output. See
|
|
266
|
+
# @param [Hash] options A set of options for output. See Adhearsion::Rayo::Component::Output.new for details.
|
|
268
267
|
#
|
|
269
268
|
# @raise [ArgumentError] if the given argument can not be played
|
|
270
|
-
# @return [
|
|
269
|
+
# @return [Adhearsion::Rayo::Component::Output]
|
|
271
270
|
#
|
|
272
271
|
def play_document!(url, options = {})
|
|
273
272
|
raise ArgumentError unless url =~ URI::regexp
|
|
274
273
|
async_player.play_url url, options
|
|
275
274
|
end
|
|
276
275
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
# play input unless input.nil?
|
|
287
|
-
#
|
|
288
|
-
# @param [String, Numeric, Date, Time, RubySpeech::SSML::Speak, Array, Hash] outputs The argument to play to the user, or an array of arguments.
|
|
289
|
-
# @param [Hash] options Additional options.
|
|
290
|
-
#
|
|
291
|
-
# @return [String, nil] The single DTMF character entered by the user, or nil if nothing was entered
|
|
292
|
-
# @raise [PlaybackError] if (one of) the given argument(s) could not be played
|
|
293
|
-
#
|
|
294
|
-
def interruptible_play(*outputs, options)
|
|
295
|
-
options = process_output_options outputs, options
|
|
296
|
-
outputs.find do |output|
|
|
297
|
-
digit = stream_file output, '0123456789#*', options
|
|
298
|
-
return digit if digit
|
|
276
|
+
def t(key, options = {})
|
|
277
|
+
this_locale = options[:locale] || locale
|
|
278
|
+
options = {default: '', locale: locale}.merge(options)
|
|
279
|
+
prompt = ::I18n.t "#{key}.audio", options
|
|
280
|
+
text = ::I18n.t "#{key}.text", options
|
|
281
|
+
|
|
282
|
+
if prompt.empty? && text.empty?
|
|
283
|
+
# Look for a translation key that doesn't follow the Adhearsion-I18n structure
|
|
284
|
+
text = ::I18n.t key, options
|
|
299
285
|
end
|
|
300
|
-
end
|
|
301
286
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
# @param [Object] argument String or Hash specifying output and options
|
|
306
|
-
# @param [String] digits String with the digits that are allowed to interrupt output
|
|
307
|
-
#
|
|
308
|
-
# @return [String, nil] The pressed digit, or nil if nothing was pressed
|
|
309
|
-
# @private
|
|
310
|
-
#
|
|
311
|
-
def stream_file(argument, digits = '0123456789#*', output_options = {})
|
|
312
|
-
result = nil
|
|
313
|
-
stopper = Punchblock::Component::Input.new :mode => :dtmf,
|
|
314
|
-
:grammar => {
|
|
315
|
-
:value => grammar_accept(digits)
|
|
316
|
-
}
|
|
287
|
+
unless prompt.empty?
|
|
288
|
+
prompt = "file://#{Adhearsion.root + "/" unless Adhearsion.config.core.i18n.audio_path.start_with?("/")}#{Adhearsion.config.core.i18n.audio_path}/#{this_locale}/#{prompt}"
|
|
289
|
+
end
|
|
317
290
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
291
|
+
RubySpeech::SSML.draw language: this_locale do
|
|
292
|
+
if prompt.empty?
|
|
293
|
+
string text
|
|
294
|
+
else
|
|
295
|
+
if Adhearsion.config.core.i18n.fallback
|
|
296
|
+
audio(src: prompt) { string text }
|
|
297
|
+
else
|
|
298
|
+
audio(src: prompt)
|
|
299
|
+
end
|
|
321
300
|
end
|
|
322
|
-
write_and_await_response stopper
|
|
323
301
|
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def locale
|
|
305
|
+
call[:locale] || I18n.default_locale
|
|
306
|
+
end
|
|
324
307
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
result = reason.respond_to?(:utterance) ? reason.utterance : nil
|
|
328
|
-
parse_dtmf result
|
|
308
|
+
def locale=(l)
|
|
309
|
+
call[:locale] = l
|
|
329
310
|
end
|
|
330
311
|
|
|
331
312
|
# @private
|