yandex_speech_api 1.1.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.
@@ -0,0 +1,103 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ module YandexSpeechApi
4
+ class Speaker
5
+ private
6
+
7
+ #
8
+ # @param [Proc] callback
9
+ # Used to set object attributes throw {do...end} block.
10
+ #
11
+ # @example Block syntax
12
+ # key = 'Your secret key'
13
+ # message = "one two three. one two three. one two three four."
14
+ #
15
+ # speaker = YandexSpeechApi::Speaker.init do |s|
16
+ # s.key = key
17
+ # s.voice = :jane
18
+ # s.language = :english
19
+ # s.speed = :slow
20
+ # s.emotion = :good
21
+ # end
22
+ # speaker.say message
23
+ #
24
+ # @return [Speaker]
25
+
26
+ def initialize(settings, &callback)
27
+ yield self if block_given?
28
+
29
+ @key ||= Key.new settings[:key] || :unknown
30
+ @voice ||= Voice.new settings[:voice] || :jane
31
+ @speed ||= Speed.new settings[:speed] || :standard
32
+ @emotion ||= Emotion.new settings[:emotion] || :neutral
33
+ @language ||= Language.new settings[:language] || :english
34
+ @format ||= Format.new settings[:format] || :mp3
35
+ end
36
+
37
+ ##
38
+ # Prepares and sends request on Yandex Servers.
39
+ #
40
+ # @param [String] text
41
+ # Something that should been said.
42
+ # @param [Hash] params
43
+ # Overrides object settings (only for this request)
44
+ #
45
+ # @return [String]
46
+
47
+ def request(text, params = {})
48
+ tmp_params = generate_params_for_request text, params
49
+ Connection.send tmp_params
50
+ end
51
+
52
+ ##
53
+ # Generates params for request.
54
+ #
55
+ # @param [String] text
56
+ #
57
+ # @param [Hash] params ({})
58
+ # @option params [Format] :format (nil).
59
+ # @option params [Language] :language (nil).
60
+ # @option params [Voice] :voice (nil).
61
+ # @option params [Key] :key (nil).
62
+ # @option params [Emotion] :emotion (nil).
63
+ # @option params [Speed] :speed (nil).
64
+ #
65
+ # @exception TextTooBig
66
+ # Raised when param +text+ too big (>2000 symbols)
67
+ #
68
+ # @return [Hash]
69
+
70
+ def generate_params_for_request(text, params = {})
71
+ tmp_text = text.dup.encode(Encoding::UTF_8, invalid: :replace,
72
+ undef: :replace, replace: '')
73
+ raise TextTooBig if tmp_text.length > 2000
74
+
75
+ tmp = {
76
+ text: tmp_text,
77
+ format: params[:format] ? params[:format].type : format.type,
78
+ lang: params[:language] ? params[:language].code : language.code,
79
+ speaker: params[:voice] ? params[:voice].name : voice.name,
80
+ key: params[:key] ? params[:key].get : key.get,
81
+ emotion: params[:emotion] ? params[:emotion].type : emotion.type,
82
+ speed: params[:speed] ? params[:speed].value : speed.value
83
+ }
84
+
85
+ return tmp
86
+ end
87
+
88
+ def generate_path # no-doc
89
+ dir_path = File.join ENV['HOME'], 'downloads'
90
+
91
+ Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
92
+ filename = "yandex_speech_audio_#{Time.now.strftime "%Y-%m-%d_%H-%M-%S"}"
93
+
94
+ return File.join(dir_path, filename)
95
+ end
96
+
97
+ ##
98
+ # Raised when user tries to #say too big text.
99
+
100
+ class TextTooBig < YandexSpeechError
101
+ def initialize; super 'Text message length limited by 2000 symbols per request' end; end
102
+ end # class Speaker
103
+ end # module YandexSpeechApi
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ module YandexSpeechApi
4
+ class Speed
5
+ class << self
6
+
7
+ # @example #1
8
+ # list[:slow] # ==> 0.5
9
+ #
10
+ # @example #2
11
+ # list[:wrong_key] # ==> nil
12
+ #
13
+ # @return [Hash]
14
+
15
+ def modes
16
+ {
17
+ :slowest => 0.1, # minimal allowed speed
18
+ :slow => 0.5,
19
+ :standard => 1.0, # default
20
+ :fast => 1.5,
21
+ :fastest => 3.0 # maximal allowed speed
22
+ }
23
+ end
24
+ end # class << self
25
+
26
+ # @return [Float]
27
+ # In range [(0.1)..3.0]
28
+
29
+ attr_reader :value
30
+
31
+ def initialize(speed)
32
+ @value = if speed.is_a? Numeric
33
+ speed.round 2
34
+ else
35
+ Speed.modes[speed.downcase.to_sym]
36
+ end
37
+
38
+ raise SpeedModeNotAllowed, speed if @value.nil?
39
+ raise SpeedValueNotInRange, @value unless speed_in_valid_range? @value
40
+ end
41
+
42
+ private
43
+
44
+ def speed_in_valid_range?(number)
45
+ number.between? 0.1, 3
46
+ end
47
+
48
+ ##
49
+ # Raised when speed mode is unknown.
50
+
51
+ class SpeedModeNotAllowed < YandexSpeechError
52
+ def initialize(speed); super "Speed '#{speed}' not allowed for usage. To see list of allowed formats use Emotion#list." end; end
53
+
54
+ ##
55
+ # Raised when +speed+ param is not in [(0.1)..3] range.
56
+
57
+ class SpeedValueNotInRange < YandexSpeechError
58
+ def initialize(value); super "Speed value '#{value}' should be from [(0.1)..3] range" end; end
59
+ end # class Speed
60
+ end # module YandexSpeechApi
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ module YandexSpeechApi
4
+
5
+ # @example Valid Usage
6
+ # Voice.new('Oksana') # ==> instance of voice class
7
+ #
8
+ # @example Bad Usage
9
+ # Voice.new(:bill) # ==> VoiceNotAllowed exception
10
+
11
+ class Voice
12
+
13
+ ##
14
+ # List of allowed voices
15
+ #
16
+ # @return [Array<String>]
17
+
18
+ def self.list
19
+ %i(jane oksana alyss omazh zahar ermil)
20
+ end
21
+
22
+ # @return [Symbol]
23
+ # possible values: :jane, :oksana, :alyss, :omazh, :zahar, :ermil
24
+
25
+ attr_reader :name
26
+
27
+ def initialize(voice)
28
+ @name = voice.downcase.to_sym
29
+ raise VoiceNotAllowed, voice unless voice_known? @name
30
+ end
31
+
32
+ private
33
+
34
+ def voice_known?(name)
35
+ Voice.list.include? name
36
+ end
37
+
38
+ ##
39
+ # Raised when unknown voice was selected.
40
+
41
+ class VoiceNotAllowed < YandexSpeechError
42
+ def initialize(voice)
43
+ super "Voice '#{voice}' not allowed for usage. To see list of allowed voices use Voice#list" end; end
44
+ end # class Voice
45
+ end # module YandexSpeechApi
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ require 'coveralls'
4
+ Coveralls.wear!
5
+
6
+ require 'webmock/rspec'
7
+
8
+ require_relative '../lib/yandex_speech'
9
+
10
+ RSpec.configure do |config|
11
+ WebMock.disable_net_connect! allow_localhost: true
12
+
13
+ config.filter_run_excluding :disabled => true
14
+ end
15
+
16
+ SimpleCov.coverage_dir("spec/coverage")
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module YandexSpeechApi
6
+ describe Connection do
7
+ context '#send' do
8
+ it 'raises an exception for fallen request' do
9
+ stub_request(:any, /https:\/\/tts.voicetech.yandex.net\/.*/)
10
+ .to_return status: 500, body: 'Body'
11
+
12
+ expect {described_class.send {}}
13
+ .to raise_exception described_class::ConnectionError
14
+ end
15
+
16
+ it 'returns response body for successful request' do
17
+ stub_request(:any, /https:\/\/tts.voicetech.yandex.net\/.*/)
18
+ .to_return status: 200, body: 'Body'
19
+
20
+ expect(described_class.send {}).to be_eql "Body"
21
+ end
22
+ end # context '#send'
23
+ end # describe Connection
24
+ end # module YandexSpeechApi
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module YandexSpeechApi
6
+ describe Emotion do
7
+ context '#new' do
8
+ it 'raises an exception for unknown emotion' do
9
+ expect { described_class.new :some_random_emotion }
10
+ .to raise_exception described_class::EmotionNotAllowed
11
+ end
12
+
13
+ it 'creates object instance when emotion param is symbol' do
14
+ expect(described_class.new(:good))
15
+ .to be_instance_of Emotion
16
+ end
17
+
18
+ it 'creates object instance when emotion param is string' do
19
+ expect(described_class.new('GOOD'))
20
+ .to be_instance_of Emotion
21
+ end
22
+
23
+ it 'creates :good emotion without any exception' do
24
+ expect { described_class.new :good }.to_not raise_exception
25
+ end
26
+ end # context #new
27
+
28
+ context '#list' do
29
+ it 'shows list of allowed emotions' do
30
+ expect(described_class.list).to_not be_nil
31
+ end
32
+ end # context #list
33
+ end # describe Emotion
34
+ end # module YandexSpeechApi
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module YandexSpeechApi
6
+ describe Format do
7
+ context '#new' do
8
+ it 'raises an exception for unknown format type' do
9
+ expect { described_class.new :some_random_format }
10
+ .to raise_exception described_class::FormatNotAllowed
11
+ end
12
+
13
+ it 'creates object instance when format param is symbol' do
14
+ expect(described_class.new(:wav))
15
+ .to be_instance_of Format
16
+ end
17
+
18
+ it 'creates object instance when format param is string' do
19
+ expect(described_class.new('Wav'))
20
+ .to be_instance_of Format
21
+ end
22
+ end # context #new
23
+
24
+ context '#list' do
25
+ it 'shows list of all possible formats' do
26
+ expect(described_class.list).to_not be_nil
27
+ end
28
+ end # context #list
29
+ end # describe Format
30
+ end # module YandexSpeechApi
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module YandexSpeechApi
6
+ describe Helpers do
7
+ context '#recognize_operation_system' do
8
+
9
+ it "returns :windows for CONFIG['host_os'] == msys" do
10
+ stub_const 'RbConfig::CONFIG', {'host_os' => 'msys'}
11
+ expect(described_class.recognize_operation_system).to eql(:windows)
12
+ end
13
+
14
+ it "returns :mac_os for CONFIG['host_os'] == darwin" do
15
+ stub_const 'RbConfig::CONFIG', {'host_os' => 'darwin'}
16
+ expect(described_class.recognize_operation_system).to eql(:mac_os)
17
+ end
18
+ end # context '#recognize_operation_system'
19
+ end # describe Helpers
20
+ end # module YandexSpeechApi
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module YandexSpeechApi
6
+ describe Key do
7
+ after :each do
8
+ described_class.instance_variable_set :@global_key, nil
9
+ end
10
+
11
+ context '#global_key=(other)' do
12
+ it 'raises an exception +other+ param is not present' do
13
+ key = described_class.new :unknown
14
+ expect { described_class.global_key = key }
15
+ .to raise_error Key::InvalidGlobalKey
16
+ end
17
+ end # context '#global_key=(other)'
18
+
19
+ context '#global_key' do
20
+ it 'returns +false+ when global key not set' do
21
+ expect(Key.global_key?).to be_falsey
22
+ end
23
+
24
+ it 'returns +true+ when global key set' do
25
+ described_class.global_key = 'Secret Key'
26
+ expect(Key.global_key?).to be_truthy
27
+ end
28
+ end # context '#global_key'
29
+
30
+ context '#get' do
31
+ it 'raises an exception for not defined (instance or global) key' do
32
+ key = described_class.new :unknown
33
+ expect { key.get }.to raise_error Key::KeyNotDefined
34
+ end
35
+
36
+ it 'not raises an exception when instance key defined' do
37
+ key = described_class.new 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx'
38
+ expect { key.get }.to_not raise_error
39
+ end
40
+
41
+ it 'not raises an exception when global key defined' do
42
+ described_class.global_key = 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx'
43
+ key = described_class.new :unknown
44
+ expect { key.get }.to_not raise_error
45
+ end
46
+
47
+ it 'not raises an exception for any key instance when global key defined' do
48
+ described_class.global_key = 'xxxxx-xxxxx-xxxxx-xxxxx-xxxxx'
49
+
50
+ key = described_class.new :unknown
51
+ key2 = described_class.new 'test key'
52
+
53
+ expect { key.get }.to_not raise_error
54
+ expect { key2.get }.to_not raise_error
55
+ end
56
+ end # context #get
57
+ end # describe Key
58
+ end # module YandexSpeechApi
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module YandexSpeechApi
6
+ describe Language do
7
+ context '#new' do
8
+ it 'raises an exception for unknown language' do
9
+ expect { described_class.new :wommi_lang }
10
+ .to raise_exception described_class::UnknownLanguageError
11
+ end
12
+
13
+ it 'creates object instance when +language+ param is symbol' do
14
+ expect{described_class.new(:ukrain)}.to_not raise_exception
15
+ end
16
+
17
+ it 'creates object instance when +language+ param is string' do
18
+ expect{described_class.new('Ukrain')}.to_not raise_exception
19
+ end
20
+ end # context #new
21
+
22
+ context '#allowed_languages' do
23
+ it 'shows list of all possible languages' do
24
+ expect(described_class.allowed_languages).to_not be_nil
25
+ end
26
+ end # context #allowed_languages
27
+
28
+ context '#code' do
29
+ it 'returns valid code for any class instance from #list' do
30
+ sample = described_class.allowed_languages.sample
31
+
32
+ expect{described_class.new(sample)}.to_not raise_exception
33
+ end
34
+ end # context #code
35
+ end # describe Language
36
+ end # module YandexSpeechApi
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ module YandexSpeechApi
7
+ module MP3_Player
8
+ describe Base do
9
+ context '#play' do
10
+ it 'raises an exception when file not found' do
11
+ expect{described_class.new.play('lalalala.')}
12
+ .to raise_exception described_class::FileNotFound
13
+ end
14
+
15
+ it 'raises an exception when file has wrong extension' do
16
+ expect_any_instance_of(described_class)
17
+ .to receive(:validate_file_presence).and_return nil
18
+
19
+ expect{described_class.new.play('lalalala.')}
20
+ .to raise_exception described_class::UnknownExtension
21
+ end
22
+ end # context '#play'
23
+ end # describe Linux_MP3_Player
24
+ end # module MP3_Player
25
+ end # module YandexSpeechApi