nuance 0.0.2
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.
- data/.DS_Store +0 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +60 -0
- data/LICENSE.txt +20 -0
- data/README.md +42 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/examples/DT-202c.wav +0 -0
- data/examples/transcribe.rb +13 -0
- data/lib/nuance.rb +7 -0
- data/lib/nuance/dictation-base64.cer +30 -0
- data/lib/nuance/text_to_speech.rb +7 -0
- data/lib/nuance/transcription.rb +156 -0
- data/nuance.gemspec +84 -0
- data/spec/.DS_Store +0 -0
- data/spec/DT-202c.wav +0 -0
- data/spec/nuance-text_to_speech_spec.rb +12 -0
- data/spec/nuance-transcription_spec.rb +211 -0
- data/spec/spec_helper.rb +15 -0
- metadata +217 -0
data/.DS_Store
ADDED
Binary file
|
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
nuance (0.0.2)
|
5
|
+
celluloid (= 0.12.4)
|
6
|
+
faraday (= 0.8.4)
|
7
|
+
hashie (= 1.2.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
celluloid (0.12.4)
|
13
|
+
facter (>= 1.6.12)
|
14
|
+
timers (>= 1.0.0)
|
15
|
+
diff-lcs (1.1.3)
|
16
|
+
facter (1.7.1)
|
17
|
+
fakeweb (1.3.0)
|
18
|
+
faraday (0.8.4)
|
19
|
+
multipart-post (~> 1.1)
|
20
|
+
git (1.2.5)
|
21
|
+
hashie (1.2.0)
|
22
|
+
jeweler (1.8.4)
|
23
|
+
bundler (~> 1.0)
|
24
|
+
git (>= 1.2.5)
|
25
|
+
rake
|
26
|
+
rdoc
|
27
|
+
json (1.8.0)
|
28
|
+
multi_json (1.7.7)
|
29
|
+
multipart-post (1.2.0)
|
30
|
+
rake (10.1.0)
|
31
|
+
rdoc (3.12)
|
32
|
+
json (~> 1.4)
|
33
|
+
rspec (2.12.0)
|
34
|
+
rspec-core (~> 2.12.0)
|
35
|
+
rspec-expectations (~> 2.12.0)
|
36
|
+
rspec-mocks (~> 2.12.0)
|
37
|
+
rspec-core (2.12.2)
|
38
|
+
rspec-expectations (2.12.1)
|
39
|
+
diff-lcs (~> 1.1.3)
|
40
|
+
rspec-mocks (2.12.2)
|
41
|
+
simplecov (0.7.1)
|
42
|
+
multi_json (~> 1.0)
|
43
|
+
simplecov-html (~> 0.7.1)
|
44
|
+
simplecov-html (0.7.1)
|
45
|
+
timers (1.1.0)
|
46
|
+
yard (0.8.3)
|
47
|
+
|
48
|
+
PLATFORMS
|
49
|
+
ruby
|
50
|
+
|
51
|
+
DEPENDENCIES
|
52
|
+
bundler (= 1.3.5)
|
53
|
+
facter (= 1.7.1)
|
54
|
+
fakeweb (= 1.3.0)
|
55
|
+
jeweler (= 1.8.4)
|
56
|
+
nuance!
|
57
|
+
rdoc (= 3.12)
|
58
|
+
rspec (= 2.12.0)
|
59
|
+
simplecov (= 0.7.1)
|
60
|
+
yard (= 0.8.3)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Tropo, Inc
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
nuance
|
2
|
+
======
|
3
|
+
|
4
|
+
A Ruby Gem for consuming the Nuance transcription and text to speech REST APIs. More details may be found at the [Nuance Mobile Develper](http://www.nuance.com/for-partners/by-solution/mobile-developer-program/index.htm) site.
|
5
|
+
|
6
|
+
Installation
|
7
|
+
------------
|
8
|
+
|
9
|
+
```
|
10
|
+
gem install nuance
|
11
|
+
```
|
12
|
+
|
13
|
+
Usage
|
14
|
+
-----
|
15
|
+
|
16
|
+
The languages supported may be found [here](http://dragonmobile.nuancemobiledeveloper.com/public/index.php?task=supportedLanguages). Here is an example:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
# blocking
|
20
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => ENV['NUANCE_APP_ID'],
|
21
|
+
:app_key => ENV['NUANCE_APP_KEY'],
|
22
|
+
:id => '0' })
|
23
|
+
result = nuance_transcription.transcribe({ :file_contents => File.open('spec/DT-202c.wav').read })
|
24
|
+
if result.status == 200
|
25
|
+
puts result.body
|
26
|
+
end
|
27
|
+
|
28
|
+
# non-blocking
|
29
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => ENV['NUANCE_APP_ID'],
|
30
|
+
:app_key => ENV['NUANCE_APP_KEY'],
|
31
|
+
:id => '0' })
|
32
|
+
nuance_transcription.transcribe!(:file_contents => File.open('spec/DT-202c.wav').read) do |result|
|
33
|
+
if result.status == 200
|
34
|
+
puts result.body
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
Copyright
|
39
|
+
---------
|
40
|
+
|
41
|
+
Copyright (c) 2013 Tropo, Inc. See LICENSE.txt for further details.
|
42
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "nuance"
|
18
|
+
gem.homepage = "http://github.com/jsgoecke/nuance"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = "A Ruby Gem for consuming the Nuance transcription and text to speech REST APIs"
|
21
|
+
gem.description = "A Ruby Gem for consuming the Nuance transcription and text to speech REST APIs"
|
22
|
+
gem.email = "jason@goecke.net"
|
23
|
+
gem.authors = ["Jason Goecke"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.simplecov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
require 'yard'
|
42
|
+
YARD::Rake::YardocTask.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.2
|
Binary file
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'nuance'
|
2
|
+
|
3
|
+
# Blocking
|
4
|
+
nuance = Nuance::Transcription.new({ :app_id => ENV['NUANCE_APP_ID'],
|
5
|
+
:app_key => ENV['NUANCE_APP_KEY'],
|
6
|
+
:id => '123' })
|
7
|
+
|
8
|
+
p nuance.transcribe(:file_contents => File.open('DT-202c.wav').read)
|
9
|
+
|
10
|
+
# Non-blocking
|
11
|
+
nuance.transcribe!(:file_contents => File.open('DT-202c.wav').read) do |result|
|
12
|
+
p result
|
13
|
+
end
|
data/lib/nuance.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIFLTCCBBWgAwIBAgIDAcXvMA0GCSqGSIb3DQEBBQUAMEAxCzAJBgNVBAYTAlVT
|
3
|
+
MRcwFQYDVQQKEw5HZW9UcnVzdCwgSW5jLjEYMBYGA1UEAxMPR2VvVHJ1c3QgU1NM
|
4
|
+
IENBMB4XDTEyMTAyNDEzMTA0NFoXDTE0MTEyNjE0MTA1NVowgbkxKTAnBgNVBAUT
|
5
|
+
IHk5Sk5Db3ZoUGJOQ2EvaUJNZE9jNGthWWhqNjhhSTliMQswCQYDVQQGEwJVUzEW
|
6
|
+
MBQGA1UECBMNTWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHUGVhYm9keTEjMCEGA1UE
|
7
|
+
ChMaTnVhbmNlIENvbW11bmljYXRpb25zIEluYy4xETAPBgNVBAsTCE1vYmlsaXR5
|
8
|
+
MR0wGwYDVQQDDBQqLm51YW5jZW1vYmlsaXR5Lm5ldDCCASIwDQYJKoZIhvcNAQEB
|
9
|
+
BQADggEPADCCAQoCggEBAMV2moXwKA1tLUVmTdM5ZaVBr9a4I2OkTIjefNdFxtuH
|
10
|
+
YBWKXA2eCDcy6pHk9V34HbGqAo1aEylJiXN90Y2uL43QdkAM9lPnRZRzynpPcKCh
|
11
|
+
VODhWa8brXT1gVeoGlh9OXZE3RiK+rPHNUUfAOfGTg7bnXmiK6Bml58SExLpQxtI
|
12
|
+
9Wy9tNoTWJ4v1L6bxK776qE12DvaxyFNFgJp5m0R7hQmMXeyQzSrylsjlfUcgKR/
|
13
|
+
O1LSxnAq7Kv3ijUxA0gKu7elWYdXI71/zRdjvNr9dSekb19rP/rcoNZsGQvT3uuc
|
14
|
+
JnJVdujLbmSBm9U/JWHjzOC5Yhoul4RogGX442wMmXsCAwEAAaOCAbQwggGwMB8G
|
15
|
+
A1UdIwQYMBaAFEJ5VBthzVUrPmPVPEhX9Z/7Rc5KMA4GA1UdDwEB/wQEAwIEsDAd
|
16
|
+
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwMwYDVR0RBCwwKoIUKi5udWFu
|
17
|
+
Y2Vtb2JpbGl0eS5uZXSCEm51YW5jZW1vYmlsaXR5Lm5ldDA9BgNVHR8ENjA0MDKg
|
18
|
+
MKAuhixodHRwOi8vZ3Rzc2wtY3JsLmdlb3RydXN0LmNvbS9jcmxzL2d0c3NsLmNy
|
19
|
+
bDAdBgNVHQ4EFgQUNuyQCo6RJvAYlmfaaSZIVfPZpiMwDAYDVR0TAQH/BAIwADBv
|
20
|
+
BggrBgEFBQcBAQRjMGEwKgYIKwYBBQUHMAGGHmh0dHA6Ly9ndHNzbC1vY3NwLmdl
|
21
|
+
b3RydXN0LmNvbTAzBggrBgEFBQcwAoYnaHR0cDovL2d0c3NsLWFpYS5nZW90cnVz
|
22
|
+
dC5jb20vZ3Rzc2wuY3J0MEwGA1UdIARFMEMwQQYKYIZIAYb4RQEHNjAzMDEGCCsG
|
23
|
+
AQUFBwIBFiVodHRwOi8vd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvY3BzMA0G
|
24
|
+
CSqGSIb3DQEBBQUAA4IBAQBA81miz43odjvvarBucFDKfKbhrQAWrEQB+Avri97g
|
25
|
+
ytN0xkfpdov0b/qLRNxm2oohqRKmKG0QdsVKfObWL1GoJrZo/YJc3IRcoBlZXUr2
|
26
|
+
QGZShAmAV6nBXlPAcbp+ryfLWEGRPCc3rs1TLsGrExxsLW6QcnKdnaoTuR7rWfbD
|
27
|
+
CnBoPFRnOgakXf1hxyNSSRgcx0oetFSL/jASD2bylRPU09eA9beZsOEcfGp4I7ON
|
28
|
+
+U77F36aRMgOfwE1JWiAjgcsUywHCfRo7084HtozrvUYmqgaxi2J5KQ6JOxsbOFS
|
29
|
+
8hAxHOOsAqEUWOje7shQBTGW30FheDKjms7yUPuYh5me
|
30
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Nuance
|
2
|
+
class Transcription
|
3
|
+
include Celluloid
|
4
|
+
Celluloid.logger = nil
|
5
|
+
|
6
|
+
attr_reader :base_uri
|
7
|
+
|
8
|
+
##
|
9
|
+
# Creates an ATTSpeech object
|
10
|
+
#
|
11
|
+
# @param [Hash] args the options to intantiate with
|
12
|
+
# @option args [String] :api_id the Nuance App API ID
|
13
|
+
# @option args [String] :app_key the Nuance App Key
|
14
|
+
# @option args [String] :id the Nuance id
|
15
|
+
# @option args [String] :base_url the url for the Nuance API, default is 'https://api.att.com'
|
16
|
+
#
|
17
|
+
# @return [Object] an instance of Nuance::Transcription
|
18
|
+
def initialize(options={})
|
19
|
+
raise ArgumentError, ':app_id must be set' if !options[:app_id]
|
20
|
+
raise ArgumentError, ':app_key must be set' if !options[:app_key]
|
21
|
+
raise ArgumentError, ':id must be set' if !options[:id]
|
22
|
+
|
23
|
+
@base_uri = options[:base_uri] || 'https://dictation.nuancemobility.net'
|
24
|
+
@app_id = options[:app_id] || ENV['NUANCE_APP_ID']
|
25
|
+
@app_key = options[:app_key] || ENV['NUANCE_APP_KEY']
|
26
|
+
@id = options[:id] || rand(100000000)
|
27
|
+
@resource = "/NMDPAsrCmdServlet/dictation?appId=#{@app_id}&appKey=#{@app_key}&id=#{@id}"
|
28
|
+
@logging = options[:logging] || false
|
29
|
+
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Allows you to send a file and return the transcription
|
35
|
+
#
|
36
|
+
# @param [String] file_contents to be processed
|
37
|
+
# @option args [String] :content_type the content type of the audio file to transcribe
|
38
|
+
# @option args [String] :accept_type the accept type of the audio file to transcribe
|
39
|
+
# @option args [String] :accept_topic the accept topic of the audio file to transcribe
|
40
|
+
# @option args [String] :lanugage the language of the audio file to transcribe
|
41
|
+
# @option args [String] :accept the accept of the audio file to transcribe
|
42
|
+
# @param [Block] block to be called when the transcription completes
|
43
|
+
#
|
44
|
+
# @return [Hash] the resulting response from the Nuance API
|
45
|
+
def transcribe(options={}, &block)
|
46
|
+
@content_type = options[:content_type] || 'audio/x-wav;codec=pcm;bit=16;rate=8000'
|
47
|
+
@accept_topic = options[:accept_topic] || 'Dictation'
|
48
|
+
@accept_language = options[:language] || 'en_US'
|
49
|
+
@accept = options[:accept] || 'application/xml'
|
50
|
+
|
51
|
+
@ssl_verify = options[:ssl_verify] || true
|
52
|
+
raise ArgumentError, ':content_type must be valid' if !content_type_valid?(options[:content_type])
|
53
|
+
raise ArgumentError, ':file_contents must be present' if !options[:file_contents]
|
54
|
+
raise ArgumentError, ':language must be valid' if !language_valid?(options[:language])
|
55
|
+
|
56
|
+
create_connection
|
57
|
+
|
58
|
+
begin
|
59
|
+
response = @connection.post @resource,
|
60
|
+
options[:file_contents],
|
61
|
+
{ :Content_Type => @content_type,
|
62
|
+
:Accept_Language => @accept_language,
|
63
|
+
:Accept_Topic => @accept_topic,
|
64
|
+
:Accept => @accept,
|
65
|
+
:Transfer_Encoding => 'chunked' }
|
66
|
+
if response.status == 200
|
67
|
+
block.call process(response) if block_given?
|
68
|
+
process(response)
|
69
|
+
else
|
70
|
+
response
|
71
|
+
end
|
72
|
+
rescue => e
|
73
|
+
raise RuntimeError, e.to_s
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
##
|
80
|
+
# Validate the content type
|
81
|
+
#
|
82
|
+
# @param [String] content_type
|
83
|
+
# @return [Boolean] if valid or not
|
84
|
+
def content_type_valid?(content_type)
|
85
|
+
valid_types = %w{ audio/x-wav;codec=pcm;bit=16;rate=8000
|
86
|
+
audio/x-wav;codec=pcm;bit=16;rate=16000
|
87
|
+
audio/x-speex;rate=8000
|
88
|
+
audio/x-speex;rate=16000
|
89
|
+
audio/amr
|
90
|
+
audio/qcelp
|
91
|
+
audio/evrc
|
92
|
+
}
|
93
|
+
return true if valid_types.grep(/#{content_type}/).length > 0
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Validate the language
|
98
|
+
#
|
99
|
+
# @param [String] language
|
100
|
+
# @return [Boolean] if valid or not
|
101
|
+
def language_valid?(language)
|
102
|
+
valid_types = %w{ en_AU
|
103
|
+
en_GB
|
104
|
+
en_US
|
105
|
+
ar_EG
|
106
|
+
ar_SA
|
107
|
+
ar_AE
|
108
|
+
zh_HK
|
109
|
+
cs_CZ
|
110
|
+
da_DK
|
111
|
+
nl_NL
|
112
|
+
fi_FI
|
113
|
+
fr_CA
|
114
|
+
fr_FR
|
115
|
+
de_DE
|
116
|
+
el_GR
|
117
|
+
hu_HU
|
118
|
+
id_ID
|
119
|
+
it_IT
|
120
|
+
ja_JP
|
121
|
+
ko_KR
|
122
|
+
ms_MY
|
123
|
+
cn_MA
|
124
|
+
zh_TW
|
125
|
+
no_NO
|
126
|
+
pl_PL
|
127
|
+
pt_BR
|
128
|
+
pt_PT
|
129
|
+
ro_RO
|
130
|
+
ru_RU
|
131
|
+
sk_SK
|
132
|
+
es_ES
|
133
|
+
es_MX
|
134
|
+
es_US
|
135
|
+
sv_SE
|
136
|
+
tr_TR
|
137
|
+
vi_VN
|
138
|
+
}
|
139
|
+
return true if valid_types.grep(/#{language}/).length > 0
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Creates the Faraday connection object
|
144
|
+
def create_connection
|
145
|
+
@connection = Faraday.new(:url => @base_uri, :ssl => { :verify => @ssl_verify, :ca_file => 'lib/nuance/dictation-base64.cer' }) do |faraday|
|
146
|
+
faraday.adapter Faraday.default_adapter
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def process(response)
|
153
|
+
Hashie::Mash.new({ :status => 200, :body => response.body.split(/\r?\n/)[0] })
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
data/nuance.gemspec
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "nuance"
|
8
|
+
s.version = "0.0.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jason Goecke"]
|
12
|
+
s.date = "2013-07-08"
|
13
|
+
s.description = "A Ruby Gem for consuming the Nuance transcription and text to speech REST APIs"
|
14
|
+
s.email = "jason@goecke.net"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".DS_Store",
|
21
|
+
".document",
|
22
|
+
".rspec",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"examples/DT-202c.wav",
|
30
|
+
"examples/transcribe.rb",
|
31
|
+
"lib/nuance.rb",
|
32
|
+
"lib/nuance/dictation-base64.cer",
|
33
|
+
"lib/nuance/text_to_speech.rb",
|
34
|
+
"lib/nuance/transcription.rb",
|
35
|
+
"nuance.gemspec",
|
36
|
+
"spec/.DS_Store",
|
37
|
+
"spec/DT-202c.wav",
|
38
|
+
"spec/nuance-text_to_speech_spec.rb",
|
39
|
+
"spec/nuance-transcription_spec.rb",
|
40
|
+
"spec/spec_helper.rb"
|
41
|
+
]
|
42
|
+
s.homepage = "http://github.com/jsgoecke/nuance"
|
43
|
+
s.licenses = ["MIT"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = "1.8.23"
|
46
|
+
s.summary = "A Ruby Gem for consuming the Nuance transcription and text to speech REST APIs"
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
s.specification_version = 3
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_runtime_dependency(%q<nuance>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<rspec>, ["= 2.12.0"])
|
54
|
+
s.add_development_dependency(%q<yard>, ["= 0.8.3"])
|
55
|
+
s.add_development_dependency(%q<rdoc>, ["= 3.12"])
|
56
|
+
s.add_development_dependency(%q<bundler>, ["= 1.3.5"])
|
57
|
+
s.add_development_dependency(%q<facter>, ["= 1.7.1"])
|
58
|
+
s.add_development_dependency(%q<jeweler>, ["= 1.8.4"])
|
59
|
+
s.add_development_dependency(%q<simplecov>, ["= 0.7.1"])
|
60
|
+
s.add_development_dependency(%q<fakeweb>, ["= 1.3.0"])
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<nuance>, [">= 0"])
|
63
|
+
s.add_dependency(%q<rspec>, ["= 2.12.0"])
|
64
|
+
s.add_dependency(%q<yard>, ["= 0.8.3"])
|
65
|
+
s.add_dependency(%q<rdoc>, ["= 3.12"])
|
66
|
+
s.add_dependency(%q<bundler>, ["= 1.3.5"])
|
67
|
+
s.add_dependency(%q<facter>, ["= 1.7.1"])
|
68
|
+
s.add_dependency(%q<jeweler>, ["= 1.8.4"])
|
69
|
+
s.add_dependency(%q<simplecov>, ["= 0.7.1"])
|
70
|
+
s.add_dependency(%q<fakeweb>, ["= 1.3.0"])
|
71
|
+
end
|
72
|
+
else
|
73
|
+
s.add_dependency(%q<nuance>, [">= 0"])
|
74
|
+
s.add_dependency(%q<rspec>, ["= 2.12.0"])
|
75
|
+
s.add_dependency(%q<yard>, ["= 0.8.3"])
|
76
|
+
s.add_dependency(%q<rdoc>, ["= 3.12"])
|
77
|
+
s.add_dependency(%q<bundler>, ["= 1.3.5"])
|
78
|
+
s.add_dependency(%q<facter>, ["= 1.7.1"])
|
79
|
+
s.add_dependency(%q<jeweler>, ["= 1.8.4"])
|
80
|
+
s.add_dependency(%q<simplecov>, ["= 0.7.1"])
|
81
|
+
s.add_dependency(%q<fakeweb>, ["= 1.3.0"])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
data/spec/.DS_Store
ADDED
Binary file
|
data/spec/DT-202c.wav
ADDED
Binary file
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Nuance::TextToSpeech do
|
4
|
+
it 'should raise a RuntimeError, since it is not implemented' do
|
5
|
+
begin
|
6
|
+
Nuance::TextToSpeech.new
|
7
|
+
rescue => e
|
8
|
+
e.instance_of?(RuntimeError).should eql true
|
9
|
+
e.to_s.should eql "Not implemented. Coming soon..."
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Nuance::Transcription do
|
4
|
+
before(:all) do
|
5
|
+
@options = { :app_id => 'abc', :app_key => '123', :id => '0' }
|
6
|
+
@transcription = "Hello World"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#validations' do
|
10
|
+
it "should create a NuanceTranscription object" do
|
11
|
+
Nuance::Transcription.new(@options).class.should eql Nuance::Transcription
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should raise an ArgumentError if :app_key not specified' do
|
15
|
+
begin
|
16
|
+
options = { :app_id => 'foo' }
|
17
|
+
Nuance::Transcription.new(options)
|
18
|
+
rescue => e
|
19
|
+
e.to_s.should eql ":app_key must be set"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should raise an ArgumentError if :app_id not specified' do
|
24
|
+
begin
|
25
|
+
options = { :app_key => 'foo' }
|
26
|
+
Nuance::Transcription.new(options)
|
27
|
+
rescue => e
|
28
|
+
e.to_s.should eql ":app_id must be set"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should raise an ArgumentError if :id not specified' do
|
33
|
+
begin
|
34
|
+
options = { :app_id => 'foo', :app_key => 'bar' }
|
35
|
+
Nuance::Transcription.new(options)
|
36
|
+
rescue => e
|
37
|
+
e.to_s.should eql ':id must be set'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should have the default base url set for Nuance' do
|
42
|
+
nuance = Nuance::Transcription.new(@options)
|
43
|
+
nuance.base_uri.should eql 'https://dictation.nuancemobility.net'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should set a custom base url' do
|
47
|
+
@options.merge!({ :base_uri => 'https://foobar.com' })
|
48
|
+
nuance = Nuance::Transcription.new(@options)
|
49
|
+
nuance.base_uri.should eql 'https://foobar.com'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#transcriptions" do
|
54
|
+
FakeWeb.register_uri(:post, %r|https://dictation.nuancemobility.net/NMDPAsrCmdServlet/dictation|,
|
55
|
+
:status => ['200', 'OK'],
|
56
|
+
:body => 'Hello World')
|
57
|
+
|
58
|
+
describe '#validations' do
|
59
|
+
it 'should allow a valid content type' do
|
60
|
+
content_types = %w{ audio/x-wav;codec=pcm;bit=16;rate=8000
|
61
|
+
audio/x-wav;codec=pcm;bit=16;rate=16000
|
62
|
+
audio/x-speex;rate=8000
|
63
|
+
audio/x-speex;rate=16000
|
64
|
+
audio/amr
|
65
|
+
audio/qcelp
|
66
|
+
audio/evrc
|
67
|
+
}
|
68
|
+
content_types.each do |type|
|
69
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => @options[:app_id],
|
70
|
+
:app_key => @options[:app_key],
|
71
|
+
:id => @options[:id] })
|
72
|
+
result = nuance_transcription.transcribe({ :file_contents => File.open('spec/DT-202c.wav').read,
|
73
|
+
:content_type => type })
|
74
|
+
result.status.should eql 200
|
75
|
+
result.body.should eql @transcription
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should raise an ArgumentError if not a valid content type' do
|
80
|
+
begin
|
81
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => @options[:app_id],
|
82
|
+
:app_key => @options[:app_key],
|
83
|
+
:id => @options[:id] })
|
84
|
+
nuance_transcription.transcribe({ :file_contents => File.open('spec/DT-202c.wav').read,
|
85
|
+
:content_type => 'audio/mp3' })
|
86
|
+
rescue => e
|
87
|
+
e.to_s.should eql ':content_type must be valid'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should allow a valid language type' do
|
92
|
+
languages = %w{ en_AU
|
93
|
+
en_GB
|
94
|
+
en_US
|
95
|
+
ar_EG
|
96
|
+
ar_SA
|
97
|
+
ar_AE
|
98
|
+
zh_HK
|
99
|
+
cs_CZ
|
100
|
+
da_DK
|
101
|
+
nl_NL
|
102
|
+
fi_FI
|
103
|
+
fr_CA
|
104
|
+
fr_FR
|
105
|
+
de_DE
|
106
|
+
el_GR
|
107
|
+
hu_HU
|
108
|
+
id_ID
|
109
|
+
it_IT
|
110
|
+
ja_JP
|
111
|
+
ko_KR
|
112
|
+
ms_MY
|
113
|
+
cn_MA
|
114
|
+
zh_TW
|
115
|
+
no_NO
|
116
|
+
pl_PL
|
117
|
+
pt_BR
|
118
|
+
pt_PT
|
119
|
+
ro_RO
|
120
|
+
ru_RU
|
121
|
+
sk_SK
|
122
|
+
es_ES
|
123
|
+
es_MX
|
124
|
+
es_US
|
125
|
+
sv_SE
|
126
|
+
tr_TR
|
127
|
+
vi_VN
|
128
|
+
}
|
129
|
+
languages.each do |language|
|
130
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => @options[:app_id],
|
131
|
+
:app_key => @options[:app_key],
|
132
|
+
:id => @options[:id] })
|
133
|
+
result = nuance_transcription.transcribe({ :file_contents => File.open('spec/DT-202c.wav').read,
|
134
|
+
:content_type => 'audio/amr',
|
135
|
+
:language => language })
|
136
|
+
result.status.should eql 200
|
137
|
+
result.body.should eql @transcription
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should raise an ArgumentError if not a valid language' do
|
142
|
+
begin
|
143
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => @options[:app_id],
|
144
|
+
:app_key => @options[:app_key],
|
145
|
+
:id => @options[:id] })
|
146
|
+
nuance_transcription.transcribe({ :file_contents => File.open('spec/DT-202c.wav').read,
|
147
|
+
:language => 'esperanto' })
|
148
|
+
rescue => e
|
149
|
+
e.to_s.should eql ':language must be valid'
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should raise an ArgumentError if no file contents provided' do
|
154
|
+
begin
|
155
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => @options[:app_id],
|
156
|
+
:app_key => @options[:app_key],
|
157
|
+
:id => @options[:id] })
|
158
|
+
nuance_transcription.transcribe
|
159
|
+
rescue => e
|
160
|
+
e.to_s.should eql ':file_contents must be present'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#blocking call' do
|
166
|
+
it "should return a transcription" do
|
167
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => @options[:app_id],
|
168
|
+
:app_key => @options[:app_key],
|
169
|
+
:id => @options[:id],
|
170
|
+
:ssl_verify => false })
|
171
|
+
result = nuance_transcription.transcribe({ :file_contents => File.open('spec/DT-202c.wav').read })
|
172
|
+
result.status.should eql 200
|
173
|
+
result.body.should eql @transcription
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe '#non-blocking call' do
|
178
|
+
it "should return a Celluloid::Future object when processing an audio file" do
|
179
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => @options[:app_id],
|
180
|
+
:app_key => @options[:app_key],
|
181
|
+
:id => @options[:id] })
|
182
|
+
future = nuance_transcription.future(:transcribe, :file_contents => File.open('spec/DT-202c.wav').read)
|
183
|
+
future.instance_of?(Celluloid::Future).should eql true
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should allow us to use a future to process an audio file" do
|
187
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => @options[:app_id],
|
188
|
+
:app_key => @options[:app_key],
|
189
|
+
:id => @options[:id] })
|
190
|
+
future = nuance_transcription.future(:transcribe, :file_contents => File.open('spec/DT-202c.wav').read)
|
191
|
+
future.value.status.should eql 200
|
192
|
+
future.value.body.should eql @transcription
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe '#non-blocking call with a block' do
|
197
|
+
it "should allow us to use a future to process an audio file and pass a block" do
|
198
|
+
nuance_transcription = Nuance::Transcription.new({ :app_id => @options[:app_id],
|
199
|
+
:app_key => @options[:app_key],
|
200
|
+
:id => @options[:id] })
|
201
|
+
result = nil
|
202
|
+
nuance_transcription.transcribe!(:file_contents => File.open('spec/DT-202c.wav').read) do |transcription|
|
203
|
+
result = transcription
|
204
|
+
end
|
205
|
+
sleep 0.1
|
206
|
+
result.status.should eql 200
|
207
|
+
result.body.should eql @transcription
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'fakeweb'
|
5
|
+
require 'nuance'
|
6
|
+
|
7
|
+
# Requires supporting files with custom matchers and macros, etc,
|
8
|
+
# in ./support/ and its subdirectories.
|
9
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
10
|
+
|
11
|
+
#FakeWeb.allow_net_connect = false
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nuance
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jason Goecke
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nuance
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.12.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.12.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: yard
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.8.3
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.3
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rdoc
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - '='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.12'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - '='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '3.12'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - '='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.3.5
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - '='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.3.5
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: facter
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - '='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.7.1
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - '='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.7.1
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: jeweler
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - '='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.8.4
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - '='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 1.8.4
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: simplecov
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - '='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.7.1
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - '='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 0.7.1
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: fakeweb
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - '='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 1.3.0
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - '='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 1.3.0
|
158
|
+
description: A Ruby Gem for consuming the Nuance transcription and text to speech
|
159
|
+
REST APIs
|
160
|
+
email: jason@goecke.net
|
161
|
+
executables: []
|
162
|
+
extensions: []
|
163
|
+
extra_rdoc_files:
|
164
|
+
- LICENSE.txt
|
165
|
+
- README.md
|
166
|
+
files:
|
167
|
+
- .DS_Store
|
168
|
+
- .document
|
169
|
+
- .rspec
|
170
|
+
- Gemfile
|
171
|
+
- Gemfile.lock
|
172
|
+
- LICENSE.txt
|
173
|
+
- README.md
|
174
|
+
- Rakefile
|
175
|
+
- VERSION
|
176
|
+
- examples/DT-202c.wav
|
177
|
+
- examples/transcribe.rb
|
178
|
+
- lib/nuance.rb
|
179
|
+
- lib/nuance/dictation-base64.cer
|
180
|
+
- lib/nuance/text_to_speech.rb
|
181
|
+
- lib/nuance/transcription.rb
|
182
|
+
- nuance.gemspec
|
183
|
+
- spec/.DS_Store
|
184
|
+
- spec/DT-202c.wav
|
185
|
+
- spec/nuance-text_to_speech_spec.rb
|
186
|
+
- spec/nuance-transcription_spec.rb
|
187
|
+
- spec/spec_helper.rb
|
188
|
+
homepage: http://github.com/jsgoecke/nuance
|
189
|
+
licenses:
|
190
|
+
- MIT
|
191
|
+
post_install_message:
|
192
|
+
rdoc_options: []
|
193
|
+
require_paths:
|
194
|
+
- lib
|
195
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
196
|
+
none: false
|
197
|
+
requirements:
|
198
|
+
- - ! '>='
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0'
|
201
|
+
segments:
|
202
|
+
- 0
|
203
|
+
hash: 808019071920198107
|
204
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
|
+
none: false
|
206
|
+
requirements:
|
207
|
+
- - ! '>='
|
208
|
+
- !ruby/object:Gem::Version
|
209
|
+
version: '0'
|
210
|
+
requirements: []
|
211
|
+
rubyforge_project:
|
212
|
+
rubygems_version: 1.8.23
|
213
|
+
signing_key:
|
214
|
+
specification_version: 3
|
215
|
+
summary: A Ruby Gem for consuming the Nuance transcription and text to speech REST
|
216
|
+
APIs
|
217
|
+
test_files: []
|