openai/openai-dotnet

Public

mirrored from https://github.com/openai/openai-dotnetAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
OpenAI_2.2.0-beta.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/Custom/Chat/ChatClient.cs

259lines · modeblame

d5b5c604Liudmila Molkova2 years ago1using OpenAI.Telemetry;
9f9f2936Jose Arriaga Maldonado2 years ago2using System;
3using System.ClientModel;
4using System.ClientModel.Primitives;
5using System.Collections.Generic;
6using System.Linq;
19a65a0aKrzysztof Cwalina2 years ago7using System.Threading;
9f9f2936Jose Arriaga Maldonado2 years ago8using System.Threading.Tasks;
9
10namespace OpenAI.Chat;
11
13a9c686Jose Arriaga Maldonado1 years ago12// CUSTOM:
13// - Renamed.
14// - Suppressed constructor that takes endpoint parameter; endpoint is now a property in the options class.
15// - Suppressed methods that only take the options parameter.
16/// <summary> The service client for OpenAI chat operations. </summary>
9f9f2936Jose Arriaga Maldonado2 years ago17[CodeGenClient("Chat")]
13a9c686Jose Arriaga Maldonado1 years ago18[CodeGenSuppress("ChatClient", typeof(ClientPipeline), typeof(ApiKeyCredential), typeof(Uri))]
e0fee603Jose Arriaga Maldonado1 years ago19[CodeGenSuppress("CreateChatCompletionAsync", typeof(ChatCompletionOptions), typeof(CancellationToken))]
20[CodeGenSuppress("CreateChatCompletion", typeof(ChatCompletionOptions), typeof(CancellationToken))]
9f9f2936Jose Arriaga Maldonado2 years ago21public partial class ChatClient
22{
23private readonly string _model;
d5b5c604Liudmila Molkova2 years ago24private readonly OpenTelemetrySource _telemetry;
9f9f2936Jose Arriaga Maldonado2 years ago25
2ab1a942Jose Arriaga Maldonado1 years ago26// CUSTOM: Added as a convenience.
e0fee603Jose Arriaga Maldonado1 years ago27/// <summary> Initializes a new instance of <see cref="ChatClient"/>. </summary>
2ab1a942Jose Arriaga Maldonado1 years ago28/// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
29/// <param name="apiKey"> The API key to authenticate with the service. </param>
30/// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="apiKey"/> is null. </exception>
31/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
32public ChatClient(string model, string apiKey) : this(model, new ApiKeyCredential(apiKey), new OpenAIClientOptions())
33{
34}
35
13a9c686Jose Arriaga Maldonado1 years ago36// CUSTOM:
37// - Added `model` parameter.
38// - Used a custom pipeline.
39// - Demoted the endpoint parameter to be a property in the options class.
e0fee603Jose Arriaga Maldonado1 years ago40/// <summary> Initializes a new instance of <see cref="ChatClient"/>. </summary>
13a9c686Jose Arriaga Maldonado1 years ago41/// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
42/// <param name="credential"> The API key to authenticate with the service. </param>
43/// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="credential"/> is null. </exception>
44/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
45public ChatClient(string model, ApiKeyCredential credential) : this(model, credential, new OpenAIClientOptions())
46{
47}
9f9f2936Jose Arriaga Maldonado2 years ago48
13a9c686Jose Arriaga Maldonado1 years ago49// CUSTOM:
50// - Added `model` parameter.
51// - Used a custom pipeline.
52// - Demoted the endpoint parameter to be a property in the options class.
53// - Added telemetry support.
e0fee603Jose Arriaga Maldonado1 years ago54/// <summary> Initializes a new instance of <see cref="ChatClient"/>. </summary>
13a9c686Jose Arriaga Maldonado1 years ago55/// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
56/// <param name="credential"> The API key to authenticate with the service. </param>
57/// <param name="options"> The options to configure the client. </param>
58/// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="credential"/> is null. </exception>
59/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
60public ChatClient(string model, ApiKeyCredential credential, OpenAIClientOptions options)
61{
62Argument.AssertNotNullOrEmpty(model, nameof(model));
63Argument.AssertNotNull(credential, nameof(credential));
64options ??= new OpenAIClientOptions();
9f9f2936Jose Arriaga Maldonado2 years ago65
13a9c686Jose Arriaga Maldonado1 years ago66_model = model;
e0fee603Jose Arriaga Maldonado1 years ago67Pipeline = OpenAIClient.CreatePipeline(credential, options);
13a9c686Jose Arriaga Maldonado1 years ago68_endpoint = OpenAIClient.GetEndpoint(options);
69_telemetry = new OpenTelemetrySource(model, _endpoint);
70}
71
72// CUSTOM:
73// - Added `model` parameter.
74// - Used a custom pipeline.
75// - Demoted the endpoint parameter to be a property in the options class.
76// - Added telemetry support.
77// - Made protected.
e0fee603Jose Arriaga Maldonado1 years ago78/// <summary> Initializes a new instance of <see cref="ChatClient"/>. </summary>
13a9c686Jose Arriaga Maldonado1 years ago79/// <param name="pipeline"> The HTTP pipeline to send and receive REST requests and responses. </param>
80/// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
81/// <param name="options"> The options to configure the client. </param>
82/// <exception cref="ArgumentNullException"> <paramref name="pipeline"/> or <paramref name="model"/> is null. </exception>
83/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
84protected internal ChatClient(ClientPipeline pipeline, string model, OpenAIClientOptions options)
9f9f2936Jose Arriaga Maldonado2 years ago85{
13a9c686Jose Arriaga Maldonado1 years ago86Argument.AssertNotNull(pipeline, nameof(pipeline));
9f9f2936Jose Arriaga Maldonado2 years ago87Argument.AssertNotNullOrEmpty(model, nameof(model));
13a9c686Jose Arriaga Maldonado1 years ago88options ??= new OpenAIClientOptions();
9f9f2936Jose Arriaga Maldonado2 years ago89
90_model = model;
e0fee603Jose Arriaga Maldonado1 years ago91Pipeline = pipeline;
13a9c686Jose Arriaga Maldonado1 years ago92_endpoint = OpenAIClient.GetEndpoint(options);
93_telemetry = new OpenTelemetrySource(model, _endpoint);
9f9f2936Jose Arriaga Maldonado2 years ago94}
95
13a9c686Jose Arriaga Maldonado1 years ago96/// <summary> Generates a completion for the given chat. </summary>
97/// <param name="messages"> The messages comprising the chat so far. </param>
98/// <param name="options"> The options to configure the chat completion. </param>
99/// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
100/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
101/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
19a65a0aKrzysztof Cwalina2 years ago102public virtual async Task<ClientResult<ChatCompletion>> CompleteChatAsync(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
9f9f2936Jose Arriaga Maldonado2 years ago103{
104Argument.AssertNotNullOrEmpty(messages, nameof(messages));
105
106options ??= new();
107CreateChatCompletionOptions(messages, ref options);
d5b5c604Liudmila Molkova2 years ago108using OpenTelemetryScope scope = _telemetry.StartChatScope(options);
109
110try
111{
e0fee603Jose Arriaga Maldonado1 years ago112using BinaryContent content = options;
d5b5c604Liudmila Molkova2 years ago113
114ClientResult result = await CompleteChatAsync(content, cancellationToken.ToRequestOptions()).ConfigureAwait(false);
e0fee603Jose Arriaga Maldonado1 years ago115ChatCompletion chatCompletion = (ChatCompletion)result;
d5b5c604Liudmila Molkova2 years ago116scope?.RecordChatCompletion(chatCompletion);
117return ClientResult.FromValue(chatCompletion, result.GetRawResponse());
118}
119catch (Exception ex)
120{
121scope?.RecordException(ex);
122throw;
123}
9f9f2936Jose Arriaga Maldonado2 years ago124}
125
13a9c686Jose Arriaga Maldonado1 years ago126/// <summary> Generates a completion for the given chat. </summary>
127/// <param name="messages"> The messages comprising the chat so far. </param>
128/// <param name="options"> The options to configure the chat completion. </param>
129/// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
130/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
131/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
19a65a0aKrzysztof Cwalina2 years ago132public virtual ClientResult<ChatCompletion> CompleteChat(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
9f9f2936Jose Arriaga Maldonado2 years ago133{
134Argument.AssertNotNullOrEmpty(messages, nameof(messages));
135
136options ??= new();
137CreateChatCompletionOptions(messages, ref options);
d5b5c604Liudmila Molkova2 years ago138using OpenTelemetryScope scope = _telemetry.StartChatScope(options);
139
140try
141{
e0fee603Jose Arriaga Maldonado1 years ago142using BinaryContent content = options;
d5b5c604Liudmila Molkova2 years ago143ClientResult result = CompleteChat(content, cancellationToken.ToRequestOptions());
e0fee603Jose Arriaga Maldonado1 years ago144ChatCompletion chatCompletion = (ChatCompletion)result;
d5b5c604Liudmila Molkova2 years ago145
146scope?.RecordChatCompletion(chatCompletion);
147return ClientResult.FromValue(chatCompletion, result.GetRawResponse());
148}
149catch (Exception ex)
150{
151scope?.RecordException(ex);
152throw;
153}
9f9f2936Jose Arriaga Maldonado2 years ago154}
155
13a9c686Jose Arriaga Maldonado1 years ago156/// <summary> Generates a completion for the given chat. </summary>
157/// <param name="messages"> The messages comprising the chat so far. </param>
158/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
159/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
160public virtual async Task<ClientResult<ChatCompletion>> CompleteChatAsync(params ChatMessage[] messages)
161=> await CompleteChatAsync(messages, default(ChatCompletionOptions)).ConfigureAwait(false);
162
163/// <summary> Generates a completion for the given chat. </summary>
164/// <param name="messages"> The messages comprising the chat so far. </param>
165/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
166/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
1c40de67Krzysztof Cwalina2 years ago167public virtual ClientResult<ChatCompletion> CompleteChat(params ChatMessage[] messages)
168=> CompleteChat(messages, default(ChatCompletionOptions));
169
9f9f2936Jose Arriaga Maldonado2 years ago170/// <summary>
13a9c686Jose Arriaga Maldonado1 years ago171/// Generates a completion for the given chat. The completion is streamed back token by token as it is being
172/// generated by the model instead of waiting for it to be finished first.
9f9f2936Jose Arriaga Maldonado2 years ago173/// </summary>
174/// <remarks>
13a9c686Jose Arriaga Maldonado1 years ago175/// <see cref="AsyncCollectionResult{T}"/> implements the <see cref="IAsyncEnumerable{T}"/> interface and can be
176/// enumerated over using the <c>await foreach</c> pattern.
9f9f2936Jose Arriaga Maldonado2 years ago177/// </remarks>
13a9c686Jose Arriaga Maldonado1 years ago178/// <param name="messages"> The messages comprising the chat so far. </param>
179/// <param name="options"> The options to configure the chat completion. </param>
180/// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
181/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
182/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
7bdecfd8Anne Thompson2 years ago183public virtual AsyncCollectionResult<StreamingChatCompletionUpdate> CompleteChatStreamingAsync(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
9f9f2936Jose Arriaga Maldonado2 years ago184{
185Argument.AssertNotNull(messages, nameof(messages));
186
187options ??= new();
188CreateChatCompletionOptions(messages, ref options, stream: true);
189
e0fee603Jose Arriaga Maldonado1 years ago190using BinaryContent content = options;
19a65a0aKrzysztof Cwalina2 years ago191
2ab1a942Jose Arriaga Maldonado1 years ago192async Task<ClientResult> sendRequestAsync() =>
19a65a0aKrzysztof Cwalina2 years ago193await CompleteChatAsync(content, cancellationToken.ToRequestOptions(streaming: true)).ConfigureAwait(false);
2ab1a942Jose Arriaga Maldonado1 years ago194return new InternalAsyncStreamingChatCompletionUpdateCollection(sendRequestAsync, cancellationToken);
9f9f2936Jose Arriaga Maldonado2 years ago195}
196
1c40de67Krzysztof Cwalina2 years ago197/// <summary>
13a9c686Jose Arriaga Maldonado1 years ago198/// Generates a completion for the given chat. The completion is streamed back token by token as it is being
199/// generated by the model instead of waiting for it to be finished first.
1c40de67Krzysztof Cwalina2 years ago200/// </summary>
201/// <remarks>
a330c2e7Jose Arriaga Maldonado1 years ago202/// <see cref="CollectionResult{T}"/> implements the <see cref="IEnumerable{T}"/> interface and can be
13a9c686Jose Arriaga Maldonado1 years ago203/// enumerated over using the <c>await foreach</c> pattern.
1c40de67Krzysztof Cwalina2 years ago204/// </remarks>
13a9c686Jose Arriaga Maldonado1 years ago205/// <param name="messages"> The messages comprising the chat so far. </param>
206/// <param name="options"> The options to configure the chat completion. </param>
207/// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
208/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
209/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
7bdecfd8Anne Thompson2 years ago210public virtual CollectionResult<StreamingChatCompletionUpdate> CompleteChatStreaming(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
9f9f2936Jose Arriaga Maldonado2 years ago211{
212Argument.AssertNotNull(messages, nameof(messages));
213
214options ??= new();
215CreateChatCompletionOptions(messages, ref options, stream: true);
216
e0fee603Jose Arriaga Maldonado1 years ago217using BinaryContent content = options;
2ab1a942Jose Arriaga Maldonado1 years ago218ClientResult sendRequest() => CompleteChat(content, cancellationToken.ToRequestOptions(streaming: true));
219return new InternalStreamingChatCompletionUpdateCollection(sendRequest, cancellationToken);
9f9f2936Jose Arriaga Maldonado2 years ago220}
221
1c40de67Krzysztof Cwalina2 years ago222/// <summary>
13a9c686Jose Arriaga Maldonado1 years ago223/// Generates a completion for the given chat. The completion is streamed back token by token as it is being
224/// generated by the model instead of waiting for it to be finished first.
225/// </summary>
226/// <remarks>
227/// <see cref="AsyncCollectionResult{T}"/> implements the <see cref="IAsyncEnumerable{T}"/> interface and can be
228/// enumerated over using the <c>await foreach</c> pattern.
229/// </remarks>
230/// <param name="messages"> The messages comprising the chat so far. </param>
231/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
232/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
233public virtual AsyncCollectionResult<StreamingChatCompletionUpdate> CompleteChatStreamingAsync(params ChatMessage[] messages)
234=> CompleteChatStreamingAsync(messages, default(ChatCompletionOptions));
235
236/// <summary>
237/// Generates a completion for the given chat. The completion is streamed back token by token as it is being
238/// generated by the model instead of waiting for it to be finished first.
1c40de67Krzysztof Cwalina2 years ago239/// </summary>
240/// <remarks>
a330c2e7Jose Arriaga Maldonado1 years ago241/// <see cref="CollectionResult{T}"/> implements the <see cref="IEnumerable{T}"/> interface and can be
13a9c686Jose Arriaga Maldonado1 years ago242/// enumerated over using the <c>await foreach</c> pattern.
1c40de67Krzysztof Cwalina2 years ago243/// </remarks>
13a9c686Jose Arriaga Maldonado1 years ago244/// <param name="messages"> The messages comprising the chat so far. </param>
245/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
246/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
7bdecfd8Anne Thompson2 years ago247public virtual CollectionResult<StreamingChatCompletionUpdate> CompleteChatStreaming(params ChatMessage[] messages)
1c40de67Krzysztof Cwalina2 years ago248=> CompleteChatStreaming(messages, default(ChatCompletionOptions));
249
9f9f2936Jose Arriaga Maldonado2 years ago250private void CreateChatCompletionOptions(IEnumerable<ChatMessage> messages, ref ChatCompletionOptions options, bool stream = false)
251{
252options.Messages = messages.ToList();
253options.Model = _model;
d5b5c604Liudmila Molkova2 years ago254options.Stream = stream
9f9f2936Jose Arriaga Maldonado2 years ago255? true
256: null;
257options.StreamOptions = stream ? options.StreamOptions : null;
258}
259}