Skip to content

Commit 5060287

Browse files
com.rest.elevenlabs 3.3.0 (#86)
- Added ability to specify fully customizable domain proxies - Added env var parsing for `ELEVENLABS_API_KEY` - Added Copy Button for the Voice ID to Voice Lab Dashboard - Added Shared Voices API - Added SoundEffects API endpoints - Added Dubbing API endpoints - Updated models - Updated com.utilities.rest -> 2.5.7 --------- Co-authored-by: AmarTrivedi1 <149634562+AmarTrivedi1@users.noreply.github.com>
1 parent 2493b06 commit 5060287

File tree

54 files changed

+1710
-86
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1710
-86
lines changed

Documentation~/README.md

Lines changed: 115 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ The recommended installation method is though the unity package manager and [Ope
4848

4949
### Table of Contents
5050

51-
- [Authentication](#authentication) :construction:
51+
- [Authentication](#authentication)
5252
- [API Proxy](#api-proxy)
5353
- [Editor Dashboard](#editor-dashboard)
5454
- [Speech Synthesis Dashboard](#speech-synthesis-dashboard)
@@ -59,6 +59,7 @@ The recommended installation method is though the unity package manager and [Ope
5959
- [Text to Speech](#text-to-speech)
6060
- [Stream Text To Speech](#stream-text-to-speech)
6161
- [Voices](#voices)
62+
- [Get Shared Voices](#get-shared-voices) :new:
6263
- [Get All Voices](#get-all-voices)
6364
- [Get Default Voice Settings](#get-default-voice-settings)
6465
- [Get Voice](#get-voice)
@@ -69,6 +70,13 @@ The recommended installation method is though the unity package manager and [Ope
6970
- [Samples](#samples)
7071
- [Download Voice Sample](#download-voice-sample)
7172
- [Delete Voice Sample](#delete-voice-sample)
73+
- [Dubbing](#dubbing) :new:
74+
- [Dub](#dub) :new:
75+
- [Get Dubbing Metadata](#get-dubbing-metadata) :new:
76+
- [Get Transcript for Dub](#get-transcript-for-dub) :new:
77+
- [Get dubbed file](#get-dubbed-file) :new:
78+
- [Delete Dubbing Project](#delete-dubbing-project) :new:
79+
- [SFX Generation](#sfx-generation) :new:
7280
- [History](#history)
7381
- [Get History](#get-history)
7482
- [Get History Item](#get-history-item)
@@ -176,8 +184,9 @@ In this example, we demonstrate how to set up and use `ElevenLabsProxyStartup` i
176184
1. Create a new [ASP.NET Core minimal web API](https://learn.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-6.0) project.
177185
2. Add the ElevenLabs-DotNet nuget package to your project.
178186
- Powershell install: `Install-Package ElevenLabs-DotNet-Proxy`
187+
- Dotnet install: `dotnet add package ElevenLabs-DotNet-Proxy`
179188
- Manually editing .csproj: `<PackageReference Include="ElevenLabs-DotNet-Proxy" />`
180-
3. Create a new class that inherits from `AbstractAuthenticationFilter` and override the `ValidateAuthentication` method. This will implement the `IAuthenticationFilter` that you will use to check user session token against your internal server.
189+
3. Create a new class that inherits from `AbstractAuthenticationFilter` and override the `ValidateAuthenticationAsync` method. This will implement the `IAuthenticationFilter` that you will use to check user session token against your internal server.
181190
4. In `Program.cs`, create a new proxy web application by calling `ElevenLabsProxyStartup.CreateDefaultHost` method, passing your custom `AuthenticationFilter` as a type argument.
182191
5. Create `ElevenLabsAuthentication` and `ElevenLabsClientSettings` as you would normally with your API keys, org id, or Azure settings.
183192

@@ -186,11 +195,13 @@ public partial class Program
186195
{
187196
private class AuthenticationFilter : AbstractAuthenticationFilter
188197
{
189-
public override void ValidateAuthentication(IHeaderDictionary request)
198+
public override async Task ValidateAuthenticationAsync(IHeaderDictionary request)
190199
{
200+
await Task.CompletedTask; // remote resource call
201+
191202
// You will need to implement your own class to properly test
192203
// custom issued tokens you've setup for your end users.
193-
if (!request["xi-api-key"].ToString().Contains(userToken))
204+
if (!request["xi-api-key"].ToString().Contains(TestUserToken))
194205
{
195206
throw new AuthenticationException("User is not authorized");
196207
}
@@ -265,7 +276,9 @@ audioSource.PlayOneShot(voiceClip.AudioClip);
265276
voiceClip.CopyIntoProject(editorDownloadDirectory);
266277
```
267278

268-
### Stream Text to Speech
279+
#### [Stream Text To Speech](https://docs.elevenlabs.io/api-reference/text-to-speech-stream)
280+
281+
Stream text to speech.
269282

270283
```csharp
271284
var api = new ElevenLabsClient();
@@ -289,6 +302,19 @@ audioSource.clip = voiceClip.AudioClip;
289302

290303
Access to voices created either by the user or ElevenLabs.
291304

305+
#### Get Shared Voices
306+
307+
Gets a list of shared voices in the public voice library.
308+
309+
```csharp
310+
var api = new ElevenLabsClient();
311+
var results = await ElevenLabsClient.SharedVoicesEndpoint.GetSharedVoicesAsync();
312+
foreach (var voice in results.Voices)
313+
{
314+
Debug.Log($"{voice.OwnerId} | {voice.VoiceId} | {voice.Date} | {voice.Name}");
315+
}
316+
```
317+
292318
#### Get All Voices
293319

294320
Gets a list of all available voices.
@@ -383,6 +409,87 @@ var success = await api.VoicesEndpoint.DeleteVoiceSampleAsync(voiceId, sampleId)
383409
Debug.Log($"Was successful? {success}");
384410
```
385411

412+
### [Dubbing](https://elevenlabs.io/docs/api-reference/create-dub)
413+
414+
#### Dub
415+
416+
Dubs provided audio or video file into given language.
417+
418+
```csharp
419+
var api = new ElevenLabsClient();
420+
// from URI
421+
var request = new DubbingRequest(new Uri("https://youtu.be/Zo5-rhYOlNk"), "ja", "en", 1, true);
422+
// from file
423+
var request = new DubbingRequest(filePath, "es", "en", 1);
424+
var metadata = await api.DubbingEndpoint.DubAsync(request, progress: new Progress<DubbingProjectMetadata>(metadata =>
425+
{
426+
switch (metadata.Status)
427+
{
428+
case "dubbing":
429+
Debug.Log($"Dubbing for {metadata.DubbingId} in progress... Expected Duration: {metadata.ExpectedDurationSeconds:0.00} seconds");
430+
break;
431+
case "dubbed":
432+
Debug.Log($"Dubbing for {metadata.DubbingId} complete in {metadata.TimeCompleted.TotalSeconds:0.00} seconds!");
433+
break;
434+
default:
435+
Debug.Log($"Status: {metadata.Status}");
436+
break;
437+
}
438+
}));
439+
```
440+
441+
#### Get Dubbing Metadata
442+
443+
Returns metadata about a dubbing project, including whether it’s still in progress or not.
444+
445+
```csharp
446+
var api = new ElevenLabsClient();
447+
var metadata = api.await GetDubbingProjectMetadataAsync("dubbing-id");
448+
```
449+
450+
#### Get Dubbed File
451+
452+
Returns downloaded dubbed file path.
453+
454+
> [!IMPORTANT]
455+
> Videos will be returned in MP4 format and audio only dubs will be returned in MP3.
456+
457+
```csharp
458+
var dubbedClipPath = await ElevenLabsClient.DubbingEndpoint.GetDubbedFileAsync(metadata.DubbingId, request.TargetLanguage);
459+
var dubbedClip = await Rest.DownloadAudioClipAsync($"file://{dubbedClipPath}", AudioType.MPEG);
460+
audioSource.PlayOneShot(dubbedClip);
461+
```
462+
463+
#### Get Transcript for Dub
464+
465+
Returns transcript for the dub in the desired format.
466+
467+
```csharp
468+
var srcFile = new FileInfo(audioPath);
469+
var transcriptPath = new FileInfo($"{srcFile.FullName}.dubbed.{request.TargetLanguage}.srt");
470+
var transcriptFile = await ElevenLabsClient.DubbingEndpoint.GetTranscriptForDubAsync(metadata.DubbingId, request.TargetLanguage);
471+
await File.WriteAllTextAsync(transcriptPath.FullName, transcriptFile);
472+
```
473+
474+
#### Delete Dubbing Project
475+
476+
Deletes a dubbing project.
477+
478+
```csharp
479+
var api = new ElevenLabsClient();
480+
await api.DubbingEndpoint.DeleteDubbingProjectAsync("dubbing-id");
481+
```
482+
483+
### SFX Generation
484+
485+
API that converts text into sounds & uses the most advanced AI audio model ever.
486+
487+
```csharp
488+
var api = new ElevenLabsClient();
489+
var request = new SoundGenerationRequest("Star Wars Light Saber parry");
490+
var clip = await api.SoundGenerationEndpoint.GenerateSoundAsync(request);
491+
```
492+
386493
### [History](https://docs.elevenlabs.io/api-reference/history)
387494

388495
Access to your previously synthesized audio clips including its metadata.
@@ -393,9 +500,9 @@ Get metadata about all your generated audio.
393500

394501
```csharp
395502
var api = new ElevenLabsClient();
396-
var historyInfo = await api.HistoryEndpoint.GetHistoryAsync();
503+
var historyItems = await api.HistoryEndpoint.GetHistoryAsync();
397504

398-
foreach (var item in historyInfo.HistoryItems.OrderBy(item => item.Date))
505+
foreach (var item in historyItems.OrderBy(historyItem => historyItem.Date))
399506
{
400507
Debug.Log($"{item.State} {item.Date} | {item.Id} | {item.Text.Length} | {item.Text}");
401508
}
@@ -407,7 +514,7 @@ Get information about a specific item.
407514

408515
```csharp
409516
var api = new ElevenLabsClient();
410-
var historyItem = api.HistoryEndpoint.GetHistoryItemAsync(voiceClip.Id);
517+
var historyItem = await api.HistoryEndpoint.GetHistoryItemAsync(voiceClip.Id);
411518
```
412519

413520
#### Download History Audio

Editor/ElevenLabsDashboard.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// Licensed under the MIT License. See LICENSE in the project root for license information.
22

3-
using ElevenLabs.Extensions;
43
using ElevenLabs.History;
54
using ElevenLabs.Models;
65
using ElevenLabs.User;
@@ -363,6 +362,8 @@ private async void AddVoice()
363362

364363
private static readonly GUIContent deleteContent = new("Delete");
365364

365+
private static readonly GUIContent copyContent = new("Copy");
366+
366367
private static readonly GUIContent refreshContent = new("Refresh");
367368

368369
private static readonly GUIContent downloadingContent = new("Download in progress...");
@@ -1224,8 +1225,24 @@ private void RenderVoiceLab()
12241225
EditorGUILayout.Space(EndWidth);
12251226
EditorGUILayout.EndHorizontal();
12261227
EditorGUI.indentLevel++;
1227-
EditorGUILayout.LabelField(voice.Id, EditorStyles.boldLabel);
1228+
1229+
EditorGUILayout.BeginHorizontal();
1230+
{
1231+
EditorGUILayout.LabelField(voice.Id, EditorStyles.boldLabel);
1232+
GUILayout.FlexibleSpace();
1233+
1234+
if (GUILayout.Button(copyContent, defaultColumnWidthOption))
1235+
{
1236+
EditorGUIUtility.systemCopyBuffer = voice.Id;
1237+
Debug.Log($"Voice ID {voice.Id} copied to clipboard");
1238+
}
12281239

1240+
GUI.enabled = true;
1241+
}
1242+
EditorGUILayout.Space(EndWidth);
1243+
EditorGUILayout.EndHorizontal();
1244+
EditorGUI.indentLevel++;
1245+
12291246
if (!voiceLabels.TryGetValue(voice.Id, out var cachedLabels))
12301247
{
12311248
cachedLabels = new Dictionary<string, string>();

Runtime/Authentication/ElevenLabsAuthentication.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace ElevenLabs
1414
public sealed class ElevenLabsAuthentication : AbstractAuthentication<ElevenLabsAuthentication, ElevenLabsAuthInfo, ElevenLabsConfiguration>
1515
{
1616
internal const string CONFIG_FILE = ".elevenlabs";
17+
private const string ELEVENLABS_API_KEY = nameof(ELEVENLABS_API_KEY);
1718
private const string ELEVEN_LABS_API_KEY = nameof(ELEVEN_LABS_API_KEY);
1819

1920
/// <summary>
@@ -85,6 +86,12 @@ public override ElevenLabsAuthentication LoadFromAsset(ElevenLabsConfiguration c
8586
public override ElevenLabsAuthentication LoadFromEnvironment()
8687
{
8788
var apiKey = Environment.GetEnvironmentVariable(ELEVEN_LABS_API_KEY);
89+
90+
if (string.IsNullOrWhiteSpace(apiKey))
91+
{
92+
apiKey = Environment.GetEnvironmentVariable(ELEVENLABS_API_KEY);
93+
}
94+
8895
return string.IsNullOrEmpty(apiKey) ? null : new ElevenLabsAuthentication(apiKey);
8996
}
9097

@@ -136,6 +143,7 @@ public override ElevenLabsAuthentication LoadFromDirectory(string directory = nu
136143

137144
apiKey = part switch
138145
{
146+
ELEVENLABS_API_KEY => nextPart.Trim(),
139147
ELEVEN_LABS_API_KEY => nextPart.Trim(),
140148
_ => apiKey
141149
};

Runtime/Authentication/ElevenLabsSettingsInfo.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace ElevenLabs
77
{
88
public sealed class ElevenLabsSettingsInfo : ISettingsInfo
99
{
10+
internal const string Https = "https://";
1011
internal const string ElevenLabsDomain = "api.elevenlabs.io";
1112
internal const string DefaultApiVersion = "v1";
1213

@@ -18,7 +19,7 @@ public ElevenLabsSettingsInfo()
1819
Domain = ElevenLabsDomain;
1920
ApiVersion = DefaultApiVersion;
2021
BaseRequest = $"/{ApiVersion}/";
21-
BaseRequestUrlFormat = $"https://{Domain}{BaseRequest}{{0}}";
22+
BaseRequestUrlFormat = $"{Https}{Domain}{BaseRequest}{{0}}";
2223
}
2324

2425
/// <summary>
@@ -33,8 +34,8 @@ public ElevenLabsSettingsInfo(string domain, string apiVersion = DefaultApiVersi
3334
domain = ElevenLabsDomain;
3435
}
3536

36-
if (!domain.Contains(".") &&
37-
!domain.Contains(":"))
37+
if (!domain.Contains('.') &&
38+
!domain.Contains(':'))
3839
{
3940
throw new ArgumentException($"Invalid parameter \"{nameof(domain)}\".");
4041
}
@@ -44,10 +45,10 @@ public ElevenLabsSettingsInfo(string domain, string apiVersion = DefaultApiVersi
4445
apiVersion = DefaultApiVersion;
4546
}
4647

47-
Domain = domain;
48+
Domain = domain.Contains("http") ? domain : $"{Https}{domain}";
4849
ApiVersion = apiVersion;
4950
BaseRequest = $"/{ApiVersion}/";
50-
BaseRequestUrlFormat = $"https://{Domain}{BaseRequest}{{0}}";
51+
BaseRequestUrlFormat = $"{Domain}{BaseRequest}{{0}}";
5152
}
5253

5354
public string Domain { get; }

Runtime/Common/GeneratedClip.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Licensed under the MIT License. See LICENSE in the project root for license information.
2+
3+
using ElevenLabs.Extensions;
4+
using System;
5+
using UnityEngine;
6+
using UnityEngine.Scripting;
7+
8+
namespace ElevenLabs
9+
{
10+
[Preserve]
11+
[Serializable]
12+
public class GeneratedClip : ISerializationCallbackReceiver
13+
{
14+
[Preserve]
15+
internal GeneratedClip(string id, string text, AudioClip audioClip, string cachedPath)
16+
{
17+
this.id = id;
18+
this.text = text;
19+
TextHash = $"{id}{text}".GenerateGuid();
20+
textHash = TextHash.ToString();
21+
this.audioClip = audioClip;
22+
this.cachedPath = cachedPath;
23+
}
24+
25+
[SerializeField]
26+
private string id;
27+
28+
[Preserve]
29+
public string Id => id;
30+
31+
[SerializeField]
32+
private string text;
33+
34+
[Preserve]
35+
public string Text => text;
36+
37+
[SerializeField]
38+
private string textHash;
39+
40+
[Preserve]
41+
public Guid TextHash { get; private set; }
42+
43+
[SerializeField]
44+
private AudioClip audioClip;
45+
46+
[Preserve]
47+
public AudioClip AudioClip => audioClip;
48+
49+
[SerializeField]
50+
private string cachedPath;
51+
52+
[Preserve]
53+
public string CachedPath => cachedPath;
54+
55+
public void OnBeforeSerialize() => textHash = TextHash.ToString();
56+
57+
public void OnAfterDeserialize() => TextHash = Guid.Parse(textHash);
58+
}
59+
}

Runtime/Common/GeneratedClip.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)