alexa_generator 0.1.2 → 0.2.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 +4 -4
- data/lib/alexa_generator/{alexa_syntax_error.rb → errors.rb} +3 -0
- data/lib/alexa_generator/intent.rb +35 -1
- data/lib/alexa_generator/interaction_model.rb +29 -13
- data/lib/alexa_generator/slot.rb +9 -5
- data/lib/alexa_generator/version.rb +1 -1
- data/lib/alexa_generator.rb +1 -1
- data/spec/alexa_generator/intent_spec.rb +8 -0
- data/spec/alexa_generator/interaction_model_spec.rb +58 -18
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e8ba24c9e6ca19a170be8d4e925ac95e89511e2
|
4
|
+
data.tar.gz: 48408c740b0ec858c3159824f2ea190a9ff487df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7048fadeedc9213ce2f34823c7a12257ea7092b32a3b1b691f175ea6d5cd374b927cff87907811871e75260c8066390fa83c9acf96283f2caee05edfeca53d7d
|
7
|
+
data.tar.gz: 4f94f8409c5e413a44f71b5ba2d1b5a6386bf4c8622c1b32d83b566a501f6779180ca947075980b0a88d8ac5b30eb2b6a35d68766f1331c6575a2c994f5cf3bb
|
@@ -3,6 +3,31 @@ require 'alexa_generator/sample_utterance_template'
|
|
3
3
|
|
4
4
|
module AlexaGenerator
|
5
5
|
class Intent
|
6
|
+
|
7
|
+
module AmazonIntentType
|
8
|
+
VALUES = [
|
9
|
+
CANCEL = :"AMAZON.CancelIntent",
|
10
|
+
HELP = :"AMAZON.HelpIntent",
|
11
|
+
LOOP_OFF = :"AMAZON.LoopOffIntent",
|
12
|
+
LOOP_ON = :"AMAZON.LoopOnIntent",
|
13
|
+
NEXT = :"AMAZON.NextIntent",
|
14
|
+
NO = :"AMAZON.NoIntent",
|
15
|
+
PAUSE = :"AMAZON.PauseIntent",
|
16
|
+
PREVIOUS = :"AMAZON.PreviousIntent",
|
17
|
+
REPEAT = :"AMAZON.RepeatIntent",
|
18
|
+
RESUME = :"AMAZON.ResumeIntent",
|
19
|
+
SHUFFLE_OFF = :"AMAZON.ShuffleOffIntent",
|
20
|
+
SHUFFLE_ON = :"AMAZON.ShuffleOnIntent",
|
21
|
+
START_OVER = :"AMAZON.StartOverIntent",
|
22
|
+
STOP = :"AMAZON.StopIntent",
|
23
|
+
YES = :"AMAZON.YesIntent"
|
24
|
+
]
|
25
|
+
|
26
|
+
def self.amazon_intent?(val)
|
27
|
+
VALUES.include?(val.to_sym)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
6
31
|
attr_reader :name, :slots
|
7
32
|
|
8
33
|
class Builder
|
@@ -16,6 +41,11 @@ module AlexaGenerator
|
|
16
41
|
end
|
17
42
|
|
18
43
|
def add_slot(name, type, &block)
|
44
|
+
if AmazonIntentType.amazon_intent?(@name)
|
45
|
+
raise AlexaGenerator::InvalidIntentError,
|
46
|
+
"Amazon intents don't support slots. Tried to add a slot to intent of type: #{type}"
|
47
|
+
end
|
48
|
+
|
19
49
|
builder = Slot.build(name, type, &block)
|
20
50
|
|
21
51
|
slot_bindings = builder.bindings.map { |x| SlotBinding.new(name, x) }
|
@@ -41,10 +71,14 @@ module AlexaGenerator
|
|
41
71
|
@name = name
|
42
72
|
@slots = slots
|
43
73
|
end
|
74
|
+
|
75
|
+
def amazon_intent?
|
76
|
+
AmazonIntentType.amazon_intent?(@name)
|
77
|
+
end
|
44
78
|
|
45
79
|
def self.build(name, &block)
|
46
80
|
builder = Builder.new(name)
|
47
|
-
block.call(builder)
|
81
|
+
block.call(builder) if block
|
48
82
|
builder
|
49
83
|
end
|
50
84
|
end
|
@@ -45,29 +45,35 @@ module AlexaGenerator
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def intent_schema
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
}
|
48
|
+
intents = []
|
49
|
+
|
50
|
+
@intents.values.each do |intent|
|
51
|
+
slots = []
|
52
|
+
|
53
|
+
intent.slots.each do |slot|
|
54
|
+
slots << {name: slot.name, type: slot.type}
|
55
|
+
end
|
56
|
+
|
57
|
+
intents << {intent: intent.name, slots: slots}
|
58
|
+
end
|
59
|
+
|
60
|
+
{ intents: intents }
|
61
61
|
end
|
62
62
|
|
63
63
|
def sample_utterances(intent_name)
|
64
64
|
templates = @utterance_templates[intent_name] || []
|
65
|
+
slot_types = collect_slot_types
|
65
66
|
utterances = Set.new
|
66
67
|
|
67
68
|
templates.each do |template|
|
68
69
|
# Consider only the slots that are referenced in this template
|
69
70
|
relevant_slots = template.referenced_slots
|
70
71
|
|
72
|
+
# Amazon wants only the LITERAL ones
|
73
|
+
relevant_slots.select! do |s|
|
74
|
+
AlexaGenerator::Slot::SlotType.literal?(slot_types[s.to_sym])
|
75
|
+
end
|
76
|
+
|
71
77
|
# Compute all possible value bindings for the relevant slots
|
72
78
|
slot_values = relevant_slots.
|
73
79
|
# Extract value bindings for each slot
|
@@ -106,6 +112,16 @@ module AlexaGenerator
|
|
106
112
|
end
|
107
113
|
end
|
108
114
|
|
115
|
+
def collect_slot_types
|
116
|
+
out = {}
|
117
|
+
@intents.values.each do |intent|
|
118
|
+
intent.slots.map do |slot|
|
119
|
+
out[slot.name.to_sym] = slot.type.to_s
|
120
|
+
end
|
121
|
+
end
|
122
|
+
out
|
123
|
+
end
|
124
|
+
|
109
125
|
def self.build(&block)
|
110
126
|
builder = Builder.new
|
111
127
|
block.call(builder)
|
data/lib/alexa_generator/slot.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
module AlexaGenerator
|
2
2
|
class Slot
|
3
3
|
module SlotType
|
4
|
-
LITERAL = :LITERAL
|
5
|
-
NUMBER = :NUMBER
|
6
|
-
DATE = :DATE
|
7
|
-
TIME = :TIME
|
8
|
-
DURATION = :DURATION
|
4
|
+
LITERAL = :"AMAZON.LITERAL"
|
5
|
+
NUMBER = :"AMAZON.NUMBER"
|
6
|
+
DATE = :"AMAZON.DATE"
|
7
|
+
TIME = :"AMAZON.TIME"
|
8
|
+
DURATION = :"AMAZON.DURATION"
|
9
|
+
|
10
|
+
def self.literal?(value)
|
11
|
+
[:LITERAL, LITERAL].include?(value.to_sym)
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
15
|
class Builder
|
data/lib/alexa_generator.rb
CHANGED
@@ -33,5 +33,13 @@ describe AlexaGenerator::Slot do
|
|
33
33
|
expect(intent.slots.count).to eq(1)
|
34
34
|
expect(intent.slots.first.name).to eq(:SlotOne)
|
35
35
|
end
|
36
|
+
|
37
|
+
it 'should whine when trying to add a slot to an Amazon intent' do
|
38
|
+
AlexaGenerator::Intent.build(AlexaGenerator::Intent::AmazonIntentType::CANCEL) do |intent|
|
39
|
+
expect {
|
40
|
+
intent.add_slot(:SlotOne, AlexaGenerator::Slot::SlotType::LITERAL)
|
41
|
+
}.to raise_error(AlexaGenerator::InvalidIntentError)
|
42
|
+
end
|
43
|
+
end
|
36
44
|
end
|
37
45
|
end
|
@@ -43,6 +43,56 @@ describe AlexaGenerator::InteractionModel do
|
|
43
43
|
})
|
44
44
|
end
|
45
45
|
|
46
|
+
it 'should allow built in intents' do
|
47
|
+
iface = AlexaGenerator::InteractionModel.build do |iface|
|
48
|
+
iface.add_intent(AlexaGenerator::Intent::AmazonIntentType::CANCEL)
|
49
|
+
end
|
50
|
+
|
51
|
+
expect(iface).to be_an_instance_of(AlexaGenerator::InteractionModel)
|
52
|
+
expect(iface.intent_schema).to eq(
|
53
|
+
{
|
54
|
+
intents: [
|
55
|
+
{
|
56
|
+
intent: :"AMAZON.CancelIntent",
|
57
|
+
slots: []
|
58
|
+
}
|
59
|
+
]
|
60
|
+
})
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should combine custom and built in intents' do
|
64
|
+
iface = AlexaGenerator::InteractionModel.build do |iface|
|
65
|
+
iface.add_intent(AlexaGenerator::Intent::AmazonIntentType::CANCEL)
|
66
|
+
iface.add_intent(:IntentOne) do |intent|
|
67
|
+
intent.add_slot(:SlotOne, AlexaGenerator::Slot::SlotType::LITERAL) do |slot|
|
68
|
+
slot.add_binding('value1')
|
69
|
+
end
|
70
|
+
|
71
|
+
intent.add_utterance_template('test {SlotOne} test')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
expect(iface).to be_an_instance_of(AlexaGenerator::InteractionModel)
|
76
|
+
expect(iface.intent_schema).to eq(
|
77
|
+
{
|
78
|
+
intents: [
|
79
|
+
{
|
80
|
+
intent: :"AMAZON.CancelIntent",
|
81
|
+
slots: []
|
82
|
+
},
|
83
|
+
{
|
84
|
+
intent: :IntentOne,
|
85
|
+
slots: [
|
86
|
+
{
|
87
|
+
name: :SlotOne,
|
88
|
+
type: AlexaGenerator::Slot::SlotType::LITERAL
|
89
|
+
}
|
90
|
+
]
|
91
|
+
}
|
92
|
+
]
|
93
|
+
})
|
94
|
+
end
|
95
|
+
|
46
96
|
it 'should produce bound utterances' do
|
47
97
|
iface = AlexaGenerator::InteractionModel.build do |iface|
|
48
98
|
iface.add_intent(:MyIntent) do |intent|
|
@@ -67,15 +117,10 @@ describe AlexaGenerator::InteractionModel do
|
|
67
117
|
|
68
118
|
actual = iface.sample_utterances(:MyIntent)
|
69
119
|
|
70
|
-
|
71
|
-
expect(actual).to
|
72
|
-
expect(actual).to include('MyIntent Alexa, please {fix my motorcycle|SlotOne} {
|
73
|
-
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {
|
74
|
-
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {two|SlotTwo} at {noon|SlotThree}')
|
75
|
-
expect(actual).to include('MyIntent Alexa, please {fix my motorcycle|SlotOne} {one|SlotTwo} at {6 a.m.|SlotThree}')
|
76
|
-
expect(actual).to include('MyIntent Alexa, please {fix my motorcycle|SlotOne} {two|SlotTwo} at {6 a.m.|SlotThree}')
|
77
|
-
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {one|SlotTwo} at {6 a.m.|SlotThree}')
|
78
|
-
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {two|SlotTwo} at {6 a.m.|SlotThree}')
|
120
|
+
# only the literal ones get examples
|
121
|
+
expect(actual.count).to eq(2)
|
122
|
+
expect(actual).to include('MyIntent Alexa, please {fix my motorcycle|SlotOne} {SlotTwo} at {SlotThree}')
|
123
|
+
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {SlotTwo} at {SlotThree}')
|
79
124
|
end
|
80
125
|
end
|
81
126
|
|
@@ -144,15 +189,10 @@ describe AlexaGenerator::InteractionModel do
|
|
144
189
|
it 'should produce bound utterances' do
|
145
190
|
actual = AlexaGenerator::InteractionModel.new(intents, utterance_templates, slot_bindings).sample_utterances(:MyIntent)
|
146
191
|
|
147
|
-
|
148
|
-
expect(actual).to
|
149
|
-
expect(actual).to include('MyIntent Alexa, please {fix my motorcycle|SlotOne} {
|
150
|
-
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {
|
151
|
-
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {two|SlotTwo} at {noon|SlotThree}')
|
152
|
-
expect(actual).to include('MyIntent Alexa, please {fix my motorcycle|SlotOne} {one|SlotTwo} at {6 a.m.|SlotThree}')
|
153
|
-
expect(actual).to include('MyIntent Alexa, please {fix my motorcycle|SlotOne} {two|SlotTwo} at {6 a.m.|SlotThree}')
|
154
|
-
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {one|SlotTwo} at {6 a.m.|SlotThree}')
|
155
|
-
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {two|SlotTwo} at {6 a.m.|SlotThree}')
|
192
|
+
# only the literal ones get examples
|
193
|
+
expect(actual.count).to eq(2)
|
194
|
+
expect(actual).to include('MyIntent Alexa, please {fix my motorcycle|SlotOne} {SlotTwo} at {SlotThree}')
|
195
|
+
expect(actual).to include('MyIntent Alexa, please {make me a sandwich|SlotOne} {SlotTwo} at {SlotThree}')
|
156
196
|
end
|
157
197
|
end
|
158
198
|
end
|
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alexa_generator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Mullins
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 3.0.0
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 3.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
description:
|
@@ -44,14 +44,14 @@ executables: []
|
|
44
44
|
extensions: []
|
45
45
|
extra_rdoc_files: []
|
46
46
|
files:
|
47
|
-
- .gitignore
|
47
|
+
- ".gitignore"
|
48
48
|
- Gemfile
|
49
49
|
- LICENSE
|
50
50
|
- README.md
|
51
51
|
- Rakefile
|
52
52
|
- alexa_generator.gemspec
|
53
53
|
- lib/alexa_generator.rb
|
54
|
-
- lib/alexa_generator/
|
54
|
+
- lib/alexa_generator/errors.rb
|
55
55
|
- lib/alexa_generator/intent.rb
|
56
56
|
- lib/alexa_generator/intent_schema.rb
|
57
57
|
- lib/alexa_generator/interaction_model.rb
|
@@ -73,17 +73,17 @@ require_paths:
|
|
73
73
|
- lib
|
74
74
|
required_ruby_version: !ruby/object:Gem::Requirement
|
75
75
|
requirements:
|
76
|
-
- -
|
76
|
+
- - ">="
|
77
77
|
- !ruby/object:Gem::Version
|
78
78
|
version: '0'
|
79
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
84
|
requirements: []
|
85
85
|
rubyforge_project:
|
86
|
-
rubygems_version: 2.
|
86
|
+
rubygems_version: 2.5.1
|
87
87
|
signing_key:
|
88
88
|
specification_version: 4
|
89
89
|
summary: Generates voice interfaces for Alexa apps based on templates.
|