From 22a7ec518de999a7bce1afaa22e2803a0821fb4b Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 09:51:52 +0000 Subject: [PATCH 01/15] SDK regeneration --- reference.md | 1009 +++++++++++++++++ src/AssemblyAI/AssemblyAI.Custom.props | 20 + src/AssemblyAI/Core/EnumSerializer.cs | 53 + src/AssemblyAI/Core/Extensions.cs | 4 +- src/AssemblyAI/Core/IRequestOptions.cs | 34 + src/AssemblyAI/Core/OneOfSerializer.cs | 26 +- .../Public/AssemblyAIClientEnvironment.cs | 11 +- src/AssemblyAI/Core/Public/ClientOptions.cs | 29 +- .../Core/Public/ExtendedClientOptions.cs | 21 - .../Core/Public/ExtendedRequestOptions.cs | 9 - src/AssemblyAI/Core/Public/RequestOptions.cs | 4 +- src/AssemblyAI/Core/Public/Version.cs | 6 + src/AssemblyAI/Core/RawClient.cs | 120 +- src/AssemblyAI/Files/FilesClient.cs | 1 + src/AssemblyAI/Lemur/ExtendedLemurClient.cs | 6 - src/AssemblyAI/Lemur/LemurClient.cs | 18 +- .../Lemur/Requests/LemurActionItemsParams.cs | 2 - .../Requests/LemurQuestionAnswerParams.cs | 1 - .../Lemur/Requests/LemurSummaryParams.cs | 2 - .../Lemur/Requests/LemurTaskParams.cs | 1 - src/AssemblyAI/Lemur/Types/LemurBaseParams.cs | 1 - src/AssemblyAI/Lemur/Types/LemurModel.cs | 6 +- src/AssemblyAI/Lemur/Types/LemurQuestion.cs | 1 - src/AssemblyAI/Realtime/RealtimeClient.cs | 1 + .../Realtime/Types/AudioEncoding.cs | 2 +- .../Realtime/Types/FinalTranscript.cs | 2 +- src/AssemblyAI/Realtime/Types/MessageType.cs | 2 +- .../Realtime/Types/RealtimeTranscriptType.cs | 2 +- .../Transcripts/TranscriptsClient.cs | 13 +- .../Types/AudioIntelligenceModelStatus.cs | 2 +- .../Transcripts/Types/ContentSafetyLabel.cs | 2 +- .../Transcripts/Types/EntityType.cs | 2 +- src/AssemblyAI/Transcripts/Types/PiiPolicy.cs | 2 +- .../Types/RedactPiiAudioQuality.cs | 2 +- src/AssemblyAI/Transcripts/Types/Sentiment.cs | 2 +- .../Transcripts/Types/SpeechModel.cs | 2 +- .../Transcripts/Types/SubstitutionPolicy.cs | 2 +- .../Transcripts/Types/SubtitleFormat.cs | 2 +- .../Transcripts/Types/SummaryModel.cs | 2 +- .../Transcripts/Types/SummaryType.cs | 2 +- .../Types/TopicDetectionResultLabelsItem.cs | 2 +- .../Transcripts/Types/Transcript.cs | 2 +- .../Transcripts/Types/TranscriptBoostParam.cs | 2 +- .../Types/TranscriptLanguageCode.cs | 2 +- .../Types/TranscriptReadyStatus.cs | 2 +- .../Transcripts/Types/TranscriptStatus.cs | 2 +- 46 files changed, 1289 insertions(+), 152 deletions(-) create mode 100644 reference.md create mode 100644 src/AssemblyAI/AssemblyAI.Custom.props create mode 100644 src/AssemblyAI/Core/EnumSerializer.cs create mode 100644 src/AssemblyAI/Core/IRequestOptions.cs delete mode 100644 src/AssemblyAI/Core/Public/ExtendedClientOptions.cs delete mode 100644 src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs create mode 100644 src/AssemblyAI/Core/Public/Version.cs delete mode 100644 src/AssemblyAI/Lemur/ExtendedLemurClient.cs diff --git a/reference.md b/reference.md new file mode 100644 index 0000000..f847917 --- /dev/null +++ b/reference.md @@ -0,0 +1,1009 @@ +# Reference +## Files +## Transcripts +
client.Transcripts.ListAsync(ListTranscriptParams { ... }) -> TranscriptList +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve a list of transcripts you created. +Transcripts are sorted from newest to oldest. The previous URL always points to a page with older transcripts. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Transcripts.ListAsync(new ListTranscriptParams()); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `ListTranscriptParams` + +
+
+
+
+ + +
+
+
+ +
client.Transcripts.SubmitAsync(TranscriptParams { ... }) -> Transcript +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Create a transcript from a media file that is accessible via a URL. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Transcripts.SubmitAsync( + new TranscriptParams + { + LanguageCode = TranscriptLanguageCode.EnUs, + LanguageDetection = true, + LanguageConfidenceThreshold = 0.7f, + Punctuate = true, + FormatText = true, + Disfluencies = false, + Multichannel = true, + DualChannel = false, + WebhookUrl = "https://your-webhook-url/path", + WebhookAuthHeaderName = "webhook-secret", + WebhookAuthHeaderValue = "webhook-secret-value", + AutoHighlights = true, + AudioStartFrom = 10, + AudioEndAt = 280, + WordBoost = new List() { "aws", "azure", "google cloud" }, + BoostParam = TranscriptBoostParam.High, + FilterProfanity = true, + RedactPii = true, + RedactPiiAudio = true, + RedactPiiAudioQuality = RedactPiiAudioQuality.Mp3, + RedactPiiPolicies = new List() + { + PiiPolicy.UsSocialSecurityNumber, + PiiPolicy.CreditCardNumber, + }, + RedactPiiSub = SubstitutionPolicy.Hash, + SpeakerLabels = true, + SpeakersExpected = 2, + ContentSafety = true, + IabCategories = true, + CustomSpelling = new List() + { + new TranscriptCustomSpelling + { + From = new List() { "dicarlo" }, + To = "Decarlo", + }, + }, + SentimentAnalysis = true, + AutoChapters = true, + EntityDetection = true, + SpeechThreshold = 0.5f, + Summarization = true, + SummaryModel = SummaryModel.Informative, + SummaryType = SummaryType.Bullets, + CustomTopics = true, + Topics = new List() { "topics" }, + AudioUrl = "https://assembly.ai/wildfires.mp3", + } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `TranscriptParams` + +
+
+
+
+ + +
+
+
+ +
client.Transcripts.GetAsync(transcriptId) -> Transcript +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get the transcript resource. The transcript is ready when the "status" is "completed". +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Transcripts.GetAsync("transcript_id"); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**transcriptId:** `string` — ID of the transcript + +
+
+
+
+ + +
+
+
+ +
client.Transcripts.DeleteAsync(transcriptId) -> Transcript +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Remove the data from the transcript and mark it as deleted. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Transcripts.DeleteAsync("{transcript_id}"); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**transcriptId:** `string` — ID of the transcript + +
+
+
+
+ + +
+
+
+ +
client.Transcripts.GetSubtitlesAsync(transcriptId, subtitleFormat, GetSubtitlesParams { ... }) -> string +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Export your transcript in SRT or VTT format to use with a video player for subtitles and closed captions. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Transcripts.GetSubtitlesAsync( + "string", + SubtitleFormat.Srt, + new GetSubtitlesParams { CharsPerCaption = 1 } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**transcriptId:** `string` — ID of the transcript + +
+
+ +
+
+ +**subtitleFormat:** `SubtitleFormat` — The format of the captions + +
+
+ +
+
+ +**request:** `GetSubtitlesParams` + +
+
+
+
+ + +
+
+
+ +
client.Transcripts.GetSentencesAsync(transcriptId) -> SentencesResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get the transcript split by sentences. The API will attempt to semantically segment the transcript into sentences to create more reader-friendly transcripts. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Transcripts.GetSentencesAsync("transcript_id"); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**transcriptId:** `string` — ID of the transcript + +
+
+
+
+ + +
+
+
+ +
client.Transcripts.GetParagraphsAsync(transcriptId) -> ParagraphsResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Get the transcript split by paragraphs. The API will attempt to semantically segment your transcript into paragraphs to create more reader-friendly transcripts. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Transcripts.GetParagraphsAsync("transcript_id"); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**transcriptId:** `string` — ID of the transcript + +
+
+
+
+ + +
+
+
+ +
client.Transcripts.WordSearchAsync(transcriptId, WordSearchParams { ... }) -> WordSearchResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Search through the transcript for keywords. You can search for individual words, numbers, or phrases containing up to five words or numbers. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Transcripts.WordSearchAsync("string", new WordSearchParams { Words = ["string"] }); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**transcriptId:** `string` — ID of the transcript + +
+
+ +
+
+ +**request:** `WordSearchParams` + +
+
+
+
+ + +
+
+
+ +
client.Transcripts.GetRedactedAudioAsync(transcriptId) -> RedactedAudioResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve the redacted audio object containing the status and URL to the redacted audio. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Transcripts.GetRedactedAudioAsync("transcript_id"); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**transcriptId:** `string` — ID of the transcript + +
+
+
+
+ + +
+
+
+ +## Realtime +
client.Realtime.CreateTemporaryTokenAsync(CreateRealtimeTemporaryTokenParams { ... }) -> RealtimeTemporaryTokenResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Create a temporary authentication token for Streaming Speech-to-Text +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Realtime.CreateTemporaryTokenAsync( + new CreateRealtimeTemporaryTokenParams { ExpiresIn = 480 } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `CreateRealtimeTemporaryTokenParams` + +
+
+
+
+ + +
+
+
+ +## LeMUR +
client.Lemur.TaskAsync(LemurTaskParams { ... }) -> LemurTaskResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Use the LeMUR task endpoint to input your own LLM prompt. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Lemur.TaskAsync( + new LemurTaskParams + { + TranscriptIds = new List() { "64nygnr62k-405c-4ae8-8a6b-d90b40ff3cce" }, + Context = "This is an interview about wildfires.", + FinalModel = LemurModel.AnthropicClaude35Sonnet, + MaxOutputSize = 3000, + Temperature = 0f, + Prompt = "List all the locations affected by wildfires.", + } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `LemurTaskParams` + +
+
+
+
+ + +
+
+
+ +
client.Lemur.SummaryAsync(LemurSummaryParams { ... }) -> LemurSummaryResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Custom Summary allows you to distill a piece of audio into a few impactful sentences. +You can give the model context to obtain more targeted results while outputting the results in a variety of formats described in human language. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Lemur.SummaryAsync( + new LemurSummaryParams + { + TranscriptIds = new List() { "47b95ba5-8889-44d8-bc80-5de38306e582" }, + Context = "This is an interview about wildfires.", + FinalModel = LemurModel.AnthropicClaude35Sonnet, + MaxOutputSize = 3000, + Temperature = 0f, + } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `LemurSummaryParams` + +
+
+
+
+ + +
+
+
+ +
client.Lemur.QuestionAnswerAsync(LemurQuestionAnswerParams { ... }) -> LemurQuestionAnswerResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Question & Answer allows you to ask free-form questions about a single transcript or a group of transcripts. +The questions can be any whose answers you find useful, such as judging whether a caller is likely to become a customer or whether all items on a meeting's agenda were covered. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Lemur.QuestionAnswerAsync( + new LemurQuestionAnswerParams + { + TranscriptIds = new List() { "64nygnr62k-405c-4ae8-8a6b-d90b40ff3cce" }, + Context = "This is an interview about wildfires.", + FinalModel = LemurModel.AnthropicClaude35Sonnet, + MaxOutputSize = 3000, + Temperature = 0f, + Questions = new List() + { + new LemurQuestion + { + Question = "Where are there wildfires?", + AnswerFormat = "List of countries in ISO 3166-1 alpha-2 format", + AnswerOptions = new List() { "US", "CA" }, + }, + new LemurQuestion + { + Question = "Is global warming affecting wildfires?", + AnswerOptions = new List() { "yes", "no" }, + }, + }, + } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `LemurQuestionAnswerParams` + +
+
+
+
+ + +
+
+
+ +
client.Lemur.ActionItemsAsync(LemurActionItemsParams { ... }) -> LemurActionItemsResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Use LeMUR to generate a list of action items from a transcript +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Lemur.ActionItemsAsync( + new LemurActionItemsParams + { + TranscriptIds = new List() { "64nygnr62k-405c-4ae8-8a6b-d90b40ff3cce" }, + Context = "This is an interview about wildfires.", + FinalModel = LemurModel.AnthropicClaude35Sonnet, + MaxOutputSize = 3000, + Temperature = 0f, + AnswerFormat = "Bullet Points", + } +); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `LemurActionItemsParams` + +
+
+
+
+ + +
+
+
+ +
client.Lemur.GetResponseAsync(requestId) -> OneOf +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Retrieve a LeMUR response that was previously generated. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Lemur.GetResponseAsync("request_id"); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**requestId:** `string` + +The ID of the LeMUR request you previously made. +This would be found in the response of the original request. + +
+
+
+
+ + +
+
+
+ +
client.Lemur.PurgeRequestDataAsync(requestId) -> PurgeLemurRequestDataResponse +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Delete the data for a previously submitted LeMUR request. +The LLM response data, as well as any context provided in the original request will be removed. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```csharp +await client.Lemur.PurgeRequestDataAsync("request_id"); +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**requestId:** `string` — The ID of the LeMUR request whose data you want to delete. This would be found in the response of the original request. + +
+
+
+
+ + +
+
+
diff --git a/src/AssemblyAI/AssemblyAI.Custom.props b/src/AssemblyAI/AssemblyAI.Custom.props new file mode 100644 index 0000000..70df284 --- /dev/null +++ b/src/AssemblyAI/AssemblyAI.Custom.props @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/src/AssemblyAI/Core/EnumSerializer.cs b/src/AssemblyAI/Core/EnumSerializer.cs new file mode 100644 index 0000000..ef9a1ff --- /dev/null +++ b/src/AssemblyAI/Core/EnumSerializer.cs @@ -0,0 +1,53 @@ +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace AssemblyAI.Core; + +internal class EnumSerializer : JsonConverter + where TEnum : struct, System.Enum +{ + private readonly Dictionary _enumToString = new(); + private readonly Dictionary _stringToEnum = new(); + + public EnumSerializer() + { + var type = typeof(TEnum); + var values = Enum.GetValues(type); + + foreach (var value in values) + { + var enumValue = (TEnum)value; + var enumMember = type.GetMember(enumValue.ToString())[0]; + var attr = enumMember + .GetCustomAttributes(typeof(EnumMemberAttribute), false) + .Cast() + .FirstOrDefault(); + + var stringValue = + attr?.Value + ?? value.ToString() + ?? throw new Exception("Unexpected null enum toString value"); + + _enumToString.Add(enumValue, stringValue); + _stringToEnum.Add(stringValue, enumValue); + } + } + + public override TEnum Read( + ref Utf8JsonReader reader, + System.Type typeToConvert, + JsonSerializerOptions options + ) + { + var stringValue = + reader.GetString() + ?? throw new Exception("The JSON value could not be read as a string."); + return _stringToEnum.TryGetValue(stringValue, out var enumValue) ? enumValue : default; + } + + public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options) + { + writer.WriteStringValue(_enumToString[value]); + } +} diff --git a/src/AssemblyAI/Core/Extensions.cs b/src/AssemblyAI/Core/Extensions.cs index 167b9e5..a1c7fef 100644 --- a/src/AssemblyAI/Core/Extensions.cs +++ b/src/AssemblyAI/Core/Extensions.cs @@ -4,11 +4,11 @@ namespace AssemblyAI.Core; internal static class Extensions { - internal static string Stringify(this Enum value) + public static string Stringify(this Enum value) { var field = value.GetType().GetField(value.ToString()); var attribute = (EnumMemberAttribute) - Attribute.GetCustomAttribute(field!, typeof(EnumMemberAttribute))!; + Attribute.GetCustomAttribute(field, typeof(EnumMemberAttribute)); return attribute?.Value ?? value.ToString(); } } diff --git a/src/AssemblyAI/Core/IRequestOptions.cs b/src/AssemblyAI/Core/IRequestOptions.cs new file mode 100644 index 0000000..cf3ef5a --- /dev/null +++ b/src/AssemblyAI/Core/IRequestOptions.cs @@ -0,0 +1,34 @@ +using System; +using System.Net.Http; + +#nullable enable + +namespace AssemblyAI.Core; + +internal interface IRequestOptions +{ + /// + /// The Base URL for the API. + /// + public string? BaseUrl { get; init; } + + /// + /// The http client used to make requests. + /// + public HttpClient? HttpClient { get; init; } + + /// + /// The http headers sent with the request. + /// + internal Headers Headers { get; init; } + + /// + /// The http client used to make requests. + /// + public int? MaxRetries { get; init; } + + /// + /// The timeout for the request. + /// + public TimeSpan? Timeout { get; init; } +} diff --git a/src/AssemblyAI/Core/OneOfSerializer.cs b/src/AssemblyAI/Core/OneOfSerializer.cs index c4c18fd..786b12d 100644 --- a/src/AssemblyAI/Core/OneOfSerializer.cs +++ b/src/AssemblyAI/Core/OneOfSerializer.cs @@ -5,10 +5,9 @@ namespace AssemblyAI.Core; -internal class OneOfSerializer : JsonConverter - where TOneOf : IOneOf +internal class OneOfSerializer : JsonConverter { - public override TOneOf? Read( + public override IOneOf? Read( ref Utf8JsonReader reader, System.Type typeToConvert, JsonSerializerOptions options @@ -17,14 +16,14 @@ JsonSerializerOptions options if (reader.TokenType is JsonTokenType.Null) return default; - foreach (var (type, cast) in s_types) + foreach (var (type, cast) in GetOneOfTypes(typeToConvert)) { try { var readerCopy = reader; var result = JsonSerializer.Deserialize(ref readerCopy, type, options); reader.Skip(); - return (TOneOf)cast.Invoke(null, [result])!; + return (IOneOf)cast.Invoke(null, [result])!; } catch (JsonException) { } } @@ -34,20 +33,18 @@ JsonSerializerOptions options ); } - private static readonly (System.Type type, MethodInfo cast)[] s_types = GetOneOfTypes(); - - public override void Write(Utf8JsonWriter writer, TOneOf value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, IOneOf value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value.Value, options); } - private static (System.Type type, MethodInfo cast)[] GetOneOfTypes() + private static (System.Type type, MethodInfo cast)[] GetOneOfTypes(System.Type typeToConvert) { - var casts = typeof(TOneOf) + var casts = typeToConvert .GetRuntimeMethods() .Where(m => m.IsSpecialName && m.Name == "op_Implicit") .ToArray(); - var type = typeof(TOneOf); + var type = typeToConvert; while (type != null) { if ( @@ -62,6 +59,11 @@ private static (System.Type type, MethodInfo cast)[] GetOneOfTypes() type = type.BaseType; } - throw new InvalidOperationException($"{typeof(TOneOf)} isn't OneOf or OneOfBase"); + throw new InvalidOperationException($"{type} isn't OneOf or OneOfBase"); + } + + public override bool CanConvert(System.Type typeToConvert) + { + return typeof(IOneOf).IsAssignableFrom(typeToConvert); } } diff --git a/src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs b/src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs index 9bdec3e..148f07b 100644 --- a/src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs +++ b/src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs @@ -1,13 +1,6 @@ -// ReSharper disable CheckNamespace namespace AssemblyAI; -/// -/// Available AssemblyAI API environments -/// -public static class AssemblyAIClientEnvironment +public class AssemblyAIClientEnvironment { - /// - /// The default base URL for the AssemblyAI API. - /// - public const string Default = "https://api.assemblyai.com"; + public static string Default = "https://api.assemblyai.com"; } diff --git a/src/AssemblyAI/Core/Public/ClientOptions.cs b/src/AssemblyAI/Core/Public/ClientOptions.cs index 8241f7a..a12c55f 100644 --- a/src/AssemblyAI/Core/Public/ClientOptions.cs +++ b/src/AssemblyAI/Core/Public/ClientOptions.cs @@ -1,6 +1,8 @@ +using System; using System.Net.Http; using AssemblyAI.Core; -// ReSharper disable CheckNamespace + +#nullable enable namespace AssemblyAI; @@ -9,25 +11,40 @@ public partial class ClientOptions /// /// The Base URL for the API. /// - public string BaseUrl { get; set; } = AssemblyAIClientEnvironment.Default; + public string BaseUrl { get; init; } = AssemblyAIClientEnvironment.Default; /// /// The http client used to make requests. /// - public HttpClient HttpClient { get; set; } = new(); + public HttpClient HttpClient { get; init; } = new HttpClient(); /// - /// The amount to retry sending the HTTP request if it fails. + /// The http client used to make requests. /// - public int MaxRetries { get; set; } = 2; + public int MaxRetries { get; init; } = 2; /// /// The timeout for the request. /// - public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30); + public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(30); /// /// The http headers sent with the request. /// internal Headers Headers { get; init; } = new(); + + /// + /// Clones this and returns a new instance + /// + internal ClientOptions Clone() + { + return new ClientOptions + { + BaseUrl = BaseUrl, + HttpClient = HttpClient, + MaxRetries = MaxRetries, + Timeout = Timeout, + Headers = new Headers(new Dictionary(Headers)), + }; + } } diff --git a/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs b/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs deleted file mode 100644 index 291f27b..0000000 --- a/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ReSharper disable PartialTypeWithSinglePart -// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global -// ReSharper disable CheckNamespace - -namespace AssemblyAI; - -/// -/// The options for the AssemblyAI client. -/// -public partial class ClientOptions -{ - /// - /// The AssemblyAI API key - /// - public required string ApiKey { get; set; } - - /// - /// The AssemblyAI user agent - /// - public UserAgent UserAgent { get; set; } = new(); -} \ No newline at end of file diff --git a/src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs b/src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs deleted file mode 100644 index 7dbbd7f..0000000 --- a/src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -// ReSharper disable CheckNamespace -// ReSharper disable ClassNeverInstantiated.Global - -namespace AssemblyAI; - -/// -/// The options for one or multiple requests to the AssemblyAI API. -/// -public partial class RequestOptions; diff --git a/src/AssemblyAI/Core/Public/RequestOptions.cs b/src/AssemblyAI/Core/Public/RequestOptions.cs index 688540f..bf56473 100644 --- a/src/AssemblyAI/Core/Public/RequestOptions.cs +++ b/src/AssemblyAI/Core/Public/RequestOptions.cs @@ -6,7 +6,7 @@ namespace AssemblyAI; -public partial class RequestOptions +public partial class RequestOptions : IRequestOptions { /// /// The Base URL for the API. @@ -31,5 +31,5 @@ public partial class RequestOptions /// /// The http headers sent with the request. /// - internal Headers Headers { get; init; } = new(); + Headers IRequestOptions.Headers { get; init; } = new(); } diff --git a/src/AssemblyAI/Core/Public/Version.cs b/src/AssemblyAI/Core/Public/Version.cs new file mode 100644 index 0000000..93e43c9 --- /dev/null +++ b/src/AssemblyAI/Core/Public/Version.cs @@ -0,0 +1,6 @@ +namespace AssemblyAI; + +internal class Version +{ + public const string Current = "1.2.1"; +} diff --git a/src/AssemblyAI/Core/RawClient.cs b/src/AssemblyAI/Core/RawClient.cs index 82444ad..63e6e93 100644 --- a/src/AssemblyAI/Core/RawClient.cs +++ b/src/AssemblyAI/Core/RawClient.cs @@ -1,4 +1,5 @@ using System.Net.Http; +using System.Net.Http.Headers; using System.Text; using System.Threading; @@ -11,8 +12,11 @@ namespace AssemblyAI.Core; /// internal class RawClient(ClientOptions clientOptions) { + private const int InitialRetryDelayMs = 1000; + private const int MaxRetryDelayMs = 60000; + /// - /// The http client used to make requests. + /// The client options applied on every request. /// public readonly ClientOptions Options = clientOptions; @@ -21,36 +25,13 @@ public async Task MakeRequestAsync( CancellationToken cancellationToken = default ) { - var url = BuildUrl(request); - var httpRequest = new HttpRequestMessage(request.Method, url); - if (request.ContentType != null) - { - request.Headers.Add("Content-Type", request.ContentType); - } - SetHeaders(httpRequest, Options.Headers); - SetHeaders(httpRequest, request.Headers); - SetHeaders(httpRequest, request.Options?.Headers ?? new()); + // Apply the request timeout. + var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + var timeout = request.Options?.Timeout ?? Options.Timeout; + cts.CancelAfter(timeout); - // Add the request body to the request - if (request is JsonApiRequest jsonRequest) - { - if (jsonRequest.Body != null) - { - httpRequest.Content = new StringContent( - JsonUtils.Serialize(jsonRequest.Body), - Encoding.UTF8, - "application/json" - ); - } - } - else if (request is StreamApiRequest { Body: not null } streamRequest) - { - httpRequest.Content = new StreamContent(streamRequest.Body); - } - // Send the request - var httpClient = request.Options?.HttpClient ?? Options.HttpClient; - var response = await httpClient.SendAsync(httpRequest, cancellationToken); - return new ApiResponse { StatusCode = (int)response.StatusCode, Raw = response }; + // Send the request. + return await SendWithRetriesAsync(request, cts.Token); } public record BaseApiRequest @@ -67,7 +48,7 @@ public record BaseApiRequest public Headers Headers { get; init; } = new(); - public RequestOptions? Options { get; init; } + public IRequestOptions? Options { get; init; } } /// @@ -96,19 +77,70 @@ public record ApiResponse public required HttpResponseMessage Raw { get; init; } } - private void SetHeaders(HttpRequestMessage httpRequest, Headers headers) + private async Task SendWithRetriesAsync( + BaseApiRequest request, + CancellationToken cancellationToken + ) { - foreach (var header in headers) + var httpClient = request.Options?.HttpClient ?? Options.HttpClient; + var maxRetries = request.Options?.MaxRetries ?? Options.MaxRetries; + var response = await httpClient.SendAsync(BuildHttpRequest(request), cancellationToken); + for (var i = 0; i < maxRetries; i++) { - var value = header.Value?.Match(str => str, func => func.Invoke()); - if (value != null) + if (!ShouldRetry(response)) { - httpRequest.Headers.TryAddWithoutValidation(header.Key, value); + break; } + var delayMs = Math.Min(InitialRetryDelayMs * (int)Math.Pow(2, i), MaxRetryDelayMs); + await System.Threading.Tasks.Task.Delay(delayMs, cancellationToken); + response = await httpClient.SendAsync(BuildHttpRequest(request), cancellationToken); } + return new ApiResponse { StatusCode = (int)response.StatusCode, Raw = response }; } - private string BuildUrl(BaseApiRequest request) + private static bool ShouldRetry(HttpResponseMessage response) + { + var statusCode = (int)response.StatusCode; + return statusCode is 408 or 429 or >= 500; + } + + private HttpRequestMessage BuildHttpRequest(BaseApiRequest request) + { + var url = BuildUrl(request); + var httpRequest = new HttpRequestMessage(request.Method, url); + switch (request) + { + // Add the request body to the request. + case JsonApiRequest jsonRequest: + { + if (jsonRequest.Body != null) + { + httpRequest.Content = new StringContent( + JsonUtils.Serialize(jsonRequest.Body), + Encoding.UTF8, + "application/json" + ); + } + break; + } + case StreamApiRequest { Body: not null } streamRequest: + httpRequest.Content = new StreamContent(streamRequest.Body); + break; + } + if (request.ContentType != null) + { + httpRequest.Content.Headers.ContentType = MediaTypeHeaderValue.Parse( + request.ContentType + ); + } + SetHeaders(httpRequest, Options.Headers); + SetHeaders(httpRequest, request.Headers); + SetHeaders(httpRequest, request.Options?.Headers ?? new Headers()); + + return httpRequest; + } + + private static string BuildUrl(BaseApiRequest request) { var baseUrl = request.Options?.BaseUrl ?? request.BaseUrl; var trimmedBaseUrl = baseUrl.TrimEnd('/'); @@ -139,7 +171,19 @@ private string BuildUrl(BaseApiRequest request) return current; } ); - url = url.Substring(0, url.Length - 1); + url = url[..^1]; return url; } + + private static void SetHeaders(HttpRequestMessage httpRequest, Headers headers) + { + foreach (var header in headers) + { + var value = header.Value?.Match(str => str, func => func.Invoke()); + if (value != null) + { + httpRequest.Headers.TryAddWithoutValidation(header.Key, value); + } + } + } } diff --git a/src/AssemblyAI/Files/FilesClient.cs b/src/AssemblyAI/Files/FilesClient.cs index 91ae90b..28bf90c 100644 --- a/src/AssemblyAI/Files/FilesClient.cs +++ b/src/AssemblyAI/Files/FilesClient.cs @@ -33,6 +33,7 @@ public async Task UploadAsync( Method = HttpMethod.Post, Path = "v2/upload", Body = request, + ContentType = "application/octet-stream", Options = options, }, cancellationToken diff --git a/src/AssemblyAI/Lemur/ExtendedLemurClient.cs b/src/AssemblyAI/Lemur/ExtendedLemurClient.cs deleted file mode 100644 index 1a7b4ae..0000000 --- a/src/AssemblyAI/Lemur/ExtendedLemurClient.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace AssemblyAI.Lemur; - -/// -/// The client to interact with the AssemblyAI LeMUR API. -/// -public partial class LemurClient; diff --git a/src/AssemblyAI/Lemur/LemurClient.cs b/src/AssemblyAI/Lemur/LemurClient.cs index 36b72b0..130f8a1 100644 --- a/src/AssemblyAI/Lemur/LemurClient.cs +++ b/src/AssemblyAI/Lemur/LemurClient.cs @@ -26,7 +26,7 @@ internal LemurClient(RawClient client) /// await client.Lemur.TaskAsync( /// new LemurTaskParams /// { - /// TranscriptIds = new List() { "64nygnr62k-405c-4ae8-8a6b-d90b40ff3cce" }, + /// TranscriptIds = new List<string>() { "64nygnr62k-405c-4ae8-8a6b-d90b40ff3cce" }, /// Context = "This is an interview about wildfires.", /// FinalModel = LemurModel.AnthropicClaude35Sonnet, /// MaxOutputSize = 3000, @@ -49,6 +49,7 @@ public async Task TaskAsync( Method = HttpMethod.Post, Path = "lemur/v3/generate/task", Body = request, + ContentType = "application/json", Options = options, }, cancellationToken @@ -82,7 +83,7 @@ public async Task TaskAsync( /// await client.Lemur.SummaryAsync( /// new LemurSummaryParams /// { - /// TranscriptIds = new List() { "47b95ba5-8889-44d8-bc80-5de38306e582" }, + /// TranscriptIds = new List<string>() { "47b95ba5-8889-44d8-bc80-5de38306e582" }, /// Context = "This is an interview about wildfires.", /// FinalModel = LemurModel.AnthropicClaude35Sonnet, /// MaxOutputSize = 3000, @@ -104,6 +105,7 @@ public async Task SummaryAsync( Method = HttpMethod.Post, Path = "lemur/v3/generate/summary", Body = request, + ContentType = "application/json", Options = options, }, cancellationToken @@ -137,23 +139,23 @@ public async Task SummaryAsync( /// await client.Lemur.QuestionAnswerAsync( /// new LemurQuestionAnswerParams /// { - /// TranscriptIds = new List() { "64nygnr62k-405c-4ae8-8a6b-d90b40ff3cce" }, + /// TranscriptIds = new List<string>() { "64nygnr62k-405c-4ae8-8a6b-d90b40ff3cce" }, /// Context = "This is an interview about wildfires.", /// FinalModel = LemurModel.AnthropicClaude35Sonnet, /// MaxOutputSize = 3000, /// Temperature = 0f, - /// Questions = new List() + /// Questions = new List<LemurQuestion>() /// { /// new LemurQuestion /// { /// Question = "Where are there wildfires?", /// AnswerFormat = "List of countries in ISO 3166-1 alpha-2 format", - /// AnswerOptions = new List() { "US", "CA" }, + /// AnswerOptions = new List<string>() { "US", "CA" }, /// }, /// new LemurQuestion /// { /// Question = "Is global warming affecting wildfires?", - /// AnswerOptions = new List() { "yes", "no" }, + /// AnswerOptions = new List<string>() { "yes", "no" }, /// }, /// }, /// } @@ -173,6 +175,7 @@ public async Task QuestionAnswerAsync( Method = HttpMethod.Post, Path = "lemur/v3/generate/question-answer", Body = request, + ContentType = "application/json", Options = options, }, cancellationToken @@ -205,7 +208,7 @@ public async Task QuestionAnswerAsync( /// await client.Lemur.ActionItemsAsync( /// new LemurActionItemsParams /// { - /// TranscriptIds = new List() { "64nygnr62k-405c-4ae8-8a6b-d90b40ff3cce" }, + /// TranscriptIds = new List<string>() { "64nygnr62k-405c-4ae8-8a6b-d90b40ff3cce" }, /// Context = "This is an interview about wildfires.", /// FinalModel = LemurModel.AnthropicClaude35Sonnet, /// MaxOutputSize = 3000, @@ -228,6 +231,7 @@ public async Task ActionItemsAsync( Method = HttpMethod.Post, Path = "lemur/v3/generate/action-items", Body = request, + ContentType = "application/json", Options = options, }, cancellationToken diff --git a/src/AssemblyAI/Lemur/Requests/LemurActionItemsParams.cs b/src/AssemblyAI/Lemur/Requests/LemurActionItemsParams.cs index b2a08a1..8e892fb 100644 --- a/src/AssemblyAI/Lemur/Requests/LemurActionItemsParams.cs +++ b/src/AssemblyAI/Lemur/Requests/LemurActionItemsParams.cs @@ -11,7 +11,6 @@ public record LemurActionItemsParams /// /// How you want the action items to be returned. This can be any text. /// Defaults to "Bullet Points". - /// /// [JsonPropertyName("answer_format")] public string? AnswerFormat { get; set; } @@ -34,7 +33,6 @@ public record LemurActionItemsParams /// Context to provide the model. This can be a string or a free-form JSON value. /// [JsonPropertyName("context")] - [JsonConverter(typeof(OneOfSerializer>))] public OneOf? Context { get; set; } /// diff --git a/src/AssemblyAI/Lemur/Requests/LemurQuestionAnswerParams.cs b/src/AssemblyAI/Lemur/Requests/LemurQuestionAnswerParams.cs index dbdf8ef..40a5b04 100644 --- a/src/AssemblyAI/Lemur/Requests/LemurQuestionAnswerParams.cs +++ b/src/AssemblyAI/Lemur/Requests/LemurQuestionAnswerParams.cs @@ -32,7 +32,6 @@ public record LemurQuestionAnswerParams /// Context to provide the model. This can be a string or a free-form JSON value. /// [JsonPropertyName("context")] - [JsonConverter(typeof(OneOfSerializer>))] public OneOf? Context { get; set; } /// diff --git a/src/AssemblyAI/Lemur/Requests/LemurSummaryParams.cs b/src/AssemblyAI/Lemur/Requests/LemurSummaryParams.cs index 1c946e4..35e4633 100644 --- a/src/AssemblyAI/Lemur/Requests/LemurSummaryParams.cs +++ b/src/AssemblyAI/Lemur/Requests/LemurSummaryParams.cs @@ -10,7 +10,6 @@ public record LemurSummaryParams { /// /// How you want the summary to be returned. This can be any text. Examples: "TLDR", "bullet points" - /// /// [JsonPropertyName("answer_format")] public string? AnswerFormat { get; set; } @@ -33,7 +32,6 @@ public record LemurSummaryParams /// Context to provide the model. This can be a string or a free-form JSON value. /// [JsonPropertyName("context")] - [JsonConverter(typeof(OneOfSerializer>))] public OneOf? Context { get; set; } /// diff --git a/src/AssemblyAI/Lemur/Requests/LemurTaskParams.cs b/src/AssemblyAI/Lemur/Requests/LemurTaskParams.cs index bc38010..2901d5d 100644 --- a/src/AssemblyAI/Lemur/Requests/LemurTaskParams.cs +++ b/src/AssemblyAI/Lemur/Requests/LemurTaskParams.cs @@ -32,7 +32,6 @@ public record LemurTaskParams /// Context to provide the model. This can be a string or a free-form JSON value. /// [JsonPropertyName("context")] - [JsonConverter(typeof(OneOfSerializer>))] public OneOf? Context { get; set; } /// diff --git a/src/AssemblyAI/Lemur/Types/LemurBaseParams.cs b/src/AssemblyAI/Lemur/Types/LemurBaseParams.cs index d757dd1..138ebfc 100644 --- a/src/AssemblyAI/Lemur/Types/LemurBaseParams.cs +++ b/src/AssemblyAI/Lemur/Types/LemurBaseParams.cs @@ -26,7 +26,6 @@ public record LemurBaseParams /// Context to provide the model. This can be a string or a free-form JSON value. /// [JsonPropertyName("context")] - [JsonConverter(typeof(OneOfSerializer>))] public OneOf? Context { get; set; } /// diff --git a/src/AssemblyAI/Lemur/Types/LemurModel.cs b/src/AssemblyAI/Lemur/Types/LemurModel.cs index bf1b231..941b238 100644 --- a/src/AssemblyAI/Lemur/Types/LemurModel.cs +++ b/src/AssemblyAI/Lemur/Types/LemurModel.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Lemur; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum LemurModel { [EnumMember(Value = "anthropic/claude-3-5-sonnet")] @@ -27,10 +27,6 @@ public enum LemurModel [EnumMember(Value = "anthropic/claude-2")] AnthropicClaude2_0, - [EnumMember(Value = "anthropic/claude-2")] - [Obsolete("Use AnthropicClaude2_0")] - AnthropicClaude2, - [EnumMember(Value = "default")] Default, diff --git a/src/AssemblyAI/Lemur/Types/LemurQuestion.cs b/src/AssemblyAI/Lemur/Types/LemurQuestion.cs index 59ac5fc..0fca4e2 100644 --- a/src/AssemblyAI/Lemur/Types/LemurQuestion.cs +++ b/src/AssemblyAI/Lemur/Types/LemurQuestion.cs @@ -18,7 +18,6 @@ public record LemurQuestion /// Any context about the transcripts you wish to provide. This can be a string or any object. /// [JsonPropertyName("context")] - [JsonConverter(typeof(OneOfSerializer>))] public OneOf? Context { get; set; } /// diff --git a/src/AssemblyAI/Realtime/RealtimeClient.cs b/src/AssemblyAI/Realtime/RealtimeClient.cs index d06e881..b9e1c4f 100644 --- a/src/AssemblyAI/Realtime/RealtimeClient.cs +++ b/src/AssemblyAI/Realtime/RealtimeClient.cs @@ -40,6 +40,7 @@ public async Task CreateTemporaryTokenAsync( Method = HttpMethod.Post, Path = "v2/realtime/token", Body = request, + ContentType = "application/json", Options = options, }, cancellationToken diff --git a/src/AssemblyAI/Realtime/Types/AudioEncoding.cs b/src/AssemblyAI/Realtime/Types/AudioEncoding.cs index e15f895..617d74b 100644 --- a/src/AssemblyAI/Realtime/Types/AudioEncoding.cs +++ b/src/AssemblyAI/Realtime/Types/AudioEncoding.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Realtime; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum AudioEncoding { [EnumMember(Value = "pcm_s16le")] diff --git a/src/AssemblyAI/Realtime/Types/FinalTranscript.cs b/src/AssemblyAI/Realtime/Types/FinalTranscript.cs index 4816900..89e3a43 100644 --- a/src/AssemblyAI/Realtime/Types/FinalTranscript.cs +++ b/src/AssemblyAI/Realtime/Types/FinalTranscript.cs @@ -20,7 +20,7 @@ public record FinalTranscript public required bool Punctuated { get; set; } /// - /// Whether the text is formatted, for example Dollar -> $ + /// Whether the text is formatted, for example Dollar -> $ /// [JsonPropertyName("text_formatted")] public required bool TextFormatted { get; set; } diff --git a/src/AssemblyAI/Realtime/Types/MessageType.cs b/src/AssemblyAI/Realtime/Types/MessageType.cs index e315ba9..b1e7925 100644 --- a/src/AssemblyAI/Realtime/Types/MessageType.cs +++ b/src/AssemblyAI/Realtime/Types/MessageType.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Realtime; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum MessageType { [EnumMember(Value = "SessionBegins")] diff --git a/src/AssemblyAI/Realtime/Types/RealtimeTranscriptType.cs b/src/AssemblyAI/Realtime/Types/RealtimeTranscriptType.cs index 67b92f8..fa64fcb 100644 --- a/src/AssemblyAI/Realtime/Types/RealtimeTranscriptType.cs +++ b/src/AssemblyAI/Realtime/Types/RealtimeTranscriptType.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Realtime; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum RealtimeTranscriptType { [EnumMember(Value = "PartialTranscript")] diff --git a/src/AssemblyAI/Transcripts/TranscriptsClient.cs b/src/AssemblyAI/Transcripts/TranscriptsClient.cs index eec587d..a1c69a5 100644 --- a/src/AssemblyAI/Transcripts/TranscriptsClient.cs +++ b/src/AssemblyAI/Transcripts/TranscriptsClient.cs @@ -110,13 +110,13 @@ public async Task ListAsync( /// AutoHighlights = true, /// AudioStartFrom = 10, /// AudioEndAt = 280, - /// WordBoost = new List() { "aws", "azure", "google cloud" }, + /// WordBoost = new List<string>() { "aws", "azure", "google cloud" }, /// BoostParam = TranscriptBoostParam.High, /// FilterProfanity = true, /// RedactPii = true, /// RedactPiiAudio = true, /// RedactPiiAudioQuality = RedactPiiAudioQuality.Mp3, - /// RedactPiiPolicies = new List() + /// RedactPiiPolicies = new List<PiiPolicy>() /// { /// PiiPolicy.UsSocialSecurityNumber, /// PiiPolicy.CreditCardNumber, @@ -126,11 +126,11 @@ public async Task ListAsync( /// SpeakersExpected = 2, /// ContentSafety = true, /// IabCategories = true, - /// CustomSpelling = new List() + /// CustomSpelling = new List<TranscriptCustomSpelling>() /// { /// new TranscriptCustomSpelling /// { - /// From = new List() { "dicarlo" }, + /// From = new List<string>() { "dicarlo" }, /// To = "Decarlo", /// }, /// }, @@ -142,7 +142,7 @@ public async Task ListAsync( /// SummaryModel = SummaryModel.Informative, /// SummaryType = SummaryType.Bullets, /// CustomTopics = true, - /// Topics = new List() { "topics" }, + /// Topics = new List<string>() { "topics" }, /// AudioUrl = "https://assembly.ai/wildfires.mp3", /// } /// ); @@ -161,6 +161,7 @@ public async Task SubmitAsync( Method = HttpMethod.Post, Path = "v2/transcript", Body = request, + ContentType = "application/json", Options = options, }, cancellationToken @@ -303,7 +304,7 @@ public async Task GetSubtitlesAsync( { BaseUrl = _client.Options.BaseUrl, Method = HttpMethod.Get, - Path = $"v2/transcript/{transcriptId}/{subtitleFormat.Stringify()}", + Path = $"v2/transcript/{transcriptId}/{subtitleFormat}", Query = _query, Options = options, }, diff --git a/src/AssemblyAI/Transcripts/Types/AudioIntelligenceModelStatus.cs b/src/AssemblyAI/Transcripts/Types/AudioIntelligenceModelStatus.cs index 84b0259..b5c3f15 100644 --- a/src/AssemblyAI/Transcripts/Types/AudioIntelligenceModelStatus.cs +++ b/src/AssemblyAI/Transcripts/Types/AudioIntelligenceModelStatus.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum AudioIntelligenceModelStatus { [EnumMember(Value = "success")] diff --git a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs index 86fb05d..8aa0b8c 100644 --- a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs +++ b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs @@ -23,7 +23,7 @@ public record ContentSafetyLabel /// How severely the topic is discussed in the section, from 0 to 1 /// [JsonPropertyName("severity")] - public required double? Severity { get; set; } + public required double Severity { get; set; } public override string ToString() { diff --git a/src/AssemblyAI/Transcripts/Types/EntityType.cs b/src/AssemblyAI/Transcripts/Types/EntityType.cs index 98f95bc..21f9f17 100644 --- a/src/AssemblyAI/Transcripts/Types/EntityType.cs +++ b/src/AssemblyAI/Transcripts/Types/EntityType.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum EntityType { [EnumMember(Value = "account_number")] diff --git a/src/AssemblyAI/Transcripts/Types/PiiPolicy.cs b/src/AssemblyAI/Transcripts/Types/PiiPolicy.cs index 441d1f0..d277e3f 100644 --- a/src/AssemblyAI/Transcripts/Types/PiiPolicy.cs +++ b/src/AssemblyAI/Transcripts/Types/PiiPolicy.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum PiiPolicy { [EnumMember(Value = "account_number")] diff --git a/src/AssemblyAI/Transcripts/Types/RedactPiiAudioQuality.cs b/src/AssemblyAI/Transcripts/Types/RedactPiiAudioQuality.cs index 6b59661..3df5fe9 100644 --- a/src/AssemblyAI/Transcripts/Types/RedactPiiAudioQuality.cs +++ b/src/AssemblyAI/Transcripts/Types/RedactPiiAudioQuality.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum RedactPiiAudioQuality { [EnumMember(Value = "mp3")] diff --git a/src/AssemblyAI/Transcripts/Types/Sentiment.cs b/src/AssemblyAI/Transcripts/Types/Sentiment.cs index 9748841..6841a5c 100644 --- a/src/AssemblyAI/Transcripts/Types/Sentiment.cs +++ b/src/AssemblyAI/Transcripts/Types/Sentiment.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum Sentiment { [EnumMember(Value = "POSITIVE")] diff --git a/src/AssemblyAI/Transcripts/Types/SpeechModel.cs b/src/AssemblyAI/Transcripts/Types/SpeechModel.cs index ea981fd..defb060 100644 --- a/src/AssemblyAI/Transcripts/Types/SpeechModel.cs +++ b/src/AssemblyAI/Transcripts/Types/SpeechModel.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum SpeechModel { [EnumMember(Value = "best")] diff --git a/src/AssemblyAI/Transcripts/Types/SubstitutionPolicy.cs b/src/AssemblyAI/Transcripts/Types/SubstitutionPolicy.cs index b29eeb6..632c992 100644 --- a/src/AssemblyAI/Transcripts/Types/SubstitutionPolicy.cs +++ b/src/AssemblyAI/Transcripts/Types/SubstitutionPolicy.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum SubstitutionPolicy { [EnumMember(Value = "entity_name")] diff --git a/src/AssemblyAI/Transcripts/Types/SubtitleFormat.cs b/src/AssemblyAI/Transcripts/Types/SubtitleFormat.cs index ebe6a8f..5c5fad3 100644 --- a/src/AssemblyAI/Transcripts/Types/SubtitleFormat.cs +++ b/src/AssemblyAI/Transcripts/Types/SubtitleFormat.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum SubtitleFormat { [EnumMember(Value = "srt")] diff --git a/src/AssemblyAI/Transcripts/Types/SummaryModel.cs b/src/AssemblyAI/Transcripts/Types/SummaryModel.cs index d935aa2..86cfbcb 100644 --- a/src/AssemblyAI/Transcripts/Types/SummaryModel.cs +++ b/src/AssemblyAI/Transcripts/Types/SummaryModel.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum SummaryModel { [EnumMember(Value = "informative")] diff --git a/src/AssemblyAI/Transcripts/Types/SummaryType.cs b/src/AssemblyAI/Transcripts/Types/SummaryType.cs index 4145146..25632e8 100644 --- a/src/AssemblyAI/Transcripts/Types/SummaryType.cs +++ b/src/AssemblyAI/Transcripts/Types/SummaryType.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum SummaryType { [EnumMember(Value = "bullets")] diff --git a/src/AssemblyAI/Transcripts/Types/TopicDetectionResultLabelsItem.cs b/src/AssemblyAI/Transcripts/Types/TopicDetectionResultLabelsItem.cs index b9cc515..2c1ff25 100644 --- a/src/AssemblyAI/Transcripts/Types/TopicDetectionResultLabelsItem.cs +++ b/src/AssemblyAI/Transcripts/Types/TopicDetectionResultLabelsItem.cs @@ -14,7 +14,7 @@ public record TopicDetectionResultLabelsItem public required double Relevance { get; set; } /// - /// The IAB taxonomical label for the label of the detected topic, where > denotes supertopic/subtopic relationship + /// The IAB taxonomical label for the label of the detected topic, where > denotes supertopic/subtopic relationship /// [JsonPropertyName("label")] public required string Label { get; set; } diff --git a/src/AssemblyAI/Transcripts/Types/Transcript.cs b/src/AssemblyAI/Transcripts/Types/Transcript.cs index 93294f0..c20869d 100644 --- a/src/AssemblyAI/Transcripts/Types/Transcript.cs +++ b/src/AssemblyAI/Transcripts/Types/Transcript.cs @@ -5,7 +5,7 @@ namespace AssemblyAI.Transcripts; -public partial record Transcript +public record Transcript { /// /// The unique identifier of your transcript diff --git a/src/AssemblyAI/Transcripts/Types/TranscriptBoostParam.cs b/src/AssemblyAI/Transcripts/Types/TranscriptBoostParam.cs index 6f1ca95..47cdf2f 100644 --- a/src/AssemblyAI/Transcripts/Types/TranscriptBoostParam.cs +++ b/src/AssemblyAI/Transcripts/Types/TranscriptBoostParam.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum TranscriptBoostParam { [EnumMember(Value = "low")] diff --git a/src/AssemblyAI/Transcripts/Types/TranscriptLanguageCode.cs b/src/AssemblyAI/Transcripts/Types/TranscriptLanguageCode.cs index 31f39d4..172e0f6 100644 --- a/src/AssemblyAI/Transcripts/Types/TranscriptLanguageCode.cs +++ b/src/AssemblyAI/Transcripts/Types/TranscriptLanguageCode.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum TranscriptLanguageCode { [EnumMember(Value = "en")] diff --git a/src/AssemblyAI/Transcripts/Types/TranscriptReadyStatus.cs b/src/AssemblyAI/Transcripts/Types/TranscriptReadyStatus.cs index 999ae77..bcf7d89 100644 --- a/src/AssemblyAI/Transcripts/Types/TranscriptReadyStatus.cs +++ b/src/AssemblyAI/Transcripts/Types/TranscriptReadyStatus.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum TranscriptReadyStatus { [EnumMember(Value = "completed")] diff --git a/src/AssemblyAI/Transcripts/Types/TranscriptStatus.cs b/src/AssemblyAI/Transcripts/Types/TranscriptStatus.cs index 9b253d0..6554b48 100644 --- a/src/AssemblyAI/Transcripts/Types/TranscriptStatus.cs +++ b/src/AssemblyAI/Transcripts/Types/TranscriptStatus.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Transcripts; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum TranscriptStatus { [EnumMember(Value = "queued")] From e37be5941fcd0f9603401725d2e84126c9a45ae6 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 10:15:32 -0500 Subject: [PATCH 02/15] Undo undesired changes --- .fernignore | 6 ++++++ src/AssemblyAI/Core/Extensions.cs | 4 ++-- .../Public/AssemblyAIClientEnvironment.cs | 11 ++++++++-- src/AssemblyAI/Core/Public/ClientOptions.cs | 14 ++++++------- .../Core/Public/ExtendedClientOptions.cs | 21 +++++++++++++++++++ .../Core/Public/ExtendedRequestOptions.cs | 9 ++++++++ src/AssemblyAI/Lemur/ExtendedLemurClient.cs | 6 ++++++ src/AssemblyAI/Lemur/Types/LemurModel.cs | 6 +++++- 8 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 src/AssemblyAI/Core/Public/ExtendedClientOptions.cs create mode 100644 src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs create mode 100644 src/AssemblyAI/Lemur/ExtendedLemurClient.cs diff --git a/.fernignore b/.fernignore index 58ffc1e..76a3cde 100644 --- a/.fernignore +++ b/.fernignore @@ -10,6 +10,10 @@ icon.png src/AssemblyAI.sln src/AssemblyAI/AssemblyAI.csproj src/AssemblyAI/Core/JsonConfiguration.cs +src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs +src/AssemblyAI/Core/Public/ExtendedClientOptions.cs +src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs +src/AssemblyAI/Core/Public/ClientOptions.cs src/AssemblyAI/Core/Public/ApiException.cs src/AssemblyAI/Core/Public/AssemblyAIException.cs src/AssemblyAI/Core/StringEnumSerializer.cs @@ -27,6 +31,8 @@ src/AssemblyAI/Transcripts/Types/TranscriptParamsMapper.cs src/AssemblyAI/Transcripts/Types/TranscriptParamsCloner.cs src/AssemblyAI/Transcripts/TranscriptNotCompletedStatusException.cs src/AssemblyAI/Lemur/Types/LemurResponse.cs +src/AssemblyAI/Lemur/Types/LemurModel.cs +src/AssemblyAI/Lemur/ExtendedLemurClient.cs src/AssemblyAI/Realtime/RealtimeTranscriber.cs src/AssemblyAI/Realtime/WebsocketClient src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs diff --git a/src/AssemblyAI/Core/Extensions.cs b/src/AssemblyAI/Core/Extensions.cs index a1c7fef..167b9e5 100644 --- a/src/AssemblyAI/Core/Extensions.cs +++ b/src/AssemblyAI/Core/Extensions.cs @@ -4,11 +4,11 @@ namespace AssemblyAI.Core; internal static class Extensions { - public static string Stringify(this Enum value) + internal static string Stringify(this Enum value) { var field = value.GetType().GetField(value.ToString()); var attribute = (EnumMemberAttribute) - Attribute.GetCustomAttribute(field, typeof(EnumMemberAttribute)); + Attribute.GetCustomAttribute(field!, typeof(EnumMemberAttribute))!; return attribute?.Value ?? value.ToString(); } } diff --git a/src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs b/src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs index 148f07b..9bdec3e 100644 --- a/src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs +++ b/src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs @@ -1,6 +1,13 @@ +// ReSharper disable CheckNamespace namespace AssemblyAI; -public class AssemblyAIClientEnvironment +/// +/// Available AssemblyAI API environments +/// +public static class AssemblyAIClientEnvironment { - public static string Default = "https://api.assemblyai.com"; + /// + /// The default base URL for the AssemblyAI API. + /// + public const string Default = "https://api.assemblyai.com"; } diff --git a/src/AssemblyAI/Core/Public/ClientOptions.cs b/src/AssemblyAI/Core/Public/ClientOptions.cs index a12c55f..77cbe0f 100644 --- a/src/AssemblyAI/Core/Public/ClientOptions.cs +++ b/src/AssemblyAI/Core/Public/ClientOptions.cs @@ -1,8 +1,6 @@ -using System; using System.Net.Http; using AssemblyAI.Core; - -#nullable enable +// ReSharper disable CheckNamespace namespace AssemblyAI; @@ -11,22 +9,22 @@ public partial class ClientOptions /// /// The Base URL for the API. /// - public string BaseUrl { get; init; } = AssemblyAIClientEnvironment.Default; + public string BaseUrl { get; set; } = AssemblyAIClientEnvironment.Default; /// /// The http client used to make requests. /// - public HttpClient HttpClient { get; init; } = new HttpClient(); + public HttpClient HttpClient { get; set; } = new(); /// - /// The http client used to make requests. + /// The amount to retry sending the HTTP request if it fails. /// - public int MaxRetries { get; init; } = 2; + public int MaxRetries { get; set; } = 2; /// /// The timeout for the request. /// - public TimeSpan Timeout { get; init; } = TimeSpan.FromSeconds(30); + public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30); /// /// The http headers sent with the request. diff --git a/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs b/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs new file mode 100644 index 0000000..291f27b --- /dev/null +++ b/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs @@ -0,0 +1,21 @@ +// ReSharper disable PartialTypeWithSinglePart +// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global +// ReSharper disable CheckNamespace + +namespace AssemblyAI; + +/// +/// The options for the AssemblyAI client. +/// +public partial class ClientOptions +{ + /// + /// The AssemblyAI API key + /// + public required string ApiKey { get; set; } + + /// + /// The AssemblyAI user agent + /// + public UserAgent UserAgent { get; set; } = new(); +} \ No newline at end of file diff --git a/src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs b/src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs new file mode 100644 index 0000000..7dbbd7f --- /dev/null +++ b/src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs @@ -0,0 +1,9 @@ +// ReSharper disable CheckNamespace +// ReSharper disable ClassNeverInstantiated.Global + +namespace AssemblyAI; + +/// +/// The options for one or multiple requests to the AssemblyAI API. +/// +public partial class RequestOptions; diff --git a/src/AssemblyAI/Lemur/ExtendedLemurClient.cs b/src/AssemblyAI/Lemur/ExtendedLemurClient.cs new file mode 100644 index 0000000..1a7b4ae --- /dev/null +++ b/src/AssemblyAI/Lemur/ExtendedLemurClient.cs @@ -0,0 +1,6 @@ +namespace AssemblyAI.Lemur; + +/// +/// The client to interact with the AssemblyAI LeMUR API. +/// +public partial class LemurClient; diff --git a/src/AssemblyAI/Lemur/Types/LemurModel.cs b/src/AssemblyAI/Lemur/Types/LemurModel.cs index 941b238..bf1b231 100644 --- a/src/AssemblyAI/Lemur/Types/LemurModel.cs +++ b/src/AssemblyAI/Lemur/Types/LemurModel.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Lemur; -[JsonConverter(typeof(EnumSerializer))] +[JsonConverter(typeof(StringEnumSerializer))] public enum LemurModel { [EnumMember(Value = "anthropic/claude-3-5-sonnet")] @@ -27,6 +27,10 @@ public enum LemurModel [EnumMember(Value = "anthropic/claude-2")] AnthropicClaude2_0, + [EnumMember(Value = "anthropic/claude-2")] + [Obsolete("Use AnthropicClaude2_0")] + AnthropicClaude2, + [EnumMember(Value = "default")] Default, From 8b93441d38753e5c683e2b09247aacfc2d73e7a7 Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:21:52 +0000 Subject: [PATCH 03/15] SDK regeneration --- src/AssemblyAI/Core/Extensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AssemblyAI/Core/Extensions.cs b/src/AssemblyAI/Core/Extensions.cs index 167b9e5..a1c7fef 100644 --- a/src/AssemblyAI/Core/Extensions.cs +++ b/src/AssemblyAI/Core/Extensions.cs @@ -4,11 +4,11 @@ namespace AssemblyAI.Core; internal static class Extensions { - internal static string Stringify(this Enum value) + public static string Stringify(this Enum value) { var field = value.GetType().GetField(value.ToString()); var attribute = (EnumMemberAttribute) - Attribute.GetCustomAttribute(field!, typeof(EnumMemberAttribute))!; + Attribute.GetCustomAttribute(field, typeof(EnumMemberAttribute)); return attribute?.Value ?? value.ToString(); } } From 43cb2b0c94aae58e13bc6ca478b667cd8bd055b9 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 10:28:26 -0500 Subject: [PATCH 04/15] Use generated version file for User Agent --- src/AssemblyAI/Core/CustomConstants.cs | 10 ---------- src/AssemblyAI/UserAgent.cs | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 src/AssemblyAI/Core/CustomConstants.cs diff --git a/src/AssemblyAI/Core/CustomConstants.cs b/src/AssemblyAI/Core/CustomConstants.cs deleted file mode 100644 index 353dc84..0000000 --- a/src/AssemblyAI/Core/CustomConstants.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace AssemblyAI.Core; - -internal static class CustomConstants -{ - /// - /// This is used for the AssemblyAI User-Agent. - /// If you update this, make sure to also update the version numbers in AssemblyAI.csproj - /// - internal const string Version = "1.2.0"; -} \ No newline at end of file diff --git a/src/AssemblyAI/UserAgent.cs b/src/AssemblyAI/UserAgent.cs index b001f7e..bfbc81f 100644 --- a/src/AssemblyAI/UserAgent.cs +++ b/src/AssemblyAI/UserAgent.cs @@ -40,7 +40,7 @@ public UserAgent(UserAgent a, UserAgent b) { _userAgent = Merge(a._userAgent, b._userAgent) as Dictionary; } - + /// /// Get or set a user agent item by key. /// @@ -71,7 +71,7 @@ public string ToAssemblyAIUserAgentString() private static UserAgent CreateDefaultUserAgent() { var defaultUserAgent = new Dictionary(); - defaultUserAgent["sdk"] = new UserAgentItem("CSharp", CustomConstants.Version); + defaultUserAgent["sdk"] = new UserAgentItem("CSharp", Version.Current); #if NET462_OR_GREATER defaultUserAgent["runtime_env"] = new UserAgentItem(".NET Framework", $"{Environment.Version}"); #else @@ -82,7 +82,7 @@ private static UserAgent CreateDefaultUserAgent() return new UserAgent(defaultUserAgent); } - + #if NET462_OR_GREATER #else /// From 858ec6211c467fae3bd6db4605139b1b5edfd2f9 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 10:28:56 -0500 Subject: [PATCH 05/15] remove more files frm fern ignore temporarily --- .fernignore | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/.fernignore b/.fernignore index 76a3cde..2a80fcd 100644 --- a/.fernignore +++ b/.fernignore @@ -5,50 +5,30 @@ LICENSE assemblyai.png icon.png .gitignore -.github/workflows/ci.yml .github/workflows/publish-reference.yml src/AssemblyAI.sln -src/AssemblyAI/AssemblyAI.csproj -src/AssemblyAI/Core/JsonConfiguration.cs src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs src/AssemblyAI/Core/Public/ExtendedClientOptions.cs src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs src/AssemblyAI/Core/Public/ClientOptions.cs src/AssemblyAI/Core/Public/ApiException.cs src/AssemblyAI/Core/Public/AssemblyAIException.cs -src/AssemblyAI/Core/StringEnumSerializer.cs -src/AssemblyAI/Core/CustomConstants.cs -src/AssemblyAI/Types/Error.cs src/AssemblyAI/UserAgent.cs src/AssemblyAI/Event.cs -src/AssemblyAI/AssemblyAIClient.cs src/AssemblyAI/DependencyInjectionExtensions.cs -src/AssemblyAI/EnumConverter.cs src/AssemblyAI/Files/ExtendedFilesClient.cs src/AssemblyAI/Transcripts/ExtendedTranscriptsClient.cs src/AssemblyAI/Transcripts/Types/TranscriptExtensions.cs src/AssemblyAI/Transcripts/Types/TranscriptParamsMapper.cs src/AssemblyAI/Transcripts/Types/TranscriptParamsCloner.cs src/AssemblyAI/Transcripts/TranscriptNotCompletedStatusException.cs -src/AssemblyAI/Lemur/Types/LemurResponse.cs -src/AssemblyAI/Lemur/Types/LemurModel.cs src/AssemblyAI/Lemur/ExtendedLemurClient.cs src/AssemblyAI/Realtime/RealtimeTranscriber.cs src/AssemblyAI/Realtime/WebsocketClient -src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs src/AssemblyAI/Realtime/ExtendedRealtimeClient.cs src/AssemblyAI/Realtime/RealtimeTranscriberOptions.cs -src/AssemblyAI/Realtime/Types/TerminateSession.cs -src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs -src/AssemblyAI/Realtime/Types/Realtime.cs -src/AssemblyAI.Test src/AssemblyAI.UnitTests src/AssemblyAI.IntegrationTests docfx - -# TODO: remove these ignores when AssemblyAI fixes the API -src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs -src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs - Samples From a422b94684c46e217c73065635b9d07db1717371 Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:31:21 +0000 Subject: [PATCH 06/15] SDK regeneration --- .github/workflows/ci.yml | 42 +++---- .../AssemblyAI.Test.Custom.props | 7 ++ src/AssemblyAI.Test/AssemblyAI.Test.csproj | 33 +++++ .../Core/EnumSerializerTests.cs | 61 ++++++++++ src/AssemblyAI.Test/Core/RawClientTests.cs | 113 ++++++++++++++++++ src/AssemblyAI.Test/TestClient.cs | 8 ++ src/AssemblyAI/AssemblyAI.csproj | 91 ++------------ src/AssemblyAI/AssemblyAIClient.cs | 82 ++++++------- src/AssemblyAI/Core/JsonConfiguration.cs | 110 +++-------------- src/AssemblyAI/Core/StringEnumSerializer.cs | 60 ---------- src/AssemblyAI/EnumConverter.cs | 27 ----- src/AssemblyAI/Lemur/Types/LemurModel.cs | 6 +- src/AssemblyAI/Lemur/Types/LemurResponse.cs | 21 ---- .../Realtime/Types/ForceEndUtterance.cs | 20 ++++ src/AssemblyAI/Realtime/Types/Realtime.cs | 17 +++ .../Realtime/Types/RealtimeTranscript.cs | 19 --- .../Realtime/Types/TerminateSession.cs | 20 ++++ .../Types/ContentSafetyLabelsResult.cs | 12 +- .../Types/TopicDetectionModelResult.cs | 9 +- src/AssemblyAI/Types/Error.cs | 23 ++++ 20 files changed, 399 insertions(+), 382 deletions(-) create mode 100644 src/AssemblyAI.Test/AssemblyAI.Test.Custom.props create mode 100644 src/AssemblyAI.Test/AssemblyAI.Test.csproj create mode 100644 src/AssemblyAI.Test/Core/EnumSerializerTests.cs create mode 100644 src/AssemblyAI.Test/Core/RawClientTests.cs create mode 100644 src/AssemblyAI.Test/TestClient.cs delete mode 100644 src/AssemblyAI/Core/StringEnumSerializer.cs delete mode 100644 src/AssemblyAI/EnumConverter.cs delete mode 100644 src/AssemblyAI/Lemur/Types/LemurResponse.cs create mode 100644 src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs create mode 100644 src/AssemblyAI/Realtime/Types/Realtime.cs delete mode 100644 src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs create mode 100644 src/AssemblyAI/Realtime/Types/TerminateSession.cs create mode 100644 src/AssemblyAI/Types/Error.cs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86fbd20..810c2ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,16 +4,16 @@ on: [push] jobs: compile: - name: Compile runs-on: ubuntu-latest - env: - DOTNET_NOLOGO: true + steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v3 + + - uses: actions/checkout@master - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v1 with: dotnet-version: 8.x @@ -24,29 +24,19 @@ jobs: - name: Build Release run: dotnet build src -c Release /p:ContinuousIntegrationBuild=true - tests: - strategy: - fail-fast: false - matrix: - framework: [net462, net6.0] - os: [ubuntu-latest, windows-latest] - exclude: - - os: ubuntu-latest - framework: net462 - name: Run Tests on ${{ matrix.os }} with ${{ matrix.framework }} + unit-tests: runs-on: ubuntu-latest + steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v3 - uses: actions/checkout@master - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v1 with: - dotnet-version: | - 8.x - 6.x + dotnet-version: 8.x - name: Install tools run: | @@ -54,24 +44,20 @@ jobs: - name: Run Tests run: | - dotnet test src --framework ${{ matrix.framework }} - env: - ASSEMBLYAI_API_KEY: ${{ secrets.ASSEMBLYAI_API_KEY }} - TEST_TRANSCRIPT_ID: ${{ secrets.TEST_TRANSCRIPT_ID }} - TEST_TRANSCRIPT_IDS: ${{ secrets.TEST_TRANSCRIPT_IDS }} + dotnet test src + publish: - name: Publish to NuGet needs: [compile] if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v4 + uses: actions/checkout@v3 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v1 with: dotnet-version: 8.x diff --git a/src/AssemblyAI.Test/AssemblyAI.Test.Custom.props b/src/AssemblyAI.Test/AssemblyAI.Test.Custom.props new file mode 100644 index 0000000..55e683b --- /dev/null +++ b/src/AssemblyAI.Test/AssemblyAI.Test.Custom.props @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/src/AssemblyAI.Test/AssemblyAI.Test.csproj b/src/AssemblyAI.Test/AssemblyAI.Test.csproj new file mode 100644 index 0000000..44d0560 --- /dev/null +++ b/src/AssemblyAI.Test/AssemblyAI.Test.csproj @@ -0,0 +1,33 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + \ No newline at end of file diff --git a/src/AssemblyAI.Test/Core/EnumSerializerTests.cs b/src/AssemblyAI.Test/Core/EnumSerializerTests.cs new file mode 100644 index 0000000..32fdcb7 --- /dev/null +++ b/src/AssemblyAI.Test/Core/EnumSerializerTests.cs @@ -0,0 +1,61 @@ +using System; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; +using AssemblyAI.Core; +using NUnit.Framework; + +namespace AssemblyAI.Test.Core +{ + [TestFixture] + public class StringEnumSerializerTests + { + private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true }; + + private const DummyEnum KnownEnumValue2 = DummyEnum.KnownValue2; + private const string KnownEnumValue2String = "known_value2"; + + private static readonly string JsonWithKnownEnum2 = $$""" + { + "enum_property": "{{KnownEnumValue2String}}" + } + """; + + [Test] + public void ShouldParseKnownEnumValue2() + { + var obj = JsonSerializer.Deserialize(JsonWithKnownEnum2, JsonOptions); + Assert.That(obj, Is.Not.Null); + Assert.That(obj.EnumProperty, Is.EqualTo(KnownEnumValue2)); + } + + [Test] + public void ShouldSerializeKnownEnumValue2() + { + var json = JsonSerializer.SerializeToElement( + new DummyObject { EnumProperty = KnownEnumValue2 }, + JsonOptions + ); + TestContext.Out.WriteLine("Serialized JSON: \n" + json); + var enumString = json.GetProperty("enum_property").GetString(); + Assert.That(enumString, Is.Not.Null); + Assert.That(enumString, Is.EqualTo(KnownEnumValue2String)); + } + } + + public class DummyObject + { + [JsonPropertyName("enum_property")] + public DummyEnum EnumProperty { get; set; } + } + + [JsonConverter(typeof(EnumSerializer))] + public enum DummyEnum + { + [EnumMember(Value = "known_value1")] + KnownValue1, + + [EnumMember(Value = "known_value2")] + KnownValue2, + } +} diff --git a/src/AssemblyAI.Test/Core/RawClientTests.cs b/src/AssemblyAI.Test/Core/RawClientTests.cs new file mode 100644 index 0000000..d9a8d70 --- /dev/null +++ b/src/AssemblyAI.Test/Core/RawClientTests.cs @@ -0,0 +1,113 @@ +using System; +using System.Net.Http; +using AssemblyAI.Core; +using FluentAssertions; +using NUnit.Framework; +using WireMock.Server; +using SystemTask = System.Threading.Tasks.Task; +using WireMockRequest = WireMock.RequestBuilders.Request; +using WireMockResponse = WireMock.ResponseBuilders.Response; + +namespace AssemblyAI.Test.Core +{ + [TestFixture] + public class RawClientTests + { + private WireMockServer _server; + private HttpClient _httpClient; + private RawClient _rawClient; + private string _baseUrl; + private const int _maxRetries = 3; + + [SetUp] + public void SetUp() + { + _server = WireMockServer.Start(); + _baseUrl = _server.Url ?? ""; + _httpClient = new HttpClient { BaseAddress = new Uri(_baseUrl) }; + _rawClient = new RawClient( + new ClientOptions() { HttpClient = _httpClient, MaxRetries = _maxRetries } + ); + } + + [Test] + [TestCase(408)] + [TestCase(429)] + [TestCase(500)] + [TestCase(504)] + public async SystemTask MakeRequestAsync_ShouldRetry_OnRetryableStatusCodes(int statusCode) + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WhenStateIs("Server Error") + .WillSetStateTo("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode)); + + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WhenStateIs("Success") + .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); + + var request = new RawClient.BaseApiRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.MakeRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(200)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.That(content, Is.EqualTo("Success")); + + Assert.That(_server.LogEntries.Count, Is.EqualTo(_maxRetries)); + } + + [Test] + [TestCase(400)] + [TestCase(409)] + public async SystemTask MakeRequestAsync_ShouldRetry_OnNonRetryableStatusCodes( + int statusCode + ) + { + _server + .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) + .InScenario("Retry") + .WillSetStateTo("Server Error") + .RespondWith( + WireMockResponse.Create().WithStatusCode(statusCode).WithBody("Failure") + ); + + var request = new RawClient.BaseApiRequest + { + BaseUrl = _baseUrl, + Method = HttpMethod.Get, + Path = "/test", + }; + + var response = await _rawClient.MakeRequestAsync(request); + Assert.That(response.StatusCode, Is.EqualTo(statusCode)); + + var content = await response.Raw.Content.ReadAsStringAsync(); + Assert.That(content, Is.EqualTo("Failure")); + + Assert.That(_server.LogEntries.Count, Is.EqualTo(1)); + } + + [TearDown] + public void TearDown() + { + _server.Dispose(); + _httpClient.Dispose(); + } + } +} diff --git a/src/AssemblyAI.Test/TestClient.cs b/src/AssemblyAI.Test/TestClient.cs new file mode 100644 index 0000000..c8c868b --- /dev/null +++ b/src/AssemblyAI.Test/TestClient.cs @@ -0,0 +1,8 @@ +using NUnit.Framework; + +#nullable enable + +namespace AssemblyAI.Test; + +[TestFixture] +public class TestClient { } diff --git a/src/AssemblyAI/AssemblyAI.csproj b/src/AssemblyAI/AssemblyAI.csproj index 2213c92..593c6d6 100644 --- a/src/AssemblyAI/AssemblyAI.csproj +++ b/src/AssemblyAI/AssemblyAI.csproj @@ -1,109 +1,44 @@ + net462;net8.0;net7.0;net6.0;netstandard2.0 enable - false 12 enable - AssemblyAI - AssemblyAI - AssemblyAI - 1.2.0 - 1.2.0.0 - 1.2.0.0 - 1.2.0 - AssemblyAI C# .NET SDK - AssemblyAI - The AssemblyAI C# .NET SDK provides an easy-to-use interface for interacting with the AssemblyAI API, which supports async and real-time transcription, audio intelligence models, as well as the latest LeMUR models. - Copyright 2024 (c) AssemblyAI, Inc. All rights reserved. - ASR;Speech-To-Text;STT;Speech;AI;AssemblyAI - AssemblyAI - AssemblyAI - Library - MIT - https://github.com/AssemblyAI/assemblyai-csharp-sdk - https://github.com/AssemblyAI/assemblyai-csharp-sdk.git - https://www.assemblyai.com/favicon.png - icon.png + 1.2.1 + $(Version) + $(Version) README.md - true - true - true - snupkg - git - - - true - - - - - - - - + https://github.com/AssemblyAI/assemblyai-csharp-sdk true - - - - - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - - - - - - - - + + - - + - <_Parameter1>AssemblyAI.UnitTests + <_Parameter1>AssemblyAI.Test - - - - - - - - - - - - - - - - - - - - + diff --git a/src/AssemblyAI/AssemblyAIClient.cs b/src/AssemblyAI/AssemblyAIClient.cs index 6f14267..1da89d8 100644 --- a/src/AssemblyAI/AssemblyAIClient.cs +++ b/src/AssemblyAI/AssemblyAIClient.cs @@ -1,63 +1,49 @@ -using System.Net.Http; using AssemblyAI.Core; using AssemblyAI.Files; using AssemblyAI.Lemur; using AssemblyAI.Realtime; using AssemblyAI.Transcripts; +#nullable enable namespace AssemblyAI; -/// -/// The client to interact with the AssemblyAI API. -/// -public class AssemblyAIClient +public partial class AssemblyAIClient { - /// - public FilesClient Files { get; private init; } - - /// - public ExtendedTranscriptsClient Transcripts { get; private init; } - - /// - public RealtimeClient Realtime { get; private init; } - - /// - public LemurClient Lemur { get; private init; } - - /// - /// Create a new instance of the class. - /// - /// Your AssemblyAI API key - /// Thrown if apiKey is null or empty. - public AssemblyAIClient(string apiKey) : this(new ClientOptions - { - ApiKey = apiKey - }) - { - } + private RawClient _client; - /// - /// Create a new instance of the class. - /// - /// The AssemblyAI client options - /// Thrown if ClientOptions.ApiKey is null or empty. - public AssemblyAIClient(ClientOptions clientOptions) + public AssemblyAIClient(string? apiKey = null, ClientOptions? clientOptions = null) { - if (string.IsNullOrEmpty(clientOptions.ApiKey)) + var defaultHeaders = new Headers( + new Dictionary() + { + { "Authorization", apiKey }, + { "X-Fern-Language", "C#" }, + { "X-Fern-SDK-Name", "AssemblyAI" }, + { "X-Fern-SDK-Version", Version.Current }, + { "User-Agent", "AssemblyAI/1.2.1" }, + } + ); + clientOptions ??= new ClientOptions(); + foreach (var header in defaultHeaders) { - throw new ArgumentException("AssemblyAI API Key is required."); + if (!clientOptions.Headers.ContainsKey(header.Key)) + { + clientOptions.Headers[header.Key] = header.Value; + } } - - // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract - clientOptions.HttpClient ??= new HttpClient(); - clientOptions.Headers.Add("Authorization", clientOptions.ApiKey); - clientOptions.Headers.Add("User-Agent", new UserAgent(UserAgent.Default, clientOptions.UserAgent).ToAssemblyAIUserAgentString()); - var client = new RawClient(clientOptions); - - Files = new FilesClient(client); - Transcripts = new ExtendedTranscriptsClient(client, this); - Realtime = new RealtimeClient(client); - Lemur = new LemurClient(client); + _client = new RawClient(clientOptions); + Files = new FilesClient(_client); + Transcripts = new TranscriptsClient(_client); + Realtime = new RealtimeClient(_client); + Lemur = new LemurClient(_client); } -} \ No newline at end of file + + public FilesClient Files { get; init; } + + public TranscriptsClient Transcripts { get; init; } + + public RealtimeClient Realtime { get; init; } + + public LemurClient Lemur { get; init; } +} diff --git a/src/AssemblyAI/Core/JsonConfiguration.cs b/src/AssemblyAI/Core/JsonConfiguration.cs index 7606b88..769365f 100644 --- a/src/AssemblyAI/Core/JsonConfiguration.cs +++ b/src/AssemblyAI/Core/JsonConfiguration.cs @@ -1,110 +1,36 @@ using System.Text.Json; -using System.Text.Json.Nodes; using System.Text.Json.Serialization; -using AssemblyAI.Lemur; -using OneOf; namespace AssemblyAI.Core; -/// -/// The JSON options used by the AssemblyAI SDK. -/// -internal static class JsonOptions +internal static partial class JsonOptions { - /// - /// The JSON options used by the AssemblyAI SDK. - /// - internal static readonly JsonSerializerOptions JsonSerializerOptions; + public static readonly JsonSerializerOptions JsonSerializerOptions; static JsonOptions() { - JsonSerializerOptions = new JsonSerializerOptions + var options = new JsonSerializerOptions { - Converters = - { - new DateTimeSerializer(), - new OneOfSerializer>() - }, + Converters = { new DateTimeSerializer(), new OneOfSerializer() }, WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, }; + ConfigureJsonSerializerOptions(options); + JsonSerializerOptions = options; } + + static partial void ConfigureJsonSerializerOptions(JsonSerializerOptions defaultOptions); } -/// -/// Utilities class for JSON serialization and deserialization. -/// -public static class JsonUtils +internal static class JsonUtils { - /// - /// Serialize an object to JSON using the AssemblyAI SDKs JSON options. - /// - /// Object to serialize - /// Type of the object to serialize - /// The object serialized as JSON - public static string Serialize(T obj) - => JsonSerializer.Serialize(obj, JsonOptions.JsonSerializerOptions); - - /// - /// Serialize an object to JSON using the AssemblyAI SDKs JSON options. - /// - /// Object to serialize - /// Type of the object to serialize - /// The object serialized as JSON - public static JsonDocument SerializeToDocument(T obj) - => JsonSerializer.SerializeToDocument(obj, JsonOptions.JsonSerializerOptions); - - /// - /// Serialize an object to JSON using the AssemblyAI SDKs JSON options. - /// - /// Object to serialize - /// Type of the object to serialize - /// The object serialized as JSON - public static JsonElement SerializeToElement(T obj) - => JsonSerializer.SerializeToElement(obj, JsonOptions.JsonSerializerOptions); - - /// - /// Serialize an object to JSON using the AssemblyAI SDKs JSON options. - /// - /// Object to serialize - /// Type of the object to serialize - /// The object serialized as JSON - public static JsonNode? SerializeToNode(T obj) - => JsonSerializer.SerializeToNode(obj, JsonOptions.JsonSerializerOptions); - - /// - /// Deserialize a JSON string to an object using the AssemblyAI SDKs JSON options. - /// - /// The JSON string - /// The type to deserialize the JSON to - /// The deserialized object of type T - public static T Deserialize(string json) - => JsonSerializer.Deserialize(json, JsonOptions.JsonSerializerOptions)!; - - /// - /// Deserialize a JSON document to an object using the AssemblyAI SDKs JSON options. - /// - /// The JSON string - /// The type to deserialize the JSON to - /// The deserialized object of type T - public static T Deserialize(JsonDocument json) - => json.Deserialize(JsonOptions.JsonSerializerOptions)!; - - /// - /// Deserialize a JSON element to an object using the AssemblyAI SDKs JSON options. - /// - /// The JSON string - /// The type to deserialize the JSON to - /// The deserialized object of type T - public static T Deserialize(JsonElement json) - => json.Deserialize(JsonOptions.JsonSerializerOptions)!; + public static string Serialize(T obj) + { + return JsonSerializer.Serialize(obj, JsonOptions.JsonSerializerOptions); + } - /// - /// Deserialize a JSON node to an object using the AssemblyAI SDKs JSON options. - /// - /// The JSON string - /// The type to deserialize the JSON to - /// The deserialized object of type T - public static T Deserialize(JsonNode json) - => json.Deserialize(JsonOptions.JsonSerializerOptions)!; -} \ No newline at end of file + public static T Deserialize(string json) + { + return JsonSerializer.Deserialize(json, JsonOptions.JsonSerializerOptions)!; + } +} diff --git a/src/AssemblyAI/Core/StringEnumSerializer.cs b/src/AssemblyAI/Core/StringEnumSerializer.cs deleted file mode 100644 index 9b53fef..0000000 --- a/src/AssemblyAI/Core/StringEnumSerializer.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Runtime.Serialization; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace AssemblyAI.Core; - -internal class StringEnumSerializer : JsonConverter - where TEnum : struct, System.Enum -{ - private readonly Dictionary _enumToString = new(); - private readonly Dictionary _stringToEnum = new(); - - public StringEnumSerializer() - { - var type = typeof(TEnum); - var values = Enum.GetValues(type); - - foreach (var value in values) - { - var enumValue = (TEnum)value; - var enumMember = type.GetMember(enumValue.ToString())[0]; - var attr = enumMember - .GetCustomAttributes(typeof(EnumMemberAttribute), false) - .Cast() - .FirstOrDefault(); - - var stringValue = - attr?.Value - ?? value.ToString() - ?? throw new Exception("Unexpected null enum toString value"); - - if(!_enumToString.ContainsKey(enumValue)) - { - _enumToString.Add(enumValue, stringValue); - } - - if (!_stringToEnum.ContainsKey(stringValue)) - { - _stringToEnum.Add(stringValue, enumValue); - } - } - } - - public override TEnum Read( - ref Utf8JsonReader reader, - System.Type typeToConvert, - JsonSerializerOptions options - ) - { - var stringValue = - reader.GetString() - ?? throw new Exception("The JSON value could not be read as a string."); - return _stringToEnum.TryGetValue(stringValue, out var enumValue) ? enumValue : default; - } - - public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options) - { - writer.WriteStringValue(_enumToString[value]); - } -} diff --git a/src/AssemblyAI/EnumConverter.cs b/src/AssemblyAI/EnumConverter.cs deleted file mode 100644 index 6384bd2..0000000 --- a/src/AssemblyAI/EnumConverter.cs +++ /dev/null @@ -1,27 +0,0 @@ -using AssemblyAI.Core; - -namespace AssemblyAI; - -/// -/// Convert an AssemblyAI enum to a string and vice versa. -/// -public static class EnumConverter -{ - /// - /// Convert a string value to an enum. For example, "en_us" to TranscriptLanguageCode.EnUs. - /// - /// String value of the enum - /// The enum type to convert into - /// An enum value of the given enum type - /// This method uses the Value property of EnumMemberAttribute on the given enum value. - public static T ToEnum(string value) where T : Enum => JsonUtils.Deserialize($"\"{value}\""); - - /// - /// Convert an enum value to a string value. For example, TranscriptLanguageCode.EnUs to "en_us". - /// - /// Enum value - /// - /// The string value of the given enum - /// This method uses the Value property of EnumMemberAttribute on the given enum value. - public static string ToString(T value) where T : Enum => JsonUtils.Serialize(value).Trim('"'); -} \ No newline at end of file diff --git a/src/AssemblyAI/Lemur/Types/LemurModel.cs b/src/AssemblyAI/Lemur/Types/LemurModel.cs index bf1b231..941b238 100644 --- a/src/AssemblyAI/Lemur/Types/LemurModel.cs +++ b/src/AssemblyAI/Lemur/Types/LemurModel.cs @@ -6,7 +6,7 @@ namespace AssemblyAI.Lemur; -[JsonConverter(typeof(StringEnumSerializer))] +[JsonConverter(typeof(EnumSerializer))] public enum LemurModel { [EnumMember(Value = "anthropic/claude-3-5-sonnet")] @@ -27,10 +27,6 @@ public enum LemurModel [EnumMember(Value = "anthropic/claude-2")] AnthropicClaude2_0, - [EnumMember(Value = "anthropic/claude-2")] - [Obsolete("Use AnthropicClaude2_0")] - AnthropicClaude2, - [EnumMember(Value = "default")] Default, diff --git a/src/AssemblyAI/Lemur/Types/LemurResponse.cs b/src/AssemblyAI/Lemur/Types/LemurResponse.cs deleted file mode 100644 index 345ccc4..0000000 --- a/src/AssemblyAI/Lemur/Types/LemurResponse.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Text.Json.Serialization; -using AssemblyAI.Core; -using OneOf; - -namespace AssemblyAI.Lemur; - -public class LemurResponse : OneOfBase -{ - private LemurResponse(OneOf response) : base(response) - { - } - - public static implicit operator LemurResponse(OneOf _) => new(_); - public static implicit operator LemurResponse(LemurStringResponse _) => new(_); - public static implicit operator LemurResponse(LemurQuestionAnswerResponse _) => new(_); - - public bool IsLemurStringResponse => IsT0; - public bool IsLemurQuestionAnswerResponse => IsT1; - public LemurStringResponse AsLemurStringResponse => AsT0; - public LemurQuestionAnswerResponse AsLemurQuestionAnswerResponse => AsT1; -} \ No newline at end of file diff --git a/src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs b/src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs new file mode 100644 index 0000000..1ceef1a --- /dev/null +++ b/src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; +using AssemblyAI.Core; + +#nullable enable + +namespace AssemblyAI.Realtime; + +public record ForceEndUtterance +{ + /// + /// A boolean value to communicate that you wish to force the end of the utterance + /// + [JsonPropertyName("force_end_utterance")] + public required bool ForceEndUtterance_ { get; set; } + + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/AssemblyAI/Realtime/Types/Realtime.cs b/src/AssemblyAI/Realtime/Types/Realtime.cs new file mode 100644 index 0000000..a0a389b --- /dev/null +++ b/src/AssemblyAI/Realtime/Types/Realtime.cs @@ -0,0 +1,17 @@ +using System.Runtime.Serialization; +using System.Text.Json.Serialization; +using AssemblyAI.Core; + +#nullable enable + +namespace AssemblyAI.Realtime; + +[JsonConverter(typeof(EnumSerializer))] +public enum Realtime +{ + [EnumMember(Value = "pcm_s16le")] + PcmS16le, + + [EnumMember(Value = "pcm_mulaw")] + PcmMulaw, +} diff --git a/src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs b/src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs deleted file mode 100644 index 9c03d21..0000000 --- a/src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs +++ /dev/null @@ -1,19 +0,0 @@ -using OneOf; - -// ReSharper disable once CheckNamespace -namespace AssemblyAI.Realtime; - -public class RealtimeTranscript : OneOfBase -{ - private RealtimeTranscript(OneOf transcript) : base(transcript) - { - } - - public static implicit operator RealtimeTranscript(PartialTranscript _) => new(_); - public static implicit operator RealtimeTranscript(FinalTranscript _) => new(_); - - public bool IsPartialTranscript => IsT0; - public bool IsFinalTranscript => IsT1; - public PartialTranscript AsPartialTranscript => AsT0; - public FinalTranscript AsFinalTranscript => AsT1; -} \ No newline at end of file diff --git a/src/AssemblyAI/Realtime/Types/TerminateSession.cs b/src/AssemblyAI/Realtime/Types/TerminateSession.cs new file mode 100644 index 0000000..c61ade6 --- /dev/null +++ b/src/AssemblyAI/Realtime/Types/TerminateSession.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; +using AssemblyAI.Core; + +#nullable enable + +namespace AssemblyAI.Realtime; + +public record TerminateSession +{ + /// + /// Set to true to end your streaming session forever + /// + [JsonPropertyName("terminate_session")] + public required bool TerminateSession_ { get; set; } + + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs index da73443..5b5c57e 100644 --- a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs +++ b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs @@ -1,5 +1,5 @@ using System.Text.Json.Serialization; -using AssemblyAI.Transcripts; +using AssemblyAI.Core; #nullable enable @@ -11,8 +11,11 @@ public record ContentSafetyLabelsResult /// The status of the Content Moderation model. Either success, or unavailable in the rare case that the model failed. /// [JsonPropertyName("status")] - public AudioIntelligenceModelStatus Status { get; set; } + public required AudioIntelligenceModelStatus Status { get; set; } + /// + /// An array of results for the Content Moderation model + /// [JsonPropertyName("results")] public IEnumerable Results { get; set; } = new List(); @@ -29,4 +32,9 @@ public record ContentSafetyLabelsResult [JsonPropertyName("severity_score_summary")] public Dictionary SeverityScoreSummary { get; set; } = new Dictionary(); + + public override string ToString() + { + return JsonUtils.Serialize(this); + } } diff --git a/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs b/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs index fa7d26f..b7a7714 100644 --- a/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs +++ b/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs @@ -1,5 +1,5 @@ using System.Text.Json.Serialization; -using AssemblyAI.Transcripts; +using AssemblyAI.Core; #nullable enable @@ -11,7 +11,7 @@ public record TopicDetectionModelResult /// The status of the Topic Detection model. Either success, or unavailable in the rare case that the model failed. /// [JsonPropertyName("status")] - public AudioIntelligenceModelStatus Status { get; set; } + public required AudioIntelligenceModelStatus Status { get; set; } /// /// An array of results for the Topic Detection model @@ -25,4 +25,9 @@ public record TopicDetectionModelResult /// [JsonPropertyName("summary")] public Dictionary Summary { get; set; } = new Dictionary(); + + public override string ToString() + { + return JsonUtils.Serialize(this); + } } diff --git a/src/AssemblyAI/Types/Error.cs b/src/AssemblyAI/Types/Error.cs new file mode 100644 index 0000000..0764cb8 --- /dev/null +++ b/src/AssemblyAI/Types/Error.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; +using AssemblyAI.Core; + +#nullable enable + +namespace AssemblyAI; + +public record Error +{ + /// + /// Error message + /// + [JsonPropertyName("error")] + public required string Error_ { get; set; } + + [JsonPropertyName("status")] + public string? Status { get; set; } + + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} From e91c97c2890054ec7388ddc2642b960fa8687904 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 11:25:24 -0500 Subject: [PATCH 07/15] Undo undesired changes/fix solution --- .fernignore | 28 ++++- .github/workflows/ci.yml | 42 ++++--- .../Core/EnumSerializerTests.cs | 2 +- src/AssemblyAI.Test/Core/RawClientTests.cs | 113 ------------------ src/AssemblyAI.Test/TestClient.cs | 8 -- .../AssemblyAI.UnitTests.csproj | 10 +- src/AssemblyAI.sln | 10 +- src/AssemblyAI/AssemblyAI.Custom.props | 56 +++++++-- src/AssemblyAI/AssemblyAI.csproj | 1 - src/AssemblyAI/AssemblyAIClient.cs | 82 +++++++------ src/AssemblyAI/Core/EnumSerializer.cs | 11 +- src/AssemblyAI/Core/JsonConfiguration.cs | 82 +++++++++++-- src/AssemblyAI/Core/Public/ClientOptions.cs | 15 --- .../Core/Public/ExtendedClientOptions.cs | 19 +++ src/AssemblyAI/EnumConverter.cs | 27 +++++ src/AssemblyAI/Lemur/Types/LemurModel.cs | 4 + src/AssemblyAI/Lemur/Types/LemurResponse.cs | 21 ++++ .../Realtime/Types/ForceEndUtterance.cs | 20 ---- src/AssemblyAI/Realtime/Types/Realtime.cs | 17 --- .../Realtime/Types/RealtimeTranscript.cs | 19 +++ .../Realtime/Types/TerminateSession.cs | 20 ---- .../Types/ContentSafetyLabelsResult.cs | 3 +- .../Types/TopicDetectionModelResult.cs | 3 +- src/AssemblyAI/Types/Error.cs | 23 ---- src/AssemblyAI/UserAgent.cs | 16 +++ 25 files changed, 355 insertions(+), 297 deletions(-) delete mode 100644 src/AssemblyAI.Test/Core/RawClientTests.cs delete mode 100644 src/AssemblyAI.Test/TestClient.cs create mode 100644 src/AssemblyAI/EnumConverter.cs create mode 100644 src/AssemblyAI/Lemur/Types/LemurResponse.cs delete mode 100644 src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs delete mode 100644 src/AssemblyAI/Realtime/Types/Realtime.cs create mode 100644 src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs delete mode 100644 src/AssemblyAI/Realtime/Types/TerminateSession.cs delete mode 100644 src/AssemblyAI/Types/Error.cs diff --git a/.fernignore b/.fernignore index 2a80fcd..d7bf0cc 100644 --- a/.fernignore +++ b/.fernignore @@ -5,29 +5,47 @@ LICENSE assemblyai.png icon.png .gitignore +.github/workflows/ci.yml .github/workflows/publish-reference.yml src/AssemblyAI.sln +src/AssemblyAI/AssemblyAI.Custom.props +src/AssemblyAI/AssemblyAIClient.cs +src/AssemblyAI/UserAgent.cs +src/AssemblyAI/Event.cs +src/AssemblyAI/DependencyInjectionExtensions.cs +src/AssemblyAI/EnumConverter.cs +src/AssemblyAI/Types/Error.cs +src/AssemblyAI/Core/EnumSerializer.cs +src/AssemblyAI/Core/JsonConfiguration.cs src/AssemblyAI/Core/Public/ExtendedRequestOptions.cs -src/AssemblyAI/Core/Public/ExtendedClientOptions.cs src/AssemblyAI/Core/Public/AssemblyAIClientEnvironment.cs src/AssemblyAI/Core/Public/ClientOptions.cs +src/AssemblyAI/Core/Public/ExtendedClientOptions.cs src/AssemblyAI/Core/Public/ApiException.cs src/AssemblyAI/Core/Public/AssemblyAIException.cs -src/AssemblyAI/UserAgent.cs -src/AssemblyAI/Event.cs -src/AssemblyAI/DependencyInjectionExtensions.cs src/AssemblyAI/Files/ExtendedFilesClient.cs src/AssemblyAI/Transcripts/ExtendedTranscriptsClient.cs +src/AssemblyAI/Transcripts/TranscriptNotCompletedStatusException.cs src/AssemblyAI/Transcripts/Types/TranscriptExtensions.cs src/AssemblyAI/Transcripts/Types/TranscriptParamsMapper.cs src/AssemblyAI/Transcripts/Types/TranscriptParamsCloner.cs -src/AssemblyAI/Transcripts/TranscriptNotCompletedStatusException.cs +src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs +src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs src/AssemblyAI/Lemur/ExtendedLemurClient.cs +src/AssemblyAI/Lemur/Types/LemurResponse.cs +src/AssemblyAI/Lemur/Types/LemurModel.cs src/AssemblyAI/Realtime/RealtimeTranscriber.cs src/AssemblyAI/Realtime/WebsocketClient src/AssemblyAI/Realtime/ExtendedRealtimeClient.cs src/AssemblyAI/Realtime/RealtimeTranscriberOptions.cs +src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs +src/AssemblyAI/Realtime/Types/TerminateSession.cs +src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs +src/AssemblyAI/Realtime/Types/Realtime.cs +src/AssemblyAI.Test/TestClient.cs +src/AssemblyAI.Test/Core/RawClientTests.cs src/AssemblyAI.UnitTests + src/AssemblyAI.IntegrationTests docfx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 810c2ca..86fbd20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,16 +4,16 @@ on: [push] jobs: compile: + name: Compile runs-on: ubuntu-latest - + env: + DOTNET_NOLOGO: true steps: - name: Checkout repo - uses: actions/checkout@v3 - - - uses: actions/checkout@master + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: dotnet-version: 8.x @@ -24,19 +24,29 @@ jobs: - name: Build Release run: dotnet build src -c Release /p:ContinuousIntegrationBuild=true - unit-tests: + tests: + strategy: + fail-fast: false + matrix: + framework: [net462, net6.0] + os: [ubuntu-latest, windows-latest] + exclude: + - os: ubuntu-latest + framework: net462 + name: Run Tests on ${{ matrix.os }} with ${{ matrix.framework }} runs-on: ubuntu-latest - steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - uses: actions/checkout@master - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.x + dotnet-version: | + 8.x + 6.x - name: Install tools run: | @@ -44,20 +54,24 @@ jobs: - name: Run Tests run: | - dotnet test src - + dotnet test src --framework ${{ matrix.framework }} + env: + ASSEMBLYAI_API_KEY: ${{ secrets.ASSEMBLYAI_API_KEY }} + TEST_TRANSCRIPT_ID: ${{ secrets.TEST_TRANSCRIPT_ID }} + TEST_TRANSCRIPT_IDS: ${{ secrets.TEST_TRANSCRIPT_IDS }} publish: + name: Publish to NuGet needs: [compile] if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: dotnet-version: 8.x diff --git a/src/AssemblyAI.Test/Core/EnumSerializerTests.cs b/src/AssemblyAI.Test/Core/EnumSerializerTests.cs index 32fdcb7..ad33b46 100644 --- a/src/AssemblyAI.Test/Core/EnumSerializerTests.cs +++ b/src/AssemblyAI.Test/Core/EnumSerializerTests.cs @@ -8,7 +8,7 @@ namespace AssemblyAI.Test.Core { [TestFixture] - public class StringEnumSerializerTests + public class EnumSerializerTests { private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true }; diff --git a/src/AssemblyAI.Test/Core/RawClientTests.cs b/src/AssemblyAI.Test/Core/RawClientTests.cs deleted file mode 100644 index d9a8d70..0000000 --- a/src/AssemblyAI.Test/Core/RawClientTests.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using System.Net.Http; -using AssemblyAI.Core; -using FluentAssertions; -using NUnit.Framework; -using WireMock.Server; -using SystemTask = System.Threading.Tasks.Task; -using WireMockRequest = WireMock.RequestBuilders.Request; -using WireMockResponse = WireMock.ResponseBuilders.Response; - -namespace AssemblyAI.Test.Core -{ - [TestFixture] - public class RawClientTests - { - private WireMockServer _server; - private HttpClient _httpClient; - private RawClient _rawClient; - private string _baseUrl; - private const int _maxRetries = 3; - - [SetUp] - public void SetUp() - { - _server = WireMockServer.Start(); - _baseUrl = _server.Url ?? ""; - _httpClient = new HttpClient { BaseAddress = new Uri(_baseUrl) }; - _rawClient = new RawClient( - new ClientOptions() { HttpClient = _httpClient, MaxRetries = _maxRetries } - ); - } - - [Test] - [TestCase(408)] - [TestCase(429)] - [TestCase(500)] - [TestCase(504)] - public async SystemTask MakeRequestAsync_ShouldRetry_OnRetryableStatusCodes(int statusCode) - { - _server - .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) - .InScenario("Retry") - .WillSetStateTo("Server Error") - .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode)); - - _server - .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) - .InScenario("Retry") - .WhenStateIs("Server Error") - .WillSetStateTo("Success") - .RespondWith(WireMockResponse.Create().WithStatusCode(statusCode)); - - _server - .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) - .InScenario("Retry") - .WhenStateIs("Success") - .RespondWith(WireMockResponse.Create().WithStatusCode(200).WithBody("Success")); - - var request = new RawClient.BaseApiRequest - { - BaseUrl = _baseUrl, - Method = HttpMethod.Get, - Path = "/test", - }; - - var response = await _rawClient.MakeRequestAsync(request); - Assert.That(response.StatusCode, Is.EqualTo(200)); - - var content = await response.Raw.Content.ReadAsStringAsync(); - Assert.That(content, Is.EqualTo("Success")); - - Assert.That(_server.LogEntries.Count, Is.EqualTo(_maxRetries)); - } - - [Test] - [TestCase(400)] - [TestCase(409)] - public async SystemTask MakeRequestAsync_ShouldRetry_OnNonRetryableStatusCodes( - int statusCode - ) - { - _server - .Given(WireMockRequest.Create().WithPath("/test").UsingGet()) - .InScenario("Retry") - .WillSetStateTo("Server Error") - .RespondWith( - WireMockResponse.Create().WithStatusCode(statusCode).WithBody("Failure") - ); - - var request = new RawClient.BaseApiRequest - { - BaseUrl = _baseUrl, - Method = HttpMethod.Get, - Path = "/test", - }; - - var response = await _rawClient.MakeRequestAsync(request); - Assert.That(response.StatusCode, Is.EqualTo(statusCode)); - - var content = await response.Raw.Content.ReadAsStringAsync(); - Assert.That(content, Is.EqualTo("Failure")); - - Assert.That(_server.LogEntries.Count, Is.EqualTo(1)); - } - - [TearDown] - public void TearDown() - { - _server.Dispose(); - _httpClient.Dispose(); - } - } -} diff --git a/src/AssemblyAI.Test/TestClient.cs b/src/AssemblyAI.Test/TestClient.cs deleted file mode 100644 index c8c868b..0000000 --- a/src/AssemblyAI.Test/TestClient.cs +++ /dev/null @@ -1,8 +0,0 @@ -using NUnit.Framework; - -#nullable enable - -namespace AssemblyAI.Test; - -[TestFixture] -public class TestClient { } diff --git a/src/AssemblyAI.UnitTests/AssemblyAI.UnitTests.csproj b/src/AssemblyAI.UnitTests/AssemblyAI.UnitTests.csproj index f4966e9..c55147c 100644 --- a/src/AssemblyAI.UnitTests/AssemblyAI.UnitTests.csproj +++ b/src/AssemblyAI.UnitTests/AssemblyAI.UnitTests.csproj @@ -26,7 +26,10 @@ - + + + FernGenerated\%(RecursiveDir)%(Filename)%(Extension) + @@ -36,4 +39,9 @@ all + + + + + \ No newline at end of file diff --git a/src/AssemblyAI.sln b/src/AssemblyAI.sln index 5870e21..b4139df 100644 --- a/src/AssemblyAI.sln +++ b/src/AssemblyAI.sln @@ -7,7 +7,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyAI", "AssemblyAI\As EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyAI.IntegrationTests", "AssemblyAI.IntegrationTests\AssemblyAI.IntegrationTests.csproj", "{311AB518-6FCF-453B-A4B7-12E444C9479E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyAI.UnitTests", "AssemblyAI.UnitTests\AssemblyAI.UnitTests.csproj", "{F432A09F-C463-438F-AF0D-EB7951F0DBB9}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyAI.UnitTests", "AssemblyAI.UnitTests\AssemblyAI.UnitTests.csproj", "{547C3456-F649-4E68-A591-0538486F7DE3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -26,9 +26,9 @@ Global {311AB518-6FCF-453B-A4B7-12E444C9479E}.Debug|Any CPU.Build.0 = Debug|Any CPU {311AB518-6FCF-453B-A4B7-12E444C9479E}.Release|Any CPU.ActiveCfg = Release|Any CPU {311AB518-6FCF-453B-A4B7-12E444C9479E}.Release|Any CPU.Build.0 = Release|Any CPU - {F432A09F-C463-438F-AF0D-EB7951F0DBB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F432A09F-C463-438F-AF0D-EB7951F0DBB9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F432A09F-C463-438F-AF0D-EB7951F0DBB9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F432A09F-C463-438F-AF0D-EB7951F0DBB9}.Release|Any CPU.Build.0 = Release|Any CPU + {547C3456-F649-4E68-A591-0538486F7DE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {547C3456-F649-4E68-A591-0538486F7DE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {547C3456-F649-4E68-A591-0538486F7DE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {547C3456-F649-4E68-A591-0538486F7DE3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/AssemblyAI/AssemblyAI.Custom.props b/src/AssemblyAI/AssemblyAI.Custom.props index 70df284..9aa6220 100644 --- a/src/AssemblyAI/AssemblyAI.Custom.props +++ b/src/AssemblyAI/AssemblyAI.Custom.props @@ -4,17 +4,57 @@ Configure additional MSBuild properties for your project in this file: - Step 2: Modify this file to your liking. --> - \ No newline at end of file diff --git a/src/AssemblyAI/AssemblyAI.csproj b/src/AssemblyAI/AssemblyAI.csproj index 593c6d6..12924ae 100644 --- a/src/AssemblyAI/AssemblyAI.csproj +++ b/src/AssemblyAI/AssemblyAI.csproj @@ -1,4 +1,3 @@ - diff --git a/src/AssemblyAI/AssemblyAIClient.cs b/src/AssemblyAI/AssemblyAIClient.cs index 1da89d8..6f14267 100644 --- a/src/AssemblyAI/AssemblyAIClient.cs +++ b/src/AssemblyAI/AssemblyAIClient.cs @@ -1,49 +1,63 @@ +using System.Net.Http; using AssemblyAI.Core; using AssemblyAI.Files; using AssemblyAI.Lemur; using AssemblyAI.Realtime; using AssemblyAI.Transcripts; -#nullable enable namespace AssemblyAI; -public partial class AssemblyAIClient +/// +/// The client to interact with the AssemblyAI API. +/// +public class AssemblyAIClient { - private RawClient _client; + /// + public FilesClient Files { get; private init; } + + /// + public ExtendedTranscriptsClient Transcripts { get; private init; } + + /// + public RealtimeClient Realtime { get; private init; } + + /// + public LemurClient Lemur { get; private init; } + + /// + /// Create a new instance of the class. + /// + /// Your AssemblyAI API key + /// Thrown if apiKey is null or empty. + public AssemblyAIClient(string apiKey) : this(new ClientOptions + { + ApiKey = apiKey + }) + { + } - public AssemblyAIClient(string? apiKey = null, ClientOptions? clientOptions = null) + /// + /// Create a new instance of the class. + /// + /// The AssemblyAI client options + /// Thrown if ClientOptions.ApiKey is null or empty. + public AssemblyAIClient(ClientOptions clientOptions) { - var defaultHeaders = new Headers( - new Dictionary() - { - { "Authorization", apiKey }, - { "X-Fern-Language", "C#" }, - { "X-Fern-SDK-Name", "AssemblyAI" }, - { "X-Fern-SDK-Version", Version.Current }, - { "User-Agent", "AssemblyAI/1.2.1" }, - } - ); - clientOptions ??= new ClientOptions(); - foreach (var header in defaultHeaders) + if (string.IsNullOrEmpty(clientOptions.ApiKey)) { - if (!clientOptions.Headers.ContainsKey(header.Key)) - { - clientOptions.Headers[header.Key] = header.Value; - } + throw new ArgumentException("AssemblyAI API Key is required."); } - _client = new RawClient(clientOptions); - Files = new FilesClient(_client); - Transcripts = new TranscriptsClient(_client); - Realtime = new RealtimeClient(_client); - Lemur = new LemurClient(_client); + + // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract + clientOptions.HttpClient ??= new HttpClient(); + clientOptions.Headers.Add("Authorization", clientOptions.ApiKey); + clientOptions.Headers.Add("User-Agent", new UserAgent(UserAgent.Default, clientOptions.UserAgent).ToAssemblyAIUserAgentString()); + var client = new RawClient(clientOptions); + + Files = new FilesClient(client); + Transcripts = new ExtendedTranscriptsClient(client, this); + Realtime = new RealtimeClient(client); + Lemur = new LemurClient(client); } - - public FilesClient Files { get; init; } - - public TranscriptsClient Transcripts { get; init; } - - public RealtimeClient Realtime { get; init; } - - public LemurClient Lemur { get; init; } -} +} \ No newline at end of file diff --git a/src/AssemblyAI/Core/EnumSerializer.cs b/src/AssemblyAI/Core/EnumSerializer.cs index ef9a1ff..6710643 100644 --- a/src/AssemblyAI/Core/EnumSerializer.cs +++ b/src/AssemblyAI/Core/EnumSerializer.cs @@ -29,8 +29,15 @@ public EnumSerializer() ?? value.ToString() ?? throw new Exception("Unexpected null enum toString value"); - _enumToString.Add(enumValue, stringValue); - _stringToEnum.Add(stringValue, enumValue); + if(!_enumToString.ContainsKey(enumValue)) + { + _enumToString.Add(enumValue, stringValue); + } + + if (!_stringToEnum.ContainsKey(stringValue)) + { + _stringToEnum.Add(stringValue, enumValue); + } } } diff --git a/src/AssemblyAI/Core/JsonConfiguration.cs b/src/AssemblyAI/Core/JsonConfiguration.cs index 769365f..7d75fe4 100644 --- a/src/AssemblyAI/Core/JsonConfiguration.cs +++ b/src/AssemblyAI/Core/JsonConfiguration.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.Json.Serialization; namespace AssemblyAI.Core; @@ -22,15 +23,80 @@ static JsonOptions() static partial void ConfigureJsonSerializerOptions(JsonSerializerOptions defaultOptions); } -internal static class JsonUtils +/// +/// Utilities class for JSON serialization and deserialization. +/// +public static class JsonUtils { + /// + /// Serialize an object to JSON using the AssemblyAI SDKs JSON options. + /// + /// Object to serialize + /// Type of the object to serialize + /// The object serialized as JSON public static string Serialize(T obj) - { - return JsonSerializer.Serialize(obj, JsonOptions.JsonSerializerOptions); - } + => JsonSerializer.Serialize(obj, JsonOptions.JsonSerializerOptions); + + /// + /// Serialize an object to JSON using the AssemblyAI SDKs JSON options. + /// + /// Object to serialize + /// Type of the object to serialize + /// The object serialized as JSON + public static JsonDocument SerializeToDocument(T obj) + => JsonSerializer.SerializeToDocument(obj, JsonOptions.JsonSerializerOptions); + /// + /// Serialize an object to JSON using the AssemblyAI SDKs JSON options. + /// + /// Object to serialize + /// Type of the object to serialize + /// The object serialized as JSON + public static JsonElement SerializeToElement(T obj) + => JsonSerializer.SerializeToElement(obj, JsonOptions.JsonSerializerOptions); + + /// + /// Serialize an object to JSON using the AssemblyAI SDKs JSON options. + /// + /// Object to serialize + /// Type of the object to serialize + /// The object serialized as JSON + public static JsonNode? SerializeToNode(T obj) + => JsonSerializer.SerializeToNode(obj, JsonOptions.JsonSerializerOptions); + + /// + /// Deserialize a JSON string to an object using the AssemblyAI SDKs JSON options. + /// + /// The JSON string + /// The type to deserialize the JSON to + /// The deserialized object of type T public static T Deserialize(string json) - { - return JsonSerializer.Deserialize(json, JsonOptions.JsonSerializerOptions)!; - } -} + => JsonSerializer.Deserialize(json, JsonOptions.JsonSerializerOptions)!; + + /// + /// Deserialize a JSON document to an object using the AssemblyAI SDKs JSON options. + /// + /// The JSON string + /// The type to deserialize the JSON to + /// The deserialized object of type T + public static T Deserialize(JsonDocument json) + => json.Deserialize(JsonOptions.JsonSerializerOptions)!; + + /// + /// Deserialize a JSON element to an object using the AssemblyAI SDKs JSON options. + /// + /// The JSON string + /// The type to deserialize the JSON to + /// The deserialized object of type T + public static T Deserialize(JsonElement json) + => json.Deserialize(JsonOptions.JsonSerializerOptions)!; + + /// + /// Deserialize a JSON node to an object using the AssemblyAI SDKs JSON options. + /// + /// The JSON string + /// The type to deserialize the JSON to + /// The deserialized object of type T + public static T Deserialize(JsonNode json) + => json.Deserialize(JsonOptions.JsonSerializerOptions)!; +} \ No newline at end of file diff --git a/src/AssemblyAI/Core/Public/ClientOptions.cs b/src/AssemblyAI/Core/Public/ClientOptions.cs index 77cbe0f..8241f7a 100644 --- a/src/AssemblyAI/Core/Public/ClientOptions.cs +++ b/src/AssemblyAI/Core/Public/ClientOptions.cs @@ -30,19 +30,4 @@ public partial class ClientOptions /// The http headers sent with the request. /// internal Headers Headers { get; init; } = new(); - - /// - /// Clones this and returns a new instance - /// - internal ClientOptions Clone() - { - return new ClientOptions - { - BaseUrl = BaseUrl, - HttpClient = HttpClient, - MaxRetries = MaxRetries, - Timeout = Timeout, - Headers = new Headers(new Dictionary(Headers)), - }; - } } diff --git a/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs b/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs index 291f27b..4f666e2 100644 --- a/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs +++ b/src/AssemblyAI/Core/Public/ExtendedClientOptions.cs @@ -2,6 +2,8 @@ // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global // ReSharper disable CheckNamespace +using AssemblyAI.Core; + namespace AssemblyAI; /// @@ -18,4 +20,21 @@ public partial class ClientOptions /// The AssemblyAI user agent /// public UserAgent UserAgent { get; set; } = new(); + + /// + /// Clones this and returns a new instance + /// + internal ClientOptions Clone() + { + return new ClientOptions + { + ApiKey = ApiKey, + UserAgent = UserAgent.Clone(), + BaseUrl = BaseUrl, + HttpClient = HttpClient, + MaxRetries = MaxRetries, + Timeout = Timeout, + Headers = new Headers(new Dictionary(Headers)), + }; + } } \ No newline at end of file diff --git a/src/AssemblyAI/EnumConverter.cs b/src/AssemblyAI/EnumConverter.cs new file mode 100644 index 0000000..6384bd2 --- /dev/null +++ b/src/AssemblyAI/EnumConverter.cs @@ -0,0 +1,27 @@ +using AssemblyAI.Core; + +namespace AssemblyAI; + +/// +/// Convert an AssemblyAI enum to a string and vice versa. +/// +public static class EnumConverter +{ + /// + /// Convert a string value to an enum. For example, "en_us" to TranscriptLanguageCode.EnUs. + /// + /// String value of the enum + /// The enum type to convert into + /// An enum value of the given enum type + /// This method uses the Value property of EnumMemberAttribute on the given enum value. + public static T ToEnum(string value) where T : Enum => JsonUtils.Deserialize($"\"{value}\""); + + /// + /// Convert an enum value to a string value. For example, TranscriptLanguageCode.EnUs to "en_us". + /// + /// Enum value + /// + /// The string value of the given enum + /// This method uses the Value property of EnumMemberAttribute on the given enum value. + public static string ToString(T value) where T : Enum => JsonUtils.Serialize(value).Trim('"'); +} \ No newline at end of file diff --git a/src/AssemblyAI/Lemur/Types/LemurModel.cs b/src/AssemblyAI/Lemur/Types/LemurModel.cs index 941b238..cf87e74 100644 --- a/src/AssemblyAI/Lemur/Types/LemurModel.cs +++ b/src/AssemblyAI/Lemur/Types/LemurModel.cs @@ -27,6 +27,10 @@ public enum LemurModel [EnumMember(Value = "anthropic/claude-2")] AnthropicClaude2_0, + [EnumMember(Value = "anthropic/claude-2")] + [Obsolete("Use AnthropicClaude2_0")] + AnthropicClaude2, + [EnumMember(Value = "default")] Default, diff --git a/src/AssemblyAI/Lemur/Types/LemurResponse.cs b/src/AssemblyAI/Lemur/Types/LemurResponse.cs new file mode 100644 index 0000000..345ccc4 --- /dev/null +++ b/src/AssemblyAI/Lemur/Types/LemurResponse.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; +using AssemblyAI.Core; +using OneOf; + +namespace AssemblyAI.Lemur; + +public class LemurResponse : OneOfBase +{ + private LemurResponse(OneOf response) : base(response) + { + } + + public static implicit operator LemurResponse(OneOf _) => new(_); + public static implicit operator LemurResponse(LemurStringResponse _) => new(_); + public static implicit operator LemurResponse(LemurQuestionAnswerResponse _) => new(_); + + public bool IsLemurStringResponse => IsT0; + public bool IsLemurQuestionAnswerResponse => IsT1; + public LemurStringResponse AsLemurStringResponse => AsT0; + public LemurQuestionAnswerResponse AsLemurQuestionAnswerResponse => AsT1; +} \ No newline at end of file diff --git a/src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs b/src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs deleted file mode 100644 index 1ceef1a..0000000 --- a/src/AssemblyAI/Realtime/Types/ForceEndUtterance.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Text.Json.Serialization; -using AssemblyAI.Core; - -#nullable enable - -namespace AssemblyAI.Realtime; - -public record ForceEndUtterance -{ - /// - /// A boolean value to communicate that you wish to force the end of the utterance - /// - [JsonPropertyName("force_end_utterance")] - public required bool ForceEndUtterance_ { get; set; } - - public override string ToString() - { - return JsonUtils.Serialize(this); - } -} diff --git a/src/AssemblyAI/Realtime/Types/Realtime.cs b/src/AssemblyAI/Realtime/Types/Realtime.cs deleted file mode 100644 index a0a389b..0000000 --- a/src/AssemblyAI/Realtime/Types/Realtime.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Runtime.Serialization; -using System.Text.Json.Serialization; -using AssemblyAI.Core; - -#nullable enable - -namespace AssemblyAI.Realtime; - -[JsonConverter(typeof(EnumSerializer))] -public enum Realtime -{ - [EnumMember(Value = "pcm_s16le")] - PcmS16le, - - [EnumMember(Value = "pcm_mulaw")] - PcmMulaw, -} diff --git a/src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs b/src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs new file mode 100644 index 0000000..9c03d21 --- /dev/null +++ b/src/AssemblyAI/Realtime/Types/RealtimeTranscript.cs @@ -0,0 +1,19 @@ +using OneOf; + +// ReSharper disable once CheckNamespace +namespace AssemblyAI.Realtime; + +public class RealtimeTranscript : OneOfBase +{ + private RealtimeTranscript(OneOf transcript) : base(transcript) + { + } + + public static implicit operator RealtimeTranscript(PartialTranscript _) => new(_); + public static implicit operator RealtimeTranscript(FinalTranscript _) => new(_); + + public bool IsPartialTranscript => IsT0; + public bool IsFinalTranscript => IsT1; + public PartialTranscript AsPartialTranscript => AsT0; + public FinalTranscript AsFinalTranscript => AsT1; +} \ No newline at end of file diff --git a/src/AssemblyAI/Realtime/Types/TerminateSession.cs b/src/AssemblyAI/Realtime/Types/TerminateSession.cs deleted file mode 100644 index c61ade6..0000000 --- a/src/AssemblyAI/Realtime/Types/TerminateSession.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Text.Json.Serialization; -using AssemblyAI.Core; - -#nullable enable - -namespace AssemblyAI.Realtime; - -public record TerminateSession -{ - /// - /// Set to true to end your streaming session forever - /// - [JsonPropertyName("terminate_session")] - public required bool TerminateSession_ { get; set; } - - public override string ToString() - { - return JsonUtils.Serialize(this); - } -} diff --git a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs index 5b5c57e..6025352 100644 --- a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs +++ b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs @@ -1,5 +1,6 @@ using System.Text.Json.Serialization; using AssemblyAI.Core; +using AssemblyAI.Transcripts; #nullable enable @@ -11,7 +12,7 @@ public record ContentSafetyLabelsResult /// The status of the Content Moderation model. Either success, or unavailable in the rare case that the model failed. /// [JsonPropertyName("status")] - public required AudioIntelligenceModelStatus Status { get; set; } + public AudioIntelligenceModelStatus Status { get; set; } /// /// An array of results for the Content Moderation model diff --git a/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs b/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs index b7a7714..b094a05 100644 --- a/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs +++ b/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using AssemblyAI.Transcripts; using AssemblyAI.Core; #nullable enable @@ -11,7 +12,7 @@ public record TopicDetectionModelResult /// The status of the Topic Detection model. Either success, or unavailable in the rare case that the model failed. /// [JsonPropertyName("status")] - public required AudioIntelligenceModelStatus Status { get; set; } + public AudioIntelligenceModelStatus Status { get; set; } /// /// An array of results for the Topic Detection model diff --git a/src/AssemblyAI/Types/Error.cs b/src/AssemblyAI/Types/Error.cs deleted file mode 100644 index 0764cb8..0000000 --- a/src/AssemblyAI/Types/Error.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Text.Json.Serialization; -using AssemblyAI.Core; - -#nullable enable - -namespace AssemblyAI; - -public record Error -{ - /// - /// Error message - /// - [JsonPropertyName("error")] - public required string Error_ { get; set; } - - [JsonPropertyName("status")] - public string? Status { get; set; } - - public override string ToString() - { - return JsonUtils.Serialize(this); - } -} diff --git a/src/AssemblyAI/UserAgent.cs b/src/AssemblyAI/UserAgent.cs index bfbc81f..625616d 100644 --- a/src/AssemblyAI/UserAgent.cs +++ b/src/AssemblyAI/UserAgent.cs @@ -152,6 +152,14 @@ private static Dictionary Merge( return newUserAgent as Dictionary; } + + /// + /// Clones this and returns a new instance + /// + internal UserAgent Clone() + { + return new UserAgent(_userAgent.ToDictionary(kv => kv.Key, kv => kv.Value?.Clone())); + } } /// @@ -163,4 +171,12 @@ public class UserAgentItem(string name, string version) { public string Name { get; set; } = name; public string Version { get; set; } = version; + + /// + /// Clones this and returns a new instance + /// + internal UserAgentItem Clone() + { + return new UserAgentItem(Name, Version); + } } \ No newline at end of file From 61dc80989b79ad9f291b255def7caf8b0091a788 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 11:44:04 -0500 Subject: [PATCH 08/15] Use non deprecated Lemur model in test --- src/AssemblyAI.IntegrationTests/LemurTests.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/AssemblyAI.IntegrationTests/LemurTests.cs b/src/AssemblyAI.IntegrationTests/LemurTests.cs index 8977d4a..a65dbf7 100644 --- a/src/AssemblyAI.IntegrationTests/LemurTests.cs +++ b/src/AssemblyAI.IntegrationTests/LemurTests.cs @@ -13,7 +13,7 @@ public async Task Should_Generate_Summary() var client = Helpers.CreateClient(); var response = await client.Lemur.SummaryAsync(new LemurSummaryParams { - FinalModel = LemurModel.Basic, + FinalModel = LemurModel.AnthropicClaude3_Haiku, TranscriptIds = TranscriptIds, AnswerFormat = "one sentence" }).ConfigureAwait(false); @@ -32,7 +32,7 @@ public async Task Should_Generate_Answer() var client = Helpers.CreateClient(); var response = await client.Lemur.QuestionAnswerAsync(new LemurQuestionAnswerParams { - FinalModel = LemurModel.Basic, + FinalModel = LemurModel.AnthropicClaude3_Haiku, TranscriptIds = TranscriptIds, Questions = new[] { @@ -63,7 +63,7 @@ public async Task Should_Generate_Action_Items() var client = Helpers.CreateClient(); var response = await client.Lemur.ActionItemsAsync(new LemurActionItemsParams { - FinalModel = LemurModel.Basic, + FinalModel = LemurModel.AnthropicClaude3_Haiku, TranscriptIds = TranscriptIds }).ConfigureAwait(false); @@ -81,7 +81,7 @@ public async Task Should_Generate_Task() var client = Helpers.CreateClient(); var response = await client.Lemur.TaskAsync(new LemurTaskParams { - FinalModel = LemurModel.Basic, + FinalModel = LemurModel.AnthropicClaude3_Haiku, TranscriptIds = TranscriptIds, Prompt = "Write a haiku about this conversation." }).ConfigureAwait(false); @@ -101,7 +101,7 @@ public void Should_Fail_To_Generate_Summary() var client = Helpers.CreateClient(); var ex = Assert.ThrowsAsync(async () => await client.Lemur.SummaryAsync(new LemurSummaryParams { - FinalModel = LemurModel.Basic, + FinalModel = LemurModel.AnthropicClaude3_Haiku, TranscriptIds = ["bad-id"], AnswerFormat = "one sentence" }).ConfigureAwait(false)); @@ -115,7 +115,7 @@ public async Task Should_Return_Response() var client = Helpers.CreateClient(); var taskResponse = await client.Lemur.TaskAsync(new LemurTaskParams { - FinalModel = LemurModel.Basic, + FinalModel = LemurModel.AnthropicClaude3_Haiku, TranscriptIds = TranscriptIds, Prompt = "Write a haiku about this conversation." }).ConfigureAwait(false); @@ -132,7 +132,7 @@ public async Task Should_Return_Response() var qaResponse = await client.Lemur.QuestionAnswerAsync(new LemurQuestionAnswerParams { - FinalModel = LemurModel.Basic, + FinalModel = LemurModel.AnthropicClaude3_Haiku, TranscriptIds = TranscriptIds, Questions = [ @@ -145,7 +145,7 @@ public async Task Should_Return_Response() }).ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false); - + var qaResponse2OneOf = await client.Lemur.GetResponseAsync(qaResponse.RequestId).ConfigureAwait(false); var qaResponse2 = qaResponse2OneOf.AsT1; Assert.Multiple(() => @@ -161,13 +161,13 @@ public async Task Should_Purge_Request_Data() var client = Helpers.CreateClient(); var summaryResponse = await client.Lemur.SummaryAsync(new LemurSummaryParams { - FinalModel = LemurModel.Basic, + FinalModel = LemurModel.AnthropicClaude3_Haiku, TranscriptIds = TranscriptIds, AnswerFormat = "one sentence" }).ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false); - + var deletionRequest = await client.Lemur.PurgeRequestDataAsync(summaryResponse.RequestId).ConfigureAwait(false); Assert.Multiple(() => { From 82384b4a857d52815a9f4e15f55a7b19d1d0ab89 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:12:57 -0500 Subject: [PATCH 09/15] Make ContentSafetyLabel.Severity nullable --- .fernignore | 5 +++-- src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.fernignore b/.fernignore index d7bf0cc..8c5a672 100644 --- a/.fernignore +++ b/.fernignore @@ -29,8 +29,6 @@ src/AssemblyAI/Transcripts/TranscriptNotCompletedStatusException.cs src/AssemblyAI/Transcripts/Types/TranscriptExtensions.cs src/AssemblyAI/Transcripts/Types/TranscriptParamsMapper.cs src/AssemblyAI/Transcripts/Types/TranscriptParamsCloner.cs -src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs -src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs src/AssemblyAI/Lemur/ExtendedLemurClient.cs src/AssemblyAI/Lemur/Types/LemurResponse.cs src/AssemblyAI/Lemur/Types/LemurModel.cs @@ -50,3 +48,6 @@ src/AssemblyAI.IntegrationTests docfx Samples + +# TODO: remove these ignores when AssemblyAI fixes the API +src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs \ No newline at end of file diff --git a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs index 8aa0b8c..86fb05d 100644 --- a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs +++ b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs @@ -23,7 +23,7 @@ public record ContentSafetyLabel /// How severely the topic is discussed in the section, from 0 to 1 /// [JsonPropertyName("severity")] - public required double Severity { get; set; } + public required double? Severity { get; set; } public override string ToString() { From f181ba07f4fc06478f1db801211b1735dcf8e6d2 Mon Sep 17 00:00:00 2001 From: fern-api <115122769+fern-api[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:15:04 +0000 Subject: [PATCH 10/15] SDK regeneration --- src/AssemblyAI.Test/Core/EnumSerializerTests.cs | 2 +- src/AssemblyAI/AssemblyAI.csproj | 1 + src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs | 3 +-- src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/AssemblyAI.Test/Core/EnumSerializerTests.cs b/src/AssemblyAI.Test/Core/EnumSerializerTests.cs index ad33b46..32fdcb7 100644 --- a/src/AssemblyAI.Test/Core/EnumSerializerTests.cs +++ b/src/AssemblyAI.Test/Core/EnumSerializerTests.cs @@ -8,7 +8,7 @@ namespace AssemblyAI.Test.Core { [TestFixture] - public class EnumSerializerTests + public class StringEnumSerializerTests { private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true }; diff --git a/src/AssemblyAI/AssemblyAI.csproj b/src/AssemblyAI/AssemblyAI.csproj index 12924ae..593c6d6 100644 --- a/src/AssemblyAI/AssemblyAI.csproj +++ b/src/AssemblyAI/AssemblyAI.csproj @@ -1,3 +1,4 @@ + diff --git a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs index 6025352..5b5c57e 100644 --- a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs +++ b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs @@ -1,6 +1,5 @@ using System.Text.Json.Serialization; using AssemblyAI.Core; -using AssemblyAI.Transcripts; #nullable enable @@ -12,7 +11,7 @@ public record ContentSafetyLabelsResult /// The status of the Content Moderation model. Either success, or unavailable in the rare case that the model failed. /// [JsonPropertyName("status")] - public AudioIntelligenceModelStatus Status { get; set; } + public required AudioIntelligenceModelStatus Status { get; set; } /// /// An array of results for the Content Moderation model diff --git a/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs b/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs index b094a05..b7a7714 100644 --- a/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs +++ b/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs @@ -1,5 +1,4 @@ using System.Text.Json.Serialization; -using AssemblyAI.Transcripts; using AssemblyAI.Core; #nullable enable @@ -12,7 +11,7 @@ public record TopicDetectionModelResult /// The status of the Topic Detection model. Either success, or unavailable in the rare case that the model failed. /// [JsonPropertyName("status")] - public AudioIntelligenceModelStatus Status { get; set; } + public required AudioIntelligenceModelStatus Status { get; set; } /// /// An array of results for the Topic Detection model From 174fdc2837f83bd270940a9fd550adb137cae019 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:17:03 -0500 Subject: [PATCH 11/15] undo undesired changes --- .fernignore | 4 +++- src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs | 2 +- src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.fernignore b/.fernignore index 8c5a672..d62dbe2 100644 --- a/.fernignore +++ b/.fernignore @@ -50,4 +50,6 @@ docfx Samples # TODO: remove these ignores when AssemblyAI fixes the API -src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs \ No newline at end of file +src/AssemblyAI/Transcripts/Types/ContentSafetyLabel.cs +src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs +src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs \ No newline at end of file diff --git a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs index 5b5c57e..a785a55 100644 --- a/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs +++ b/src/AssemblyAI/Transcripts/Types/ContentSafetyLabelsResult.cs @@ -11,7 +11,7 @@ public record ContentSafetyLabelsResult /// The status of the Content Moderation model. Either success, or unavailable in the rare case that the model failed. /// [JsonPropertyName("status")] - public required AudioIntelligenceModelStatus Status { get; set; } + public AudioIntelligenceModelStatus Status { get; set; } /// /// An array of results for the Content Moderation model diff --git a/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs b/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs index b7a7714..b41d7ad 100644 --- a/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs +++ b/src/AssemblyAI/Transcripts/Types/TopicDetectionModelResult.cs @@ -11,7 +11,7 @@ public record TopicDetectionModelResult /// The status of the Topic Detection model. Either success, or unavailable in the rare case that the model failed. /// [JsonPropertyName("status")] - public required AudioIntelligenceModelStatus Status { get; set; } + public AudioIntelligenceModelStatus Status { get; set; } /// /// An array of results for the Topic Detection model From 54297f55e505b410d1320a95c9c42f79a90fe5c6 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:23:31 -0500 Subject: [PATCH 12/15] Use AnthropicClaude2_1 for Action items --- src/AssemblyAI.IntegrationTests/LemurTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AssemblyAI.IntegrationTests/LemurTests.cs b/src/AssemblyAI.IntegrationTests/LemurTests.cs index a65dbf7..37502d9 100644 --- a/src/AssemblyAI.IntegrationTests/LemurTests.cs +++ b/src/AssemblyAI.IntegrationTests/LemurTests.cs @@ -63,7 +63,7 @@ public async Task Should_Generate_Action_Items() var client = Helpers.CreateClient(); var response = await client.Lemur.ActionItemsAsync(new LemurActionItemsParams { - FinalModel = LemurModel.AnthropicClaude3_Haiku, + FinalModel = LemurModel.AnthropicClaude2_1, TranscriptIds = TranscriptIds }).ConfigureAwait(false); From e21601e2116789679fa5c2d427fe80e41c0690bf Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:29:57 -0500 Subject: [PATCH 13/15] Fix GetSubtitlesAsync --- src/AssemblyAI/Transcripts/TranscriptsClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AssemblyAI/Transcripts/TranscriptsClient.cs b/src/AssemblyAI/Transcripts/TranscriptsClient.cs index a1c69a5..7fae161 100644 --- a/src/AssemblyAI/Transcripts/TranscriptsClient.cs +++ b/src/AssemblyAI/Transcripts/TranscriptsClient.cs @@ -303,8 +303,8 @@ public async Task GetSubtitlesAsync( new RawClient.JsonApiRequest { BaseUrl = _client.Options.BaseUrl, - Method = HttpMethod.Get, - Path = $"v2/transcript/{transcriptId}/{subtitleFormat}", + Method = HttpMethod.Get, + Path = $"v2/transcript/{transcriptId}/{subtitleFormat.Stringify()}", Query = _query, Options = options, }, From 65fa5d4ccf8978dabc822cf443791ba322fe7009 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:39:30 -0500 Subject: [PATCH 14/15] Run tests on correct GH actions runner --- .github/workflows/ci.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86fbd20..282cbc6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,13 +28,13 @@ jobs: strategy: fail-fast: false matrix: - framework: [net462, net6.0] + framework: [net462, net8.0] os: [ubuntu-latest, windows-latest] exclude: - os: ubuntu-latest framework: net462 name: Run Tests on ${{ matrix.os }} with ${{ matrix.framework }} - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} steps: - name: Checkout repo uses: actions/checkout@v4 @@ -44,9 +44,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: | - 8.x - 6.x + dotnet-version: 8.x - name: Install tools run: | From 67283af9d3aa8e155af1be9a081fa1e83667bb25 Mon Sep 17 00:00:00 2001 From: Niels Swimberghe <3382717+Swimburger@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:43:39 -0500 Subject: [PATCH 15/15] Target net8.0 for test projects --- .../AssemblyAI.IntegrationTests.csproj | 2 +- src/AssemblyAI.UnitTests/AssemblyAI.UnitTests.csproj | 2 +- src/AssemblyAI.UnitTests/UserAgentTests.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AssemblyAI.IntegrationTests/AssemblyAI.IntegrationTests.csproj b/src/AssemblyAI.IntegrationTests/AssemblyAI.IntegrationTests.csproj index daa67ba..4f09e4c 100644 --- a/src/AssemblyAI.IntegrationTests/AssemblyAI.IntegrationTests.csproj +++ b/src/AssemblyAI.IntegrationTests/AssemblyAI.IntegrationTests.csproj @@ -1,7 +1,7 @@ - net462;net6.0 + net462;net8.0 enable enable 12 diff --git a/src/AssemblyAI.UnitTests/AssemblyAI.UnitTests.csproj b/src/AssemblyAI.UnitTests/AssemblyAI.UnitTests.csproj index c55147c..8b39f6e 100644 --- a/src/AssemblyAI.UnitTests/AssemblyAI.UnitTests.csproj +++ b/src/AssemblyAI.UnitTests/AssemblyAI.UnitTests.csproj @@ -1,7 +1,7 @@ - net462;net6.0 + net462;net8.0 enable enable 12 diff --git a/src/AssemblyAI.UnitTests/UserAgentTests.cs b/src/AssemblyAI.UnitTests/UserAgentTests.cs index e7b7ca5..d0ab48b 100644 --- a/src/AssemblyAI.UnitTests/UserAgentTests.cs +++ b/src/AssemblyAI.UnitTests/UserAgentTests.cs @@ -15,8 +15,8 @@ public void TestDefaultUserAgent() Assert.That(userAgentString, Does.StartWith("AssemblyAI/1.0 (")); Assert.That(userAgentString, Does.EndWith(")")); Assert.That(userAgentString, Does.Contain("sdk=CSharp/")); -#if NET6_0 - Assert.That(userAgentString, Does.Contain("runtime_env=.NET/6.")); +#if NET8_0 + Assert.That(userAgentString, Does.Contain("runtime_env=.NET/8.")); #elif NET462 Assert.That(userAgentString, Does.Contain("runtime_env=.NET Framework/4.")); #else