elevenlabs 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/README.md +234 -0
- data/lib/elevenlabs/client.rb +291 -0
- data/lib/elevenlabs/errors.rb +11 -0
- data/lib/elevenlabs.rb +24 -0
- metadata +62 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c2b887df23210fbd0b7c0d2e75e667ffb46ab4c47400f8db1915b60b8984adca
|
|
4
|
+
data.tar.gz: 51287a55127cfa42b10d0e01a5463a6bd14db42bae6e6f16a36ee6884ba359a7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: '048e8939495f6e7e25920c3bcf88d9b17779435f79f56df03f057a86eec7069211eafafce8fc329046121b6df764ef8e595f45c6e5068d546654e4b29593b517'
|
|
7
|
+
data.tar.gz: 9e72052b4ef1371c3ba9790df2716c9a3d55645f40b58c39295ef01fb0e7f26c6420517f7b8e65af9aa92c64f0222ca36077d92595818ac2c7f7576acaff37d9
|
data/README.md
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Elevenlabs Ruby Gem
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/elevenlabs)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A **Ruby client** for the [ElevenLabs](https://elevenlabs.io/) **Text-to-Speech API**.
|
|
7
|
+
This gem provides an easy-to-use interface for:
|
|
8
|
+
|
|
9
|
+
- **Listing available voices**
|
|
10
|
+
- **Fetching details about a voice**
|
|
11
|
+
- **Creating a custom voice** (with uploaded sample files)
|
|
12
|
+
- **Editing an existing voice**
|
|
13
|
+
- **Deleting a voice**
|
|
14
|
+
- **Converting text to speech** and retrieving the generated audio
|
|
15
|
+
|
|
16
|
+
All requests are handled via [Faraday](https://github.com/lostisland/faraday).
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Table of Contents
|
|
21
|
+
|
|
22
|
+
- [Features](#features)
|
|
23
|
+
- [Installation](#installation)
|
|
24
|
+
- [Usage](#usage)
|
|
25
|
+
- [Basic Example](#basic-example)
|
|
26
|
+
- [Rails Integration](#rails-integration)
|
|
27
|
+
- [Store API Key in Rails Credentials](#store-api-key-in-rails-credentials)
|
|
28
|
+
- [Rails Initializer](#rails-initializer)
|
|
29
|
+
- [Controller Example](#controller-example)
|
|
30
|
+
- [Endpoints](#endpoints)
|
|
31
|
+
- [Error Handling](#error-handling)
|
|
32
|
+
- [Development](#development)
|
|
33
|
+
- [Contributing](#contributing)
|
|
34
|
+
- [License](#license)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- **Simple and intuitive API client** for ElevenLabs.
|
|
41
|
+
- **Multipart file uploads** for training custom voices.
|
|
42
|
+
- **Automatic authentication** via API key configuration.
|
|
43
|
+
- **Error handling** with custom exceptions.
|
|
44
|
+
- **Rails integration support** (including credentials storage).
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
Add the gem to your `Gemfile`:
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
gem "elevenlabs", "~> 0.0.1"
|
|
54
|
+
```
|
|
55
|
+
Then run:
|
|
56
|
+
```ruby
|
|
57
|
+
bundle install
|
|
58
|
+
```
|
|
59
|
+
Or install it directly using:
|
|
60
|
+
```ruby
|
|
61
|
+
gem install elevenlabs
|
|
62
|
+
```
|
|
63
|
+
Usage
|
|
64
|
+
Basic Example (Standalone Ruby)
|
|
65
|
+
```ruby
|
|
66
|
+
require "elevenlabs"
|
|
67
|
+
|
|
68
|
+
# 1. Configure the gem globally (Optional)
|
|
69
|
+
Elevenlabs.configure do |config|
|
|
70
|
+
config.api_key = "YOUR_API_KEY"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# 2. Initialize a client (will use configured API key)
|
|
74
|
+
client = Elevenlabs::Client.new
|
|
75
|
+
|
|
76
|
+
# 3. List available voices
|
|
77
|
+
voices = client.list_voices
|
|
78
|
+
puts voices # JSON response with voices
|
|
79
|
+
|
|
80
|
+
# 4. Convert text to speech
|
|
81
|
+
voice_id = "YOUR_VOICE_ID"
|
|
82
|
+
text = "Hello from Elevenlabs!"
|
|
83
|
+
audio_data = client.text_to_speech(voice_id, text)
|
|
84
|
+
|
|
85
|
+
# 5. Save the audio file
|
|
86
|
+
File.open("output.mp3", "wb") { |f| f.write(audio_data) }
|
|
87
|
+
puts "Audio file saved to output.mp3"
|
|
88
|
+
```
|
|
89
|
+
Note: You can override the API key per request:
|
|
90
|
+
```ruby
|
|
91
|
+
client = Elevenlabs::Client.new(api_key: "DIFFERENT_API_KEY")
|
|
92
|
+
```
|
|
93
|
+
Rails Integration
|
|
94
|
+
Store API Key in Rails Credentials
|
|
95
|
+
1. Open your encrypted credentials:
|
|
96
|
+
```ruby
|
|
97
|
+
EDITOR=vim rails credentials:edit
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
2. Add the ElevenLabs API key:
|
|
101
|
+
```ruby
|
|
102
|
+
eleven_labs:
|
|
103
|
+
api_key: YOUR_SECURE_KEY
|
|
104
|
+
```
|
|
105
|
+
3. Save and exit. Rails will securely encrypt your API key.
|
|
106
|
+
|
|
107
|
+
Rails Initializer
|
|
108
|
+
Create an initializer file: config/initializers/elevenlabs.rb
|
|
109
|
+
```ruby
|
|
110
|
+
# config/initializers/elevenlabs.rb
|
|
111
|
+
require "elevenlabs"
|
|
112
|
+
|
|
113
|
+
Rails.application.config.to_prepare do
|
|
114
|
+
Elevenlabs.configure do |config|
|
|
115
|
+
config.api_key = Rails.application.credentials.dig(:eleven_labs, :api_key)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
```
|
|
119
|
+
Now you can simply call:
|
|
120
|
+
```ruby
|
|
121
|
+
client = Elevenlabs::Client.new
|
|
122
|
+
```
|
|
123
|
+
without manually providing an API key.
|
|
124
|
+
|
|
125
|
+
Endpoints
|
|
126
|
+
1. List Voices
|
|
127
|
+
```ruby
|
|
128
|
+
client.list_voices
|
|
129
|
+
# => { "voices" => [...] }
|
|
130
|
+
```
|
|
131
|
+
2. Get Voice Details
|
|
132
|
+
```ruby
|
|
133
|
+
client.get_voice("VOICE_ID")
|
|
134
|
+
# => { "voice_id" => "...", "name" => "...", ... }
|
|
135
|
+
```
|
|
136
|
+
3. Create a Custom Voice
|
|
137
|
+
```ruby
|
|
138
|
+
sample_files = [File.open("sample1.mp3", "rb")]
|
|
139
|
+
client.create_voice("Custom Voice", sample_files, description: "My custom AI voice")
|
|
140
|
+
# => JSON response with new voice details
|
|
141
|
+
```
|
|
142
|
+
4. Check if a voice is banned?
|
|
143
|
+
```ruby
|
|
144
|
+
sample_files = [File.open("trump.mp3", "rb")]
|
|
145
|
+
client.create_voice("Donald Trump", sample_files, description: "My Trump Voice")
|
|
146
|
+
=> {"voice_id"=>"<RETURNED_VOICE_ID>", "requires_verification"=>false}
|
|
147
|
+
trump= "<RETURNED_VOICE_ID>"
|
|
148
|
+
client.banned? trump
|
|
149
|
+
=> true
|
|
150
|
+
```
|
|
151
|
+
5. Edit a Voice
|
|
152
|
+
```ruby
|
|
153
|
+
client.edit_voice("VOICE_ID", name: "Updated Voice Name")
|
|
154
|
+
# => JSON response with updated details
|
|
155
|
+
```
|
|
156
|
+
6. Delete a Voice
|
|
157
|
+
```ruby
|
|
158
|
+
client.delete_voice("VOICE_ID")
|
|
159
|
+
# => JSON response acknowledging deletion
|
|
160
|
+
```
|
|
161
|
+
7. Convert Text to Speech
|
|
162
|
+
```ruby
|
|
163
|
+
audio_data = client.text_to_speech("VOICE_ID", "Hello world!")
|
|
164
|
+
File.open("output.mp3", "wb") { |f| f.write(audio_data) }
|
|
165
|
+
```
|
|
166
|
+
8 Stream Text to Speech
|
|
167
|
+
stream from terminal
|
|
168
|
+
```ruby
|
|
169
|
+
Mac: brew install sox
|
|
170
|
+
Linux: sudo apt install sox
|
|
171
|
+
|
|
172
|
+
IO.popen("play -t mp3 -", "wb") do |audio_pipe| # Notice "wb" (write binary)
|
|
173
|
+
client.text_to_speech_stream("VOICE_ID", "Some text to stream back in chunks") do |chunk|
|
|
174
|
+
audio_pipe.write(chunk.b) # Ensure chunk is written as binary
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Error Handling
|
|
180
|
+
When the API returns an error, the gem raises specific exceptions:
|
|
181
|
+
|
|
182
|
+
Exception Meaning
|
|
183
|
+
Elevenlabs::BadRequestError Invalid request parameters
|
|
184
|
+
Elevenlabs::AuthenticationError Invalid API key
|
|
185
|
+
Elevenlabs::NotFoundError Resource (voice) not found
|
|
186
|
+
Elevenlabs::APIError General API failure
|
|
187
|
+
Example:
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
begin
|
|
191
|
+
client.text_to_speech("INVALID_VOICE_ID", "Test")
|
|
192
|
+
rescue Elevenlabs::AuthenticationError => e
|
|
193
|
+
puts "Invalid API key: #{e.message}"
|
|
194
|
+
rescue Elevenlabs::NotFoundError => e
|
|
195
|
+
puts "Voice not found: #{e.message}"
|
|
196
|
+
rescue Elevenlabs::APIError => e
|
|
197
|
+
puts "General error: #{e.message}"
|
|
198
|
+
end
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Development
|
|
202
|
+
Clone this repository
|
|
203
|
+
```bash
|
|
204
|
+
git clone https://github.com/your-username/elevenlabs.git
|
|
205
|
+
cd elevenlabs
|
|
206
|
+
```
|
|
207
|
+
Install dependencies
|
|
208
|
+
```bash
|
|
209
|
+
bundle install
|
|
210
|
+
```
|
|
211
|
+
Build the gem
|
|
212
|
+
```bash
|
|
213
|
+
gem build elevenlabs.gemspec
|
|
214
|
+
```
|
|
215
|
+
Install the gem locally
|
|
216
|
+
```bash
|
|
217
|
+
gem install ./elevenlabs-0.0.1.gem
|
|
218
|
+
```
|
|
219
|
+
Contributing
|
|
220
|
+
Contributions are welcome! Please follow these steps:
|
|
221
|
+
|
|
222
|
+
Fork the repository
|
|
223
|
+
Create a feature branch (git checkout -b feature/my-new-feature)
|
|
224
|
+
Commit your changes (git commit -am 'Add new feature')
|
|
225
|
+
Push to your branch (git push origin feature/my-new-feature)
|
|
226
|
+
Create a Pull Request describing your changes
|
|
227
|
+
For bug reports, please open an issue with details.
|
|
228
|
+
|
|
229
|
+
License
|
|
230
|
+
This project is licensed under the MIT License. See the LICENSE file for details.
|
|
231
|
+
|
|
232
|
+
⭐ Thank you for using the Elevenlabs Ruby Gem!
|
|
233
|
+
If you have any questions or suggestions, feel free to open an issue or submit a Pull Request!
|
|
234
|
+
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "faraday"
|
|
4
|
+
require "faraday/multipart"
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module Elevenlabs
|
|
8
|
+
class Client
|
|
9
|
+
BASE_URL = "https://api.elevenlabs.io"
|
|
10
|
+
|
|
11
|
+
# Note the default param: `api_key: nil`
|
|
12
|
+
def initialize(api_key: nil)
|
|
13
|
+
# If the caller doesn’t provide an api_key, use the gem-wide config
|
|
14
|
+
@api_key = api_key || Elevenlabs.configuration&.api_key
|
|
15
|
+
|
|
16
|
+
@connection = Faraday.new(url: BASE_URL) do |conn|
|
|
17
|
+
conn.request :url_encoded
|
|
18
|
+
conn.response :raise_error
|
|
19
|
+
conn.adapter Faraday.default_adapter
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
#####################################################
|
|
24
|
+
# Text-to-Speech #
|
|
25
|
+
# (POST /v1/text-to-speech/{voice_id}) #
|
|
26
|
+
#####################################################
|
|
27
|
+
|
|
28
|
+
# Convert text to speech and retrieve audio (binary data)
|
|
29
|
+
# Documentation: https://elevenlabs.io/docs/api-reference/text-to-speech/convert
|
|
30
|
+
#
|
|
31
|
+
# @param [String] voice_id - the ID of the voice to use
|
|
32
|
+
# @param [String] text - text to synthesize
|
|
33
|
+
# @param [Hash] options - optional TTS parameters
|
|
34
|
+
# :model_id => String (e.g. "eleven_monolingual_v1" or "eleven_multilingual_v1")
|
|
35
|
+
# :voice_settings => Hash (stability, similarity_boost, style, use_speaker_boost, etc.)
|
|
36
|
+
# :optimize_streaming => Boolean (whether to receive chunked streaming audio)
|
|
37
|
+
#
|
|
38
|
+
# @return [String] The binary audio data (usually an MP3).
|
|
39
|
+
def text_to_speech(voice_id, text, options = {})
|
|
40
|
+
endpoint = "/v1/text-to-speech/#{voice_id}"
|
|
41
|
+
request_body = { text: text }
|
|
42
|
+
|
|
43
|
+
# If user provided voice_settings, add them
|
|
44
|
+
if options[:voice_settings]
|
|
45
|
+
request_body[:voice_settings] = options[:voice_settings]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# If user specified a model_id, add it
|
|
49
|
+
request_body[:model_id] = options[:model_id] if options[:model_id]
|
|
50
|
+
|
|
51
|
+
# If user wants streaming optimization
|
|
52
|
+
headers = default_headers
|
|
53
|
+
if options[:optimize_streaming]
|
|
54
|
+
headers["Accept"] = "audio/mpeg"
|
|
55
|
+
headers["Transfer-Encoding"] = "chunked"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
response = @connection.post(endpoint) do |req|
|
|
59
|
+
req.headers = headers
|
|
60
|
+
req.body = request_body.to_json
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Returns raw binary data (often MP3)
|
|
64
|
+
response.body
|
|
65
|
+
rescue Faraday::ClientError => e
|
|
66
|
+
handle_error(e)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
#####################################################
|
|
70
|
+
# Text-to-Speech-Stream #
|
|
71
|
+
# (POST /v1/text-to-speech/{voice_id})/stream #
|
|
72
|
+
#####################################################
|
|
73
|
+
def text_to_speech_stream(voice_id, text, options = {}, &block)
|
|
74
|
+
endpoint = "/v1/text-to-speech/#{voice_id}/stream?output_format=mp3_44100_128"
|
|
75
|
+
request_body = { text: text, model_id: options[:model_id] || "eleven_multilingual_v2" }
|
|
76
|
+
|
|
77
|
+
headers = default_headers
|
|
78
|
+
headers["Accept"] = "audio/mpeg"
|
|
79
|
+
|
|
80
|
+
response = @connection.post(endpoint, request_body.to_json, headers) do |req|
|
|
81
|
+
req.options.on_data = Proc.new do |chunk, _|
|
|
82
|
+
block.call(chunk) if block_given?
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
response
|
|
87
|
+
rescue Faraday::ClientError => e
|
|
88
|
+
handle_error(e)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
#####################################################
|
|
93
|
+
# GET Voices #
|
|
94
|
+
# (GET /v1/voices) #
|
|
95
|
+
#####################################################
|
|
96
|
+
|
|
97
|
+
# Retrieves all voices associated with your Elevenlabs account
|
|
98
|
+
# Documentation: https://elevenlabs.io/docs/api-reference/voices
|
|
99
|
+
#
|
|
100
|
+
# @return [Hash] The JSON response containing an array of voices
|
|
101
|
+
def list_voices
|
|
102
|
+
endpoint = "/v1/voices"
|
|
103
|
+
response = @connection.get(endpoint) do |req|
|
|
104
|
+
req.headers = default_headers
|
|
105
|
+
end
|
|
106
|
+
JSON.parse(response.body)
|
|
107
|
+
rescue Faraday::ClientError => e
|
|
108
|
+
handle_error(e)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
#####################################################
|
|
112
|
+
# GET a Single Voice #
|
|
113
|
+
# (GET /v1/voices/{voice_id}) #
|
|
114
|
+
#####################################################
|
|
115
|
+
|
|
116
|
+
# Retrieves details about a single voice
|
|
117
|
+
#
|
|
118
|
+
# @param [String] voice_id
|
|
119
|
+
# @return [Hash] Details of the voice
|
|
120
|
+
def get_voice(voice_id)
|
|
121
|
+
endpoint = "/v1/voices/#{voice_id}"
|
|
122
|
+
response = @connection.get(endpoint) do |req|
|
|
123
|
+
req.headers = default_headers
|
|
124
|
+
end
|
|
125
|
+
JSON.parse(response.body)
|
|
126
|
+
rescue Faraday::ClientError => e
|
|
127
|
+
handle_error(e)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
#####################################################
|
|
131
|
+
# Create a Voice #
|
|
132
|
+
# (POST /v1/voices/add) #
|
|
133
|
+
#####################################################
|
|
134
|
+
|
|
135
|
+
# Creates a new voice
|
|
136
|
+
# @param [String] name - name of the voice
|
|
137
|
+
# @param [File] samples - array of files to train the voice
|
|
138
|
+
# @param [Hash] options - additional parameters
|
|
139
|
+
# :description => String
|
|
140
|
+
#
|
|
141
|
+
# NOTE: This method may require a multipart form request
|
|
142
|
+
# if you are uploading sample audio files.
|
|
143
|
+
def create_voice(name, samples = [], options = {})
|
|
144
|
+
endpoint = "/v1/voices/add"
|
|
145
|
+
|
|
146
|
+
# Ensure Faraday handles multipart form data
|
|
147
|
+
mp_connection = Faraday.new(url: BASE_URL) do |conn|
|
|
148
|
+
conn.request :multipart
|
|
149
|
+
conn.response :raise_error
|
|
150
|
+
conn.adapter Faraday.default_adapter
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Build multipart form parameters
|
|
154
|
+
form_params = {
|
|
155
|
+
"name" => name,
|
|
156
|
+
"description" => options[:description] || ""
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# Convert File objects to multipart upload format
|
|
160
|
+
sample_files = []
|
|
161
|
+
samples.each_with_index do |sample_file, i|
|
|
162
|
+
sample_files << ["files", Faraday::UploadIO.new(sample_file.path, "audio/mpeg")]
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Perform the POST request
|
|
166
|
+
response = mp_connection.post(endpoint) do |req|
|
|
167
|
+
req.headers["xi-api-key"] = @api_key
|
|
168
|
+
req.body = form_params.merge(sample_files.to_h)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
JSON.parse(response.body)
|
|
172
|
+
rescue Faraday::ClientError => e
|
|
173
|
+
handle_error(e)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
#####################################################
|
|
178
|
+
# Edit a Voice #
|
|
179
|
+
# (POST /v1/voices/{voice_id}/edit) #
|
|
180
|
+
#####################################################
|
|
181
|
+
# Updates an existing voice
|
|
182
|
+
# @param [String] voice_id
|
|
183
|
+
# @param [Array<File>] samples
|
|
184
|
+
# @param [Hash] options
|
|
185
|
+
# options[:name] [String] name
|
|
186
|
+
# options[:description] [String] description
|
|
187
|
+
|
|
188
|
+
def edit_voice(voice_id, samples = [], options = {})
|
|
189
|
+
endpoint = "/v1/voices/#{voice_id}/edit"
|
|
190
|
+
|
|
191
|
+
# Force text fields to be strings.
|
|
192
|
+
form_params = {
|
|
193
|
+
"name" => options[:name].to_s,
|
|
194
|
+
"description" => (options[:description] || "").to_s
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
form_params["files[]"] = samples.map do |sample_file|
|
|
198
|
+
Faraday::UploadIO.new(sample_file.path, "audio/mpeg", File.basename(sample_file.path))
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
mp_connection = Faraday.new(url: BASE_URL) do |conn|
|
|
202
|
+
conn.request :multipart
|
|
203
|
+
conn.response :raise_error
|
|
204
|
+
conn.adapter Faraday.default_adapter
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
response = mp_connection.post(endpoint) do |req|
|
|
208
|
+
req.headers["xi-api-key"] = @api_key
|
|
209
|
+
req.body = form_params
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
JSON.parse(response.body)
|
|
213
|
+
rescue Faraday::ClientError => e
|
|
214
|
+
handle_error(e)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
#####################################################
|
|
218
|
+
# Delete a Voice #
|
|
219
|
+
# (DELETE /v1/voices/{voice_id}) #
|
|
220
|
+
#####################################################
|
|
221
|
+
|
|
222
|
+
# Deletes a voice from your account
|
|
223
|
+
# @param [String] voice_id
|
|
224
|
+
# @return [Hash] response
|
|
225
|
+
def delete_voice(voice_id)
|
|
226
|
+
endpoint = "/v1/voices/#{voice_id}"
|
|
227
|
+
response = @connection.delete(endpoint) do |req|
|
|
228
|
+
req.headers = default_headers
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
JSON.parse(response.body)
|
|
232
|
+
rescue Faraday::ClientError => e
|
|
233
|
+
handle_error(e)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
#####################################################
|
|
237
|
+
# Banned Voice Check #
|
|
238
|
+
#####################################################
|
|
239
|
+
|
|
240
|
+
# Checks safety control on a single voice for "BAN"
|
|
241
|
+
#
|
|
242
|
+
# @param [String] voice_id
|
|
243
|
+
# @return [Boolean]
|
|
244
|
+
def banned?(voice_id)
|
|
245
|
+
voice = get_voice(voice_id)
|
|
246
|
+
voice["safety_control"] == "BAN"
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
#####################################################
|
|
250
|
+
# Active Voice Check #
|
|
251
|
+
#####################################################
|
|
252
|
+
|
|
253
|
+
# Checks if a voice_id is in list_voices
|
|
254
|
+
#
|
|
255
|
+
# @param [String] voice_id
|
|
256
|
+
# @return [Boolean]
|
|
257
|
+
def active?(voice_id)
|
|
258
|
+
active_voices = list_voices["voices"].map{|voice| voice["voice_id"]}
|
|
259
|
+
voice_id.in?(active_voices)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
private
|
|
263
|
+
|
|
264
|
+
# Common headers needed by Elevenlabs
|
|
265
|
+
def default_headers
|
|
266
|
+
{
|
|
267
|
+
"xi-api-key" => @api_key,
|
|
268
|
+
"Content-Type" => "application/json"
|
|
269
|
+
}
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Error handling
|
|
273
|
+
def handle_error(exception)
|
|
274
|
+
status = exception.response[:status] rescue nil
|
|
275
|
+
body = exception.response[:body] rescue "{}"
|
|
276
|
+
error_info = JSON.parse(body) rescue {}
|
|
277
|
+
|
|
278
|
+
detail = error_info["detail"]
|
|
279
|
+
simple_message = detail.is_a?(Hash) ? detail["message"] || detail.to_s : detail.to_s
|
|
280
|
+
|
|
281
|
+
case status
|
|
282
|
+
when 400 then raise BadRequestError, simple_message
|
|
283
|
+
when 401 then raise AuthenticationError, simple_message
|
|
284
|
+
when 404 then raise NotFoundError, simple_message
|
|
285
|
+
else
|
|
286
|
+
raise APIError, simple_message
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Elevenlabs
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
class APIError < Error; end
|
|
6
|
+
class AuthenticationError < Error; end
|
|
7
|
+
class NotFoundError < Error; end
|
|
8
|
+
class BadRequestError < Error; end
|
|
9
|
+
# ... add more as needed ...
|
|
10
|
+
end
|
|
11
|
+
|
data/lib/elevenlabs.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# lib/elevenlabs.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "elevenlabs/client"
|
|
5
|
+
require_relative "elevenlabs/errors"
|
|
6
|
+
|
|
7
|
+
module Elevenlabs
|
|
8
|
+
VERSION = "0.0.1"
|
|
9
|
+
|
|
10
|
+
# Optional global configuration
|
|
11
|
+
class << self
|
|
12
|
+
attr_accessor :configuration
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.configure
|
|
16
|
+
self.configuration ||= Configuration.new
|
|
17
|
+
yield(configuration)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Configuration
|
|
21
|
+
attr_accessor :api_key
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
metadata
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: elevenlabs
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- hackliteracy
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-02-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: faraday
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.0'
|
|
27
|
+
description: This gem provides a convenient Ruby interface to the ElevenLabs TTS,
|
|
28
|
+
Voice Cloning, and Streaming endpoints.
|
|
29
|
+
email:
|
|
30
|
+
- hackliteracy@gmail.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- README.md
|
|
36
|
+
- lib/elevenlabs.rb
|
|
37
|
+
- lib/elevenlabs/client.rb
|
|
38
|
+
- lib/elevenlabs/errors.rb
|
|
39
|
+
homepage: https://github.com/ktamulonis/elevenlabs
|
|
40
|
+
licenses:
|
|
41
|
+
- MIT
|
|
42
|
+
metadata: {}
|
|
43
|
+
post_install_message:
|
|
44
|
+
rdoc_options: []
|
|
45
|
+
require_paths:
|
|
46
|
+
- lib
|
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '2.5'
|
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '0'
|
|
57
|
+
requirements: []
|
|
58
|
+
rubygems_version: 3.5.23
|
|
59
|
+
signing_key:
|
|
60
|
+
specification_version: 4
|
|
61
|
+
summary: A Ruby client for the ElevenLabs Text-to-Speech API
|
|
62
|
+
test_files: []
|