From 5e471581afb651782d5e6e796b5f9ed11b603e8e Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Sat, 11 Jan 2025 12:07:44 -0500 Subject: [PATCH 1/8] ElevenLabs-DotNet 3.4.2 - Added flash models - Fixed http/https protocol in client settings --- .../Authentication/ElevenLabsClientSettings.cs | 16 +++++++++++++++- ElevenLabs-DotNet/ElevenLabs-DotNet.csproj | 5 ++++- ElevenLabs-DotNet/Models/Model.cs | 12 ++++++++++++ .../TextToSpeech/TextToSpeechRequest.cs | 4 ++-- README.md | 2 +- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/ElevenLabs-DotNet/Authentication/ElevenLabsClientSettings.cs b/ElevenLabs-DotNet/Authentication/ElevenLabsClientSettings.cs index c876e39..b0b2b72 100644 --- a/ElevenLabs-DotNet/Authentication/ElevenLabsClientSettings.cs +++ b/ElevenLabs-DotNet/Authentication/ElevenLabsClientSettings.cs @@ -6,6 +6,7 @@ namespace ElevenLabs { public sealed class ElevenLabsClientSettings { + internal const string Http = "http://"; internal const string Https = "https://"; internal const string DefaultApiVersion = "v1"; internal const string ElevenLabsDomain = "api.elevenlabs.io"; @@ -44,7 +45,20 @@ public ElevenLabsClientSettings(string domain, string apiVersion = DefaultApiVer apiVersion = DefaultApiVersion; } - Domain = domain.Contains("http") ? domain : $"{Https}{domain}"; + var protocol = Https; + + if (domain.StartsWith(Http)) + { + protocol = Http; + domain = domain.Replace(Http, string.Empty); + } + else if (domain.StartsWith(Https)) + { + protocol = Https; + domain = domain.Replace(Https, string.Empty); + } + + Domain = $"{protocol}{domain}"; ApiVersion = apiVersion; BaseRequest = $"/{ApiVersion}/"; BaseRequestUrlFormat = $"{Domain}{BaseRequest}{{0}}"; diff --git a/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj b/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj index f2eada9..0bffdfb 100644 --- a/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj +++ b/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj @@ -25,8 +25,11 @@ All copyrights, trademarks, logos, and assets are the property of their respecti false true true - 3.4.1 + 3.4.2 +Version 3.4.2 +- Added flash models +- Fixed http/https protocol in client settings Version 3.4.1 - Removed text length check in TextToSpeechRequest Version 3.4.0 diff --git a/ElevenLabs-DotNet/Models/Model.cs b/ElevenLabs-DotNet/Models/Model.cs index a1bf3c7..2d864c3 100644 --- a/ElevenLabs-DotNet/Models/Model.cs +++ b/ElevenLabs-DotNet/Models/Model.cs @@ -51,6 +51,18 @@ public Model(string id) #region Predefined Models + /// + /// Our latest, ultra-low-latency model, generating speech in under 75ms. Best for developer use cases requiring speed and multiple languages. + /// + [JsonIgnore] + public static Model FlashV2 { get; } = new("eleven_flash_v2"); + + /// + /// Our latest, ultra-low-latency English only model, generating speech in under 75ms. Best for developer use cases requiring speed. + /// + [JsonIgnore] + public static Model FlashV2_5 { get; } = new("eleven_flash_v2_5"); + [JsonIgnore] [Obsolete("Use EnglishV1")] public static Model MonoLingualV1 => EnglishV1; diff --git a/ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs b/ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs index f5f2f4a..78a8126 100644 --- a/ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs +++ b/ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs @@ -52,7 +52,7 @@ public TextToSpeechRequest(string text, Model model, VoiceSettings voiceSettings /// /// /// - /// Optional, Language code (ISO 639-1) used to enforce a language for the model. Currently only supports language enforcement. + /// Optional, Language code (ISO 639-1) used to enforce a language for the model. Currently only supports language enforcement. /// For other models, an error will be returned if language code is provided. /// /// @@ -88,7 +88,7 @@ public TextToSpeechRequest( } Text = text; - Model = model ?? Models.Model.TurboV2_5; + Model = model ?? Models.Model.FlashV2; Voice = voice; VoiceSettings = voiceSettings ?? voice.Settings; OutputFormat = outputFormat; diff --git a/README.md b/README.md index d1741b3..3270132 100644 --- a/README.md +++ b/README.md @@ -239,7 +239,7 @@ Gets a list of shared voices in the public voice library. ```csharp var api = new ElevenLabsClient(); -var results = await ElevenLabsClient.SharedVoicesEndpoint.GetSharedVoicesAsync(); +var results = await api.SharedVoicesEndpoint.GetSharedVoicesAsync(); foreach (var voice in results.Voices) { Console.WriteLine($"{voice.OwnerId} | {voice.VoiceId} | {voice.Date} | {voice.Name}"); From d803be8582c776d37f581a621fd70c122f0b7fd4 Mon Sep 17 00:00:00 2001 From: Austin Hale <32556981+austinbhale@users.noreply.github.com> Date: Sat, 11 Jan 2025 09:08:59 -0800 Subject: [PATCH 2/8] feat: add overload to accept streams in the dubbing endpoint (#74) Allows files to be streamed directly. This gives more flexibility when handling files that are privately hosted or not accessible via standard file paths or Uris. --- ElevenLabs-DotNet/Dubbing/DubbingRequest.cs | 23 ++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/ElevenLabs-DotNet/Dubbing/DubbingRequest.cs b/ElevenLabs-DotNet/Dubbing/DubbingRequest.cs index 38612ce..403fedf 100644 --- a/ElevenLabs-DotNet/Dubbing/DubbingRequest.cs +++ b/ElevenLabs-DotNet/Dubbing/DubbingRequest.cs @@ -36,7 +36,7 @@ public DubbingRequest( bool? dropBackgroundAudio = null, bool? useProfanityFilter = null, string projectName = null) - : this(targetLanguage, null, filePaths, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName) + : this(targetLanguage, null, null, filePaths, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName) { } @@ -52,13 +52,30 @@ public DubbingRequest( bool? dropBackgroundAudio = null, bool? useProfanityFilter = null, string projectName = null) - : this(targetLanguage, sourceUrl, null, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName) + : this(targetLanguage, sourceUrl, null, null, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName) + { + } + + public DubbingRequest( + List<(string, string, Stream)> files, + string targetLanguage, + string sourceLanguage = null, + int? numberOfSpeakers = null, + bool? watermark = null, + int? startTime = null, + int? endTime = null, + bool? highestResolution = null, + bool? dropBackgroundAudio = null, + bool? useProfanityFilter = null, + string projectName = null) + : this(targetLanguage, null, files, null, sourceLanguage, numberOfSpeakers, watermark, startTime, endTime, highestResolution, dropBackgroundAudio, useProfanityFilter, projectName) { } private DubbingRequest( string targetLanguage, Uri sourceUrl = null, + List<(string, string, Stream)> files = null, IEnumerable filePaths = null, string sourceLanguage = null, int? numberOfSpeakers = null, @@ -78,7 +95,7 @@ private DubbingRequest( throw new ArgumentException("Either sourceUrl or filePaths must be provided."); } - var files = new List<(string, string, Stream)>(); + files ??= []; if (filePaths != null) { From b36b1939fc5134a28809f55bf6d61838450a5d54 Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Sat, 11 Jan 2025 12:28:29 -0500 Subject: [PATCH 3/8] refactor stream dub a bit --- ElevenLabs-DotNet/Dubbing/DubbingEndpoint.cs | 4 +- ElevenLabs-DotNet/Dubbing/DubbingRequest.cs | 14 ++--- ElevenLabs-DotNet/Dubbing/DubbingStream.cs | 64 ++++++++++++++++++++ ElevenLabs-DotNet/ElevenLabs-DotNet.csproj | 1 + 4 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 ElevenLabs-DotNet/Dubbing/DubbingStream.cs diff --git a/ElevenLabs-DotNet/Dubbing/DubbingEndpoint.cs b/ElevenLabs-DotNet/Dubbing/DubbingEndpoint.cs index efa9738..dcec750 100644 --- a/ElevenLabs-DotNet/Dubbing/DubbingEndpoint.cs +++ b/ElevenLabs-DotNet/Dubbing/DubbingEndpoint.cs @@ -38,9 +38,9 @@ public async Task DubAsync(DubbingRequest request, int? { if (request.Files != null) { - foreach (var (fileName, mediaType, stream) in request.Files) + foreach (var dub in request.Files) { - await payload.AppendFileToFormAsync("file", stream, fileName, new(mediaType), cancellationToken); + await payload.AppendFileToFormAsync("file", dub.Stream, dub.Name, new(dub.MediaType), cancellationToken); } } diff --git a/ElevenLabs-DotNet/Dubbing/DubbingRequest.cs b/ElevenLabs-DotNet/Dubbing/DubbingRequest.cs index 403fedf..057b910 100644 --- a/ElevenLabs-DotNet/Dubbing/DubbingRequest.cs +++ b/ElevenLabs-DotNet/Dubbing/DubbingRequest.cs @@ -57,7 +57,7 @@ public DubbingRequest( } public DubbingRequest( - List<(string, string, Stream)> files, + List files, string targetLanguage, string sourceLanguage = null, int? numberOfSpeakers = null, @@ -75,7 +75,7 @@ public DubbingRequest( private DubbingRequest( string targetLanguage, Uri sourceUrl = null, - List<(string, string, Stream)> files = null, + List files = null, IEnumerable filePaths = null, string sourceLanguage = null, int? numberOfSpeakers = null, @@ -130,7 +130,7 @@ private DubbingRequest( ".webm" => "video/webm", _ => "application/octet-stream" }; - files.Add((fileInfo.Name, mediaType, stream)); + files.Add(new(stream, fileInfo.Name, mediaType)); } } @@ -152,7 +152,7 @@ private DubbingRequest( /// /// Files to dub. /// - public IReadOnlyList<(string, string, Stream)> Files { get; } + public IReadOnlyList Files { get; } /// /// URL of the source video/audio file. @@ -221,12 +221,12 @@ private void Dispose(bool disposing) if (disposing) { if (Files == null) { return; } - foreach (var (_, _, stream) in Files) + + foreach (var dub in Files) { try { - stream?.Close(); - stream?.Dispose(); + dub.Dispose(); } catch (Exception e) { diff --git a/ElevenLabs-DotNet/Dubbing/DubbingStream.cs b/ElevenLabs-DotNet/Dubbing/DubbingStream.cs new file mode 100644 index 0000000..ddbbd63 --- /dev/null +++ b/ElevenLabs-DotNet/Dubbing/DubbingStream.cs @@ -0,0 +1,64 @@ +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using System; +using System.IO; + +namespace ElevenLabs.Dubbing +{ + public sealed class DubbingStream : IDisposable + { + public DubbingStream(Stream stream, string name, string mediaType) + { + Stream = stream ?? throw new ArgumentNullException(nameof(stream)); + + if (Stream.Length == 0) + { + throw new ArgumentException("Stream cannot be empty."); + } + + if (!Stream.CanRead) + { + throw new ArgumentException("Stream must be readable."); + } + + Name = name ?? throw new ArgumentNullException(nameof(name)); + + if (string.IsNullOrWhiteSpace(Name)) + { + throw new ArgumentException("Name cannot be empty."); + } + + MediaType = mediaType ?? throw new ArgumentNullException(nameof(mediaType)); + + if (string.IsNullOrWhiteSpace(MediaType)) + { + throw new ArgumentException("Media type cannot be empty."); + } + + if (MediaType.Contains("/")) + { + var parts = MediaType.Split('/'); + + if (parts.Length != 2 || string.IsNullOrWhiteSpace(parts[0]) || string.IsNullOrWhiteSpace(parts[1])) + { + throw new ArgumentException("Invalid media type."); + } + } + else + { + throw new ArgumentException("Invalid media type."); + } + } + + public Stream Stream { get; } + + public string Name { get; } + + public string MediaType { get; } + + public void Dispose() + { + Stream?.Dispose(); + } + } +} diff --git a/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj b/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj index 0bffdfb..9321319 100644 --- a/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj +++ b/ElevenLabs-DotNet/ElevenLabs-DotNet.csproj @@ -29,6 +29,7 @@ All copyrights, trademarks, logos, and assets are the property of their respecti Version 3.4.2 - Added flash models +- Added stream input support to dubbing endpoint - Fixed http/https protocol in client settings Version 3.4.1 - Removed text length check in TextToSpeechRequest From 169d30cbf10d9c35af52b151c5d32804c58bfb48 Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Sat, 11 Jan 2025 12:32:25 -0500 Subject: [PATCH 4/8] docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3270132..2daac8c 100644 --- a/README.md +++ b/README.md @@ -391,7 +391,7 @@ var assetsDir = Path.GetFullPath("../../../Assets"); var dubbedPath = new FileInfo(Path.Combine(assetsDir, $"online.dubbed.{request.TargetLanguage}.mp4")); { await using var fs = File.Open(dubbedPath.FullName, FileMode.Create); - await foreach (var chunk in ElevenLabsClient.DubbingEndpoint.GetDubbedFileAsync(metadata.DubbingId, request.TargetLanguage)) + await foreach (var chunk in api.DubbingEndpoint.GetDubbedFileAsync(metadata.DubbingId, request.TargetLanguage)) { await fs.WriteAsync(chunk); } From 9297ad574e7ae9e8f54199d50d0f042921a00bc1 Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Sat, 11 Jan 2025 12:42:58 -0500 Subject: [PATCH 5/8] update workflow with docfx generation --- .github/workflows/Publish-Nuget.yml | 64 +++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/.github/workflows/Publish-Nuget.yml b/.github/workflows/Publish-Nuget.yml index 636806e..d452939 100644 --- a/.github/workflows/Publish-Nuget.yml +++ b/.github/workflows/Publish-Nuget.yml @@ -1,4 +1,4 @@ -name: Nuget Publish +name: Build and Publish on: push: @@ -22,15 +22,28 @@ on: dotnet-version: description: ".NET version to use" required: false - default: "6.0.x" + default: "8.0.x" + +permissions: + contents: read + pages: write + checks: write + id-token: write + pull-requests: write + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: false env: - DOTNET_VERSION: ${{ github.event.inputs.dotnet-version || '6.0.x' }} - PACKAGE_VERSION: '' + DOTNET_VERSION: ${{ github.event.inputs.dotnet-version || '8.0.x' }} jobs: build: if: ${{ !github.event_name == 'pull_request' || !github.event.pull_request.draft }} + env: + PACKAGE_VERSION: '' + COVERAGE_FILE_PATH: '' runs-on: ubuntu-latest steps: @@ -38,7 +51,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-dotnet@v3 + - uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} @@ -61,11 +74,18 @@ jobs: report_individual_runs: true compare_to_earlier_commit: false + - name: Determine Coverage File Path + if: ${{ github.ref != 'refs/heads/main' && github.event_name != 'push' && always() }} + shell: bash + run: | + COVERAGE_FILE_PATH=$(find ./test-results -name 'coverage.cobertura.xml' | head -n 1) + echo "COVERAGE_FILE_PATH=$COVERAGE_FILE_PATH" >> $GITHUB_ENV + - name: Code Coverage Summary Report if: ${{ github.ref != 'refs/heads/main' && github.event_name != 'push' && always() }} uses: irongut/CodeCoverageSummary@v1.3.0 with: - filename: test-results/**/coverage.cobertura.xml + filename: ${{ env.COVERAGE_FILE_PATH }} badge: true format: 'markdown' output: 'both' @@ -114,7 +134,7 @@ jobs: echo "PACKAGE_VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append shell: pwsh - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: always() with: name: ElevenLabs-DotNet.${{ env.PACKAGE_VERSION }} @@ -124,3 +144,33 @@ jobs: ${{ github.workspace }}/ElevenLabs-DotNet/bin/Release/ElevenLabs-DotNet-Proxy.${{ env.PACKAGE_VERSION }}.nupkg ${{ github.workspace }}/ElevenLabs-DotNet/bin/Release/ElevenLabs-DotNet-Proxy.${{ env.PACKAGE_VERSION }}.symbols.nupkg if-no-files-found: ignore + + docs: + if: ${{ github.ref == 'refs/heads/main' && github.event_name == 'push' }} + needs: build + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: build docfx + run: | + dotnet tool update -g docfx + docfx .docs/docfx.json + + - uses: actions/upload-pages-artifact@v3 + with: + path: '_site' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4.0.3 From 54fcb8b37468386e480002dd2b47779e49b13e2c Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Sat, 11 Jan 2025 12:45:09 -0500 Subject: [PATCH 6/8] fix dotnet version --- .github/workflows/Publish-Nuget.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Publish-Nuget.yml b/.github/workflows/Publish-Nuget.yml index d452939..17c54ac 100644 --- a/.github/workflows/Publish-Nuget.yml +++ b/.github/workflows/Publish-Nuget.yml @@ -22,7 +22,7 @@ on: dotnet-version: description: ".NET version to use" required: false - default: "8.0.x" + default: "8.x" permissions: contents: read @@ -36,7 +36,7 @@ concurrency: cancel-in-progress: false env: - DOTNET_VERSION: ${{ github.event.inputs.dotnet-version || '8.0.x' }} + DOTNET_VERSION: ${{ github.event.inputs.dotnet-version || '8.x' }} jobs: build: From 8a17053e5138fbf83f8014bacabc2fed0a60f7b1 Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Sat, 11 Jan 2025 12:48:39 -0500 Subject: [PATCH 7/8] add docfx links --- .github/workflows/Publish-Nuget.yml | 2 +- README.md | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Publish-Nuget.yml b/.github/workflows/Publish-Nuget.yml index 17c54ac..a3e2851 100644 --- a/.github/workflows/Publish-Nuget.yml +++ b/.github/workflows/Publish-Nuget.yml @@ -32,7 +32,7 @@ permissions: pull-requests: write concurrency: - group: ${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: false env: diff --git a/README.md b/README.md index 2daac8c..d55e285 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,11 @@ dotnet add package ElevenLabs-DotNet --- -## Documentation +## [Documentation](https://rageagainstthepixel.github.io/ElevenLabs-DotNet) + +> Check out our new api docs! + + ### Table of Contents From 8cbf3a5a93ef85a3f4c65e1f8cedaeea7bf2734a Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Sat, 11 Jan 2025 12:56:19 -0500 Subject: [PATCH 8/8] fix docs --- ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs b/ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs index 78a8126..1397e05 100644 --- a/ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs +++ b/ElevenLabs-DotNet/TextToSpeech/TextToSpeechRequest.cs @@ -30,7 +30,7 @@ public TextToSpeechRequest(string text, Model model, VoiceSettings voiceSettings /// Optional, that will override the default settings in . /// /// - /// Optional, to use. Defaults to . + /// Optional, to use. Defaults to . /// /// /// Output format of the generated audio.