voice_form 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ == 0.3.0 2009-03-22
2
+ * Lots of refactoring for prompts. Prompts can now be a symbol for a component instance method.
3
+ * Added prompt bargein option to set whether the caller can interrupt a prompt
4
+ * Added Simon game example in the examples folder
5
+ * Added as_digits helper
6
+ * Added component start_voice_form class method to start the form without creating component instance first.
7
+
8
+ == 0.2.0 2009-01-16
9
+ * Updated to work with Adhearsion 0.8.0 release. Examples updated to match new usage.
10
+
11
+ == 0.1.1 2008-11-12
12
+ * refactored to auto include voice_form method in components, no more 'include VoiceForm'
13
+
14
+ == 0.1.0 2008-11-11
15
+ * Gemified using newgem
16
+
17
+ == 2008-11-11
18
+ * Added form field confirm callback to enable confirmation of input
19
+
20
+ == 2008-11-04
21
+ * Changed form.exit_form to form.exit
22
+
23
+ == 2008-11-03
24
+ * First commit
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Adam Meehan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,251 @@
1
+ # VoiceForm
2
+
3
+ A plugin for Adhearsion to add form functionality and flow, similar to VoiceXML style forms.
4
+
5
+ By Adam Meehan (adam.meehan@gmail.com, [http://duckpunching.com/](http://duckpunching.com/))
6
+
7
+ Released under the MIT license.
8
+
9
+ ## Introduction
10
+
11
+ The plugin adds form features to Adhearsion components to quickly and semantically setup data
12
+ input for your voice application. You define a form and form fields in which to collect data and
13
+ setup callbacks to instruct the caller, give feedback, confirm input and validate input.
14
+
15
+
16
+ ## Install
17
+
18
+ sudo gem install adzap-voice_form --source=http://gems.github.com/
19
+
20
+ At the bottom your projects startup.rb file put
21
+
22
+ require 'voice_form'
23
+
24
+ ## Example
25
+
26
+ Here is the Adhearsion example Simon game redone using voice_form:
27
+
28
+ class SimonGame
29
+ include VoiceForm
30
+
31
+ voice_form do
32
+ setup do
33
+ @number = ''
34
+ end
35
+
36
+ field(:attempt, :attempts => 1) do
37
+ prompt :play => :current_number, :bargein => false, :timeout => 2
38
+
39
+ setup do
40
+ @number << random_number
41
+ end
42
+
43
+ validate do
44
+ @attempt == @number
45
+ end
46
+
47
+ success do
48
+ call.play 'good'
49
+ form.restart
50
+ end
51
+
52
+ failure do
53
+ call.play %W[#{@number.length-1} times wrong-try-again-smarty]
54
+ @number = ''
55
+ form.restart
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ def random_number
62
+ rand(10).to_s
63
+ end
64
+
65
+ def current_number
66
+ as_digits(@number)
67
+ end
68
+ end
69
+
70
+ That covers most of the functionality, and hopefully it makes sense pretty much straight
71
+ away.
72
+
73
+ To start the form, in your dialplan:
74
+
75
+ For Adhearsion 0.7.999
76
+
77
+ general {
78
+ simon_game = new_simon_game
79
+ simon_game.start_voice_form(self)
80
+ }
81
+
82
+ For Adhearsion 0.8.x
83
+
84
+ general {
85
+ SimonGame.start_voice_form(self)
86
+ }
87
+
88
+ You don't have to start the form from the dialplan, but it makes it simple. You could start it from
89
+ within a component method.
90
+
91
+ All callback blocks (setup, validate, timeout etc.) are evaluated in the component scope so you can use
92
+ component methods and instance variables in them and they will work. You don't have to define any
93
+ callbacks if the field is straight forward and only depends on its length.
94
+
95
+ For a more complete example see the examples folder.
96
+
97
+ ## Commands
98
+
99
+ ### voice_form
100
+
101
+ The flow of the form works like a stack. So each field and do_block are executed in order until the
102
+ end of the form is reached. You can jump around the stack by using `form.goto :field_name` which
103
+ will move the *stack pointer* to the field after the current field is completed and move forward
104
+ through the form stack from that point, regardless whether a field has already been completed.
105
+
106
+ You can also use `form.restart` to start the form over from the beginning.
107
+
108
+ The form setup block is only run once and is not executed again, even with a `form.restart`.
109
+
110
+
111
+ ### field
112
+
113
+ This defines the field with the name given to collect on the form. The field method can be used
114
+ in a `voice_form` or on its own inside a component method.
115
+
116
+ The options available are:
117
+
118
+ - :length - the number of digits to accept
119
+ - :min_length - minimum number of digits to accept
120
+ - :max_length - maximum number of digits to accept
121
+ - :attempts - number of tries to get a valid input
122
+ - :call - the method name for the call context if other than 'call'. Used for standalone fields not in a form.
123
+
124
+ All fields defined get an accessor method defined of the same name in the component class.
125
+ This means you can access its value using the instance variable or the accessor method inside any of
126
+ the field callbacks and in other fields on a form.
127
+
128
+ The `prompt` and `reprompt` methods are a wrapper around the input command. And as such is always
129
+ interruptable or you can _bargein_ when you want to starting keying numbers. You pass in a
130
+ hash of options to control the prompt such as:
131
+
132
+ - :play - play one or more sound files
133
+ - :speak - play TTS text (needs my Adhearsion hack for speak in input command)
134
+ - :timeout - number of seconds to wait for input. Default is 5.
135
+ - :repeats - number of attempts to use this prompt until the next one is used
136
+ - :bargein - whether to allow caller to interrupt prompt. Default is true.
137
+
138
+ The length expected for the input is taken from the options passed to the `field` method.
139
+
140
+ You can only use one of :play or :speak.
141
+
142
+ There can only be one `prompt` but you can have multiple `reprompt`s. When you add a reprompt it changes
143
+ what the prompt is if there is input the first time or the input is invalid.
144
+
145
+
146
+ ### Callbacks
147
+
148
+ The available callbacks that can be defined for a field are as follows
149
+
150
+ - setup
151
+ - timeout
152
+ - validate
153
+ - invalid
154
+ - confirm
155
+ - success
156
+ - failure
157
+
158
+ Each of them takes a block which is executed as a specific point in the process of getting form input.
159
+ All of them are optional. The block for a callback is evaluated in the scope of the component so any
160
+ instance variables and component methods are available to use including the call context.
161
+
162
+ The details of each callback are as follows
163
+
164
+ #### setup
165
+
166
+ This is run once only for a field if defined before any prompts
167
+
168
+ #### timeout
169
+
170
+ This is run if no input is received or input is not of a valid length as defined by length or min_length
171
+ field options.
172
+
173
+ #### validate
174
+
175
+ This is run after input of a valid length. The validate block is where you put validation logic of the
176
+ value just input by the user. The block should return `true` if the value is valid or `false` otherwise.
177
+ If the validate callback returns false then the invalid callback will be called next.
178
+
179
+ #### invalid
180
+
181
+ The invalid callback is called if validate block returns false.
182
+
183
+ #### confirm
184
+
185
+ The confirm callback is called after the input has been validated. The confirm callback is a little different
186
+ from the others. Idea is that you return either an array or string of the audio files or TTS text, respectively,
187
+ you want to play as the prompt for confirming the value entered. The confirm block also takes a few options:
188
+
189
+ - :accept - the number to press to accept the field value entered. Default is 1.
190
+ - :reject - the number to press the reject the field value entered and try again. Default is 2.
191
+ - :attempts - the number of attempts to try to get a confirmation response. Default is 3
192
+ - :timeout - the number of seconds to wait for input after the confirmation response. Default is 3.
193
+
194
+ The value returned from the block should form the complete list of audio files or TTS text to prompt the user
195
+ including the values to accept of reject the value.
196
+
197
+ For example, in a field called my_field:
198
+
199
+ confirm(:accept => 1, :reject => 2, :attempts => 3) do
200
+ ['you-entered', as_digits(@my_field), 'is-this-correct', 'press-1-accept-2-try-again'].flatten
201
+ end
202
+
203
+ The above will `play` the array of audio files as the prompt for confirmation.
204
+
205
+ confirm(:accept => 1, :reject => 2, :attempts => 3) do
206
+ "You entered #{@my_field}. Is this correct? Press 1 to accept or 2 try again."
207
+ end
208
+
209
+ The above will `speak` the string as the prompt for confirmation.
210
+
211
+ If no valid input is entered for the confirmation then another you will be reprompted to enter the field value.
212
+
213
+
214
+ ### Form methods
215
+
216
+ Inside a callback you have the `form` method available. The returns the instance of the current form. The form
217
+ has some methods to allow you to perform form actions which manipulate the form stack. These actions are as follows:
218
+
219
+ #### form.goto
220
+
221
+ Inside any callback you can use the `goto` command to designate which field the form should run after the
222
+ current field. Normally the form will progress through the fields in the order defined, but a goto with shift
223
+ the current form position to the field name pass to it like so:
224
+
225
+ failure do
226
+ form.goto :other_field_name
227
+ end
228
+
229
+ The form continues from the field in the goto run each subsequent field in order. If the goto field is above the
230
+ current field then the current field will be executed again when it is reached in the stack. If the goto field
231
+ is below the current field then form will continue there, skipping whatever fields may lie between the current
232
+ and the goto field.
233
+
234
+
235
+ #### form.restart
236
+
237
+ The form may be restarted from the start at any point with `form.restart`. This will go back to the top of the
238
+ form and proceed through each field again. The form setup will not be run again however.
239
+
240
+
241
+ #### form.exit
242
+
243
+ To exit the form after the current field is complete just execute `form.exit`. The application will then be
244
+ returned to where the form was started, be it a dialplan or another form.
245
+
246
+
247
+ ## Credits
248
+
249
+ Adam Meehan (adam.meehan@gmail.com, [http://duckpunching.com/](http://duckpunching.com/))
250
+
251
+ Also thanks to Jay Phillips et al. for the brilliant work on Adhearsion ([http://adhearsion.com](http://adhearsion.com)).
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require 'spec/rake/spectask'
6
+
7
+ GEM = "voice_form"
8
+ GEM_VERSION = "0.3.0"
9
+ AUTHOR = "Adam Meehan"
10
+ EMAIL = "adam.meehan@gmail.com"
11
+ HOMEPAGE = "http://github.com/adzap/voice_form"
12
+ SUMMARY = "A plugin for Adhearsion to create forms in the style of the VoiceXML form element."
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = GEM
16
+ s.version = GEM_VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.has_rdoc = false
19
+ s.summary = SUMMARY
20
+ s.description = s.summary
21
+ s.author = AUTHOR
22
+ s.email = EMAIL
23
+ s.homepage = HOMEPAGE
24
+ s.extra_rdoc_files = ["History.txt"]
25
+ # Uncomment this to add a dependency
26
+ # s.add_dependency "foo"
27
+
28
+ s.require_path = 'lib'
29
+ s.autorequire = GEM
30
+ s.files = %w(MIT-LICENSE README.markdown Rakefile) + Dir.glob("{lib,spec,examples}/**/*")
31
+ end
32
+
33
+ task :default => :spec
34
+
35
+ desc "Run specs"
36
+ Spec::Rake::SpecTask.new do |t|
37
+ t.spec_files = FileList['spec/**/*_spec.rb']
38
+ t.spec_opts = %w(-fs --color)
39
+ end
40
+
41
+ Rake::GemPackageTask.new(spec) do |pkg|
42
+ pkg.gem_spec = spec
43
+ end
44
+
45
+ desc "install the gem locally"
46
+ task :install => [:package] do
47
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
48
+ end
49
+
50
+ desc "create a gemspec file"
51
+ task :make_spec do
52
+ File.open("#{GEM}.gemspec", "w") do |file|
53
+ file.puts spec.to_ruby
54
+ end
55
+ end
@@ -0,0 +1,62 @@
1
+ class MyComponent
2
+ include VoiceForm
3
+
4
+ MAX_AGE = 110
5
+
6
+ delegate :play, :speak, :to => :call
7
+
8
+ voice_form do
9
+ field(:age, :max_length => 3, :attempts => 3) do
10
+ prompt :speak => "Please enter your age", :timeout => 2, :repeats => 2
11
+ reprompt :speak => "Enter your age in years", :timeout => 2
12
+
13
+ confirm do
14
+ "Are you sure you are #{@age} years old? Press 1 to confirm, or 2 to retry."
15
+ end
16
+
17
+ validate { @age.to_i < MAX_AGE }
18
+
19
+ invalid do
20
+ speak "You cannot be that old. Try again."
21
+ end
22
+
23
+ success do
24
+ speak "You are #{@age} years old."
25
+ end
26
+
27
+ failure do
28
+ speak "You could not enter your age. Thats a bad sign."
29
+ end
30
+ end
31
+
32
+ do_block do
33
+ speak "Get ready for the next question."
34
+ end
35
+
36
+ field(:postcode, :length => 4, :attempts => 5) do
37
+ prompt :speak => "Please enter your 4 digit postcode", :timeout => 3
38
+
39
+ validate { @postcode[0..0] != '0' }
40
+
41
+ invalid do
42
+ if @postcode.size < 4
43
+ speak "Your postcode must 4 digits."
44
+ else
45
+ speak "Your postcode cannot start with a 0."
46
+ end
47
+ end
48
+
49
+ success do
50
+ speak "Your postcode is #{@postcode.scan(/\d/).join(', ')}."
51
+ end
52
+
53
+ failure do
54
+ if @age.empty?
55
+ speak "Lets start over shall we."
56
+ form.restart
57
+ end
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,47 @@
1
+ methods_for :dialplan do
2
+ def simon_game_voice_form
3
+ SimonGameVoiceForm.start_voice_form(self)
4
+ end
5
+ end
6
+
7
+ class SimonGameVoiceForm
8
+ include VoiceForm
9
+
10
+ voice_form do
11
+ setup do
12
+ @number = ''
13
+ end
14
+
15
+ field(:attempt, :attempts => 1) do
16
+ prompt :play => :current_number, :bargein => false, :timeout => 2
17
+
18
+ setup do
19
+ @number << random_number
20
+ end
21
+
22
+ validate do
23
+ @attempt == @number
24
+ end
25
+
26
+ success do
27
+ call.play 'good'
28
+ form.restart
29
+ end
30
+
31
+ failure do
32
+ call.play %W[#{@number.length-1} times wrong-try-again-smarty]
33
+ @number = ''
34
+ form.restart
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ def random_number
41
+ rand(10).to_s
42
+ end
43
+
44
+ def current_number
45
+ as_digits(@number)
46
+ end
47
+ end