yandex_speech_api 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +16 -0
- data/LICENSE +9 -0
- data/README.md +101 -0
- data/lib/yandex_speech.rb +253 -0
- data/lib/yandex_speech/connection.rb +52 -0
- data/lib/yandex_speech/emotion.rb +39 -0
- data/lib/yandex_speech/format.rb +38 -0
- data/lib/yandex_speech/helpers.rb +52 -0
- data/lib/yandex_speech/key.rb +106 -0
- data/lib/yandex_speech/language.rb +59 -0
- data/lib/yandex_speech/mp3_player.rb +33 -0
- data/lib/yandex_speech/mp3_player/base.rb +72 -0
- data/lib/yandex_speech/mp3_player/linux_mp3_player.rb +41 -0
- data/lib/yandex_speech/mp3_player/mac_mp3_player.rb +22 -0
- data/lib/yandex_speech/project_structure.rb +30 -0
- data/lib/yandex_speech/speaker.rb +103 -0
- data/lib/yandex_speech/speed.rb +60 -0
- data/lib/yandex_speech/voice.rb +45 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/yandex_speech/connection_spec.rb +24 -0
- data/spec/yandex_speech/emotion_spec.rb +34 -0
- data/spec/yandex_speech/format_spec.rb +30 -0
- data/spec/yandex_speech/helpers_spec.rb +20 -0
- data/spec/yandex_speech/key_spec.rb +58 -0
- data/spec/yandex_speech/language_spec.rb +36 -0
- data/spec/yandex_speech/mp3_player/base_spec.rb +25 -0
- data/spec/yandex_speech/mp3_player/linux_mp3_player_spec.rb +39 -0
- data/spec/yandex_speech/mp3_player_spec.rb +23 -0
- data/spec/yandex_speech/speed_spec.rb +33 -0
- data/spec/yandex_speech/voice_spec.rb +28 -0
- data/spec/yandex_speech_spec.rb +112 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 503bb8b1169230590382c2bed35232e8c8b0ad8c
|
4
|
+
data.tar.gz: b4e5a11c0494ff5b43a3831a44427d7a0b75d26a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 08aedbd6436613262ce70410b9c5b9f0b476dd6a6dd1758f9531a7064518d5827854832c7e9afe8a2cbd1a82f66c5bd436a888377c03ad7ce3a574f2179e5c4a
|
7
|
+
data.tar.gz: caecae0b89060595daf24261389e533f67712b48a976da40067d58e11688212ce70a95d42f6208eb3738757e6fd2bfb74d342352a416e0a017fe25d783c54b73
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) <2016> Kuzichev Michael
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# YandexSpeechApi [![Gem Version](https://badge.fury.io/rb/yandex_speech_api.svg)](https://badge.fury.io/rb/yandex_speech_api) [![Build Status](https://travis-ci.org/Medvedu/Yandex-Speech-API.svg?branch=master)](https://travis-ci.org/Medvedu/Yandex-Speech-API) [![Code Climate](https://codeclimate.com/github/Medvedu/Yandex-Speech-API/badges/gpa.svg)](https://codeclimate.com/github/Medvedu/Yandex-Speech-API) [![Inline docs](http://inch-ci.org/github/Medvedu/Yandex-Speech-API.svg?branch=master)](http://inch-ci.org/github/Medvedu/Yandex-Speech-API) [![Coverage Status](https://coveralls.io/repos/github/Medvedu/Yandex-Speech-API/badge.svg)](https://coveralls.io/github/Medvedu/Yandex-Speech-API)
|
2
|
+
|
3
|
+
## Описание
|
4
|
+
|
5
|
+
Wrapper для синтезатора речи, основанного на технологиях Yandex SpeechKit Cloud API. Предоставляет собой интерфейс для перевода машинного текста (на русском, английском, украинском или турецком язык) в речь. Может использоваться как для прямого воспроизведения текста, так и для записи речи в файл.
|
6
|
+
|
7
|
+
## Установка
|
8
|
+
|
9
|
+
1. Перед использованием необходимо получить ключ разработчика. Подробнее на официальном сайте: https://tech.yandex.ru/speechkit/cloud
|
10
|
+
2. Добавьте yandex_speech_api в Gemfile.
|
11
|
+
3. bundle install
|
12
|
+
4. Добавьте в проект:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
# ...
|
16
|
+
require 'yandex_speech'
|
17
|
+
# ...
|
18
|
+
````
|
19
|
+
|
20
|
+
Воспроизведение звука поддерживается для UNIX-подобных операционных систем (Mac + Linux).
|
21
|
+
|
22
|
+
### Примеры использования
|
23
|
+
|
24
|
+
### Пример 1
|
25
|
+
|
26
|
+
_Для начала работы с api достаточно указать ключ:_
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
key = File.open('secret key/key').readline.strip
|
30
|
+
|
31
|
+
speaker = YandexSpeechApi::Speaker.init key: key, language: 'russian'
|
32
|
+
speaker.save_to_file "Не будите спящего кота."
|
33
|
+
```
|
34
|
+
|
35
|
+
### Пример 2
|
36
|
+
|
37
|
+
_Когда это неоходимо, конструктор позволяет переписывать параметры по умолчанию, например, так можно выбрать язык:_
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
YandexSpeechApi::Key.global_key = File.open('secret key/key').readline.strip
|
41
|
+
|
42
|
+
message = "Don't trouble trouble until trouble troubles you"
|
43
|
+
speaker = YandexSpeechApi::Speaker.init(voice: :zahar, speed: 0.23)
|
44
|
+
speaker.say message
|
45
|
+
```
|
46
|
+
|
47
|
+
Обратите внимание, передавать key каждый раз нет никакой необходимости. Достаточно один раз установить YandexSpeechApi::Key.global_key.
|
48
|
+
|
49
|
+
### Пример 3
|
50
|
+
|
51
|
+
_Также поддерживаются геттеры и сеттеры:_
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
key = File.open('secret key/key').readline.strip
|
55
|
+
|
56
|
+
message = "Як поїдеш в об'їзд, то будеш і на обід, а як навпростець, то увечері."
|
57
|
+
|
58
|
+
speaker = YandexSpeechApi::Speaker.init
|
59
|
+
speaker.key = key
|
60
|
+
speaker.voice = 'Alyss'
|
61
|
+
speaker.language = 'Ukrain'
|
62
|
+
speaker.speed = 1.2
|
63
|
+
speaker.emotion = 'good'
|
64
|
+
speaker.save_to_file message, '~/downloads/sound'
|
65
|
+
```
|
66
|
+
|
67
|
+
### Пример 4
|
68
|
+
|
69
|
+
_И, наконец, установка параметров через блок:_
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
key = File.open('secret key/key').readline.strip
|
73
|
+
message = "one two three. one two three. one two three four."
|
74
|
+
|
75
|
+
speaker = YandexSpeechApi::Speaker.init do |s|
|
76
|
+
s.key = key
|
77
|
+
s.voice = :jane
|
78
|
+
s.language = :english
|
79
|
+
s.speed = :slow
|
80
|
+
s.emotion = :good
|
81
|
+
end
|
82
|
+
|
83
|
+
speaker.say message
|
84
|
+
```
|
85
|
+
|
86
|
+
## Примечания
|
87
|
+
|
88
|
+
1. За один запрос озвучивается текст, длинной до 2000 знаков.
|
89
|
+
2. Выбирая язык, учтите: вы ограничены его фонетикой, так, например, английский переводчик не умеет озвучивать русские тексты и т.п. (На самом деле это не совсем точно — хотя официальная документация и не рекомендует выставлять некорректные пары язык-текст, в то же время, _русский_ переводчик фактически может воспроизводить английские тексты)
|
90
|
+
|
91
|
+
## Зависимости
|
92
|
+
|
93
|
+
* Ruby 2.0.0 или выше
|
94
|
+
|
95
|
+
### Linux-специфичные зависимости:
|
96
|
+
|
97
|
+
* mpg123
|
98
|
+
|
99
|
+
## Лицензия
|
100
|
+
|
101
|
+
Данный код распространяется под лицензией MIT, подробнее смотрите [LICENSE](./LICENSE). Остальные права принадлежат их владельцам.
|
@@ -0,0 +1,253 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# Wrapper for Yandex Speech API (https://tech.yandex.ru/speechkit).
|
5
|
+
#
|
6
|
+
# @see https://github.com/Medvedu/Yandex-Speech-API
|
7
|
+
# @see README.md
|
8
|
+
#
|
9
|
+
# @author Kuzichev Michael
|
10
|
+
# @license MIT
|
11
|
+
module YandexSpeechApi
|
12
|
+
require_relative 'yandex_speech/project_structure'
|
13
|
+
#
|
14
|
+
# Speaker a class that convert English, Ukrain, Russian or Turkey text to
|
15
|
+
# speech. Solution based on Yandex SpeechKit technology.
|
16
|
+
#
|
17
|
+
# @example Basic usage
|
18
|
+
# key = File.open('secret key/key').readline.strip
|
19
|
+
#
|
20
|
+
# speaker = YandexSpeechApi::Speaker.init key: key, language: 'russian'
|
21
|
+
# speaker.save_to_file "Не будите спящего кота."
|
22
|
+
#
|
23
|
+
# @example Hash syntax
|
24
|
+
# key = File.open('secret key/key').readline.strip
|
25
|
+
# message = "Don't trouble trouble until trouble troubles you"
|
26
|
+
#
|
27
|
+
# speaker = YandexSpeechApi::Speaker.init({ key: key, language: 'english', voice: :zahar, speed: 0.23 })
|
28
|
+
# speaker.say message
|
29
|
+
#
|
30
|
+
# @example Block syntax
|
31
|
+
# key = File.open('secret key/key').readline.strip
|
32
|
+
# message = "one two three. one two three. one two three four."
|
33
|
+
#
|
34
|
+
# speaker = YandexSpeechApi::Speaker.init do |s|
|
35
|
+
# s.key = key
|
36
|
+
# s.voice = :jane
|
37
|
+
# s.language = :english
|
38
|
+
# s.speed = :slow
|
39
|
+
# s.emotion = :good
|
40
|
+
# end
|
41
|
+
# speaker.say message
|
42
|
+
#
|
43
|
+
# Before usage you need to get an api key. It is free for non-commercial
|
44
|
+
# purposes (at least for now).
|
45
|
+
#
|
46
|
+
# You can get this key from official site: https://tech.yandex.ru/speechkit
|
47
|
+
#
|
48
|
+
# Note: Yandex provide many services throw this site. Your need exactly
|
49
|
+
# +Yandex SpeechKit Cloud+ key. Other keys will not work!
|
50
|
+
#
|
51
|
+
# Do not share this key to third party.
|
52
|
+
#
|
53
|
+
class Speaker
|
54
|
+
class << self
|
55
|
+
##
|
56
|
+
# Creates +Speaker+ instance.
|
57
|
+
#
|
58
|
+
# @param [Proc] callback
|
59
|
+
# Used to set object state throw {do ... end} block.
|
60
|
+
#
|
61
|
+
# @param [HASH] settings
|
62
|
+
# Overrides default settings.
|
63
|
+
# @option settings [Symbol] :speed (:standard)
|
64
|
+
# @see Speaker#speed for details.
|
65
|
+
# @option settings [Symbol] :voice (:alyss)
|
66
|
+
# @see Speaker#voice for details.
|
67
|
+
# @option settings [Symbol] :emotion (:neutral)
|
68
|
+
# @see Speaker#emotion for details.
|
69
|
+
# @option settings [Symbol] :language (:english)
|
70
|
+
# @see Speaker#language for details.
|
71
|
+
# @option settings [Symbol] :format (:mp3)
|
72
|
+
# @see Speaker#format for details.
|
73
|
+
# @option settings [Symbol] :key (:unknown)
|
74
|
+
# @see Speaker#key for details.
|
75
|
+
#
|
76
|
+
# @return [YandexSpeech]
|
77
|
+
|
78
|
+
def init(settings = {}, &callback)
|
79
|
+
new settings, &callback
|
80
|
+
end
|
81
|
+
end # class << self
|
82
|
+
|
83
|
+
private_class_method :new
|
84
|
+
|
85
|
+
##
|
86
|
+
# Determines dictor speech speed.
|
87
|
+
#
|
88
|
+
# @return [Speed]
|
89
|
+
|
90
|
+
attr_reader :speed
|
91
|
+
|
92
|
+
##
|
93
|
+
# Preferred dictor voice.
|
94
|
+
#
|
95
|
+
# @return [Voice]
|
96
|
+
|
97
|
+
attr_reader :voice
|
98
|
+
|
99
|
+
##
|
100
|
+
# How emotional dictor should speak.
|
101
|
+
#
|
102
|
+
# @return [Emotion]
|
103
|
+
|
104
|
+
attr_reader :emotion
|
105
|
+
|
106
|
+
##
|
107
|
+
# Speaker language.
|
108
|
+
#
|
109
|
+
# Speaker with +russian+ language can't translate, or even synthesize
|
110
|
+
# +english+ text (actually it can, but official documentation strongly
|
111
|
+
# recommend to select right language for incoming text)
|
112
|
+
#
|
113
|
+
# @return [Language]
|
114
|
+
|
115
|
+
attr_reader :language
|
116
|
+
|
117
|
+
##
|
118
|
+
# How remote server should decode audio data for us.
|
119
|
+
#
|
120
|
+
# Do not use +:wav+ format for large texts. Result audio file will be
|
121
|
+
# too big, and service truncates resulted file.
|
122
|
+
#
|
123
|
+
# @return [Format]
|
124
|
+
|
125
|
+
attr_reader :format
|
126
|
+
|
127
|
+
##
|
128
|
+
# Defines setters for +@voice+, +@language+,+@format+, +@emotion+,
|
129
|
+
# +@speed+, +@key+ attributes.
|
130
|
+
#
|
131
|
+
# @setter #speed=(other)
|
132
|
+
# @param [Symbol, Integer, Float] other
|
133
|
+
# Expecting values are
|
134
|
+
# :slowest, :slow, :standard, :fast, :fastest
|
135
|
+
# or any Integer/Float from (0.1)..3 range.
|
136
|
+
#
|
137
|
+
# @setter #voice=(other)
|
138
|
+
# @param [Symbol] other
|
139
|
+
# Expecting values are
|
140
|
+
# :jane, :oksana, :alyss, :omazh, :zahar, :ermil
|
141
|
+
#
|
142
|
+
# @setter #emotion=(other)
|
143
|
+
# @param [Symbol] other
|
144
|
+
# Expecting values are
|
145
|
+
# :good, :evil, :neutral
|
146
|
+
#
|
147
|
+
# @setter #language=(other)
|
148
|
+
# @param [Symbol] other
|
149
|
+
# Expecting values are
|
150
|
+
# :russian, :english, :ukrain, :turkey
|
151
|
+
#
|
152
|
+
# @setter #format=(other)
|
153
|
+
# @param [Symbol] other
|
154
|
+
# Expecting values are
|
155
|
+
# :mp3, :wav, :opus
|
156
|
+
#
|
157
|
+
# @setter #key=(new_key)
|
158
|
+
# @param [String] new_key
|
159
|
+
|
160
|
+
%i(voice language format emotion speed key).each do |symbol|
|
161
|
+
define_method "#{symbol}=" do |other|
|
162
|
+
method_name = __method__.to_s.chop
|
163
|
+
klass = YandexSpeechApi.const_get method_name.capitalize
|
164
|
+
variable =
|
165
|
+
if other.is_a? klass
|
166
|
+
other
|
167
|
+
else
|
168
|
+
klass.new(other)
|
169
|
+
end
|
170
|
+
instance_variable_set "@#{method_name}", variable
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
##
|
175
|
+
# Speeches text.
|
176
|
+
#
|
177
|
+
# @example #Say usage
|
178
|
+
# key = File.open('secret key/key').readline.strip
|
179
|
+
# message = "one two three. one two three. one two three four."
|
180
|
+
#
|
181
|
+
# speaker = YandexSpeechApi::Speaker.init do |s|
|
182
|
+
# s.key = key
|
183
|
+
# s.voice = :jane
|
184
|
+
# s.language = :english
|
185
|
+
# s.speed = :slow
|
186
|
+
# s.emotion = :good
|
187
|
+
# end
|
188
|
+
# speaker.say message
|
189
|
+
#
|
190
|
+
# @param [String] text
|
191
|
+
# Something that should been said.
|
192
|
+
#
|
193
|
+
# @return [NilClass]
|
194
|
+
# You hear the sound.
|
195
|
+
|
196
|
+
def say(text)
|
197
|
+
format = Format.new :mp3
|
198
|
+
binary_data = request text, format: format
|
199
|
+
|
200
|
+
file = Tempfile.new ['yandex_speech_temp_file', ".#{format.type}"]
|
201
|
+
file.write binary_data
|
202
|
+
|
203
|
+
player = MP3_Player.init
|
204
|
+
player.play file.path
|
205
|
+
|
206
|
+
file.close(true) if file
|
207
|
+
|
208
|
+
return nil
|
209
|
+
end
|
210
|
+
|
211
|
+
##
|
212
|
+
# Saves synthesized voice to audio-file.
|
213
|
+
#
|
214
|
+
# If +path_to_file+ is empty it saves audio-file to '~/downloads'
|
215
|
+
#
|
216
|
+
# @example #save_to_file usage
|
217
|
+
# key = File.open('secret key/key').readline.strip
|
218
|
+
#
|
219
|
+
# speaker = YandexSpeechApi::Speaker.init key: key, language: 'russian'
|
220
|
+
# speaker.save_to_file "Не будите спящего кота.", 'let_cat_sleep'
|
221
|
+
#
|
222
|
+
# @param [String] text
|
223
|
+
# Something that should been said.
|
224
|
+
#
|
225
|
+
# @param [String] path_to_file ('~/downloads')
|
226
|
+
# Path to new file (without file extension).
|
227
|
+
#
|
228
|
+
# @return [String]
|
229
|
+
# Absolute path to created file.
|
230
|
+
|
231
|
+
def save_to_file(text, path_to_file = '')
|
232
|
+
path_to_file = generate_path if path_to_file.empty?
|
233
|
+
|
234
|
+
binary_data = request text
|
235
|
+
absolute_path = "#{File.expand_path(path_to_file)}.#{format.type}"
|
236
|
+
File.open(absolute_path, 'w') { |f| f.write binary_data }
|
237
|
+
|
238
|
+
return absolute_path
|
239
|
+
end
|
240
|
+
|
241
|
+
private
|
242
|
+
|
243
|
+
##
|
244
|
+
# Yandex Speech ApiKey.
|
245
|
+
#
|
246
|
+
# Key is not something that should be shared with any other class. Setter
|
247
|
+
# method is public anyway.
|
248
|
+
#
|
249
|
+
# @return [Key]
|
250
|
+
|
251
|
+
attr_reader :key
|
252
|
+
end # class Speaker
|
253
|
+
end # module YandexSpeechApi
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module YandexSpeechApi
|
4
|
+
module Connection # no-doc
|
5
|
+
class << self
|
6
|
+
|
7
|
+
##
|
8
|
+
# Sends :get request.
|
9
|
+
#
|
10
|
+
# @param [Hash] params
|
11
|
+
# @option params [String] :text
|
12
|
+
# @option params [Symbol] :format
|
13
|
+
# @option params [String] :lang
|
14
|
+
# @option params [String] :speaker
|
15
|
+
# @option params [Symbol] :emotion
|
16
|
+
# @option params [Float] :speed
|
17
|
+
# @option params [String, Symbol] :key
|
18
|
+
#
|
19
|
+
# @exception ConnectionError
|
20
|
+
# Raised when responce is not successful.
|
21
|
+
#
|
22
|
+
# @return [String]
|
23
|
+
# Binary data.
|
24
|
+
|
25
|
+
def send(**params)
|
26
|
+
uri = URI.parse URL
|
27
|
+
uri.query = URI.encode_www_form params
|
28
|
+
response = Net::HTTP.get_response uri
|
29
|
+
|
30
|
+
case response
|
31
|
+
when Net::HTTPSuccess
|
32
|
+
return response.body
|
33
|
+
else
|
34
|
+
raise ConnectionError.new response.code, response.message
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
##
|
41
|
+
# YandexAPI endpoint.
|
42
|
+
|
43
|
+
URL = "https://tts.voicetech.yandex.net/generate"
|
44
|
+
end # class << self
|
45
|
+
|
46
|
+
##
|
47
|
+
# Raised when connection failed.
|
48
|
+
|
49
|
+
class ConnectionError < YandexSpeechError
|
50
|
+
def initialize(code, message); super "Connection refused by remote server. Error code: '#{code}', Exception message: '#{message}'." end; end
|
51
|
+
end # module Connection
|
52
|
+
end # module YandexSpeechApi
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module YandexSpeechApi
|
4
|
+
class Emotion
|
5
|
+
|
6
|
+
##
|
7
|
+
# List of allowed emotions
|
8
|
+
#
|
9
|
+
# @return [Array<String>]
|
10
|
+
|
11
|
+
def self.list
|
12
|
+
%i(evil good neutral)
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# @return [Symbol]
|
17
|
+
# possible values: :evil, :good or :neutral
|
18
|
+
|
19
|
+
attr_reader :type
|
20
|
+
|
21
|
+
def initialize(emotion)
|
22
|
+
@type = emotion.downcase.to_sym
|
23
|
+
|
24
|
+
raise EmotionNotAllowed, emotion unless emotion_known? @type
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def emotion_known?(emotion)
|
30
|
+
Emotion.list.include? emotion
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Raised when unknown emotion has been selected.
|
35
|
+
|
36
|
+
class EmotionNotAllowed < YandexSpeechError
|
37
|
+
def initialize(emotion); super "Emotion '#{emotion}' not allowed for usage. To see list of allowed emotions use Emotion#list" end; end
|
38
|
+
end # class Emotion
|
39
|
+
end # module YandexSpeechApi
|