att_speech 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ # script: bundle exec rspec spec
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
1
  source "http://rubygems.org"
2
2
  gem "faraday", ">= 0.8.1"
3
- gem "celluloid", ">= 0.11.1"
4
- gem "hashie", ">=1.2.0"
3
+ gem "celluloid", ">= 0.11.1", "< 0.14.0"
4
+ gem "hashie", ">= 1.2.0"
5
5
  gem "activesupport"
6
6
 
7
7
  group :development do
@@ -0,0 +1,58 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.13)
5
+ i18n (= 0.6.1)
6
+ multi_json (~> 1.0)
7
+ celluloid (0.13.0)
8
+ timers (>= 1.0.0)
9
+ diff-lcs (1.2.4)
10
+ fakeweb (1.3.0)
11
+ faraday (0.8.7)
12
+ multipart-post (~> 1.1)
13
+ git (1.2.5)
14
+ hashie (2.0.4)
15
+ i18n (0.6.1)
16
+ jeweler (1.8.4)
17
+ bundler (~> 1.0)
18
+ git (>= 1.2.5)
19
+ rake
20
+ rdoc
21
+ json (1.7.7)
22
+ json (1.7.7-java)
23
+ multi_json (1.7.3)
24
+ multipart-post (1.2.0)
25
+ rake (10.0.4)
26
+ rdoc (4.0.1)
27
+ json (~> 1.4)
28
+ rspec (2.13.0)
29
+ rspec-core (~> 2.13.0)
30
+ rspec-expectations (~> 2.13.0)
31
+ rspec-mocks (~> 2.13.0)
32
+ rspec-core (2.13.1)
33
+ rspec-expectations (2.13.0)
34
+ diff-lcs (>= 1.1.3, < 2.0)
35
+ rspec-mocks (2.13.1)
36
+ simplecov (0.7.1)
37
+ multi_json (~> 1.0)
38
+ simplecov-html (~> 0.7.1)
39
+ simplecov-html (0.7.1)
40
+ timers (1.1.0)
41
+ yard (0.8.6.1)
42
+
43
+ PLATFORMS
44
+ java
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ activesupport
49
+ bundler (>= 1.0.0)
50
+ celluloid (>= 0.11.1, < 0.14.0)
51
+ fakeweb
52
+ faraday (>= 0.8.1)
53
+ hashie (>= 1.2.0)
54
+ jeweler (>= 1.8.4)
55
+ rdoc (>= 3.12)
56
+ rspec (>= 2.8.0)
57
+ simplecov
58
+ yard (>= 0.7)
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![Build Status](https://secure.travis-ci.org/jsgoecke/att_speech.png)
4
4
 
5
- A Ruby library for consuming the AT&T [Speech API](https://developer.att.com/developer/apiDetailPage.jsp?passedItemId=10700023) for speech to text. API details may be found [here](http://developer.att.com/developer/apiDetailPage.jsp?passedItemId=10900039).
5
+ A Ruby library for consuming the AT&T [Speech API](https://developer.att.com/developer/apiDetailPage.jsp?passedItemId=10700023) for speech to text. API details may be found [here](https://developer.att.com/developer/basicTemplate.jsp?passedItemId=13100102&api=Speech&version=3).
6
6
 
7
7
  ## Installation
8
8
 
@@ -15,8 +15,9 @@ gem install att_speech
15
15
  ```ruby
16
16
  require 'att_speech'
17
17
 
18
- att_speech = ATTSpeech.new({ :api_key => ENV['ATT_SPEECH_KEY'],
19
- :secret_key => ENV['ATT_SPEECH_SECRET'] })
18
+ att_speech = ATTSpeech.new({ :api_key => ENV['ATT_SPEECH_KEY'],
19
+ :secret_key => ENV['ATT_SPEECH_SECRET'],
20
+ :scope => 'SPEECH' }) })
20
21
 
21
22
  # Read the audio file contents
22
23
  file_contents = File.read(File.expand_path(File.dirname(File.dirname(__FILE__))) + "/bostonSeltics.wav")
@@ -30,15 +31,39 @@ future = att_speech.future(:speech_to_text, file_contents, type='audio/wav')
30
31
  p future.value
31
32
 
32
33
  # Non-blocking operation that will call a block when the transcrption is returned
33
- # Note: Remember, this is a concurrent operation so don't pass self and avoid mutable objects in the block
34
- # from the calling context, better to have discreet actions contained in the block, such as inserting in a
34
+ # Note: Remember, this is a concurrent operation so don't pass self and avoid mutable objects in the block
35
+ # from the calling context, better to have discreet actions contained in the block, such as inserting in a
35
36
  # datastore
36
37
  sleep 2
37
38
  att_speech.speech_to_text!(file_contents) { |transcription| p transcription }
38
39
  sleep 5
40
+
41
+
42
+ def write_wav_file(audio_bytes)
43
+ file_name = "ret_audio-#{Time.now.strftime('%Y%m%d-%H%M%S')}.wav"
44
+ full_file_name = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'examples', file_name))
45
+ audio_file = File.open(full_file_name, "w")
46
+ audio_file << audio_bytes
47
+ audio_file.close
48
+ end
49
+
50
+ att_text = ATTSpeech.new({ :api_key => ENV['ATT_SPEECH_KEY'],
51
+ :secret_key => ENV['ATT_SPEECH_SECRET'],
52
+ :scope => 'TTS' })
53
+
54
+ # Read the text file contents
55
+ tfp = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'examples', 'helloWorld.txt'))
56
+ txt_contents = File.read(tfp)
57
+
58
+ audio = att_text.text_to_speech(txt_contents)
59
+ write_wav_file(audio)
60
+
61
+ # Non-blocking operation with a future, if you have a longer file that requires more processing time
62
+ sleep 2
63
+ future = att_text.future(:text_to_speech, "This is a hello world.", type='text/plain')
64
+ write_wav_file(future.value)
39
65
  ```
40
66
 
41
67
  ## Copyright
42
68
 
43
- Copyright (c) 2012 Jason Goecke. See LICENSE.txt for further details.
44
-
69
+ Copyright (c) 2013 Jason Goecke. See LICENSE.txt for further details.
data/Rakefile CHANGED
@@ -17,10 +17,10 @@ Jeweler::Tasks.new do |gem|
17
17
  gem.name = "att_speech"
18
18
  gem.homepage = "http://github.com/jsgoecke/att_speech"
19
19
  gem.license = "MIT"
20
- gem.summary = %Q{TODO: one-line summary of your gem}
21
- gem.description = %Q{TODO: longer description of your gem}
20
+ gem.summary = %Q{A Ruby library for consuming the AT&T Speech API https://developer.att.com/developer/forward.jsp?passedItemId=12500023 for speech->text, and text->speech.}
21
+ gem.description = %Q{A Ruby library for consuming v3 of the AT&T Speech API for speech->text, and text->speech. Takes in either .wav or specific other audio files, and returns a text string of the spoken words. Can also take in either a text string or .txt file and returns a string of bytes from which a .wav file can be created of the spoken text.}
22
22
  gem.email = "jason@goecke.net"
23
- gem.authors = ["Jason Goecke"]
23
+ gem.authors = ["Jason Goecke, Peter Wilson"]
24
24
  # dependencies defined in Gemfile
25
25
  end
26
26
  Jeweler::RubygemsDotOrgTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.4
@@ -0,0 +1,87 @@
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 = "att_speech"
8
+ s.version = "0.0.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jason Goecke, Peter Wilson"]
12
+ s.date = "2013-05-09"
13
+ s.description = "A Ruby library for consuming v3 of the AT&T Speech API for speech->text, and text->speech. Takes in either .wav or specific other audio files, and returns a text string of the spoken words. Can also take in either a text string or .txt file and returns a string of bytes from which a .wav file can be created of the spoken text."
14
+ s.email = "jason@goecke.net"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ ".travis.yml",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "README.md",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "att_speech.gemspec",
30
+ "examples/bostonSeltics.wav",
31
+ "examples/example.rb",
32
+ "examples/helloWorld.txt",
33
+ "lib/att_speech.rb",
34
+ "lib/att_speech/att_speech.rb",
35
+ "lib/att_speech/version.rb",
36
+ "spec/att_speech_spec.rb",
37
+ "spec/spec_helper.rb"
38
+ ]
39
+ s.homepage = "http://github.com/jsgoecke/att_speech"
40
+ s.licenses = ["MIT"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = "1.8.24"
43
+ s.summary = "A Ruby library for consuming the AT&T Speech API https://developer.att.com/developer/forward.jsp?passedItemId=12500023 for speech->text, and text->speech."
44
+
45
+ if s.respond_to? :specification_version then
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<faraday>, [">= 0.8.1"])
50
+ s.add_runtime_dependency(%q<celluloid>, ["< 0.14.0", ">= 0.11.1"])
51
+ s.add_runtime_dependency(%q<hashie>, [">= 1.2.0"])
52
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
53
+ s.add_development_dependency(%q<rspec>, [">= 2.8.0"])
54
+ s.add_development_dependency(%q<yard>, [">= 0.7"])
55
+ s.add_development_dependency(%q<rdoc>, [">= 3.12"])
56
+ s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
57
+ s.add_development_dependency(%q<jeweler>, [">= 1.8.4"])
58
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
59
+ s.add_development_dependency(%q<fakeweb>, [">= 0"])
60
+ else
61
+ s.add_dependency(%q<faraday>, [">= 0.8.1"])
62
+ s.add_dependency(%q<celluloid>, ["< 0.14.0", ">= 0.11.1"])
63
+ s.add_dependency(%q<hashie>, [">= 1.2.0"])
64
+ s.add_dependency(%q<activesupport>, [">= 0"])
65
+ s.add_dependency(%q<rspec>, [">= 2.8.0"])
66
+ s.add_dependency(%q<yard>, [">= 0.7"])
67
+ s.add_dependency(%q<rdoc>, [">= 3.12"])
68
+ s.add_dependency(%q<bundler>, [">= 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, [">= 1.8.4"])
70
+ s.add_dependency(%q<simplecov>, [">= 0"])
71
+ s.add_dependency(%q<fakeweb>, [">= 0"])
72
+ end
73
+ else
74
+ s.add_dependency(%q<faraday>, [">= 0.8.1"])
75
+ s.add_dependency(%q<celluloid>, ["< 0.14.0", ">= 0.11.1"])
76
+ s.add_dependency(%q<hashie>, [">= 1.2.0"])
77
+ s.add_dependency(%q<activesupport>, [">= 0"])
78
+ s.add_dependency(%q<rspec>, [">= 2.8.0"])
79
+ s.add_dependency(%q<yard>, [">= 0.7"])
80
+ s.add_dependency(%q<rdoc>, [">= 3.12"])
81
+ s.add_dependency(%q<bundler>, [">= 1.0.0"])
82
+ s.add_dependency(%q<jeweler>, [">= 1.8.4"])
83
+ s.add_dependency(%q<simplecov>, [">= 0"])
84
+ s.add_dependency(%q<fakeweb>, [">= 0"])
85
+ end
86
+ end
87
+
@@ -0,0 +1,53 @@
1
+ $LOAD_PATH << './lib'
2
+
3
+ lp = File.join(File.dirname(File.dirname(__FILE__)), 'lib', 'att_speech.rb')
4
+ require lp
5
+
6
+ att_speech = ATTSpeech.new({ :api_key => ENV['ATT_SPEECH_KEY'],
7
+ :secret_key => ENV['ATT_SPEECH_SECRET'],
8
+ :scope => 'SPEECH' })
9
+
10
+ # Read the audio file contents
11
+ fp = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'examples', 'bostonSeltics.wav'))
12
+ file_contents = File.read(fp)
13
+
14
+ # Blocking operation
15
+ p att_speech.speech_to_text(file_contents, type='audio/wav')
16
+
17
+ # Non-blocking operation with a future, if you have a longer file that requires more processing time
18
+ sleep 2
19
+ future = att_speech.future(:speech_to_text, file_contents, type='audio/wav')
20
+ p future.value
21
+
22
+ # Non-blocking operation that will call a block when the transcrption is returned
23
+ # Note: Remember, this is a concurrent operation so don't pass self and avoid mutable objects in the block
24
+ # from the calling context, better to have discreet actions contained in the block, such as inserting in a
25
+ # datastore
26
+ sleep 2
27
+ att_speech.speech_to_text!(file_contents) { |transcription| p transcription }
28
+ sleep 5
29
+
30
+
31
+ def write_wav_file(audio_bytes)
32
+ file_name = "ret_audio-#{Time.now.strftime('%Y%m%d-%H%M%S')}.wav"
33
+ full_file_name = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'examples', file_name))
34
+ audio_file = File.open(full_file_name, "w")
35
+ audio_file << audio_bytes
36
+ audio_file.close
37
+ end
38
+
39
+ att_text = ATTSpeech.new({ :api_key => ENV['ATT_SPEECH_KEY'],
40
+ :secret_key => ENV['ATT_SPEECH_SECRET'],
41
+ :scope => 'TTS' })
42
+
43
+ # Read the text file contents
44
+ tfp = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'examples', 'helloWorld.txt'))
45
+ txt_contents = File.read(tfp)
46
+
47
+ audio = att_text.text_to_speech(txt_contents)
48
+ write_wav_file(audio)
49
+
50
+ # Non-blocking operation with a future, if you have a longer file that requires more processing time
51
+ sleep 2
52
+ future = att_text.future(:text_to_speech, "This is a hello world.", type='text/plain')
53
+ write_wav_file(future.value)
@@ -0,0 +1 @@
1
+ Hello World!
@@ -1,157 +1,192 @@
1
1
  class ATTSpeech
2
- include Celluloid
3
- Celluloid.logger = nil
4
-
5
- attr_reader :api_key, :secret_key, :access_token, :refresh_token, :base_url, :ssl_verify
6
-
7
- ##
8
- # Creates an ATTSpeech object
9
- #
10
- # @overload initialize(args)
11
- # @param [Hash] args the options to intantiate with
12
- # @option args [String] :api_key the AT&T Speech API Key
13
- # @option args [String] :secret_key the AT&T Speech API Secret Key
14
- # @option args [String] :base_url the url for the AT&T Speech API, default is 'https://api.att.com'
15
- # @option args [Boolean] :ssl_verify determines if the peer Cert is verified for SSL, default is true
16
- # @overload initialize(api_key, secret_key, base_url='https://api.att.com')
17
- # @param [String] api_key the AT&T Speech API Key
18
- # @param [String] secret_key the AT&T Speech API Secret Key
19
- # @param [String] base_url, the url for the AT&T Speech API, default is 'https://api.att.com'
20
- # @param [Boolean] ssl_verify determines if the peer Cert is verified for SSL, default is true
21
- #
22
- # @return [Object] an instance of ATTSpeech
23
- def initialize(*args)
24
- raise ArgumentError, "Requres at least the api_key and secret_key when instatiating" if args.size == 0
25
-
26
- base_url = 'https://api.att.com'
27
-
28
- if args.size == 1 && args[0].instance_of?(Hash)
29
- @api_key = args[0][:api_key]
30
- @secret_key = args[0][:secret_key]
31
- @base_url = args[0][:base_url] || base_url
32
- set_ssl_verify args[0][:ssl_verify]
33
- else
34
- @api_key = args[0]
35
- @secret_key = args[1]
36
- @base_url = args[2] || base_url
37
- set_ssl_verify args[3]
38
- end
39
-
40
- @grant_type = 'client_credentials'
41
- @scope = 'SPEECH'
42
- @access_token = ''
43
- @refresh_token = ''
44
-
45
- create_connection
46
- get_tokens
47
-
48
- self
49
- end
50
-
51
- ##
52
- # Allows you to send a file and return the speech to text result
53
- # @param [String] file_contents to be processed
54
- # @param [String] type of file to be processed, may be audio/wav, application/octet-stream or audio/amr
55
- # @param [String] speech_context to use to evaluate the audio Generic, UVerseEPG, BusinessSearch, Websearch, SMS, Voicemail, QuestionAndAnswer
56
- # @param [Block] block to be called when the transcription completes
57
- #
58
- # @return [Hash] the resulting response from the AT&T Speech API
59
- def speech_to_text(file_contents, type='audio/wav', speech_context='Generic', &block)
60
- resource = "/rest/1/SpeechToText"
61
-
62
- if type == "application/octet-stream"
63
- type = "audio/amr"
64
- end
65
-
66
- begin
67
- response = @connection.post resource, file_contents,
68
- :Authorization => "Bearer #{@access_token}",
69
- :Content_Transfer_Encoding => 'chunked',
70
- :X_SpeechContext => speech_context,
71
- :Content_Type => type,
72
- :Accept => 'application/json'
73
-
74
- result = process_response(response)
75
- block.call result if block_given?
76
- result
77
- rescue => e
78
- raise RuntimeError, e.to_s
79
- end
80
- end
81
-
82
- private
83
-
84
- ##
85
- # Creates the Faraday connection object
86
- def create_connection
87
- @connection = Faraday.new(:url => @base_url, :ssl => { :verify => @ssl_verify }) do |faraday|
88
- faraday.headers['Accept'] = 'application/json'
89
- faraday.adapter Faraday.default_adapter
90
- end
91
- end
92
-
93
- ##
94
- # Obtains the session tokens
95
- def get_tokens
96
- resource = "/oauth/access_token"
97
-
98
- begin
99
- response = @connection.post resource do |request|
100
- request.params['client_id'] = @api_key
101
- request.params['client_secret'] = @secret_key
102
- request.params['grant_type'] = @grant_type
103
- request.params['scope'] = @scope
104
- end
105
-
106
- result = process_response(response)
107
-
108
- if result[:access_token].nil? || result[:refresh_token].nil?
109
- raise RuntimeError, "Unable to complete oauth: #{response[:error]}"
110
- else
111
- @access_token = result[:access_token]
112
- @refresh_token = result[:refresh_token]
113
- end
114
- rescue => e
115
- raise RuntimeError, e.to_s
116
- end
117
- end
118
-
119
- ##
120
- # Process the JSON returned into a Hashie::Mash and making it more Ruby friendly
121
- #
122
- # @param [String] reponse json
123
- #
124
- # @return [Object] a Hashie::Mash object
125
- def process_response(response)
126
- Hashie::Mash.new(underscore_hash(JSON.parse(response.body)))
127
- end
128
-
129
- ##
130
- # Sets the ssl_verify option
131
- #
132
- # @param [Boolean] ssl_verify the variable to set
133
- def set_ssl_verify(ssl_verify)
134
- if ssl_verify == false
135
- @ssl_verify = false
136
- else
137
- @ssl_verify = true
138
- end
139
- end
140
-
141
- ##
142
- # Decamelizes the keys in a hash to be more Ruby friendly
143
- #
144
- # @param [Hash] hash to be decamelized
145
- #
146
- # @return [Hash] the hash with the keys decamalized
147
- def underscore_hash(hash)
148
- hash.inject({}) do |underscored, (key, value)|
149
- value = underscore_hash(value) if value.is_a?(Hash)
150
- if value.is_a?(Array)
151
- value = underscore_hash(value[0]) if value[0].is_a?(Hash)
152
- end
153
- underscored[key.underscore] = value
154
- underscored
155
- end
156
- end
157
- end
2
+ include Celluloid
3
+ Celluloid.logger = nil
4
+
5
+ attr_reader :api_key, :secret_key, :access_token, :refresh_token, :base_url, :ssl_verify, :scope
6
+
7
+ ##
8
+ # Creates an ATTSpeech object
9
+ #
10
+ # @overload initialize(args)
11
+ # @param [Hash] args the options to intantiate with
12
+ # @option args [String] :api_key the AT&T Speech API Key
13
+ # @option args [String] :secret_key the AT&T Speech API Secret Key
14
+ # @option args [String] :scope the Authorization Scope for the AT&T Speech API
15
+ # @option args [String] :base_url the url for the AT&T Speech API, default is 'https://api.att.com'
16
+ # @option args [Boolean] :ssl_verify determines if the peer Cert is verified for SSL, default is true
17
+ # @overload initialize(api_key, secret_key, base_url='https://api.att.com')
18
+ # @param [String] api_key the AT&T Speech API Key
19
+ # @param [String] secret_key the AT&T Speech API Secret Key
20
+ # @param [String] scope the Authorization Scope for the AT&T Speech API
21
+ # @param [String] base_url the url for the AT&T Speech API, default is 'https://api.att.com'
22
+ # @param [Boolean] ssl_verify determines if the peer Cert is verified for SSL, default is true
23
+ #
24
+ # @return [Object] an instance of ATTSpeech
25
+ def initialize(*args)
26
+ raise ArgumentError, "Requires at least the api_key, secret_key, and scope when instatiating" if args.size == 0
27
+
28
+ base_url = 'https://api.att.com'
29
+
30
+ if args.size == 1 && args[0].instance_of?(Hash)
31
+ @api_key = args[0][:api_key]
32
+ @secret_key = args[0][:secret_key]
33
+ @scope = args[0][:scope]
34
+ @base_url = args[0][:base_url] || base_url
35
+ set_ssl_verify args[0][:ssl_verify]
36
+ else
37
+ @api_key = args[0]
38
+ @secret_key = args[1]
39
+ @scope = args[2]
40
+ @base_url = args[3] || base_url
41
+ set_ssl_verify args[4]
42
+ end
43
+
44
+ raise ArgumentError, "scope must be either 'SPEECH' or 'TTS'" unless (@scope == 'SPEECH') || (@scope == 'TTS')
45
+
46
+ @grant_type = 'client_credentials'
47
+ @access_token = ''
48
+ @refresh_token = ''
49
+
50
+ if @scope == 'SPEECH'
51
+ create_connection 'application/json'
52
+ else
53
+ create_connection 'audio/x-wav'
54
+ end
55
+
56
+ get_tokens
57
+
58
+ Actor.current
59
+ end
60
+
61
+ ##
62
+ # Allows you to send a file and return the speech to text result
63
+ # @param [String] file_contents to be processed
64
+ # @param [String] type of file to be processed, may be audio/wav, application/octet-stream or audio/amr
65
+ # @param [String] speech_context to use to evaluate the audio BusinessSearch, Gaming, Generic, QuestionAndAnswer, SMS, SocialMedia, TV, VoiceMail, WebSearch
66
+ # @param [Block] block to be called when the transcription completes
67
+ #
68
+ # @return [Hash] the resulting response from the AT&T Speech API
69
+ def speech_to_text(file_contents, type='audio/wav', speech_context='Generic', &block)
70
+ resource = "/speech/v3/speechToText"
71
+
72
+ if type == "application/octet-stream"
73
+ type = "audio/amr"
74
+ end
75
+
76
+ begin
77
+ response = @connection.post( resource,
78
+ file_contents,
79
+ :Authorization => "Bearer #{@access_token}",
80
+ :Content_Transfer_Encoding => 'chunked',
81
+ :X_SpeechContext => speech_context,
82
+ :Content_Type => type,
83
+ :Accept => 'application/json' )
84
+
85
+ result = process_response(response)
86
+ block.call result if block_given?
87
+ result
88
+ rescue => e
89
+ raise RuntimeError, e.to_s
90
+ end
91
+ end
92
+
93
+
94
+ ##
95
+ # Allows you to send a string or plain text file and return the text to speech result
96
+ # @param [String] string or file_contents to be processed
97
+ # @param [String] type of file or object to be processed, may be text/plain, or application/ssml+xml
98
+ #
99
+ # @return [String] the bytes of the resulting response from the AT&T Speech API
100
+ def text_to_speech(file_contents, type='text/plain')
101
+ resource = "/speech/v3/textToSpeech"
102
+
103
+ begin
104
+ response = @connection.post( resource,
105
+ file_contents,
106
+ :Authorization => "Bearer #{@access_token}",
107
+ :Content_Type => type,
108
+ :Accept => 'audio/x-wav' )
109
+
110
+ response.body
111
+ rescue => e
112
+ raise RuntimeError, e.to_s
113
+ end
114
+ end
115
+
116
+
117
+ private
118
+
119
+ ##
120
+ # Creates the Faraday connection object
121
+ def create_connection(accept_type='application/json')
122
+ @connection = Faraday.new(:url => @base_url, :ssl => { :verify => @ssl_verify }) do |faraday|
123
+ faraday.headers['Accept'] = accept_type
124
+ faraday.adapter Faraday.default_adapter
125
+ end
126
+ end
127
+
128
+ ##
129
+ # Obtains the session tokens
130
+ def get_tokens
131
+ resource = "/oauth/access_token"
132
+
133
+ begin
134
+ response = @connection.post resource do |request|
135
+ request.params['client_id'] = @api_key
136
+ request.params['client_secret'] = @secret_key
137
+ request.params['grant_type'] = @grant_type
138
+ request.params['scope'] = @scope
139
+ end
140
+
141
+ result = process_response(response)
142
+
143
+ if result[:access_token].nil? || result[:refresh_token].nil?
144
+ raise RuntimeError, "Unable to complete oauth: #{response[:error]}"
145
+ else
146
+ @access_token = result[:access_token]
147
+ @refresh_token = result[:refresh_token]
148
+ end
149
+ rescue => e
150
+ raise RuntimeError, e.to_s
151
+ end
152
+ end
153
+
154
+ ##
155
+ # Process the JSON returned into a Hashie::Mash and making it more Ruby friendly
156
+ #
157
+ # @param [String] reponse json
158
+ #
159
+ # @return [Object] a Hashie::Mash object
160
+ def process_response(response)
161
+ Hashie::Mash.new(underscore_hash(JSON.parse(response.body)))
162
+ end
163
+
164
+ ##
165
+ # Sets the ssl_verify option
166
+ #
167
+ # @param [Boolean] ssl_verify the variable to set
168
+ def set_ssl_verify(ssl_verify)
169
+ if ssl_verify == false
170
+ @ssl_verify = false
171
+ else
172
+ @ssl_verify = true
173
+ end
174
+ end
175
+
176
+ ##
177
+ # Decamelizes the keys in a hash to be more Ruby friendly
178
+ #
179
+ # @param [Hash] hash to be decamelized
180
+ #
181
+ # @return [Hash] the hash with the keys decamalized
182
+ def underscore_hash(hash)
183
+ hash.inject({}) do |underscored, (key, value)|
184
+ value = underscore_hash(value) if value.is_a?(Hash)
185
+ if value.is_a?(Array)
186
+ value = underscore_hash(value[0]) if value[0].is_a?(Hash)
187
+ end
188
+ underscored[key.underscore] = value
189
+ underscored
190
+ end
191
+ end
192
+ end
@@ -1,3 +1,3 @@
1
1
  class ATTSpeech
2
- VERSION = "0.0.3"
3
- end
2
+ VERSION = "0.0.4"
3
+ end
@@ -2,106 +2,125 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "AttSpeech" do
4
4
  FakeWeb.allow_net_connect = false
5
-
6
- FakeWeb.register_uri(:post,
7
- "https://api.att.com/oauth/access_token?client_id=1234&client_secret=abcd&grant_type=client_credentials&scope=SPEECH",
8
- :status => ['200', 'OK'],
5
+
6
+ FakeWeb.register_uri(:post,
7
+ "https://api.att.com/oauth/access_token?client_id=1234&client_secret=abcd&grant_type=client_credentials&scope=SPEECH",
8
+ :status => ['200', 'OK'],
9
9
  :body => '{"access_token":"5678","refresh_token":"wxyz"}')
10
-
11
- FakeWeb.register_uri(:post,
12
- "http://foobar.com/oauth/access_token?client_id=1234&client_secret=abcd&grant_type=client_credentials&scope=SPEECH",
13
- :status => ['200', 'OK'],
10
+
11
+ FakeWeb.register_uri(:post,
12
+ "http://foobar.com/oauth/access_token?client_id=1234&client_secret=abcd&grant_type=client_credentials&scope=SPEECH",
13
+ :status => ['200', 'OK'],
14
14
  :body => '{"access_token":"5678","refresh_token":"wxyz"}')
15
-
16
- FakeWeb.register_uri(:post,
17
- "https://api.att.com/rest/1/SpeechToText",
18
- :status => ['200', 'OK'],
15
+
16
+ FakeWeb.register_uri(:post,
17
+ "https://api.att.com/speech/v3/speechToText",
18
+ :status => ['200', 'OK'],
19
19
  :body => "{\"Recognition\":{\"ResponseId\":\"2b0bdcf4301f5c4aba57e2765b59bcbe\",\"NBest\":[{\"WordScores\":[1,1],\"Confidence\":1,\"Grade\":\"accept\",\"ResultText\":\"Boston celtics.\",\"Words\":[\"Boston\",\"celtics.\"],\"LanguageId\":\"en-us\",\"Hypothesis\":\"Boston celtics.\"}]}}")
20
-
21
- let(:att_speech) { att_speech = ATTSpeech.new '1234', 'abcd' }
20
+
21
+ let(:att_speech) { att_speech = ATTSpeech.new('1234', 'abcd', 'SPEECH') }
22
22
  let(:att_speech_hash) { att_speech = ATTSpeech.new({ :api_key => '1234',
23
- :secret_key => 'abcd' })}
24
-
23
+ :secret_key => 'abcd',
24
+ :scope => 'SPEECH' })}
25
+
26
+
25
27
  describe 'initializing' do
26
28
  it "should raise an error of no parameters passed when creating object" do
27
29
  begin
28
30
  ATTSpeech.new
29
31
  rescue => e
30
- e.to_s.should eql "Requres at least the api_key and secret_key when instatiating"
32
+ e.to_s.should eql "Requires at least the api_key, secret_key, and scope when instatiating"
33
+ end
34
+ end
35
+
36
+ it "shoud raise an error of wrong scope when creating object without scope" do
37
+ begin
38
+ ATTSpeech.new('1234', 'abcd')
39
+ rescue => e
40
+ e.to_s.should eql "scope must be either 'SPEECH' or 'TTS'"
41
+ end
42
+ end
43
+
44
+ it "shoud raise an error of wrong scope when creating object with misspelled scope" do
45
+ begin
46
+ ATTSpeech.new('1234', 'abcd', 'misspelled scope')
47
+ rescue => e
48
+ e.to_s.should eql "scope must be either 'SPEECH' or 'TTS'"
31
49
  end
32
50
  end
33
-
51
+
34
52
  it "should create an ATTSpeech object" do
35
53
  att_speech.class.should eql ATTSpeech
36
54
  att_speech_hash.class.should eql ATTSpeech
37
55
  end
38
-
56
+
39
57
  it 'should set the url to something different' do
40
- as = ATTSpeech.new('1234', 'abcd', 'http://foobar.com', false)
58
+ as = ATTSpeech.new('1234', 'abcd', 'SPEECH', 'http://foobar.com', false)
41
59
  as.base_url.should == 'http://foobar.com'
42
60
  as.ssl_verify.should == false
43
-
61
+
44
62
  as = ATTSpeech.new({ :api_key => '1234',
45
63
  :secret_key => 'abcd',
64
+ :scope => 'SPEECH',
46
65
  :base_url => 'http://foobar.com',
47
66
  :ssl_verify => false })
48
67
  as.base_url.should == 'http://foobar.com'
49
68
  as.ssl_verify.should == false
50
69
  end
51
-
70
+
52
71
  it "should set the access_token and refresh_token" do
53
72
  att_speech.access_token.should eql '5678'
54
73
  att_speech.refresh_token.should eql 'wxyz'
55
74
  att_speech.base_url.should == 'https://api.att.com'
56
75
  att_speech.ssl_verify.should == true
57
-
76
+
58
77
  att_speech_hash.access_token.should eql '5678'
59
78
  att_speech_hash.refresh_token.should eql 'wxyz'
60
79
  att_speech_hash.base_url.should == 'https://api.att.com'
61
80
  att_speech_hash.ssl_verify.should == true
62
81
  end
63
82
  end
64
-
83
+
65
84
  describe 'blocking call' do
66
85
  it "should return a Hashie::Mash object when processing an audio file" do
67
86
  result = att_speech.speech_to_text 'spec/spec_helper.rb'
68
87
  result.instance_of?(Hashie::Mash).should eql true
69
-
88
+
70
89
  result = att_speech_hash.speech_to_text 'spec/spec_helper.rb'
71
90
  result.instance_of?(Hashie::Mash).should eql true
72
91
  end
73
-
92
+
74
93
  it "should attempt to process an audio file" do
75
94
  result = att_speech.speech_to_text 'spec/spec_helper.rb'
76
95
  result[:recognition][:response_id].should eql '2b0bdcf4301f5c4aba57e2765b59bcbe'
77
96
  result[:recognition][:n_best][:confidence].should eql 1
78
-
97
+
79
98
  result = att_speech_hash.speech_to_text 'spec/spec_helper.rb'
80
99
  result[:recognition][:response_id].should eql '2b0bdcf4301f5c4aba57e2765b59bcbe'
81
100
  result[:recognition][:n_best][:confidence].should eql 1
82
101
  end
83
102
  end
84
-
103
+
85
104
  describe 'non-blocking call' do
86
105
  it "should return a Celluloid::Future object when processing an audio file" do
87
106
  future = att_speech.future(:speech_to_text, 'spec/spec_helper.rb')
88
107
  future.instance_of?(Celluloid::Future).should eql true
89
-
108
+
90
109
  future = att_speech_hash.future(:speech_to_text, 'spec/spec_helper.rb')
91
110
  future.instance_of?(Celluloid::Future).should eql true
92
111
  end
93
-
112
+
94
113
  it "should allow us to use a future to process an audio file" do
95
114
  future = att_speech.future(:speech_to_text, 'spec/spec_helper.rb')
96
115
  future.value[:recognition][:response_id].should eql '2b0bdcf4301f5c4aba57e2765b59bcbe'
97
116
  future.value[:recognition][:n_best][:confidence].should eql 1
98
-
117
+
99
118
  future = att_speech_hash.future(:speech_to_text, 'spec/spec_helper.rb')
100
119
  future.value[:recognition][:response_id].should eql '2b0bdcf4301f5c4aba57e2765b59bcbe'
101
120
  future.value[:recognition][:n_best][:confidence].should eql 1
102
121
  end
103
122
  end
104
-
123
+
105
124
  describe 'non-blocking call with a block' do
106
125
  it "should allow us to use a future to process an audio file and pass a block" do
107
126
  result = nil
@@ -109,7 +128,7 @@ describe "AttSpeech" do
109
128
  sleep 0.5
110
129
  result[:recognition][:response_id].should eql '2b0bdcf4301f5c4aba57e2765b59bcbe'
111
130
  result[:recognition][:n_best][:confidence].should eql 1
112
-
131
+
113
132
  result = nil
114
133
  att_speech_hash.speech_to_text!('spec/spec_helper.rb') { |transcription| result = transcription }
115
134
  sleep 0.5
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: att_speech
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
- - Jason Goecke
8
+ - Jason Goecke, Peter Wilson
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-15 00:00:00.000000000 Z
12
+ date: 2013-05-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -32,6 +32,9 @@ dependencies:
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
+ - - <
36
+ - !ruby/object:Gem::Version
37
+ version: 0.14.0
35
38
  - - ! '>='
36
39
  - !ruby/object:Gem::Version
37
40
  version: 0.11.1
@@ -40,6 +43,9 @@ dependencies:
40
43
  version_requirements: !ruby/object:Gem::Requirement
41
44
  none: false
42
45
  requirements:
46
+ - - <
47
+ - !ruby/object:Gem::Version
48
+ version: 0.14.0
43
49
  - - ! '>='
44
50
  - !ruby/object:Gem::Version
45
51
  version: 0.11.1
@@ -187,7 +193,11 @@ dependencies:
187
193
  - - ! '>='
188
194
  - !ruby/object:Gem::Version
189
195
  version: '0'
190
- description: A Ruby library for consuming the AT&T Speech API for speech to text.
196
+ description: A Ruby library for consuming v3 of the AT&T Speech API for speech->text,
197
+ and text->speech. Takes in either .wav or specific other audio files, and returns
198
+ a text string of the spoken words. Can also take in either a text string or .txt
199
+ file and returns a string of bytes from which a .wav file can be created of the
200
+ spoken text.
191
201
  email: jason@goecke.net
192
202
  executables: []
193
203
  extensions: []
@@ -197,16 +207,22 @@ extra_rdoc_files:
197
207
  files:
198
208
  - .document
199
209
  - .rspec
210
+ - .travis.yml
200
211
  - Gemfile
212
+ - Gemfile.lock
201
213
  - LICENSE.txt
214
+ - README.md
202
215
  - Rakefile
203
216
  - VERSION
217
+ - att_speech.gemspec
218
+ - examples/bostonSeltics.wav
219
+ - examples/example.rb
220
+ - examples/helloWorld.txt
204
221
  - lib/att_speech.rb
205
- - lib/att_speech/version.rb
206
222
  - lib/att_speech/att_speech.rb
223
+ - lib/att_speech/version.rb
207
224
  - spec/att_speech_spec.rb
208
225
  - spec/spec_helper.rb
209
- - README.md
210
226
  homepage: http://github.com/jsgoecke/att_speech
211
227
  licenses:
212
228
  - MIT
@@ -228,10 +244,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
228
244
  version: '0'
229
245
  requirements: []
230
246
  rubyforge_project:
231
- rubygems_version: 1.8.24
247
+ rubygems_version: 1.8.25
232
248
  signing_key:
233
249
  specification_version: 3
234
- summary: A Ruby library for consuming the AT&T Speech API https://developer.att.com/developer/apiDetailPage.jsp?passedItemId=10700023
235
- for speech to text.
250
+ summary: A Ruby library for consuming the AT&T Speech API https://developer.att.com/developer/forward.jsp?passedItemId=12500023
251
+ for speech->text, and text->speech.
236
252
  test_files: []
237
- has_rdoc: