diff --git a/Deepgram.Tests/UnitTests/ClientTests/AnalyzeClientTests.cs b/Deepgram.Tests/UnitTests/ClientTests/AnalyzeClientTests.cs index 9171a07..3eae0f2 100644 --- a/Deepgram.Tests/UnitTests/ClientTests/AnalyzeClientTests.cs +++ b/Deepgram.Tests/UnitTests/ClientTests/AnalyzeClientTests.cs @@ -194,6 +194,177 @@ await analyzeClient.Invoking(y => y.AnalyzeUrlCallBack(source, null, analyzeSche await analyzeClient.DidNotReceive().PostAsync(url, Arg.Any()); } + [Test] + public async Task AnalyzeText_Should_Call_PostAsync_Returning_SyncResponse() + { + // Input and Output + var url = AbstractRestClient.GetUri(_options, $"{UriSegments.READ}"); + var expectedResponse = new AutoFaker().Generate(); + var analyzeSchema = new AutoFaker().Generate(); + analyzeSchema.CallBack = null; + var source = new AutoFaker().Generate(); + + // Fake Clients + var httpClient = MockHttpClient.CreateHttpClientWithResult(expectedResponse); + var analyzeClient = Substitute.For(_apiKey, _options, null); + + // Mock methods + analyzeClient.When(x => x.PostAsync(Arg.Any(), Arg.Any(), Arg.Any())).DoNotCallBase(); + analyzeClient.PostAsync(url, Arg.Any(), Arg.Any()).Returns(expectedResponse); + + // Act + var result = await analyzeClient.AnalyzeText(source, analyzeSchema); + + // Assert + await analyzeClient.Received().PostAsync(url, Arg.Any(), Arg.Any()); + + using (new AssertionScope()) + { + result.Should().NotBeNull(); + result.Should().BeAssignableTo(); + result.Should().BeEquivalentTo(expectedResponse); + } + } + + [Test] + public async Task AnalyzeText_Should_Throw_ArgumentException_If_CallBack_Not_Null() + { + // Input and Output + var url = AbstractRestClient.GetUri(_options, $"{UriSegments.READ}"); + var expectedResponse = new AutoFaker().Generate(); + var analyzeSchema = new AutoFaker().Generate(); + var source = new AutoFaker().Generate(); + + // Fake Clients + var httpClient = MockHttpClient.CreateHttpClientWithResult(expectedResponse); + var analyzeClient = Substitute.For(_apiKey, _options, null); + + // Mock methods + analyzeClient.When(x => x.PostAsync(Arg.Any(), Arg.Any())).DoNotCallBase(); + analyzeClient.PostAsync(url, Arg.Any()).Returns(expectedResponse); + + // Act and Assert + await analyzeClient.Invoking(y => y.AnalyzeText(source, analyzeSchema)) + .Should().ThrowAsync(); + + await analyzeClient.DidNotReceive().PostAsync(url, Arg.Any()); + } + + [Test] + public async Task AnalyzeTextCallBack_Should_Call_PostAsync_Returning_SyncResponse_With_CallBack_Parameter() + { + // Input and Output + var url = AbstractRestClient.GetUri(_options, $"{UriSegments.READ}"); + var expectedResponse = new AutoFaker().Generate(); + var source = new AutoFaker().Generate(); + var analyzeSchema = new AutoFaker().Generate(); + // analyzeSchema is not null here as we first need to get the querystring with the callBack included + + // Fake Clients + var httpClient = MockHttpClient.CreateHttpClientWithResult(expectedResponse); + var analyzeClient = Substitute.For(_apiKey, _options, null); + + // Mock methods + analyzeClient.When(x => x.PostAsync(Arg.Any(), Arg.Any(), Arg.Any())).DoNotCallBase(); + analyzeClient.PostAsync(url, Arg.Any(), Arg.Any()).Returns(expectedResponse); + + //before we act to test this call with the callBack parameter and not the callBack property we need to null the callBack property + var callBackParameter = analyzeSchema.CallBack; + analyzeSchema.CallBack = null; + + // Act + var result = await analyzeClient.AnalyzeTextCallBack(source, callBackParameter, analyzeSchema); + + // Assert + await analyzeClient.Received().PostAsync(url, Arg.Any(), Arg.Any()); + using (new AssertionScope()) + { + result.Should().NotBeNull(); + result.Should().BeAssignableTo(); + result.Should().BeEquivalentTo(expectedResponse); + } + } + + [Test] + public async Task AnalyzeTextCallBack_Should_Call_PostAsync_Returning_SyncResponse_With_CallBack_Property() + { + // Input and Output + var url = AbstractRestClient.GetUri(_options, $"{UriSegments.READ}"); + var expectedResponse = new AutoFaker().Generate(); + var source = new AutoFaker().Generate(); + var analyzeSchema = new AutoFaker().Generate(); + + // Fake Clients + var httpClient = MockHttpClient.CreateHttpClientWithResult(expectedResponse); + var analyzeClient = Substitute.For(_apiKey, _options, null); + + // Mock methods + analyzeClient.When(x => x.PostAsync(Arg.Any(), Arg.Any(), Arg.Any())).DoNotCallBase(); + analyzeClient.PostAsync(url, Arg.Any(), Arg.Any()).Returns(expectedResponse); + + // Act + var result = await analyzeClient.AnalyzeTextCallBack(source, null, analyzeSchema); + + // Assert + await analyzeClient.Received().PostAsync(url, Arg.Any(), Arg.Any()); + using (new AssertionScope()) + { + result.Should().NotBeNull(); + result.Should().BeAssignableTo(); + result.Should().BeEquivalentTo(expectedResponse); + } + } + + [Test] + public async Task AnalyzeTextCallBack_Should_Throw_ArgumentException_With_CallBack_Property_And_CallBack_Parameter_Set() + { + // Input and Output + var url = AbstractRestClient.GetUri(_options, $"{UriSegments.READ}"); + var expectedResponse = new AutoFaker().Generate(); + var source = new AutoFaker().Generate(); + var analyzeSchema = new AutoFaker().Generate(); + + // Fake Clients + var httpClient = MockHttpClient.CreateHttpClientWithResult(expectedResponse); + var analyzeClient = Substitute.For(_apiKey, _options, null); + + // Mock methods + analyzeClient.When(x => x.PostAsync(Arg.Any(), Arg.Any())).DoNotCallBase(); + analyzeClient.PostAsync(url, Arg.Any()).Returns(expectedResponse); + var callBackParameter = analyzeSchema.CallBack; + + // Act and Assert + await analyzeClient.Invoking(y => y.AnalyzeTextCallBack(source, callBackParameter, analyzeSchema)) + .Should().ThrowAsync(); + + await analyzeClient.DidNotReceive().PostAsync(url, Arg.Any()); + } + + [Test] + public async Task AnalyzeTextCallBack_Should_Throw_ArgumentException_With_No_CallBack_Set() + { + // Input and Output + var url = AbstractRestClient.GetUri(_options, $"{UriSegments.READ}"); + var expectedResponse = new AutoFaker().Generate(); + var source = new AutoFaker().Generate(); + var analyzeSchema = new AutoFaker().Generate(); + analyzeSchema.CallBack = null; + + // Fake Clients + var httpClient = MockHttpClient.CreateHttpClientWithResult(expectedResponse); + var analyzeClient = Substitute.For(_apiKey, _options, null); + + // Mock methods + analyzeClient.When(x => x.PostAsync(Arg.Any(), Arg.Any())).DoNotCallBase(); + analyzeClient.PostAsync(url, Arg.Any()).Returns(expectedResponse); + + // Act and Assert + await analyzeClient.Invoking(y => y.AnalyzeTextCallBack(source, null, analyzeSchema)) + .Should().ThrowAsync(); + + await analyzeClient.DidNotReceive().PostAsync(url, Arg.Any()); + } + [Test] public async Task AnalyzeFile_With_Stream_Should_Call_PostAsync_Returning_SyncResponse() { diff --git a/Deepgram/Clients/Analyze/v1/Client.cs b/Deepgram/Clients/Analyze/v1/Client.cs index 21984f5..e4bec72 100644 --- a/Deepgram/Clients/Analyze/v1/Client.cs +++ b/Deepgram/Clients/Analyze/v1/Client.cs @@ -43,6 +43,32 @@ public async Task AnalyzeUrl(UrlSource source, AnalyzeSchema? anal return result; } + /// + /// Analyze by providing text + /// + /// Text that is to be analyzed + /// Options for the transcription + /// + public async Task AnalyzeText(TextSource source, AnalyzeSchema? analyzeSchema, CancellationTokenSource? cancellationToken = default, Dictionary? addons = null, Dictionary? headers = null) + { + Log.Verbose("AnalyzeClient.AnalyzeText", "ENTER"); + Log.Information("AnalyzeText", $"source: {source}"); + Log.Information("AnalyzeText", $"analyzeSchema:\n{JsonSerializer.Serialize(analyzeSchema, JsonSerializeOptions.DefaultOptions)}"); + + VerifyNoCallBack(nameof(AnalyzeText), analyzeSchema); + + var uri = GetUri(_options, UriSegments.READ); + var result = await PostAsync( + uri, analyzeSchema, source, cancellationToken, addons, headers + ); + + Log.Information("AnalyzeText", $"{uri} Succeeded"); + Log.Debug("AnalyzeText", $"result: {result}"); + Log.Verbose("AnalyzeClient.AnalyzeText", "LEAVE"); + + return result; + } + /// /// Analyzes a file using the provided byte array @@ -156,6 +182,36 @@ public async Task AnalyzeUrlCallBack(UrlSource source, string? ca return result; } + + /// + /// Analyze by providing text and a CallBack + /// + /// Text that is to be analyzed + /// CallBack url + /// Options for the transcription + /// + public async Task AnalyzeTextCallBack(TextSource source, string? callBack, AnalyzeSchema? analyzeSchema, CancellationTokenSource? cancellationToken = default, Dictionary? addons = null, Dictionary? headers = null) + { + Log.Verbose("AnalyzeClient.AnalyzeTextCallBack", "ENTER"); + Log.Information("AnalyzeTextCallBack", $"source: {source}"); + Log.Information("AnalyzeTextCallBack", $"callBack: {callBack}"); + Log.Information("AnalyzeTextCallBack", $"analyzeSchema:\n{JsonSerializer.Serialize(analyzeSchema, JsonSerializeOptions.DefaultOptions)}"); + + VerifyOneCallBackSet(nameof(AnalyzeTextCallBack), callBack, analyzeSchema); + if (callBack != null) + analyzeSchema.CallBack = callBack; + + var uri = GetUri(_options, UriSegments.READ); + var result = await PostAsync( + uri, analyzeSchema, source, cancellationToken, addons, headers + ); + + Log.Information("AnalyzeTextCallBack", $"{uri} Succeeded"); + Log.Debug("AnalyzeTextCallBack", $"result: {result}"); + Log.Verbose("AnalyzeClient.AnalyzeTextCallBack", "LEAVE"); + + return result; + } #endregion #region CallbackChecks @@ -168,7 +224,7 @@ private void VerifyNoCallBack(string method, AnalyzeSchema? analyzeSchema) var exStr = $"CallBack cannot be provided as schema option to a synchronous transcription when calling {method}. Use {nameof(AnalyzeFileCallBack)} or {nameof(AnalyzeUrlCallBack)}"; Log.Error("VerifyNoCallBack", $"Exception: {exStr}"); throw new ArgumentException(exStr); - } + } } private void VerifyOneCallBackSet(string method, string? callBack, AnalyzeSchema? analyzeSchema) diff --git a/Deepgram/Clients/Interfaces/v1/IAnalyzeClient.cs b/Deepgram/Clients/Interfaces/v1/IAnalyzeClient.cs index ce23933..569b699 100644 --- a/Deepgram/Clients/Interfaces/v1/IAnalyzeClient.cs +++ b/Deepgram/Clients/Interfaces/v1/IAnalyzeClient.cs @@ -18,6 +18,14 @@ public interface IAnalyzeClient public Task AnalyzeUrl(UrlSource source, AnalyzeSchema? analyzeSchema, CancellationTokenSource? cancellationToken = default, Dictionary? addons = null, Dictionary? headers = null); + /// + /// Analyze by providing text + /// + /// Text that is to be analyzed + /// Options for the transcription + /// + public Task AnalyzeText(TextSource source, AnalyzeSchema? analyzeSchema, CancellationTokenSource? cancellationToken = default, Dictionary? addons = null, Dictionary? headers = null); + /// /// Analyzes a file using the provided byte array /// @@ -70,5 +78,14 @@ public Task AnalyzeFileCallBack(Stream source, string? callBack, public Task AnalyzeUrlCallBack(UrlSource source, string? callBack, AnalyzeSchema? analyzeSchema, CancellationTokenSource? cancellationToken = default, Dictionary? addons = null, Dictionary? headers = null); + + // + /// Analyze by providing text and a CallBack + /// + /// Text that is to be analyzed + /// CallBack url + /// Options for the transcription + /// + public Task AnalyzeTextCallBack(TextSource source, string? callBack, AnalyzeSchema? analyzeSchema, CancellationTokenSource? cancellationToken = default, Dictionary? addons = null, Dictionary? headers = null); #endregion } diff --git a/Deepgram/Models/Analyze/v1/TextSource.cs b/Deepgram/Models/Analyze/v1/TextSource.cs new file mode 100644 index 0000000..833f4da --- /dev/null +++ b/Deepgram/Models/Analyze/v1/TextSource.cs @@ -0,0 +1,24 @@ +// Copyright 2024 Deepgram .NET SDK contributors. All Rights Reserved. +// Use of this source code is governed by a MIT license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT + +namespace Deepgram.Models.Analyze.v1; + +public class TextSource(string text) +{ + /// + /// Url of the text to analyze + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("text")] + public string? Text { get; set; } = text; + + /// + /// Override ToString method to serialize the object + /// + public override string ToString() + { + return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + } +} +