diff --git a/api/OpenAI.net8.0.cs b/api/OpenAI.net8.0.cs index 64ec7236d..e2cd12337 100644 --- a/api/OpenAI.net8.0.cs +++ b/api/OpenAI.net8.0.cs @@ -3828,6 +3828,23 @@ public class ResponseStartedUpdate : RealtimeUpdate, IJsonModel { + public SemanticEagernessLevel(string value); + public static SemanticEagernessLevel Auto { get; } + public static SemanticEagernessLevel High { get; } + public static SemanticEagernessLevel Low { get; } + public static SemanticEagernessLevel Medium { get; } + public readonly bool Equals(SemanticEagernessLevel other); + [EditorBrowsable(EditorBrowsableState.Never)] + public override readonly bool Equals(object obj); + [EditorBrowsable(EditorBrowsableState.Never)] + public override readonly int GetHashCode(); + public static bool operator ==(SemanticEagernessLevel left, SemanticEagernessLevel right); + public static implicit operator SemanticEagernessLevel(string value); + public static bool operator !=(SemanticEagernessLevel left, SemanticEagernessLevel right); + public override readonly string ToString(); + } + [Experimental("OPENAI002")] public class TranscriptionSessionConfiguredUpdate : RealtimeUpdate, IJsonModel, IPersistableModel { public RealtimeContentModalities ContentModalities { get; } public RealtimeAudioFormat InputAudioFormat { get; } @@ -3862,6 +3879,7 @@ public enum TurnDetectionKind { public class TurnDetectionOptions : IJsonModel, IPersistableModel { public TurnDetectionKind Kind { get; } public static TurnDetectionOptions CreateDisabledTurnDetectionOptions(); + public static TurnDetectionOptions CreateSemanticVoiceActivityTurnDetectionOptions(SemanticEagernessLevel? eagernessLevel = null, bool? enableAutomaticResponseCreation = null, bool? enableResponseInterruption = null); public static TurnDetectionOptions CreateServerVoiceActivityTurnDetectionOptions(float? detectionThreshold = null, TimeSpan? prefixPaddingDuration = null, TimeSpan? silenceDuration = null, bool? enableAutomaticResponseCreation = null, bool? enableResponseInterruption = null); protected virtual TurnDetectionOptions JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options); protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options); diff --git a/api/OpenAI.netstandard2.0.cs b/api/OpenAI.netstandard2.0.cs index 49e2add02..aa9102db7 100644 --- a/api/OpenAI.netstandard2.0.cs +++ b/api/OpenAI.netstandard2.0.cs @@ -3370,6 +3370,22 @@ public class ResponseStartedUpdate : RealtimeUpdate, IJsonModel { + public SemanticEagernessLevel(string value); + public static SemanticEagernessLevel Auto { get; } + public static SemanticEagernessLevel High { get; } + public static SemanticEagernessLevel Low { get; } + public static SemanticEagernessLevel Medium { get; } + public readonly bool Equals(SemanticEagernessLevel other); + [EditorBrowsable(EditorBrowsableState.Never)] + public override readonly bool Equals(object obj); + [EditorBrowsable(EditorBrowsableState.Never)] + public override readonly int GetHashCode(); + public static bool operator ==(SemanticEagernessLevel left, SemanticEagernessLevel right); + public static implicit operator SemanticEagernessLevel(string value); + public static bool operator !=(SemanticEagernessLevel left, SemanticEagernessLevel right); + public override readonly string ToString(); + } public class TranscriptionSessionConfiguredUpdate : RealtimeUpdate, IJsonModel, IPersistableModel { public RealtimeContentModalities ContentModalities { get; } public RealtimeAudioFormat InputAudioFormat { get; } @@ -3401,6 +3417,7 @@ public enum TurnDetectionKind { public class TurnDetectionOptions : IJsonModel, IPersistableModel { public TurnDetectionKind Kind { get; } public static TurnDetectionOptions CreateDisabledTurnDetectionOptions(); + public static TurnDetectionOptions CreateSemanticVoiceActivityTurnDetectionOptions(SemanticEagernessLevel? eagernessLevel = null, bool? enableAutomaticResponseCreation = null, bool? enableResponseInterruption = null); public static TurnDetectionOptions CreateServerVoiceActivityTurnDetectionOptions(float? detectionThreshold = null, TimeSpan? prefixPaddingDuration = null, TimeSpan? silenceDuration = null, bool? enableAutomaticResponseCreation = null, bool? enableResponseInterruption = null); protected virtual TurnDetectionOptions JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options); protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options); diff --git a/scripts/Export-Api.ps1 b/scripts/Export-Api.ps1 index 75df7b127..9afddbe60 100644 --- a/scripts/Export-Api.ps1 +++ b/scripts/Export-Api.ps1 @@ -258,6 +258,9 @@ function Invoke-GenAPI { # Remove Diagnostics.DebuggerStepThrough attribute. $content = $content -creplace ".*Diagnostics.DebuggerStepThrough.*\n", "" + # Remove ModelReaderWriterBuildable attributes. + $content = $content -creplace '\[ModelReaderWriterBuildable\(typeof\([^\)]+\)\)\]\s*', '' + # Remove internal APIs. $content = $content -creplace " * internal.*`n", "" diff --git a/src/Custom/Realtime/GeneratorStubs.cs b/src/Custom/Realtime/GeneratorStubs.cs index e6982c8dc..ce756310b 100644 --- a/src/Custom/Realtime/GeneratorStubs.cs +++ b/src/Custom/Realtime/GeneratorStubs.cs @@ -11,3 +11,4 @@ namespace OpenAI.Realtime; [CodeGenType("RealtimeResponseUsage")] public partial class ConversationTokenUsage { } [CodeGenType("RealtimeToolType")] public readonly partial struct ConversationToolKind { } [CodeGenType("DotNetRealtimeVoiceIds")] public readonly partial struct ConversationVoice { } +[CodeGenType("RealtimeSemanticVadTurnDetectionEagerness")] public readonly partial struct SemanticEagernessLevel { } diff --git a/src/Custom/Realtime/Internal/GeneratorStubs.cs b/src/Custom/Realtime/Internal/GeneratorStubs.cs index 31aba6bc0..8b41ccc44 100644 --- a/src/Custom/Realtime/Internal/GeneratorStubs.cs +++ b/src/Custom/Realtime/Internal/GeneratorStubs.cs @@ -35,7 +35,6 @@ namespace OpenAI.Realtime; [Experimental("OPENAI002")][CodeGenType("RealtimeResponseStatusDetailsType")] internal readonly partial struct InternalRealtimeResponseStatusDetailsType { } [Experimental("OPENAI002")][CodeGenType("RealtimeResponseVoice")] internal readonly partial struct InternalRealtimeResponseVoice { } [Experimental("OPENAI002")][CodeGenType("RealtimeSemanticVadTurnDetection")] internal partial class InternalRealtimeSemanticVadTurnDetection { } -[Experimental("OPENAI002")][CodeGenType("RealtimeSemanticVadTurnDetectionEagerness")] internal readonly partial struct InternalRealtimeSemanticVadTurnDetectionEagerness { } [Experimental("OPENAI002")][CodeGenType("RealtimeServerEventConversationCreated")] internal partial class InternalRealtimeServerEventConversationCreated { } [Experimental("OPENAI002")][CodeGenType("RealtimeServerEventConversationCreatedConversation")] internal partial class InternalRealtimeServerEventConversationCreatedConversation { } [Experimental("OPENAI002")][CodeGenType("RealtimeServerEventConversationItemInputAudioTranscriptionFailedError")] internal partial class InternalRealtimeServerEventConversationItemInputAudioTranscriptionFailedError { } diff --git a/src/Custom/Realtime/TurnDetectionOptions.Serialization.cs b/src/Custom/Realtime/TurnDetectionOptions.Serialization.cs index c59721371..0890cff32 100644 --- a/src/Custom/Realtime/TurnDetectionOptions.Serialization.cs +++ b/src/Custom/Realtime/TurnDetectionOptions.Serialization.cs @@ -20,6 +20,7 @@ internal static TurnDetectionOptions DeserializeTurnDetectionOptions(JsonElement { case "none": return InternalRealtimeNoTurnDetection.DeserializeInternalRealtimeNoTurnDetection(element, options); case "server_vad": return InternalRealtimeServerVadTurnDetection.DeserializeInternalRealtimeServerVadTurnDetection(element, options); + case "semantic_vad": return InternalRealtimeSemanticVadTurnDetection.DeserializeInternalRealtimeSemanticVadTurnDetection(element, options); default: return null; } } diff --git a/src/Custom/Realtime/TurnDetectionOptions.cs b/src/Custom/Realtime/TurnDetectionOptions.cs index 381722ee2..a0fd33eeb 100644 --- a/src/Custom/Realtime/TurnDetectionOptions.cs +++ b/src/Custom/Realtime/TurnDetectionOptions.cs @@ -35,8 +35,8 @@ public static TurnDetectionOptions CreateServerVoiceActivityTurnDetectionOptions }; } - internal static TurnDetectionOptions CreateSemanticVoiceActivityTurnDetectionOptions( - InternalRealtimeSemanticVadTurnDetectionEagerness? eagernessLevel = null, + public static TurnDetectionOptions CreateSemanticVoiceActivityTurnDetectionOptions( + SemanticEagernessLevel? eagernessLevel = null, bool? enableAutomaticResponseCreation = null, bool? enableResponseInterruption = null) { diff --git a/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetection.Serialization.cs b/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetection.Serialization.cs index 1c244187f..5cbe93781 100644 --- a/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetection.Serialization.cs +++ b/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetection.Serialization.cs @@ -57,7 +57,7 @@ internal static InternalRealtimeSemanticVadTurnDetection DeserializeInternalReal bool? responseCreationEnabled = default; bool? responseInterruptionEnabled = default; IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); - InternalRealtimeSemanticVadTurnDetectionEagerness? eagerness = default; + SemanticEagernessLevel? eagerness = default; foreach (var prop in element.EnumerateObject()) { if (prop.NameEquals("type"u8)) @@ -89,7 +89,7 @@ internal static InternalRealtimeSemanticVadTurnDetection DeserializeInternalReal { continue; } - eagerness = new InternalRealtimeSemanticVadTurnDetectionEagerness(prop.Value.GetString()); + eagerness = new SemanticEagernessLevel(prop.Value.GetString()); continue; } // Plugin customization: remove options.Format != "W" check diff --git a/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetection.cs b/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetection.cs index 4be69a310..634bf079a 100644 --- a/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetection.cs +++ b/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetection.cs @@ -13,11 +13,11 @@ public InternalRealtimeSemanticVadTurnDetection() : this(TurnDetectionKind.Seman { } - internal InternalRealtimeSemanticVadTurnDetection(TurnDetectionKind kind, bool? responseCreationEnabled, bool? responseInterruptionEnabled, IDictionary additionalBinaryDataProperties, InternalRealtimeSemanticVadTurnDetectionEagerness? eagerness) : base(kind, responseCreationEnabled, responseInterruptionEnabled, additionalBinaryDataProperties) + internal InternalRealtimeSemanticVadTurnDetection(TurnDetectionKind kind, bool? responseCreationEnabled, bool? responseInterruptionEnabled, IDictionary additionalBinaryDataProperties, SemanticEagernessLevel? eagerness) : base(kind, responseCreationEnabled, responseInterruptionEnabled, additionalBinaryDataProperties) { Eagerness = eagerness; } - internal InternalRealtimeSemanticVadTurnDetectionEagerness? Eagerness { get; set; } + public SemanticEagernessLevel? Eagerness { get; set; } } } diff --git a/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetectionEagerness.cs b/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetectionEagerness.cs deleted file mode 100644 index c8b423001..000000000 --- a/src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetectionEagerness.cs +++ /dev/null @@ -1,50 +0,0 @@ -// - -#nullable disable - -using System; -using System.ComponentModel; -using OpenAI; - -namespace OpenAI.Realtime -{ - internal readonly partial struct InternalRealtimeSemanticVadTurnDetectionEagerness : IEquatable - { - private readonly string _value; - private const string LowValue = "low"; - private const string MediumValue = "medium"; - private const string HighValue = "high"; - private const string AutoValue = "auto"; - - public InternalRealtimeSemanticVadTurnDetectionEagerness(string value) - { - Argument.AssertNotNull(value, nameof(value)); - - _value = value; - } - - internal static InternalRealtimeSemanticVadTurnDetectionEagerness Low { get; } = new InternalRealtimeSemanticVadTurnDetectionEagerness(LowValue); - - internal static InternalRealtimeSemanticVadTurnDetectionEagerness Medium { get; } = new InternalRealtimeSemanticVadTurnDetectionEagerness(MediumValue); - - internal static InternalRealtimeSemanticVadTurnDetectionEagerness High { get; } = new InternalRealtimeSemanticVadTurnDetectionEagerness(HighValue); - - internal static InternalRealtimeSemanticVadTurnDetectionEagerness Auto { get; } = new InternalRealtimeSemanticVadTurnDetectionEagerness(AutoValue); - - public static bool operator ==(InternalRealtimeSemanticVadTurnDetectionEagerness left, InternalRealtimeSemanticVadTurnDetectionEagerness right) => left.Equals(right); - - public static bool operator !=(InternalRealtimeSemanticVadTurnDetectionEagerness left, InternalRealtimeSemanticVadTurnDetectionEagerness right) => !left.Equals(right); - - public static implicit operator InternalRealtimeSemanticVadTurnDetectionEagerness(string value) => new InternalRealtimeSemanticVadTurnDetectionEagerness(value); - - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool Equals(object obj) => obj is InternalRealtimeSemanticVadTurnDetectionEagerness other && Equals(other); - - public bool Equals(InternalRealtimeSemanticVadTurnDetectionEagerness other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); - - [EditorBrowsable(EditorBrowsableState.Never)] - public override int GetHashCode() => _value != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(_value) : 0; - - public override string ToString() => _value; - } -} diff --git a/src/Generated/Models/Realtime/SemanticEagernessLevel.cs b/src/Generated/Models/Realtime/SemanticEagernessLevel.cs new file mode 100644 index 000000000..85b851e11 --- /dev/null +++ b/src/Generated/Models/Realtime/SemanticEagernessLevel.cs @@ -0,0 +1,52 @@ +// + +#nullable disable + +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using OpenAI; + +namespace OpenAI.Realtime +{ + [Experimental("OPENAI002")] + public readonly partial struct SemanticEagernessLevel : IEquatable + { + private readonly string _value; + private const string LowValue = "low"; + private const string MediumValue = "medium"; + private const string HighValue = "high"; + private const string AutoValue = "auto"; + + public SemanticEagernessLevel(string value) + { + Argument.AssertNotNull(value, nameof(value)); + + _value = value; + } + + public static SemanticEagernessLevel Low { get; } = new SemanticEagernessLevel(LowValue); + + public static SemanticEagernessLevel Medium { get; } = new SemanticEagernessLevel(MediumValue); + + public static SemanticEagernessLevel High { get; } = new SemanticEagernessLevel(HighValue); + + public static SemanticEagernessLevel Auto { get; } = new SemanticEagernessLevel(AutoValue); + + public static bool operator ==(SemanticEagernessLevel left, SemanticEagernessLevel right) => left.Equals(right); + + public static bool operator !=(SemanticEagernessLevel left, SemanticEagernessLevel right) => !left.Equals(right); + + public static implicit operator SemanticEagernessLevel(string value) => new SemanticEagernessLevel(value); + + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is SemanticEagernessLevel other && Equals(other); + + public bool Equals(SemanticEagernessLevel other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(_value) : 0; + + public override string ToString() => _value; + } +} diff --git a/tests/Realtime/RealtimeSmokeTests.cs b/tests/Realtime/RealtimeSmokeTests.cs index f57ee4856..215f3482e 100644 --- a/tests/Realtime/RealtimeSmokeTests.cs +++ b/tests/Realtime/RealtimeSmokeTests.cs @@ -198,6 +198,18 @@ public void TurnDetectionSerializationWorks() JsonNode serializedNode = JsonNode.Parse(serializedOptions); Assert.That(serializedNode["turn_detection"]?["type"]?.GetValue(), Is.EqualTo("server_vad")); Assert.That(serializedNode["turn_detection"]?["threshold"]?.GetValue(), Is.EqualTo(0.42f)); + + sessionOptions = new() + { + TurnDetectionOptions = TurnDetectionOptions.CreateSemanticVoiceActivityTurnDetectionOptions( + SemanticEagernessLevel.Medium, true, true) + }; + serializedOptions = ModelReaderWriter.Write(sessionOptions); + serializedNode = JsonNode.Parse(serializedOptions); + Assert.That(serializedNode["turn_detection"]?["type"]?.GetValue(), Is.EqualTo("semantic_vad")); + Assert.That(serializedNode["turn_detection"]?["eagerness"]?.GetValue(), Is.EqualTo("medium")); + Assert.That(serializedNode["turn_detection"]?["create_response"]?.GetValue(), Is.EqualTo(true)); + Assert.That(serializedNode["turn_detection"]?["interrupt_response"]?.GetValue(), Is.EqualTo(true)); } [Test]