Skip to content

Commit 0dc8939

Browse files
committed
fix: clean up OpenAISharp public API
1 parent f6ed3b4 commit 0dc8939

17 files changed

Lines changed: 455 additions & 161 deletions

src/libs/tryAGI.OpenAI/OpenAISharp/.editorconfig

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/libs/tryAGI.OpenAI/OpenAISharp/Configuration/OpenAIConfig.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public record OpenAIConfig
1515
/// <summary>
1616
/// Base WebSocket URL for OpenAI Realtime API.
1717
/// </summary>
18-
public string BaseUrl { get; init; } = "wss://api.openai.com/v1/realtime";
18+
public Uri BaseUrl { get; init; } = new("wss://api.openai.com/v1/realtime");
1919

2020
/// <summary>
2121
/// Optional OpenAI organization ID.
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
using System.Text.Json;
2+
using System.Text.Json.Serialization;
3+
using System.Text.Json.Serialization.Metadata;
4+
5+
namespace tryAGI.OpenAI.OpenAISharp;
6+
7+
/// <inheritdoc />
8+
[JsonConverter(typeof(OpenAIOptionalJsonConverterFactory))]
9+
public readonly struct OpenAIOptional<T> : IEquatable<OpenAIOptional<T>>
10+
{
11+
/// <inheritdoc />
12+
public bool HasValue { get; }
13+
/// <inheritdoc />
14+
public T? Value { get; }
15+
16+
/// <inheritdoc />
17+
public OpenAIOptional(T? value)
18+
{
19+
HasValue = true;
20+
Value = value;
21+
}
22+
23+
/// <inheritdoc />
24+
public bool Equals(OpenAIOptional<T> other)
25+
=> HasValue == other.HasValue && EqualityComparer<T?>.Default.Equals(Value, other.Value);
26+
27+
/// <inheritdoc />
28+
public override bool Equals(object? obj)
29+
=> obj is OpenAIOptional<T> other && Equals(other);
30+
31+
/// <inheritdoc />
32+
public override int GetHashCode()
33+
=> HashCode.Combine(HasValue, Value);
34+
35+
/// <inheritdoc />
36+
public static bool operator ==(OpenAIOptional<T> left, OpenAIOptional<T> right)
37+
=> left.Equals(right);
38+
39+
/// <inheritdoc />
40+
public static bool operator !=(OpenAIOptional<T> left, OpenAIOptional<T> right)
41+
=> !left.Equals(right);
42+
}
43+
44+
/// <inheritdoc />
45+
public static class OpenAIOptional
46+
{
47+
/// <inheritdoc />
48+
public static OpenAIOptional<T> From<T>(T? value) => new(value);
49+
}
50+
51+
internal sealed class OpenAIOptionalJsonConverterFactory : JsonConverterFactory
52+
{
53+
private static readonly Dictionary<Type, JsonConverter> Converters = new()
54+
{
55+
{ typeof(OpenAIOptional<string?>), new OpenAIOptionalJsonConverter<string?>() },
56+
{ typeof(OpenAIOptional<string[]?>), new OpenAIOptionalJsonConverter<string[]?>() },
57+
{ typeof(OpenAIOptional<double?>), new OpenAIOptionalJsonConverter<double?>() },
58+
{ typeof(OpenAIOptional<int?>), new OpenAIOptionalJsonConverter<int?>() },
59+
{ typeof(OpenAIOptional<OpenAIRealtimeInputAudioTranscription?>), new OpenAIOptionalJsonConverter<OpenAIRealtimeInputAudioTranscription?>() },
60+
{ typeof(OpenAIOptional<OpenAIRealtimeTurnDetection?>), new OpenAIOptionalJsonConverter<OpenAIRealtimeTurnDetection?>() },
61+
{ typeof(OpenAIOptional<OpenAIRealtimeNoiseReduction?>), new OpenAIOptionalJsonConverter<OpenAIRealtimeNoiseReduction?>() },
62+
{ typeof(OpenAIOptional<OpenAIRealtimeTool[]?>), new OpenAIOptionalJsonConverter<OpenAIRealtimeTool[]?>() },
63+
};
64+
65+
/// <inheritdoc />
66+
public override bool CanConvert(Type typeToConvert) => Converters.ContainsKey(typeToConvert);
67+
68+
/// <inheritdoc />
69+
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
70+
=> Converters[typeToConvert];
71+
72+
private sealed class OpenAIOptionalJsonConverter<TValue> : JsonConverter<OpenAIOptional<TValue>>
73+
{
74+
/// <inheritdoc />
75+
public override OpenAIOptional<TValue> Read(
76+
ref Utf8JsonReader reader,
77+
Type typeToConvert,
78+
JsonSerializerOptions options)
79+
{
80+
if (reader.TokenType == JsonTokenType.Null)
81+
{
82+
return new OpenAIOptional<TValue>(default);
83+
}
84+
85+
var typeInfo = options.GetTypeInfo(typeof(TValue)) as JsonTypeInfo<TValue>;
86+
if (typeInfo is null)
87+
{
88+
throw new NotSupportedException($"Missing JsonTypeInfo for {typeof(TValue).Name}.");
89+
}
90+
91+
var value = JsonSerializer.Deserialize(ref reader, typeInfo);
92+
return new OpenAIOptional<TValue>(value);
93+
}
94+
95+
/// <inheritdoc />
96+
public override void Write(
97+
Utf8JsonWriter writer,
98+
OpenAIOptional<TValue> value,
99+
JsonSerializerOptions options)
100+
{
101+
if (!value.HasValue || value.Value is null)
102+
{
103+
writer.WriteNullValue();
104+
return;
105+
}
106+
107+
var typeInfo = options.GetTypeInfo(typeof(TValue)) as JsonTypeInfo<TValue>;
108+
if (typeInfo is null)
109+
{
110+
throw new NotSupportedException($"Missing JsonTypeInfo for {typeof(TValue).Name}.");
111+
}
112+
113+
JsonSerializer.Serialize(writer, value.Value, typeInfo);
114+
}
115+
}
116+
}

src/libs/tryAGI.OpenAI/OpenAISharp/Models/OpenAIRealtimeClientEvents.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,80 +29,104 @@ namespace tryAGI.OpenAI.OpenAISharp;
2929
[JsonDerivedType(typeof(OpenAIRealtimeTranscriptionSessionUpdateEvent), typeDiscriminator: "transcription_session.update")]
3030
public abstract record OpenAIRealtimeClientEvent
3131
{
32+
/// <inheritdoc />
3233
[JsonPropertyName("event_id")]
3334
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
3435
public string? EventId { get; init; }
3536
}
3637

38+
/// <inheritdoc />
3739
public sealed record OpenAIRealtimeSessionUpdateEvent : OpenAIRealtimeClientEvent
3840
{
41+
/// <inheritdoc />
3942
[JsonPropertyName("session")]
4043
public required OpenAIRealtimeSessionUpdate Session { get; init; }
4144
}
4245

46+
/// <inheritdoc />
4347
public sealed record OpenAIRealtimeResponseCreateEvent : OpenAIRealtimeClientEvent
4448
{
49+
/// <inheritdoc />
4550
[JsonPropertyName("response")]
4651
public required OpenAIRealtimeResponse Response { get; init; }
4752
}
4853

54+
/// <inheritdoc />
4955
public sealed record OpenAIRealtimeResponseCancelEvent : OpenAIRealtimeClientEvent
5056
{
57+
/// <inheritdoc />
5158
[JsonPropertyName("response_id")]
5259
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
5360
public string? ResponseId { get; init; }
5461
}
5562

63+
/// <inheritdoc />
5664
public sealed record OpenAIRealtimeConversationItemCreateEvent : OpenAIRealtimeClientEvent
5765
{
66+
/// <inheritdoc />
5867
[JsonPropertyName("item")]
5968
public required OpenAIRealtimeConversationItem Item { get; init; }
6069
}
6170

71+
/// <inheritdoc />
6272
public sealed record OpenAIRealtimeConversationItemDeleteEvent : OpenAIRealtimeClientEvent
6373
{
74+
/// <inheritdoc />
6475
[JsonPropertyName("item_id")]
6576
public required string ItemId { get; init; }
6677
}
6778

79+
/// <inheritdoc />
6880
public sealed record OpenAIRealtimeConversationItemTruncateEvent : OpenAIRealtimeClientEvent
6981
{
82+
/// <inheritdoc />
7083
[JsonPropertyName("item_id")]
7184
public required string ItemId { get; init; }
7285

86+
/// <inheritdoc />
7387
[JsonPropertyName("content_index")]
7488
public int? ContentIndex { get; init; }
7589

90+
/// <inheritdoc />
7691
[JsonPropertyName("audio_end_ms")]
7792
public int? AudioEndMs { get; init; }
7893
}
7994

95+
/// <inheritdoc />
8096
public sealed record OpenAIRealtimeInputAudioBufferAppendEvent : OpenAIRealtimeClientEvent
8197
{
98+
/// <inheritdoc />
8299
[JsonPropertyName("audio")]
83100
public required string Audio { get; init; }
84101
}
85102

103+
/// <inheritdoc />
86104
public sealed record OpenAIRealtimeInputAudioBufferCommitEvent : OpenAIRealtimeClientEvent
87105
{
88106
}
89107

108+
/// <inheritdoc />
90109
public sealed record OpenAIRealtimeInputAudioBufferClearEvent : OpenAIRealtimeClientEvent
91110
{
92111
}
93112

113+
/// <inheritdoc />
94114
public sealed record OpenAIRealtimeOutputAudioBufferClearEvent : OpenAIRealtimeClientEvent
95115
{
96116
}
97117

118+
/// <inheritdoc />
98119
public sealed record OpenAIRealtimeSessionInputAudioBufferAppendEvent : OpenAIRealtimeClientEvent
99120
{
121+
/// <inheritdoc />
100122
[JsonPropertyName("audio")]
101123
public required string Audio { get; init; }
102124
}
103125

126+
/// <inheritdoc />
104127
public sealed record OpenAIRealtimeTranscriptionSessionUpdateEvent : OpenAIRealtimeClientEvent
105128
{
129+
/// <inheritdoc />
106130
[JsonPropertyName("session")]
107131
public required OpenAIRealtimeTranscriptionSessionUpdate Session { get; init; }
108132
}

src/libs/tryAGI.OpenAI/OpenAISharp/Models/OpenAIRealtimeConnectOptions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,13 @@ public sealed record OpenAIRealtimeConnectOptions
6161
public IReadOnlyList<string>? AdditionalSubProtocols { get; init; }
6262
}
6363

64+
/// <inheritdoc />
6465
public enum OpenAIRealtimeSessionKind
6566
{
67+
/// <inheritdoc />
6668
Realtime,
69+
/// <inheritdoc />
6770
Transcription,
71+
/// <inheritdoc />
6872
Translation,
6973
}

0 commit comments

Comments
 (0)