Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
Swimburger committed Jul 22, 2024
2 parents 06371fc + 10b4059 commit a85c635
Show file tree
Hide file tree
Showing 15 changed files with 509 additions and 56 deletions.
14 changes: 8 additions & 6 deletions .fernignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

README.md
LICENSE.md
AssemblyAI/Realtime/RealtimeTranscriber.cs
AssemblyAI/Realtime/WebSocketClient
src/AssemblyAI/AssemblyAI.csproj
src/AssemblyAI/ClientOptions.cs
src/AssemblyAI/Constants.cs
src/AssemblyAI/UserAgent.cs
src/AssemblyAI/AssemblyAIClient.cs
src/AssemblyAI/DependencyInjectionExtensions.cs
src/AssemblyAI/Files/FilesCustomClient.cs
src/AssemblyAI/Transcripts/TranscriptsCustomClient.cs
src/AssemblyAI/Transcripts/Requests/ListTranscriptParams.cs
src/AssemblyAI/Realtime/RealtimeTranscriber.cs
src/AssemblyAI/Realtime/WebSocketClient
src/AssemblyAI.Test


AssemblyAI.Test
Samples
**/*.fernignore.*
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -478,4 +478,3 @@ $RECYCLE.BIN/

.idea
.runsettings

2 changes: 2 additions & 0 deletions src/AssemblyAI.Test/AssemblyAI.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0"/>
<PackageReference Include="NUnit" Version="3.13.3"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2"/>
Expand Down
84 changes: 84 additions & 0 deletions src/AssemblyAI.Test/DiClientOptionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System.Text.Json;
using AssemblyAI.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NUnit.Framework;

namespace AssemblyAI.Test;

[TestFixture]
public class DependencyInjectionClientOptionsTests
{
private static readonly ClientOptions ValidAssemblyAIOptions = new()
{
ApiKey = "MyAssemblyAIApiKey",
BaseUrl = "https://api.assemblyai.com",
MaxRetries = 2,
TimeoutInSeconds = 30
};

[Test]
public void AddAssemblyAIClient_With_Callback_Should_Match_Configuration()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(BuildEmptyConfiguration());
serviceCollection.AddAssemblyAIClient((_, options) =>
{
options.ApiKey = ValidAssemblyAIOptions.ApiKey;
options.BaseUrl = ValidAssemblyAIOptions.BaseUrl;
options.MaxRetries = ValidAssemblyAIOptions.MaxRetries;
options.TimeoutInSeconds = ValidAssemblyAIOptions.TimeoutInSeconds;
});

var serviceProvider = serviceCollection.BuildServiceProvider();
var assemblyAIClientOptions = serviceProvider.GetService<IOptions<ClientOptions>>()?.Value;

var expectedJson = JsonSerializer.Serialize(ValidAssemblyAIOptions);
var actualJson = JsonSerializer.Serialize(assemblyAIClientOptions);

Assert.That(actualJson, Is.EqualTo(expectedJson));
}

[Test]
public async Task AddAssemblyAIClient_From_Configuration_Should_Reload_On_Change()
{
const string optionsFile = "ClientOptions.json";
if (File.Exists(optionsFile)) File.Delete(optionsFile);
var jsonText = JsonSerializer.Serialize(new { AssemblyAI = ValidAssemblyAIOptions });
await File.WriteAllTextAsync(optionsFile, jsonText);

var serviceCollection = new ServiceCollection();
var configuration = new ConfigurationBuilder()
.AddJsonFile(optionsFile, optional: false, reloadOnChange: true)
.Build();

serviceCollection.AddSingleton<IConfiguration>(configuration);
serviceCollection.AddAssemblyAIClient();

var serviceProvider = serviceCollection.BuildServiceProvider();

ClientOptions updatedOptions = new()
{
ApiKey = "UpdatedApiKey",
BaseUrl = "https://api.updated.assemblyai.com",
MaxRetries = 3,
TimeoutInSeconds = 45
};

jsonText = JsonSerializer.Serialize(new { AssemblyAI = updatedOptions });
await File.WriteAllTextAsync(optionsFile, jsonText);

// Simulate waiting for the option change to be detected
await Task.Delay(1000); // This is a simplification. In real tests, use a more reliable method to wait for changes.

var monitor = serviceProvider.GetRequiredService<IOptionsMonitor<ClientOptions>>();
var options = monitor.CurrentValue;

var expectedJson = JsonSerializer.Serialize(updatedOptions);
var actualJson = JsonSerializer.Serialize(options);
Assert.That(actualJson, Is.EqualTo(expectedJson));
}

private static IConfiguration BuildEmptyConfiguration() => new ConfigurationBuilder().Build();
}
55 changes: 55 additions & 0 deletions src/AssemblyAI.Test/DiClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using NUnit.Framework;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;

namespace AssemblyAI.Test;

[TestFixture]
public class DiClientTests
{
[Test]
public void AssemblyAIClient_Should_Be_Correctly_Configured_From_DI()
{
// Arrange
var services = new ServiceCollection();
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
{ "AssemblyAI:ApiKey", "test_api_key" },
{ "AssemblyAI:BaseUrl", "https://api.test.assemblyai.com" },
{ "AssemblyAI:MaxRetries", "3" },
{ "AssemblyAI:TimeoutInSeconds", "60" }
}!)
.Build();

services.AddSingleton<IConfiguration>(configuration);
services.AddAssemblyAIClient();

// Act
var serviceProvider = services.BuildServiceProvider();
var client = serviceProvider.GetService<AssemblyAIClient>();

// Assert
Assert.That(client, Is.Not.Null);
Assert.That(client.Files, Is.Not.Null);
Assert.That(client.Transcripts, Is.Not.Null);
Assert.That(client.Realtime, Is.Not.Null);
Assert.That(client.Lemur, Is.Not.Null);
}

[Test]
public void AssemblyAIClient_Throws_Exception_When_Configuration_Missing()
{
var services = new ServiceCollection();
var configuration = new ConfigurationBuilder().Build(); // Empty configuration

services.AddSingleton<IConfiguration>(configuration);
services.AddAssemblyAIClient();

var serviceProvider = services.BuildServiceProvider();

var exception = Assert.Throws<OptionsValidationException>(() => serviceProvider.GetService<AssemblyAIClient>());
Assert.That(exception.Message, Is.EqualTo("AssemblyAI:ApiKey is required."));
}
}
3 changes: 0 additions & 3 deletions src/AssemblyAI.Test/TestClient.cs

This file was deleted.

19 changes: 19 additions & 0 deletions src/AssemblyAI.Test/TranscriptTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using NUnit.Framework;

namespace AssemblyAI.Test;

[TestFixture]
public class TranscriptTests
{
[Test]
public async Task TestTranscript()
{
var client = new AssemblyAIClient("");
var transcript = await client.Transcripts.SubmitAsync(new TranscriptParams
{
AudioUrl = "https://storage.googleapis.com/aai-docs-samples/nbc.mp3"
});
Assert.That(transcript, Is.Not.Null);
Assert.That(transcript.Status, Is.EqualTo(TranscriptStatus.Queued));
}
}
39 changes: 39 additions & 0 deletions src/AssemblyAI.Test/UserAgentTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using NUnit.Framework;

namespace AssemblyAI.Test;

[TestFixture]
public class UserAgentTests
{
[Test]
public void TestDefaultUserAgent()
{
Assert.That(UserAgent.Default, Is.Not.Null);
var userAgentString = UserAgent.Default.ToAssemblyAIUserAgentString();
Assert.That(userAgentString, Is.Not.Null);
Assert.That(userAgentString, Is.Not.Empty);
Assert.That(userAgentString, Does.StartWith("AssemblyAI/1.0 ("));
Assert.That(userAgentString, Does.EndWith(")"));
Assert.That(userAgentString, Does.Contain("sdk=CSharp/"));
Assert.That(userAgentString, Does.Contain("runtime_env=.NET/8"));
}


[Test]
public void TestMergeUserAgent()
{
var userAgent = new UserAgent(UserAgent.Default, new UserAgent(new Dictionary<string, UserAgentItem?>()
{
["integration"] = new("SemanticKernel", "1.0"),
["runtime_env"] = null
}));
var userAgentString = userAgent.ToAssemblyAIUserAgentString();
Assert.That(userAgentString, Is.Not.Null);
Assert.That(userAgentString, Is.Not.Empty);
Assert.That(userAgentString, Does.StartWith("AssemblyAI/1.0 ("));
Assert.That(userAgentString, Does.EndWith(")"));
Assert.That(userAgentString, Does.Contain("sdk=CSharp/"));
Assert.That(userAgentString, Does.Not.Contain("runtime_env"));
Assert.That(userAgentString, Does.Contain("integration=SemanticKernel/1.0"));
}
}
10 changes: 9 additions & 1 deletion src/AssemblyAI/AssemblyAI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,18 @@
</PackageReference>
</ItemGroup>


<ItemGroup Condition="'$(TargetFramework)' == 'net8.0' Or '$(TargetFramework)' == 'net7.0' Or '$(TargetFramework)' == 'net6.0' Or '$(TargetFramework)' == 'netstandard2.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="OneOf" Version="3.0.263" />
<PackageReference Include="OneOf.Extended" Version="3.0.263" />
<PackageReference Include="System.Text.Json" Version="8.0.3" />
<PackageReference Include="System.Text.Json" Version="8.0.4" />
</ItemGroup>

<ItemGroup>
Expand Down
49 changes: 33 additions & 16 deletions src/AssemblyAI/AssemblyAIClient.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,47 @@
#nullable enable

using System.Net.Http;
using AssemblyAI;
using AssemblyAI.Core;

#nullable enable

namespace AssemblyAI;

public partial class AssemblyAIClient
{
private RawClient _client;
public AssemblyAIClient(string apiKey) : this(new ClientOptions
{
ApiKey = apiKey
})
{
}

public AssemblyAIClient(string? apiKey = null, ClientOptions? clientOptions = null)
public AssemblyAIClient(ClientOptions clientOptions)
{
_client = new RawClient(
new Dictionary<string, string>()
{
{ "Authorization", apiKey },
{ "X-Fern-Language", "C#" },
{ "X-Fern-SDK-Name", "AssemblyAI" },
{ "X-Fern-SDK-Version", "0.0.2-alpha" },
},
clientOptions ?? new ClientOptions()
if (string.IsNullOrEmpty(clientOptions.ApiKey))
{
throw new ArgumentException("AssemblyAI API Key is required.");
}

clientOptions.HttpClient ??= new HttpClient();
var client = new RawClient(
new Dictionary<string, string>(),
clientOptions
);
Files = new FilesClient(_client);
Transcripts = new ExtendedTranscriptsClient(_client, this);
Realtime = new RealtimeClient(_client);
Lemur = new LemurClient(_client);
clientOptions.HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", clientOptions.ApiKey);
clientOptions.HttpClient.DefaultRequestHeaders.Add("X-Fern-Language", "C#");
clientOptions.HttpClient.DefaultRequestHeaders.Add("X-Fern-SDK-Name", "AssemblyAI");
clientOptions.HttpClient.DefaultRequestHeaders.Add("X-Fern-SDK-Version", Constants.Version);
if (clientOptions.UserAgent != null)
{
clientOptions.HttpClient.DefaultRequestHeaders.Add("User-Agent",
clientOptions.UserAgent.ToAssemblyAIUserAgentString());
}

Files = new FilesClient(client);
Transcripts = new ExtendedTranscriptsClient(client, this);
Realtime = new RealtimeClient(client);
Lemur = new LemurClient(client);
}

public FilesClient Files { get; init; }
Expand Down
53 changes: 53 additions & 0 deletions src/AssemblyAI/ClientOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#nullable enable

using System.Net.Http;
using AssemblyAI.Core;

namespace AssemblyAI;

public class ClientOptions
{
/// <summary>
/// The AssemblyAI API key
/// </summary>
public required string ApiKey { get; set; }

/// <summary>
/// The Base URL for the API.
/// </summary>
public string BaseUrl { get; set; } = Environments.DEFAULT;

private UserAgent? _userAgent = UserAgent.Default;

/// <summary>
/// The AssemblyAI user agent
/// </summary>
public UserAgent? UserAgent
{
get => _userAgent;
set
{
if (value == null)
{
_userAgent = null;
return;
}
_userAgent = new UserAgent(UserAgent.Default, value);
}
}

/// <summary>
/// The http client used to make requests.
/// </summary>
public HttpClient? HttpClient { get; set; }

/// <summary>
/// The http client used to make requests.
/// </summary>
public int MaxRetries { get; set; } = 2;

/// <summary>
/// The timeout for the request in seconds.
/// </summary>
public int TimeoutInSeconds { get; set; } = 30;
}
Loading

0 comments on commit a85c635

Please sign in to comment.