Skip to content

Commit b26193a

Browse files
ElevenLabs-DotNet 3.4.2 (#78)
- Added flash models - Added stream input support to dubbing endpoint - Fixed http/https protocol in client settings --------- Co-authored-by: Austin Hale <32556981+austinbhale@users.noreply.github.com>
1 parent 9884433 commit b26193a

File tree

9 files changed

+190
-25
lines changed

9 files changed

+190
-25
lines changed

.github/workflows/Publish-Nuget.yml

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Nuget Publish
1+
name: Build and Publish
22

33
on:
44
push:
@@ -22,23 +22,36 @@ on:
2222
dotnet-version:
2323
description: ".NET version to use"
2424
required: false
25-
default: "6.0.x"
25+
default: "8.x"
26+
27+
permissions:
28+
contents: read
29+
pages: write
30+
checks: write
31+
id-token: write
32+
pull-requests: write
33+
34+
concurrency:
35+
group: ${{ github.workflow }}-${{ github.ref }}
36+
cancel-in-progress: false
2637

2738
env:
28-
DOTNET_VERSION: ${{ github.event.inputs.dotnet-version || '6.0.x' }}
29-
PACKAGE_VERSION: ''
39+
DOTNET_VERSION: ${{ github.event.inputs.dotnet-version || '8.x' }}
3040

3141
jobs:
3242
build:
3343
if: ${{ !github.event_name == 'pull_request' || !github.event.pull_request.draft }}
44+
env:
45+
PACKAGE_VERSION: ''
46+
COVERAGE_FILE_PATH: ''
3447
runs-on: ubuntu-latest
3548

3649
steps:
3750
- uses: actions/checkout@v4
3851
with:
3952
fetch-depth: 0
4053

41-
- uses: actions/setup-dotnet@v3
54+
- uses: actions/setup-dotnet@v4
4255
with:
4356
dotnet-version: ${{ env.DOTNET_VERSION }}
4457

@@ -61,11 +74,18 @@ jobs:
6174
report_individual_runs: true
6275
compare_to_earlier_commit: false
6376

77+
- name: Determine Coverage File Path
78+
if: ${{ github.ref != 'refs/heads/main' && github.event_name != 'push' && always() }}
79+
shell: bash
80+
run: |
81+
COVERAGE_FILE_PATH=$(find ./test-results -name 'coverage.cobertura.xml' | head -n 1)
82+
echo "COVERAGE_FILE_PATH=$COVERAGE_FILE_PATH" >> $GITHUB_ENV
83+
6484
- name: Code Coverage Summary Report
6585
if: ${{ github.ref != 'refs/heads/main' && github.event_name != 'push' && always() }}
6686
uses: irongut/CodeCoverageSummary@v1.3.0
6787
with:
68-
filename: test-results/**/coverage.cobertura.xml
88+
filename: ${{ env.COVERAGE_FILE_PATH }}
6989
badge: true
7090
format: 'markdown'
7191
output: 'both'
@@ -114,7 +134,7 @@ jobs:
114134
echo "PACKAGE_VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
115135
shell: pwsh
116136

117-
- uses: actions/upload-artifact@v3
137+
- uses: actions/upload-artifact@v4
118138
if: always()
119139
with:
120140
name: ElevenLabs-DotNet.${{ env.PACKAGE_VERSION }}
@@ -124,3 +144,33 @@ jobs:
124144
${{ github.workspace }}/ElevenLabs-DotNet/bin/Release/ElevenLabs-DotNet-Proxy.${{ env.PACKAGE_VERSION }}.nupkg
125145
${{ github.workspace }}/ElevenLabs-DotNet/bin/Release/ElevenLabs-DotNet-Proxy.${{ env.PACKAGE_VERSION }}.symbols.nupkg
126146
if-no-files-found: ignore
147+
148+
docs:
149+
if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }}
150+
needs: build
151+
environment:
152+
name: github-pages
153+
url: ${{ steps.deployment.outputs.page_url }}
154+
runs-on: ubuntu-latest
155+
156+
steps:
157+
- uses: actions/checkout@v4
158+
with:
159+
fetch-depth: 0
160+
161+
- uses: actions/setup-dotnet@v4
162+
with:
163+
dotnet-version: ${{ env.DOTNET_VERSION }}
164+
165+
- name: build docfx
166+
run: |
167+
dotnet tool update -g docfx
168+
docfx .docs/docfx.json
169+
170+
- uses: actions/upload-pages-artifact@v3
171+
with:
172+
path: '_site'
173+
174+
- name: Deploy to GitHub Pages
175+
id: deployment
176+
uses: actions/deploy-pages@v4.0.3

ElevenLabs-DotNet/Authentication/ElevenLabsClientSettings.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace ElevenLabs
66
{
77
public sealed class ElevenLabsClientSettings
88
{
9+
internal const string Http = "http://";
910
internal const string Https = "https://";
1011
internal const string DefaultApiVersion = "v1";
1112
internal const string ElevenLabsDomain = "api.elevenlabs.io";
@@ -44,7 +45,20 @@ public ElevenLabsClientSettings(string domain, string apiVersion = DefaultApiVer
4445
apiVersion = DefaultApiVersion;
4546
}
4647

47-
Domain = domain.Contains("http") ? domain : $"{Https}{domain}";
48+
var protocol = Https;
49+
50+
if (domain.StartsWith(Http))
51+
{
52+
protocol = Http;
53+
domain = domain.Replace(Http, string.Empty);
54+
}
55+
else if (domain.StartsWith(Https))
56+
{
57+
protocol = Https;
58+
domain = domain.Replace(Https, string.Empty);
59+
}
60+
61+
Domain = $"{protocol}{domain}";
4862
ApiVersion = apiVersion;
4963
BaseRequest = $"/{ApiVersion}/";
5064
BaseRequestUrlFormat = $"{Domain}{BaseRequest}{{0}}";

ElevenLabs-DotNet/Dubbing/DubbingEndpoint.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ public async Task<DubbingProjectMetadata> DubAsync(DubbingRequest request, int?
3838
{
3939
if (request.Files != null)
4040
{
41-
foreach (var (fileName, mediaType, stream) in request.Files)
41+
foreach (var dub in request.Files)
4242
{
43-
await payload.AppendFileToFormAsync("file", stream, fileName, new(mediaType), cancellationToken);
43+
await payload.AppendFileToFormAsync("file", dub.Stream, dub.Name, new(dub.MediaType), cancellationToken);
4444
}
4545
}
4646

ElevenLabs-DotNet/Dubbing/DubbingRequest.cs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public DubbingRequest(
3636
bool? dropBackgroundAudio = null,
3737
bool? useProfanityFilter = null,
3838
string projectName = null)
39-
: this(targetLanguage, null, filePaths, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName)
39+
: this(targetLanguage, null, null, filePaths, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName)
4040
{
4141
}
4242

@@ -52,13 +52,30 @@ public DubbingRequest(
5252
bool? dropBackgroundAudio = null,
5353
bool? useProfanityFilter = null,
5454
string projectName = null)
55-
: this(targetLanguage, sourceUrl, null, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName)
55+
: this(targetLanguage, sourceUrl, null, null, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName)
56+
{
57+
}
58+
59+
public DubbingRequest(
60+
List<DubbingStream> files,
61+
string targetLanguage,
62+
string sourceLanguage = null,
63+
int? numberOfSpeakers = null,
64+
bool? watermark = null,
65+
int? startTime = null,
66+
int? endTime = null,
67+
bool? highestResolution = null,
68+
bool? dropBackgroundAudio = null,
69+
bool? useProfanityFilter = null,
70+
string projectName = null)
71+
: this(targetLanguage, null, files, null, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName)
5672
{
5773
}
5874

5975
private DubbingRequest(
6076
string targetLanguage,
6177
Uri sourceUrl = null,
78+
List<DubbingStream> files = null,
6279
IEnumerable<string> filePaths = null,
6380
string sourceLanguage = null,
6481
int? numberOfSpeakers = null,
@@ -78,7 +95,7 @@ private DubbingRequest(
7895
throw new ArgumentException("Either sourceUrl or filePaths must be provided.");
7996
}
8097

81-
var files = new List<(string, string, Stream)>();
98+
files ??= [];
8299

83100
if (filePaths != null)
84101
{
@@ -113,7 +130,7 @@ private DubbingRequest(
113130
".webm" => "video/webm",
114131
_ => "application/octet-stream"
115132
};
116-
files.Add((fileInfo.Name, mediaType, stream));
133+
files.Add(new(stream, fileInfo.Name, mediaType));
117134
}
118135
}
119136

@@ -135,7 +152,7 @@ private DubbingRequest(
135152
/// <summary>
136153
/// Files to dub.
137154
/// </summary>
138-
public IReadOnlyList<(string, string, Stream)> Files { get; }
155+
public IReadOnlyList<DubbingStream> Files { get; }
139156

140157
/// <summary>
141158
/// URL of the source video/audio file.
@@ -204,12 +221,12 @@ private void Dispose(bool disposing)
204221
if (disposing)
205222
{
206223
if (Files == null) { return; }
207-
foreach (var (_, _, stream) in Files)
224+
225+
foreach (var dub in Files)
208226
{
209227
try
210228
{
211-
stream?.Close();
212-
stream?.Dispose();
229+
dub.Dispose();
213230
}
214231
catch (Exception e)
215232
{
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Licensed under the MIT License. See LICENSE in the project root for license information.
2+
3+
using System;
4+
using System.IO;
5+
6+
namespace ElevenLabs.Dubbing
7+
{
8+
public sealed class DubbingStream : IDisposable
9+
{
10+
public DubbingStream(Stream stream, string name, string mediaType)
11+
{
12+
Stream = stream ?? throw new ArgumentNullException(nameof(stream));
13+
14+
if (Stream.Length == 0)
15+
{
16+
throw new ArgumentException("Stream cannot be empty.");
17+
}
18+
19+
if (!Stream.CanRead)
20+
{
21+
throw new ArgumentException("Stream must be readable.");
22+
}
23+
24+
Name = name ?? throw new ArgumentNullException(nameof(name));
25+
26+
if (string.IsNullOrWhiteSpace(Name))
27+
{
28+
throw new ArgumentException("Name cannot be empty.");
29+
}
30+
31+
MediaType = mediaType ?? throw new ArgumentNullException(nameof(mediaType));
32+
33+
if (string.IsNullOrWhiteSpace(MediaType))
34+
{
35+
throw new ArgumentException("Media type cannot be empty.");
36+
}
37+
38+
if (MediaType.Contains("/"))
39+
{
40+
var parts = MediaType.Split('/');
41+
42+
if (parts.Length != 2 || string.IsNullOrWhiteSpace(parts[0]) || string.IsNullOrWhiteSpace(parts[1]))
43+
{
44+
throw new ArgumentException("Invalid media type.");
45+
}
46+
}
47+
else
48+
{
49+
throw new ArgumentException("Invalid media type.");
50+
}
51+
}
52+
53+
public Stream Stream { get; }
54+
55+
public string Name { get; }
56+
57+
public string MediaType { get; }
58+
59+
public void Dispose()
60+
{
61+
Stream?.Dispose();
62+
}
63+
}
64+
}

ElevenLabs-DotNet/ElevenLabs-DotNet.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ All copyrights, trademarks, logos, and assets are the property of their respecti
2525
<SignAssembly>false</SignAssembly>
2626
<IncludeSymbols>true</IncludeSymbols>
2727
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
28-
<Version>3.4.1</Version>
28+
<Version>3.4.2</Version>
2929
<PackageReleaseNotes>
30+
Version 3.4.2
31+
- Added flash models
32+
- Added stream input support to dubbing endpoint
33+
- Fixed http/https protocol in client settings
3034
Version 3.4.1
3135
- Removed text length check in TextToSpeechRequest
3236
Version 3.4.0

ElevenLabs-DotNet/Models/Model.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ public Model(string id)
5151

5252
#region Predefined Models
5353

54+
/// <summary>
55+
/// Our latest, ultra-low-latency model, generating speech in under 75ms. Best for developer use cases requiring speed and multiple languages.
56+
/// </summary>
57+
[JsonIgnore]
58+
public static Model FlashV2 { get; } = new("eleven_flash_v2");
59+
60+
/// <summary>
61+
/// Our latest, ultra-low-latency English only model, generating speech in under 75ms. Best for developer use cases requiring speed.
62+
/// </summary>
63+
[JsonIgnore]
64+
public static Model FlashV2_5 { get; } = new("eleven_flash_v2_5");
65+
5466
[JsonIgnore]
5567
[Obsolete("Use EnglishV1")]
5668
public static Model MonoLingualV1 => EnglishV1;

ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public TextToSpeechRequest(string text, Model model, VoiceSettings voiceSettings
3030
/// Optional, <see cref="VoiceSettings"/> that will override the default settings in <see cref="Voice.Settings"/>.
3131
/// </param>
3232
/// <param name="model">
33-
/// Optional, <see cref="Model"/> to use. Defaults to <see cref="Model.TurboV2_5"/>.
33+
/// Optional, <see cref="Model"/> to use. Defaults to <see cref="Model.FlashV2"/>.
3434
/// </param>
3535
/// <param name="outputFormat">
3636
/// Output format of the generated audio.<br/>
@@ -52,7 +52,7 @@ public TextToSpeechRequest(string text, Model model, VoiceSettings voiceSettings
5252
/// <param name="previousRequestIds"></param>
5353
/// <param name="nextRequestIds"></param>
5454
/// <param name="languageCode">
55-
/// Optional, Language code (ISO 639-1) used to enforce a language for the model. Currently only <see cref="Model.TurboV2_5"/> supports language enforcement.
55+
/// Optional, Language code (ISO 639-1) used to enforce a language for the model. Currently only <see cref="Model.TurboV2_5"/> supports language enforcement.
5656
/// For other models, an error will be returned if language code is provided.
5757
/// </param>
5858
/// <param name="withTimestamps"></param>
@@ -88,7 +88,7 @@ public TextToSpeechRequest(
8888
}
8989

9090
Text = text;
91-
Model = model ?? Models.Model.TurboV2_5;
91+
Model = model ?? Models.Model.FlashV2;
9292
Voice = voice;
9393
VoiceSettings = voiceSettings ?? voice.Settings;
9494
OutputFormat = outputFormat;

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ dotnet add package ElevenLabs-DotNet
3838
3939
---
4040

41-
## Documentation
41+
## [Documentation](https://rageagainstthepixel.github.io/ElevenLabs-DotNet)
42+
43+
> Check out our new api docs!
44+
45+
<https://rageagainstthepixel.github.io/ElevenLabs-DotNet>
4246

4347
### Table of Contents
4448

@@ -239,7 +243,7 @@ Gets a list of shared voices in the public voice library.
239243

240244
```csharp
241245
var api = new ElevenLabsClient();
242-
var results = await ElevenLabsClient.SharedVoicesEndpoint.GetSharedVoicesAsync();
246+
var results = await api.SharedVoicesEndpoint.GetSharedVoicesAsync();
243247
foreach (var voice in results.Voices)
244248
{
245249
Console.WriteLine($"{voice.OwnerId} | {voice.VoiceId} | {voice.Date} | {voice.Name}");
@@ -391,7 +395,7 @@ var assetsDir = Path.GetFullPath("../../../Assets");
391395
var dubbedPath = new FileInfo(Path.Combine(assetsDir, $"online.dubbed.{request.TargetLanguage}.mp4"));
392396
{
393397
await using var fs = File.Open(dubbedPath.FullName, FileMode.Create);
394-
await foreach (var chunk in ElevenLabsClient.DubbingEndpoint.GetDubbedFileAsync(metadata.DubbingId, request.TargetLanguage))
398+
await foreach (var chunk in api.DubbingEndpoint.GetDubbedFileAsync(metadata.DubbingId, request.TargetLanguage))
395399
{
396400
await fs.WriteAsync(chunk);
397401
}

0 commit comments

Comments
 (0)