vocalware 0.0.1
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 +7 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +67 -0
- data/data/voices.csv +83 -0
- data/lib/vocalware.rb +24 -0
- data/lib/vocalware/client.rb +158 -0
- data/lib/vocalware/errors.rb +40 -0
- data/lib/vocalware/languages.rb +73 -0
- data/lib/vocalware/request.rb +88 -0
- data/lib/vocalware/voice.rb +94 -0
- metadata +156 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4a00fc81a9d6dde4488d2b51d17bf9ebd35d0132
|
4
|
+
data.tar.gz: 8b930de1d5e591a8516a12720d714532571a0c93
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 99f87cc818f7c778673254b66abe5b562c98ec9a9dea8c638331c038b21d236466399638097abe8cb91d2e382765b3f7da12b09b443f31844ba9dead1ceacf0a
|
7
|
+
data.tar.gz: 786b3fcea77f7464a61513fa3daa9071d1a4298bd885e44798a1c846c8213601faf79e5e31cf66e588a60d0e7f8befe0fa483f464cbf6a5cd9b84eb190a5cda8
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 TMX Credit, author Sergey Potapov
|
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.markdown
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Vocalware
|
2
|
+
|
3
|
+
[](https://travis-ci.org/TMXCredit/vocalware)
|
4
|
+
|
5
|
+
Ruby client for the [Vocalware](https://www.vocalware.com/) REST API.
|
6
|
+
|
7
|
+
## Install
|
8
|
+
|
9
|
+
Add vocalware to your Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'vocalware'
|
13
|
+
```
|
14
|
+
|
15
|
+
Run `bundle install`.
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
Lookup a voice by its attributes:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
voice = Vocalware::Voice.find(:lang => :en, :name => 'Kate')
|
23
|
+
```
|
24
|
+
As attributes you can also use `engine_id`, `lang_id`, `voice_id`, `gender`.
|
25
|
+
|
26
|
+
Initialize a client:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
client = Vocalware::Client.new(
|
30
|
+
:secret_phrase => SECRET_PHRASE,
|
31
|
+
:api_id => API_ID,
|
32
|
+
:account_id => ACCOUNT_ID,
|
33
|
+
:voice => voice
|
34
|
+
)
|
35
|
+
```
|
36
|
+
|
37
|
+
Generate speech from text:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
audio_data = client.gen('Say hello on a night like this!')
|
41
|
+
File.binwrite('./cure.mp3', audio_data)
|
42
|
+
```
|
43
|
+
|
44
|
+
### Override attributes for a single request
|
45
|
+
|
46
|
+
If you need to say few words in Spanish, you can override the `:voice`
|
47
|
+
attribute for one single request:
|
48
|
+
|
49
|
+
```
|
50
|
+
voice = Vocalware::Vocalware.find(:lang => :es, :name => 'Juan')
|
51
|
+
client.gen('Hola! Qué tal estás?', :voice => voice)
|
52
|
+
```
|
53
|
+
|
54
|
+
## Running tests
|
55
|
+
|
56
|
+
```sh
|
57
|
+
rake spec
|
58
|
+
```
|
59
|
+
|
60
|
+
|
61
|
+
## Credits
|
62
|
+
|
63
|
+
* [Sergey Potapov](https://github.com/greyblake)
|
64
|
+
|
65
|
+
## Copyright
|
66
|
+
|
67
|
+
Copyright (c) 2013 TMX Credit. See LICENSE.txt for further details.
|
data/data/voices.csv
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
engine_id , lang , name , voice_id , gender , description
|
2
|
+
2 , en , Susan , 1 , F , US
|
3
|
+
2 , en , Dave , 2 , M , US
|
4
|
+
2 , en , Elizabeth , 4 , F , UK
|
5
|
+
2 , en , Simon , 5 , M , UK
|
6
|
+
2 , en , Catherine , 6 , F , UK
|
7
|
+
2 , en , Allison , 7 , F , US
|
8
|
+
2 , en , Steven , 8 , M , US
|
9
|
+
2 , en , Alan , 9 , M , Australian
|
10
|
+
2 , en , Grace , 10 , F , Australian
|
11
|
+
2 , en , Veena , 11 , F , Indian
|
12
|
+
2 , es , Carmen , 1 , F , Castilian
|
13
|
+
2 , es , Juan , 2 , M , Castilian
|
14
|
+
2 , es , Francisca , 3 , F , Chilean
|
15
|
+
2 , es , Diego , 4 , M , Argentine
|
16
|
+
2 , es , Esperanza , 5 , F , Mexican
|
17
|
+
2 , es , Jorge , 6 , M , Castilian
|
18
|
+
2 , es , Carlos , 7 , M , American
|
19
|
+
2 , es , Soledad , 8 , F , American
|
20
|
+
2 , es , Leonor , 9 , F , Castilian
|
21
|
+
2 , es , Ximena , 10 , F , American
|
22
|
+
2 , de , Stefan , 2 , M
|
23
|
+
2 , de , Katrin , 3 , F
|
24
|
+
2 , fr , Bernard , 2 , M , European
|
25
|
+
2 , fr , Jolie , 3 , F , European
|
26
|
+
2 , fr , Florence , 4 , F , European
|
27
|
+
2 , fr , Charlotte , 5 , F , Canadian
|
28
|
+
2 , fr , Olivier , 6 , M , Canadian
|
29
|
+
2 , ca , Montserrat , 1 , F
|
30
|
+
2 , ca , Jordi , 2 , M
|
31
|
+
2 , ca , Empar , 3 , F , Valencian
|
32
|
+
2 , pt , Gabriela , 1 , F , Brasilian
|
33
|
+
2 , pt , Amalia , 2 , F , European
|
34
|
+
2 , pt , Eusebio , 3 , M , European
|
35
|
+
2 , pt , Fernanda , 4 , F , Brazilian
|
36
|
+
2 , pt , Felipe , 5 , M , Brazilian
|
37
|
+
2 , it , Paola , 1 , F
|
38
|
+
2 , it , Silvana , 2 , F
|
39
|
+
2 , it , Valentia , 3 , F
|
40
|
+
2 , it , Luca , 5 , M
|
41
|
+
2 , it , Marcello , 6 , M
|
42
|
+
2 , it , Roberto , 7 , M
|
43
|
+
2 , it , Matteo , 8 , M
|
44
|
+
2 , it , Giulia , 9 , F
|
45
|
+
2 , it , Federica , 10 , F
|
46
|
+
2 , el , Afroditi , 1 , F
|
47
|
+
2 , el , Nikos , 3 , M
|
48
|
+
2 , sv , Annika , 1 , F
|
49
|
+
2 , sv , Sven , 2 , M
|
50
|
+
2 , zh , Linlin , 1 , F , Mandarin
|
51
|
+
2 , zh , Lisheng , 2 , F , Mandarin
|
52
|
+
2 , nl , Willem , 1 , M
|
53
|
+
2 , nl , Saskia , 2 , F
|
54
|
+
2 , pl , Zosia , 1 , F
|
55
|
+
2 , pl , Krzysztof , 2 , M
|
56
|
+
2 , gl , Carmela , 1 , F
|
57
|
+
2 , tr , Kerem , 1 , M
|
58
|
+
2 , tr , Zeynep , 2 , F
|
59
|
+
2 , tr , Selin , 3 , F
|
60
|
+
2 , da , Frida , 1 , F
|
61
|
+
2 , da , Magnus , 2 , M
|
62
|
+
2 , no , Vilde , 1 , F
|
63
|
+
2 , no , Henrik , 2 , M
|
64
|
+
2 , ru , Olga , 1 , F
|
65
|
+
2 , ru , Dmitri , 2 , M
|
66
|
+
2 , fi , Milla , 1 , F
|
67
|
+
2 , fi , Marko , 2 , M
|
68
|
+
2 , ar , Tarik , 1 , M
|
69
|
+
2 , ar , Laila , 2 , F
|
70
|
+
2 , ro , Ioana , 1 , F
|
71
|
+
2 , eo , Ludoviko , 1 , M
|
72
|
+
3 , en , Kate , 1 , F , US
|
73
|
+
3 , en , Paul , 2 , M , US
|
74
|
+
3 , en , Julie , 3 , F , US
|
75
|
+
3 , en , Bridget , 4 , F , UK
|
76
|
+
3 , es , Violeta , 1 , F
|
77
|
+
3 , zh , Lily , 1 , F , Mandarin
|
78
|
+
3 , zh , Hui , 3 , F , Mandarin
|
79
|
+
3 , zh , Liang , 4 , M , Mandarin
|
80
|
+
3 , ja , Show , 2 , M
|
81
|
+
3 , ja , Misaki , 3 , F
|
82
|
+
3 , ko , Yumi , 1 , F
|
83
|
+
3 , ko , Junwoo , 2 , M
|
data/lib/vocalware.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Standard library
|
2
|
+
require 'csv'
|
3
|
+
require 'digest'
|
4
|
+
require 'cgi'
|
5
|
+
|
6
|
+
# Gems
|
7
|
+
require 'faraday'
|
8
|
+
|
9
|
+
# Vocalware
|
10
|
+
require 'vocalware/errors'
|
11
|
+
require 'vocalware/client'
|
12
|
+
require 'vocalware/languages'
|
13
|
+
require 'vocalware/voice'
|
14
|
+
require 'vocalware/request'
|
15
|
+
|
16
|
+
|
17
|
+
# Client for Vocalware REST API.
|
18
|
+
module Vocalware
|
19
|
+
# Path to directory with data.
|
20
|
+
DATA_PATH = File.expand_path('../../data', __FILE__)
|
21
|
+
|
22
|
+
# Path to CSV file with voices information.
|
23
|
+
VOICES_CSV_FILE = File.join(DATA_PATH, 'voices.csv')
|
24
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Vocalware
|
2
|
+
# Vocalware client, which uses Vocalware's REST API to generate speech.
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# # Look up voice
|
6
|
+
# voice = Vocalware::Voice.find(:lang => :en, :name => 'Kate')
|
7
|
+
#
|
8
|
+
# # Initialize client
|
9
|
+
# client =
|
10
|
+
# Vocalware::Client.new(
|
11
|
+
# :secret_phrase => SECRET_PHRASE,
|
12
|
+
# :api_id => API_ID,
|
13
|
+
# :account_id => ACCOUNT_ID,
|
14
|
+
# :voice => voice
|
15
|
+
# )
|
16
|
+
#
|
17
|
+
# # Generate mp3
|
18
|
+
# client.gen("I love ruby!") # => mp3 audio as binary string
|
19
|
+
class Client
|
20
|
+
# @attribute account_id [Integer, String] account id (ACC)
|
21
|
+
attr_accessor :account_id
|
22
|
+
|
23
|
+
# @attribute api_id [Integer, String] API id (API)
|
24
|
+
attr_accessor :api_id
|
25
|
+
|
26
|
+
# @attribute secret_phrase [String] secret phrase
|
27
|
+
attr_accessor :secret_phrase
|
28
|
+
|
29
|
+
# @attribute voice [Vocalware::Voice] voice
|
30
|
+
attr_accessor :voice
|
31
|
+
|
32
|
+
# @attribute ext [String] whether "mp3" or "swf"
|
33
|
+
attr_accessor :ext
|
34
|
+
|
35
|
+
# @attribute host [String] host to which request will be set
|
36
|
+
attr_accessor :host
|
37
|
+
|
38
|
+
# @attribute path [String] path as part of URL to send request
|
39
|
+
attr_accessor :path
|
40
|
+
|
41
|
+
# @attribute protocol [String] whether "http" or "https"
|
42
|
+
attr_accessor :protocol
|
43
|
+
|
44
|
+
# @attribute port [Integer]
|
45
|
+
attr_accessor :port
|
46
|
+
|
47
|
+
# @attribute http_client [Faraday::Connection]
|
48
|
+
attr_accessor :http_client
|
49
|
+
|
50
|
+
|
51
|
+
# Default attributes
|
52
|
+
DEFAULT_ATTRS = {
|
53
|
+
:protocol => 'http',
|
54
|
+
:host => 'www.vocalware.com',
|
55
|
+
:path => '/tts/gen.php',
|
56
|
+
:ext => 'mp3'
|
57
|
+
}
|
58
|
+
|
59
|
+
# @param attrs [Hash<Symbol, Object>] client attributes
|
60
|
+
def initialize(attrs = {})
|
61
|
+
DEFAULT_ATTRS.merge(attrs).each do |attr_name, value|
|
62
|
+
send("#{attr_name}=", value)
|
63
|
+
end
|
64
|
+
|
65
|
+
@http_client ||= Faraday.new
|
66
|
+
validate!
|
67
|
+
end
|
68
|
+
|
69
|
+
# Generate speech from passed text.
|
70
|
+
#
|
71
|
+
# @param text [String] text to generate speech
|
72
|
+
# @param opts [Hash<Symbol, Object>] options which override client
|
73
|
+
# attributes for one particular request.
|
74
|
+
#
|
75
|
+
# @return [String] audio data in format defined by +:ext+ attribute
|
76
|
+
def gen(text, opts = {})
|
77
|
+
url = build_url(text, opts)
|
78
|
+
send_request(url)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Build URL where request will be sent.
|
82
|
+
#
|
83
|
+
# @param text [String] text to generate speech
|
84
|
+
# @param opts [Hash<Symbol, Object>] options which override client
|
85
|
+
# attributes
|
86
|
+
#
|
87
|
+
# @return [String] url
|
88
|
+
def build_url(text, opts = {})
|
89
|
+
attrs = to_hash.merge(opts)
|
90
|
+
attrs[:text] = text.strip
|
91
|
+
Request.new(attrs).to_url
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Issue request to the remote service using HTTP client.
|
96
|
+
# Handle potential errors and raise {Vocalware::RequestError} with
|
97
|
+
# request information.
|
98
|
+
#
|
99
|
+
# @param url [String] end point with encoded GET parameters to send request
|
100
|
+
#
|
101
|
+
# @return [String] audio data
|
102
|
+
def send_request(url)
|
103
|
+
response = @http_client.get(url)
|
104
|
+
|
105
|
+
# If response has other status than success
|
106
|
+
unless response.status.between?(200, 299)
|
107
|
+
raise RequestError.from_url_and_response(
|
108
|
+
url, response, "Unexpected response status"
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
response_body = response.body
|
113
|
+
|
114
|
+
# In case of an error, Vocalware still returns a 200 HTTP status,
|
115
|
+
# but with an error message in the response body, instead of audio data.
|
116
|
+
case response.headers['Content-Type']
|
117
|
+
when 'audio/mpeg', 'application/x-shockwave-flash'
|
118
|
+
return response_body
|
119
|
+
else
|
120
|
+
raise RequestError.from_url(url, response_body)
|
121
|
+
end
|
122
|
+
rescue Faraday::Error::ConnectionFailed => err
|
123
|
+
raise RequestError.from_url(url, err.message)
|
124
|
+
end
|
125
|
+
private :send_request
|
126
|
+
|
127
|
+
# Ensure all required attributes are present.
|
128
|
+
#
|
129
|
+
# @return [void]
|
130
|
+
def validate!
|
131
|
+
raise(Error, 'secret_phrase is missing') unless secret_phrase
|
132
|
+
raise(Error, 'api_id is missing') unless api_id
|
133
|
+
raise(Error, 'account_id is missing') unless account_id
|
134
|
+
raise(Error, 'voice is missing') unless voice
|
135
|
+
|
136
|
+
raise(Error,
|
137
|
+
'voice must be a Vocalware::Voice'
|
138
|
+
) unless voice.is_a?(Voice)
|
139
|
+
end
|
140
|
+
private :validate!
|
141
|
+
|
142
|
+
# Represent all client attributes as a hash.
|
143
|
+
#
|
144
|
+
# @return [Hash<Symbol, Object>]
|
145
|
+
def to_hash
|
146
|
+
{ :host => host,
|
147
|
+
:path => path,
|
148
|
+
:protocol => protocol,
|
149
|
+
:port => port,
|
150
|
+
:account_id => account_id,
|
151
|
+
:api_id => api_id,
|
152
|
+
:secret_phrase => secret_phrase,
|
153
|
+
:voice => voice,
|
154
|
+
:ext => ext }
|
155
|
+
end
|
156
|
+
private :to_hash
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Vocalware
|
2
|
+
# Basic Vocalware error.
|
3
|
+
class Error < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
# Raised when no voices or more than one are found.
|
7
|
+
class FindVoiceError < Error
|
8
|
+
end
|
9
|
+
|
10
|
+
# Raised on sending and processing HTTP request to Vocalware service.
|
11
|
+
class RequestError < Error
|
12
|
+
# @attribute url [String] URL where request was sent
|
13
|
+
attr_accessor :url
|
14
|
+
|
15
|
+
# @attribute response [Faraday::Response] recevied response
|
16
|
+
attr_accessor :response
|
17
|
+
|
18
|
+
# Create instance with request URL and error message.
|
19
|
+
#
|
20
|
+
# @return [Vocalware::RequestError]
|
21
|
+
def self.from_url(url, message)
|
22
|
+
message << "\nREQUEST URL: #{url}"
|
23
|
+
new(message)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Create instance with request URL, response and error message.
|
27
|
+
#
|
28
|
+
# @return [Vocalware::RequestError]
|
29
|
+
def self.from_url_and_response(url, response, message)
|
30
|
+
message << "\nREQUEST URL: #{url}"
|
31
|
+
message << "\nRESPONSE STATUS: #{response.status}"
|
32
|
+
message << "\nRESPONSE BODY: #{response.body}"
|
33
|
+
new(message)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Raised when required parameters for request are missing.
|
38
|
+
class BuildRequestError < RequestError
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Vocalware
|
2
|
+
# Maps language ISO 639-1 code to Vocalware language id.
|
3
|
+
LANGUAGES = {
|
4
|
+
# Arabic
|
5
|
+
:ar => 27,
|
6
|
+
|
7
|
+
# Catalan
|
8
|
+
:ca => 5,
|
9
|
+
|
10
|
+
# Chinese
|
11
|
+
:zh => 10,
|
12
|
+
|
13
|
+
# Danish
|
14
|
+
:da => 19,
|
15
|
+
|
16
|
+
# Dutch
|
17
|
+
:nl => 11,
|
18
|
+
|
19
|
+
# English
|
20
|
+
:en => 1,
|
21
|
+
|
22
|
+
# Esperanto
|
23
|
+
:eo => 31,
|
24
|
+
|
25
|
+
# Finnish
|
26
|
+
:fi => 23,
|
27
|
+
|
28
|
+
# French
|
29
|
+
:fr => 4,
|
30
|
+
|
31
|
+
# Galician
|
32
|
+
:gl => 15,
|
33
|
+
|
34
|
+
# German
|
35
|
+
:de => 3,
|
36
|
+
|
37
|
+
# Greek
|
38
|
+
:el => 8,
|
39
|
+
|
40
|
+
# Italian
|
41
|
+
:it => 7,
|
42
|
+
|
43
|
+
# Japanese
|
44
|
+
:ja => 12,
|
45
|
+
|
46
|
+
# Korean
|
47
|
+
:ko => 13,
|
48
|
+
|
49
|
+
# Norwegian
|
50
|
+
:no => 20,
|
51
|
+
|
52
|
+
# Polish
|
53
|
+
:pl => 14,
|
54
|
+
|
55
|
+
# Portuguese
|
56
|
+
:pt => 6,
|
57
|
+
|
58
|
+
# Romanian
|
59
|
+
:ro => 30,
|
60
|
+
|
61
|
+
# Russian
|
62
|
+
:ru => 21,
|
63
|
+
|
64
|
+
# Spanish
|
65
|
+
:es => 2,
|
66
|
+
|
67
|
+
# Swedish
|
68
|
+
:sv => 9,
|
69
|
+
|
70
|
+
# Turkish
|
71
|
+
:tr => 16
|
72
|
+
}.freeze
|
73
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Vocalware
|
2
|
+
# Request to send to Vocalware's remote service.
|
3
|
+
# Builds a URL with all necessary parameters according to the API.
|
4
|
+
class Request
|
5
|
+
# Required parameters according to the Vocalware API reference.
|
6
|
+
REQUIRED_PARAMETERS = ['EID', 'LID', 'VID', 'TXT', 'ACC', 'API', 'CS']
|
7
|
+
|
8
|
+
# @param attrs [Hash<Symbol, Object>]
|
9
|
+
def initialize(attrs)
|
10
|
+
@attrs = attrs
|
11
|
+
validate!
|
12
|
+
end
|
13
|
+
|
14
|
+
# Build a query as a URL with GET parameters.
|
15
|
+
#
|
16
|
+
# @return [String]
|
17
|
+
def to_url
|
18
|
+
port = @attrs[:port]
|
19
|
+
url = "#{@attrs[:protocol]}://#{@attrs[:host]}"
|
20
|
+
url << ":#{port}" if port
|
21
|
+
url << "#{@attrs[:path]}?"
|
22
|
+
|
23
|
+
params_str = params.map {|name, value|
|
24
|
+
"#{CGI.escape(name)}=#{CGI.escape(value)}"
|
25
|
+
}.join('&')
|
26
|
+
url << params_str
|
27
|
+
end
|
28
|
+
|
29
|
+
# Validate all required parameters are present.
|
30
|
+
#
|
31
|
+
# @return [void]
|
32
|
+
def validate!
|
33
|
+
REQUIRED_PARAMETERS.each do |name|
|
34
|
+
if params[name].empty?
|
35
|
+
raise(BuildRequestError, "Vocalware: Parameter #{name} is required")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
private :validate!
|
40
|
+
|
41
|
+
# Build GET parameters.
|
42
|
+
#
|
43
|
+
# @return [Hash<String, String>]
|
44
|
+
def params
|
45
|
+
@params ||= begin
|
46
|
+
voice = @attrs[:voice]
|
47
|
+
{ 'EID' => voice.engine_id.to_s,
|
48
|
+
'LID' => voice.lang_id.to_s,
|
49
|
+
'VID' => voice.voice_id.to_s,
|
50
|
+
'TXT' => @attrs[:text].to_s,
|
51
|
+
'EXT' => @attrs[:ext].to_s,
|
52
|
+
'FX_TYPE' => @attrs[:fx_type].to_s,
|
53
|
+
'FX_LEVEL' => @attrs[:fx_level].to_s,
|
54
|
+
'ACC' => @attrs[:account_id].to_s,
|
55
|
+
'API' => @attrs[:api_id].to_s,
|
56
|
+
'SESSION' => @attrs[:session].to_s,
|
57
|
+
'CS' => checksum }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
private :params
|
61
|
+
|
62
|
+
# Calculate checksum. The following formula is used:
|
63
|
+
# CS = md5(EID + LID + VID + TXT + EXT + FX_TYPE + FX_LEVEL +
|
64
|
+
# + fACC + API + SESSION + SECRET PHRASE)
|
65
|
+
#
|
66
|
+
# @return [String] MD5 hex digest
|
67
|
+
def checksum
|
68
|
+
@checksum ||= begin
|
69
|
+
voice = @attrs[:voice]
|
70
|
+
data = [
|
71
|
+
voice.engine_id.to_s,
|
72
|
+
voice.lang_id.to_s,
|
73
|
+
voice.voice_id.to_s,
|
74
|
+
@attrs[:text].to_s,
|
75
|
+
@attrs[:ext].to_s,
|
76
|
+
@attrs[:fx_type].to_s,
|
77
|
+
@attrs[:fx_level].to_s,
|
78
|
+
@attrs[:account_id].to_s,
|
79
|
+
@attrs[:api_id].to_s,
|
80
|
+
@attrs[:session].to_s,
|
81
|
+
@attrs[:secret_phrase].to_s
|
82
|
+
].join('')
|
83
|
+
Digest::MD5.hexdigest(data)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
private :checksum
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Vocalware
|
2
|
+
# Voice encapsulates voice parameters like +engine_id+, +voice_id+, +lang_id+
|
3
|
+
# etc. And provides class method to look up voice by parameters.
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# # Find a voice with name Juan. Exception will be raise if the voice with
|
7
|
+
# # such name is not unique. As well as if the voice not found.
|
8
|
+
# voice = Voice.find(:name => 'Juan')
|
9
|
+
class Voice
|
10
|
+
# @attr_reader engine_id [Integer, String] engine id which is used to
|
11
|
+
# generate speech
|
12
|
+
attr_reader :engine_id
|
13
|
+
|
14
|
+
# @attr_reader lang [Symbol, String] language ISO 639-1 code (2 chars)
|
15
|
+
attr_reader :lang
|
16
|
+
|
17
|
+
# @attr_reader name [String] voice name
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
# @attr_reader voice_id [Integer, String] unique only in scope of
|
21
|
+
# +engine_id+ and +lang+
|
22
|
+
attr_reader :voice_id
|
23
|
+
|
24
|
+
# @attr_reader gender [String] whether "M" or "F"
|
25
|
+
attr_reader :gender
|
26
|
+
|
27
|
+
# @attr_reader description [String] regions, dialects, etc
|
28
|
+
attr_reader :description
|
29
|
+
|
30
|
+
# @attr_reader lang_id [Integer, String] language id
|
31
|
+
attr_reader :lang_id
|
32
|
+
|
33
|
+
# Get all voices.
|
34
|
+
#
|
35
|
+
# @return [Array<Vocalware::Voice>]
|
36
|
+
def self.all
|
37
|
+
@all ||= send(:load_all)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Find a voice by attributes.
|
41
|
+
#
|
42
|
+
# @param attrs [Hash] attributes to find a voice
|
43
|
+
#
|
44
|
+
# @return
|
45
|
+
def self.find(attrs)
|
46
|
+
voices = all.select {|voice| voice.match?(attrs) }
|
47
|
+
|
48
|
+
raise(FindVoiceError,
|
49
|
+
"No voice found using #{attrs.inspect}"
|
50
|
+
) if voices.empty?
|
51
|
+
raise(FindVoiceError,
|
52
|
+
"More than 1 voice found using #{attrs.inspect}"
|
53
|
+
) if voices.size > 1
|
54
|
+
|
55
|
+
voices.first
|
56
|
+
end
|
57
|
+
|
58
|
+
# Load and instantiate voices from CSV file.
|
59
|
+
#
|
60
|
+
# @return [Array<Vocalware::Voice>]
|
61
|
+
def self.load_all
|
62
|
+
converter = lambda { |str| str ? str.strip! : nil }
|
63
|
+
data = CSV.read( VOICES_CSV_FILE,
|
64
|
+
:headers => true,
|
65
|
+
:skip_blanks => true,
|
66
|
+
:converters => converter,
|
67
|
+
:header_converters => converter )
|
68
|
+
data.map { |row| Voice.new(row.to_hash) }
|
69
|
+
end
|
70
|
+
private_class_method :load_all
|
71
|
+
|
72
|
+
|
73
|
+
# @param attributes [Hash] voice attributes
|
74
|
+
def initialize(attributes)
|
75
|
+
attributes.each do |attr, value|
|
76
|
+
self.instance_variable_set("@#{attr}", value)
|
77
|
+
end
|
78
|
+
@lang_id = LANGUAGES[lang.to_sym] ||
|
79
|
+
raise(Error, "Unknown lang #{lang.inspect}")
|
80
|
+
end
|
81
|
+
|
82
|
+
# Verify that the voice matches the passed attributes.
|
83
|
+
#
|
84
|
+
# @param attributes [Hash]
|
85
|
+
#
|
86
|
+
# @return [Boolean]
|
87
|
+
def match?(attributes)
|
88
|
+
attributes.each do |attr, val|
|
89
|
+
return false if send(attr).to_s != val.to_s
|
90
|
+
end
|
91
|
+
true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vocalware
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- TMX Credit
|
8
|
+
- Potapov Sergey
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: faraday
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: jeweler
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 1.8.7
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.8.7
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: yard
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: metric_fu
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: pry
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: pry-nav
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
description: Ruby client for Vocalware REST API
|
113
|
+
email:
|
114
|
+
- rubygems@tmxcredit.com
|
115
|
+
- blake131313@gmail.com
|
116
|
+
executables: []
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files:
|
119
|
+
- LICENSE.txt
|
120
|
+
- README.markdown
|
121
|
+
files:
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.markdown
|
124
|
+
- data/voices.csv
|
125
|
+
- lib/vocalware.rb
|
126
|
+
- lib/vocalware/client.rb
|
127
|
+
- lib/vocalware/errors.rb
|
128
|
+
- lib/vocalware/languages.rb
|
129
|
+
- lib/vocalware/request.rb
|
130
|
+
- lib/vocalware/voice.rb
|
131
|
+
homepage: http://github.com/TMXCredit/vocalware
|
132
|
+
licenses:
|
133
|
+
- MIT
|
134
|
+
metadata: {}
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - '>='
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
requirements: []
|
150
|
+
rubyforge_project:
|
151
|
+
rubygems_version: 2.0.3
|
152
|
+
signing_key:
|
153
|
+
specification_version: 4
|
154
|
+
summary: Ruby client for Vocalware REST API
|
155
|
+
test_files: []
|
156
|
+
has_rdoc:
|