eleven_rb 0.1.0
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/CHANGELOG.md +33 -0
- data/LICENSE +21 -0
- data/README.md +311 -0
- data/lib/eleven_rb/callbacks.rb +47 -0
- data/lib/eleven_rb/client.rb +110 -0
- data/lib/eleven_rb/collections/base.rb +92 -0
- data/lib/eleven_rb/collections/library_voice_collection.rb +91 -0
- data/lib/eleven_rb/collections/voice_collection.rb +78 -0
- data/lib/eleven_rb/configuration.rb +87 -0
- data/lib/eleven_rb/errors.rb +58 -0
- data/lib/eleven_rb/http/client.rb +277 -0
- data/lib/eleven_rb/instrumentation.rb +35 -0
- data/lib/eleven_rb/objects/audio.rb +118 -0
- data/lib/eleven_rb/objects/base.rb +86 -0
- data/lib/eleven_rb/objects/cost_info.rb +72 -0
- data/lib/eleven_rb/objects/library_voice.rb +66 -0
- data/lib/eleven_rb/objects/model.rb +56 -0
- data/lib/eleven_rb/objects/subscription.rb +91 -0
- data/lib/eleven_rb/objects/user_info.rb +24 -0
- data/lib/eleven_rb/objects/voice.rb +86 -0
- data/lib/eleven_rb/objects/voice_settings.rb +41 -0
- data/lib/eleven_rb/resources/base.rb +84 -0
- data/lib/eleven_rb/resources/models.rb +65 -0
- data/lib/eleven_rb/resources/text_to_speech.rb +164 -0
- data/lib/eleven_rb/resources/user.rb +66 -0
- data/lib/eleven_rb/resources/voice_library.rb +160 -0
- data/lib/eleven_rb/resources/voices.rb +138 -0
- data/lib/eleven_rb/tts_adapter.rb +151 -0
- data/lib/eleven_rb/version.rb +5 -0
- data/lib/eleven_rb/voice_slot_manager.rb +184 -0
- data/lib/eleven_rb.rb +113 -0
- metadata +193 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Objects
|
|
5
|
+
# Base class for all response objects
|
|
6
|
+
#
|
|
7
|
+
# Provides attribute accessors and common functionality for
|
|
8
|
+
# parsing API responses into structured objects.
|
|
9
|
+
class Base
|
|
10
|
+
class << self
|
|
11
|
+
# Create an object from an API response hash
|
|
12
|
+
#
|
|
13
|
+
# @param response [Hash] the API response
|
|
14
|
+
# @return [Base] the object instance
|
|
15
|
+
def from_response(response)
|
|
16
|
+
new(response)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Define an attribute accessor
|
|
20
|
+
#
|
|
21
|
+
# @param name [Symbol] the attribute name
|
|
22
|
+
# @param key [String, nil] the JSON key (defaults to name.to_s)
|
|
23
|
+
# @param type [Class, Symbol, nil] optional type for conversion
|
|
24
|
+
def attribute(name, key: nil, type: nil)
|
|
25
|
+
key ||= name.to_s
|
|
26
|
+
|
|
27
|
+
define_method(name) do
|
|
28
|
+
value = @attributes[key]
|
|
29
|
+
return nil if value.nil?
|
|
30
|
+
|
|
31
|
+
case type
|
|
32
|
+
when :boolean
|
|
33
|
+
!!value
|
|
34
|
+
when Class
|
|
35
|
+
if value.is_a?(Array)
|
|
36
|
+
value.map { |v| type.from_response(v) }
|
|
37
|
+
else
|
|
38
|
+
type.from_response(value)
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
value
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Initialize with attributes hash
|
|
48
|
+
#
|
|
49
|
+
# @param attributes [Hash] the attributes
|
|
50
|
+
def initialize(attributes = {})
|
|
51
|
+
@attributes = attributes || {}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Return raw attributes hash
|
|
55
|
+
#
|
|
56
|
+
# @return [Hash]
|
|
57
|
+
def to_h
|
|
58
|
+
@attributes.dup
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Access raw attribute by key
|
|
62
|
+
#
|
|
63
|
+
# @param key [String, Symbol] the attribute key
|
|
64
|
+
# @return [Object, nil]
|
|
65
|
+
def [](key)
|
|
66
|
+
@attributes[key.to_s]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Check if attribute exists
|
|
70
|
+
#
|
|
71
|
+
# @param key [String, Symbol] the attribute key
|
|
72
|
+
# @return [Boolean]
|
|
73
|
+
def key?(key)
|
|
74
|
+
@attributes.key?(key.to_s)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Inspect the object
|
|
78
|
+
#
|
|
79
|
+
# @return [String]
|
|
80
|
+
def inspect
|
|
81
|
+
attrs = @attributes.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
|
|
82
|
+
"#<#{self.class.name} #{attrs}>"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Objects
|
|
5
|
+
# Cost information for TTS generation
|
|
6
|
+
class CostInfo
|
|
7
|
+
attr_reader :character_count, :voice_id, :model_id
|
|
8
|
+
|
|
9
|
+
# Approximate cost per 1000 characters by model
|
|
10
|
+
# These are estimates and may vary by subscription tier
|
|
11
|
+
COST_PER_1K_CHARS = {
|
|
12
|
+
'eleven_monolingual_v1' => 0.30,
|
|
13
|
+
'eleven_multilingual_v1' => 0.30,
|
|
14
|
+
'eleven_multilingual_v2' => 0.30,
|
|
15
|
+
'eleven_turbo_v2' => 0.18,
|
|
16
|
+
'eleven_turbo_v2_5' => 0.18,
|
|
17
|
+
'eleven_english_sts_v2' => 0.30,
|
|
18
|
+
'eleven_flash_v2' => 0.10,
|
|
19
|
+
'eleven_flash_v2_5' => 0.10
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
DEFAULT_COST_PER_1K = 0.30
|
|
23
|
+
|
|
24
|
+
# Initialize cost info
|
|
25
|
+
#
|
|
26
|
+
# @param text [String] the text being converted
|
|
27
|
+
# @param voice_id [String] the voice ID
|
|
28
|
+
# @param model_id [String] the model ID
|
|
29
|
+
def initialize(text:, voice_id:, model_id:)
|
|
30
|
+
@character_count = text.length
|
|
31
|
+
@voice_id = voice_id
|
|
32
|
+
@model_id = model_id
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Get estimated cost in USD
|
|
36
|
+
#
|
|
37
|
+
# @return [Float]
|
|
38
|
+
def estimated_cost
|
|
39
|
+
rate = COST_PER_1K_CHARS[model_id] || DEFAULT_COST_PER_1K
|
|
40
|
+
(character_count / 1000.0 * rate).round(4)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Get cost per character for this model
|
|
44
|
+
#
|
|
45
|
+
# @return [Float]
|
|
46
|
+
def cost_per_character
|
|
47
|
+
rate = COST_PER_1K_CHARS[model_id] || DEFAULT_COST_PER_1K
|
|
48
|
+
rate / 1000.0
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Check if this is a turbo/cheaper model
|
|
52
|
+
#
|
|
53
|
+
# @return [Boolean]
|
|
54
|
+
def turbo_model?
|
|
55
|
+
model_id&.include?('turbo') || model_id&.include?('flash')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Convert to hash
|
|
59
|
+
#
|
|
60
|
+
# @return [Hash]
|
|
61
|
+
def to_h
|
|
62
|
+
{
|
|
63
|
+
character_count: character_count,
|
|
64
|
+
voice_id: voice_id,
|
|
65
|
+
model_id: model_id,
|
|
66
|
+
estimated_cost: estimated_cost,
|
|
67
|
+
cost_per_character: cost_per_character
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Objects
|
|
5
|
+
# Represents a voice from the shared voice library
|
|
6
|
+
class LibraryVoice < Base
|
|
7
|
+
attribute :voice_id
|
|
8
|
+
attribute :public_owner_id
|
|
9
|
+
attribute :name
|
|
10
|
+
attribute :description
|
|
11
|
+
attribute :category
|
|
12
|
+
attribute :preview_url
|
|
13
|
+
attribute :gender
|
|
14
|
+
attribute :age
|
|
15
|
+
attribute :accent
|
|
16
|
+
attribute :language
|
|
17
|
+
attribute :locale
|
|
18
|
+
attribute :use_cases
|
|
19
|
+
attribute :notice_period
|
|
20
|
+
attribute :rate
|
|
21
|
+
attribute :cloned_by_count
|
|
22
|
+
attribute :usage_character_count_1d
|
|
23
|
+
attribute :usage_character_count_7d
|
|
24
|
+
attribute :usage_character_count_30d
|
|
25
|
+
attribute :free_users_allowed, type: :boolean
|
|
26
|
+
attribute :live_moderation_enabled, type: :boolean
|
|
27
|
+
attribute :verified, type: :boolean
|
|
28
|
+
|
|
29
|
+
# Get parameters needed to add this voice to account
|
|
30
|
+
#
|
|
31
|
+
# @return [Hash]
|
|
32
|
+
def add_params
|
|
33
|
+
{
|
|
34
|
+
public_user_id: public_owner_id,
|
|
35
|
+
voice_id: voice_id,
|
|
36
|
+
name: name
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Human-readable display name with metadata
|
|
41
|
+
#
|
|
42
|
+
# @return [String]
|
|
43
|
+
def display_name
|
|
44
|
+
parts = [name]
|
|
45
|
+
parts << "(#{gender})" if gender
|
|
46
|
+
parts << "- #{accent || language}" if accent || language
|
|
47
|
+
parts.join(' ')
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Check if this voice is popular (high usage)
|
|
51
|
+
#
|
|
52
|
+
# @param threshold [Integer] minimum usage count
|
|
53
|
+
# @return [Boolean]
|
|
54
|
+
def popular?(threshold: 10_000)
|
|
55
|
+
(usage_character_count_30d || 0) >= threshold
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Check if voice is available for free users
|
|
59
|
+
#
|
|
60
|
+
# @return [Boolean]
|
|
61
|
+
def available_for_free?
|
|
62
|
+
free_users_allowed != false
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Objects
|
|
5
|
+
# Represents an ElevenLabs TTS model
|
|
6
|
+
class Model < Base
|
|
7
|
+
attribute :model_id
|
|
8
|
+
attribute :name
|
|
9
|
+
attribute :description
|
|
10
|
+
attribute :can_be_finetuned, type: :boolean
|
|
11
|
+
attribute :can_do_text_to_speech, type: :boolean
|
|
12
|
+
attribute :can_do_voice_conversion, type: :boolean
|
|
13
|
+
attribute :can_use_style, type: :boolean
|
|
14
|
+
attribute :can_use_speaker_boost, type: :boolean
|
|
15
|
+
attribute :serves_pro_voices, type: :boolean
|
|
16
|
+
attribute :token_cost_factor
|
|
17
|
+
attribute :languages
|
|
18
|
+
attribute :max_characters_request_free_user
|
|
19
|
+
attribute :max_characters_request_subscribed_user
|
|
20
|
+
attribute :concurrency_group
|
|
21
|
+
|
|
22
|
+
# Check if this model supports a given language
|
|
23
|
+
#
|
|
24
|
+
# @param language_code [String] ISO language code
|
|
25
|
+
# @return [Boolean]
|
|
26
|
+
def supports_language?(language_code)
|
|
27
|
+
return false unless languages
|
|
28
|
+
|
|
29
|
+
languages.any? { |l| l['language_id'] == language_code }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Get list of supported language codes
|
|
33
|
+
#
|
|
34
|
+
# @return [Array<String>]
|
|
35
|
+
def supported_language_codes
|
|
36
|
+
return [] unless languages
|
|
37
|
+
|
|
38
|
+
languages.map { |l| l['language_id'] }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Check if this is a multilingual model
|
|
42
|
+
#
|
|
43
|
+
# @return [Boolean]
|
|
44
|
+
def multilingual?
|
|
45
|
+
name&.downcase&.include?('multilingual') || supported_language_codes.size > 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Check if this is a turbo/fast model
|
|
49
|
+
#
|
|
50
|
+
# @return [Boolean]
|
|
51
|
+
def turbo?
|
|
52
|
+
name&.downcase&.include?('turbo') || model_id&.include?('turbo')
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Objects
|
|
5
|
+
# Represents user subscription information
|
|
6
|
+
class Subscription < Base
|
|
7
|
+
attribute :tier
|
|
8
|
+
attribute :character_count
|
|
9
|
+
attribute :character_limit
|
|
10
|
+
attribute :voice_limit
|
|
11
|
+
attribute :professional_voice_limit
|
|
12
|
+
attribute :can_extend_character_limit, type: :boolean
|
|
13
|
+
attribute :allowed_to_extend_character_limit, type: :boolean
|
|
14
|
+
attribute :next_character_count_reset_unix
|
|
15
|
+
attribute :can_extend_voice_limit, type: :boolean
|
|
16
|
+
attribute :can_use_instant_voice_cloning, type: :boolean
|
|
17
|
+
attribute :can_use_professional_voice_cloning, type: :boolean
|
|
18
|
+
attribute :currency
|
|
19
|
+
attribute :status
|
|
20
|
+
|
|
21
|
+
# Get the number of voice slots currently used
|
|
22
|
+
# Note: This requires checking voices.list count
|
|
23
|
+
#
|
|
24
|
+
# @return [Integer, nil]
|
|
25
|
+
attr_accessor :voice_slots_used
|
|
26
|
+
|
|
27
|
+
# Set voice slots used (called by VoiceSlotManager)
|
|
28
|
+
#
|
|
29
|
+
# @param count [Integer]
|
|
30
|
+
|
|
31
|
+
# Get available voice slots
|
|
32
|
+
#
|
|
33
|
+
# @return [Integer, nil]
|
|
34
|
+
def voice_slots_available
|
|
35
|
+
return nil unless voice_limit && voice_slots_used
|
|
36
|
+
|
|
37
|
+
voice_limit - voice_slots_used
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Check if voice slots are full
|
|
41
|
+
#
|
|
42
|
+
# @return [Boolean]
|
|
43
|
+
def voice_slots_full?
|
|
44
|
+
return false unless voice_slots_available
|
|
45
|
+
|
|
46
|
+
voice_slots_available <= 0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Get remaining characters
|
|
50
|
+
#
|
|
51
|
+
# @return [Integer]
|
|
52
|
+
def characters_remaining
|
|
53
|
+
return 0 unless character_limit && character_count
|
|
54
|
+
|
|
55
|
+
character_limit - character_count
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Get percentage of characters used
|
|
59
|
+
#
|
|
60
|
+
# @return [Float]
|
|
61
|
+
def characters_used_percentage
|
|
62
|
+
return 0.0 unless character_limit&.positive?
|
|
63
|
+
|
|
64
|
+
(character_count.to_f / character_limit * 100).round(1)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Get next reset time as Time object
|
|
68
|
+
#
|
|
69
|
+
# @return [Time, nil]
|
|
70
|
+
def next_reset_at
|
|
71
|
+
return nil unless next_character_count_reset_unix
|
|
72
|
+
|
|
73
|
+
Time.at(next_character_count_reset_unix)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Check if subscription is active
|
|
77
|
+
#
|
|
78
|
+
# @return [Boolean]
|
|
79
|
+
def active?
|
|
80
|
+
status == 'active'
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Check if this is a free tier
|
|
84
|
+
#
|
|
85
|
+
# @return [Boolean]
|
|
86
|
+
def free?
|
|
87
|
+
tier&.downcase == 'free'
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Objects
|
|
5
|
+
# Represents user account information
|
|
6
|
+
class UserInfo < Base
|
|
7
|
+
attribute :user_id
|
|
8
|
+
attribute :email
|
|
9
|
+
attribute :first_name
|
|
10
|
+
attribute :is_new_user, type: :boolean
|
|
11
|
+
attribute :xi_api_key
|
|
12
|
+
attribute :can_use_delayed_payment_methods, type: :boolean
|
|
13
|
+
attribute :is_onboarding_completed, type: :boolean
|
|
14
|
+
attribute :is_onboarding_checklist_completed, type: :boolean
|
|
15
|
+
|
|
16
|
+
# Get full display name
|
|
17
|
+
#
|
|
18
|
+
# @return [String]
|
|
19
|
+
def display_name
|
|
20
|
+
first_name || email&.split('@')&.first || 'User'
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Objects
|
|
5
|
+
# Represents an ElevenLabs voice
|
|
6
|
+
class Voice < Base
|
|
7
|
+
attribute :voice_id
|
|
8
|
+
attribute :name
|
|
9
|
+
attribute :description
|
|
10
|
+
attribute :category
|
|
11
|
+
attribute :preview_url
|
|
12
|
+
attribute :labels
|
|
13
|
+
attribute :settings, type: VoiceSettings
|
|
14
|
+
attribute :samples
|
|
15
|
+
attribute :sharing
|
|
16
|
+
attribute :high_quality_base_model_ids
|
|
17
|
+
attribute :safety_control
|
|
18
|
+
|
|
19
|
+
# Get the gender from labels
|
|
20
|
+
#
|
|
21
|
+
# @return [String, nil]
|
|
22
|
+
def gender
|
|
23
|
+
labels&.dig('gender')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Get the accent from labels
|
|
27
|
+
#
|
|
28
|
+
# @return [String, nil]
|
|
29
|
+
def accent
|
|
30
|
+
labels&.dig('accent')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Get the language from labels
|
|
34
|
+
#
|
|
35
|
+
# @return [String, nil]
|
|
36
|
+
def language
|
|
37
|
+
labels&.dig('language')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Get the age from labels
|
|
41
|
+
#
|
|
42
|
+
# @return [String, nil]
|
|
43
|
+
def age
|
|
44
|
+
labels&.dig('age')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Get the use case from labels
|
|
48
|
+
#
|
|
49
|
+
# @return [String, nil]
|
|
50
|
+
def use_case
|
|
51
|
+
labels&.dig('use_case')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Check if this voice is banned
|
|
55
|
+
#
|
|
56
|
+
# @return [Boolean]
|
|
57
|
+
def banned?
|
|
58
|
+
safety_control == 'BAN'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Provider identifier for wrapper compatibility
|
|
62
|
+
#
|
|
63
|
+
# @return [Symbol]
|
|
64
|
+
def provider
|
|
65
|
+
:elevenlabs
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Alias for voice_id for wrapper compatibility
|
|
69
|
+
#
|
|
70
|
+
# @return [String]
|
|
71
|
+
def provider_voice_id
|
|
72
|
+
voice_id
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Human-readable display name with metadata
|
|
76
|
+
#
|
|
77
|
+
# @return [String]
|
|
78
|
+
def display_name
|
|
79
|
+
parts = [name]
|
|
80
|
+
parts << "(#{gender})" if gender
|
|
81
|
+
parts << "- #{accent || language}" if accent || language
|
|
82
|
+
parts.join(' ')
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Objects
|
|
5
|
+
# Voice settings for TTS generation
|
|
6
|
+
class VoiceSettings < Base
|
|
7
|
+
attribute :stability
|
|
8
|
+
attribute :similarity_boost
|
|
9
|
+
attribute :style
|
|
10
|
+
attribute :use_speaker_boost, type: :boolean
|
|
11
|
+
|
|
12
|
+
# Default settings for TTS generation
|
|
13
|
+
DEFAULTS = {
|
|
14
|
+
stability: 0.5,
|
|
15
|
+
similarity_boost: 0.75,
|
|
16
|
+
style: 0.0,
|
|
17
|
+
use_speaker_boost: true
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
# Create settings with defaults merged in
|
|
21
|
+
#
|
|
22
|
+
# @param overrides [Hash] settings to override defaults
|
|
23
|
+
# @return [VoiceSettings]
|
|
24
|
+
def self.with_defaults(overrides = {})
|
|
25
|
+
from_response(DEFAULTS.merge(overrides))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Convert to hash suitable for API request
|
|
29
|
+
#
|
|
30
|
+
# @return [Hash]
|
|
31
|
+
def to_api_hash
|
|
32
|
+
{
|
|
33
|
+
stability: stability,
|
|
34
|
+
similarity_boost: similarity_boost,
|
|
35
|
+
style: style,
|
|
36
|
+
use_speaker_boost: use_speaker_boost
|
|
37
|
+
}.compact
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Resources
|
|
5
|
+
# Base class for API resources
|
|
6
|
+
class Base
|
|
7
|
+
attr_reader :http_client
|
|
8
|
+
|
|
9
|
+
# Initialize resource
|
|
10
|
+
#
|
|
11
|
+
# @param http_client [HTTP::Client]
|
|
12
|
+
def initialize(http_client)
|
|
13
|
+
@http_client = http_client
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Make a GET request
|
|
19
|
+
#
|
|
20
|
+
# @param path [String]
|
|
21
|
+
# @param params [Hash]
|
|
22
|
+
# @return [Hash, Array]
|
|
23
|
+
def get(path, params = {})
|
|
24
|
+
http_client.get(path, params)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Make a POST request
|
|
28
|
+
#
|
|
29
|
+
# @param path [String]
|
|
30
|
+
# @param body [Hash]
|
|
31
|
+
# @param response_type [Symbol]
|
|
32
|
+
# @return [Hash, Array, String]
|
|
33
|
+
def post(path, body = {}, response_type: :json)
|
|
34
|
+
http_client.post(path, body, response_type: response_type)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Make a DELETE request
|
|
38
|
+
#
|
|
39
|
+
# @param path [String]
|
|
40
|
+
# @return [Hash]
|
|
41
|
+
def delete(path)
|
|
42
|
+
http_client.delete(path)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Make a binary POST request
|
|
46
|
+
#
|
|
47
|
+
# @param path [String]
|
|
48
|
+
# @param body [Hash]
|
|
49
|
+
# @return [String]
|
|
50
|
+
def post_binary(path, body = {})
|
|
51
|
+
http_client.post(path, body, response_type: :binary)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Make a streaming POST request
|
|
55
|
+
#
|
|
56
|
+
# @param path [String]
|
|
57
|
+
# @param body [Hash]
|
|
58
|
+
# @yield [String] chunk
|
|
59
|
+
def post_stream(path, body = {}, &block)
|
|
60
|
+
http_client.post_stream(path, body, &block)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Make a multipart POST request
|
|
64
|
+
#
|
|
65
|
+
# @param path [String]
|
|
66
|
+
# @param params [Hash]
|
|
67
|
+
# @return [Hash]
|
|
68
|
+
def post_multipart(path, params)
|
|
69
|
+
http_client.post_multipart(path, params)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Validate presence of a value
|
|
73
|
+
#
|
|
74
|
+
# @param value [Object]
|
|
75
|
+
# @param name [String]
|
|
76
|
+
# @raise [Errors::ValidationError]
|
|
77
|
+
def validate_presence!(value, name)
|
|
78
|
+
return unless value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
|
79
|
+
|
|
80
|
+
raise Errors::ValidationError, "#{name} cannot be blank"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ElevenRb
|
|
4
|
+
module Resources
|
|
5
|
+
# Models resource
|
|
6
|
+
#
|
|
7
|
+
# @example List all models
|
|
8
|
+
# models = client.models.list
|
|
9
|
+
#
|
|
10
|
+
# @example Find multilingual models
|
|
11
|
+
# client.models.multilingual
|
|
12
|
+
class Models < Base
|
|
13
|
+
# List all available models
|
|
14
|
+
#
|
|
15
|
+
# @return [Array<Objects::Model>]
|
|
16
|
+
def list
|
|
17
|
+
response = get('/models')
|
|
18
|
+
response.map { |m| Objects::Model.from_response(m) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Get a specific model by ID
|
|
22
|
+
#
|
|
23
|
+
# @param model_id [String] the model ID
|
|
24
|
+
# @return [Objects::Model, nil]
|
|
25
|
+
def get(model_id)
|
|
26
|
+
list.find { |m| m.model_id == model_id }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Get all multilingual models
|
|
30
|
+
#
|
|
31
|
+
# @return [Array<Objects::Model>]
|
|
32
|
+
def multilingual
|
|
33
|
+
list.select(&:multilingual?)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Get all turbo/fast models
|
|
37
|
+
#
|
|
38
|
+
# @return [Array<Objects::Model>]
|
|
39
|
+
def turbo
|
|
40
|
+
list.select(&:turbo?)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Get models that support TTS
|
|
44
|
+
#
|
|
45
|
+
# @return [Array<Objects::Model>]
|
|
46
|
+
def tts_capable
|
|
47
|
+
list.select(&:can_do_text_to_speech)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Get the default/recommended model for TTS
|
|
51
|
+
#
|
|
52
|
+
# @return [Objects::Model, nil]
|
|
53
|
+
def default
|
|
54
|
+
get('eleven_multilingual_v2') || tts_capable.first
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Get model IDs as array
|
|
58
|
+
#
|
|
59
|
+
# @return [Array<String>]
|
|
60
|
+
def ids
|
|
61
|
+
list.map(&:model_id)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|