From d2afa165ae375b26657723db9c313c4d9abbc688 Mon Sep 17 00:00:00 2001 From: ShivangiReja <45216704+ShivangiReja@users.noreply.github.com> Date: Fri, 18 Jul 2025 15:37:18 -0700 Subject: [PATCH 1/2] Enable semantic voice activity detection option --- src/Custom/Realtime/GeneratorStubs.cs | 1 + .../Realtime/Internal/GeneratorStubs.cs | 1 - .../TurnDetectionOptions.Serialization.cs | 1 + src/Custom/Realtime/TurnDetectionOptions.cs | 4 +- ...eSemanticVadTurnDetection.Serialization.cs | 4 +- ...nternalRealtimeSemanticVadTurnDetection.cs | 4 +- ...altimeSemanticVadTurnDetectionEagerness.cs | 50 ------------------ .../Models/Realtime/SemanticEagernessLevel.cs | 52 +++++++++++++++++++ tests/Realtime/RealtimeSmokeTests.cs | 12 +++++ 9 files changed, 72 insertions(+), 57 deletions(-) delete mode 100644 src/Generated/Models/Realtime/InternalRealtimeSemanticVadTurnDetectionEagerness.cs create mode 100644 src/Generated/Models/Realtime/SemanticEagernessLevel.cs diff --git a/src/Custom/Realtime/GeneratorStubs.cs b/src/Custom/Realtime/GeneratorStubs.cs index e6982c8d..ce756310 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 31aba6bc..8b41ccc4 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 c5972137..0890cff3 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 381722ee..a0fd33ee 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 1c244187..5cbe9378 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 4be69a31..634bf079 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 c8b42300..00000000 --- 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 00000000..85b851e1 --- /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 f57ee485..215f3482 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] From 443620cb1e8852156ecbc82c309d98d3472d44a8 Mon Sep 17 00:00:00 2001 From: ShivangiReja <45216704+ShivangiReja@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:09:03 -0700 Subject: [PATCH 2/2] Export public API --- api/OpenAI.net8.0.cs | 18 ++++++++++++++++++ api/OpenAI.netstandard2.0.cs | 17 +++++++++++++++++ scripts/Export-Api.ps1 | 3 +++ 3 files changed, 38 insertions(+) diff --git a/api/OpenAI.net8.0.cs b/api/OpenAI.net8.0.cs index 64ec7236..e2cd1233 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 49e2add0..aa9102db 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 75df7b12..9afddbe6 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", ""