openai/openai-dotnet

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
OpenAI_2.1.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/Custom/Chat/ChatClient.cs

265lines · 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))]
9f9f2936Jose Arriaga Maldonado2 years ago19[CodeGenSuppress("CreateChatCompletionAsync", typeof(ChatCompletionOptions))]
20[CodeGenSuppress("CreateChatCompletion", typeof(ChatCompletionOptions))]
21public partial class ChatClient
22{
23private readonly string _model;
d5b5c604Liudmila Molkova2 years ago24private readonly OpenTelemetrySource _telemetry;
9f9f2936Jose Arriaga Maldonado2 years ago25
75eded51ShivangiReja1 years ago26// CUSTOM: Remove virtual keyword.
27/// <summary>
28/// The HTTP pipeline for sending and receiving REST requests and responses.
29/// </summary>
30public ClientPipeline Pipeline => _pipeline;
31
2ab1a942Jose Arriaga Maldonado1 years ago32// CUSTOM: Added as a convenience.
33/// <summary> Initializes a new instance of <see cref="ChatClient">. </summary>
34/// <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>
35/// <param name="apiKey"> The API key to authenticate with the service. </param>
36/// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="apiKey"/> is null. </exception>
37/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
38public ChatClient(string model, string apiKey) : this(model, new ApiKeyCredential(apiKey), new OpenAIClientOptions())
39{
40}
41
13a9c686Jose Arriaga Maldonado1 years ago42// CUSTOM:
43// - Added `model` parameter.
44// - Used a custom pipeline.
45// - Demoted the endpoint parameter to be a property in the options class.
46/// <summary> Initializes a new instance of <see cref="ChatClient">. </summary>
47/// <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>
48/// <param name="credential"> The API key to authenticate with the service. </param>
49/// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="credential"/> is null. </exception>
50/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
51public ChatClient(string model, ApiKeyCredential credential) : this(model, credential, new OpenAIClientOptions())
52{
53}
9f9f2936Jose Arriaga Maldonado2 years ago54
13a9c686Jose Arriaga Maldonado1 years ago55// CUSTOM:
56// - Added `model` parameter.
57// - Used a custom pipeline.
58// - Demoted the endpoint parameter to be a property in the options class.
59// - Added telemetry support.
60/// <summary> Initializes a new instance of <see cref="ChatClient">. </summary>
61/// <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>
62/// <param name="credential"> The API key to authenticate with the service. </param>
63/// <param name="options"> The options to configure the client. </param>
64/// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="credential"/> is null. </exception>
65/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
66public ChatClient(string model, ApiKeyCredential credential, OpenAIClientOptions options)
67{
68Argument.AssertNotNullOrEmpty(model, nameof(model));
69Argument.AssertNotNull(credential, nameof(credential));
70options ??= new OpenAIClientOptions();
9f9f2936Jose Arriaga Maldonado2 years ago71
13a9c686Jose Arriaga Maldonado1 years ago72_model = model;
73_pipeline = OpenAIClient.CreatePipeline(credential, options);
74_endpoint = OpenAIClient.GetEndpoint(options);
75_telemetry = new OpenTelemetrySource(model, _endpoint);
76}
77
78// CUSTOM:
79// - Added `model` parameter.
80// - Used a custom pipeline.
81// - Demoted the endpoint parameter to be a property in the options class.
82// - Added telemetry support.
83// - Made protected.
84/// <summary> Initializes a new instance of <see cref="ChatClient">. </summary>
85/// <param name="pipeline"> The HTTP pipeline to send and receive REST requests and responses. </param>
86/// <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>
87/// <param name="options"> The options to configure the client. </param>
88/// <exception cref="ArgumentNullException"> <paramref name="pipeline"/> or <paramref name="model"/> is null. </exception>
89/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
90protected internal ChatClient(ClientPipeline pipeline, string model, OpenAIClientOptions options)
9f9f2936Jose Arriaga Maldonado2 years ago91{
13a9c686Jose Arriaga Maldonado1 years ago92Argument.AssertNotNull(pipeline, nameof(pipeline));
9f9f2936Jose Arriaga Maldonado2 years ago93Argument.AssertNotNullOrEmpty(model, nameof(model));
13a9c686Jose Arriaga Maldonado1 years ago94options ??= new OpenAIClientOptions();
9f9f2936Jose Arriaga Maldonado2 years ago95
96_model = model;
97_pipeline = pipeline;
13a9c686Jose Arriaga Maldonado1 years ago98_endpoint = OpenAIClient.GetEndpoint(options);
99_telemetry = new OpenTelemetrySource(model, _endpoint);
9f9f2936Jose Arriaga Maldonado2 years ago100}
101
13a9c686Jose Arriaga Maldonado1 years ago102/// <summary> Generates a completion for the given chat. </summary>
103/// <param name="messages"> The messages comprising the chat so far. </param>
104/// <param name="options"> The options to configure the chat completion. </param>
105/// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
106/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
107/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
19a65a0aKrzysztof Cwalina2 years ago108public virtual async Task<ClientResult<ChatCompletion>> CompleteChatAsync(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
9f9f2936Jose Arriaga Maldonado2 years ago109{
110Argument.AssertNotNullOrEmpty(messages, nameof(messages));
111
112options ??= new();
113CreateChatCompletionOptions(messages, ref options);
d5b5c604Liudmila Molkova2 years ago114using OpenTelemetryScope scope = _telemetry.StartChatScope(options);
115
116try
117{
118using BinaryContent content = options.ToBinaryContent();
119
120ClientResult result = await CompleteChatAsync(content, cancellationToken.ToRequestOptions()).ConfigureAwait(false);
121ChatCompletion chatCompletion = ChatCompletion.FromResponse(result.GetRawResponse());
122scope?.RecordChatCompletion(chatCompletion);
123return ClientResult.FromValue(chatCompletion, result.GetRawResponse());
124}
125catch (Exception ex)
126{
127scope?.RecordException(ex);
128throw;
129}
9f9f2936Jose Arriaga Maldonado2 years ago130}
131
13a9c686Jose Arriaga Maldonado1 years ago132/// <summary> Generates a completion for the given chat. </summary>
133/// <param name="messages"> The messages comprising the chat so far. </param>
134/// <param name="options"> The options to configure the chat completion. </param>
135/// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
136/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
137/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
19a65a0aKrzysztof Cwalina2 years ago138public virtual ClientResult<ChatCompletion> CompleteChat(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
9f9f2936Jose Arriaga Maldonado2 years ago139{
140Argument.AssertNotNullOrEmpty(messages, nameof(messages));
141
142options ??= new();
143CreateChatCompletionOptions(messages, ref options);
d5b5c604Liudmila Molkova2 years ago144using OpenTelemetryScope scope = _telemetry.StartChatScope(options);
145
146try
147{
148using BinaryContent content = options.ToBinaryContent();
149ClientResult result = CompleteChat(content, cancellationToken.ToRequestOptions());
150ChatCompletion chatCompletion = ChatCompletion.FromResponse(result.GetRawResponse());
151
152scope?.RecordChatCompletion(chatCompletion);
153return ClientResult.FromValue(chatCompletion, result.GetRawResponse());
154}
155catch (Exception ex)
156{
157scope?.RecordException(ex);
158throw;
159}
9f9f2936Jose Arriaga Maldonado2 years ago160}
161
13a9c686Jose Arriaga Maldonado1 years ago162/// <summary> Generates a completion for the given chat. </summary>
163/// <param name="messages"> The messages comprising the chat so far. </param>
164/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
165/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
166public virtual async Task<ClientResult<ChatCompletion>> CompleteChatAsync(params ChatMessage[] messages)
167=> await CompleteChatAsync(messages, default(ChatCompletionOptions)).ConfigureAwait(false);
168
169/// <summary> Generates a completion for the given chat. </summary>
170/// <param name="messages"> The messages comprising the chat so far. </param>
171/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
172/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
1c40de67Krzysztof Cwalina2 years ago173public virtual ClientResult<ChatCompletion> CompleteChat(params ChatMessage[] messages)
174=> CompleteChat(messages, default(ChatCompletionOptions));
175
9f9f2936Jose Arriaga Maldonado2 years ago176/// <summary>
13a9c686Jose Arriaga Maldonado1 years ago177/// Generates a completion for the given chat. The completion is streamed back token by token as it is being
178/// generated by the model instead of waiting for it to be finished first.
9f9f2936Jose Arriaga Maldonado2 years ago179/// </summary>
180/// <remarks>
13a9c686Jose Arriaga Maldonado1 years ago181/// <see cref="AsyncCollectionResult{T}"/> implements the <see cref="IAsyncEnumerable{T}"/> interface and can be
182/// enumerated over using the <c>await foreach</c> pattern.
9f9f2936Jose Arriaga Maldonado2 years ago183/// </remarks>
13a9c686Jose Arriaga Maldonado1 years ago184/// <param name="messages"> The messages comprising the chat so far. </param>
185/// <param name="options"> The options to configure the chat completion. </param>
186/// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
187/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
188/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
7bdecfd8Anne Thompson2 years ago189public virtual AsyncCollectionResult<StreamingChatCompletionUpdate> CompleteChatStreamingAsync(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
9f9f2936Jose Arriaga Maldonado2 years ago190{
191Argument.AssertNotNull(messages, nameof(messages));
192
193options ??= new();
194CreateChatCompletionOptions(messages, ref options, stream: true);
195
196using BinaryContent content = options.ToBinaryContent();
19a65a0aKrzysztof Cwalina2 years ago197
2ab1a942Jose Arriaga Maldonado1 years ago198async Task<ClientResult> sendRequestAsync() =>
19a65a0aKrzysztof Cwalina2 years ago199await CompleteChatAsync(content, cancellationToken.ToRequestOptions(streaming: true)).ConfigureAwait(false);
2ab1a942Jose Arriaga Maldonado1 years ago200return new InternalAsyncStreamingChatCompletionUpdateCollection(sendRequestAsync, cancellationToken);
9f9f2936Jose Arriaga Maldonado2 years ago201}
202
1c40de67Krzysztof Cwalina2 years ago203/// <summary>
13a9c686Jose Arriaga Maldonado1 years ago204/// Generates a completion for the given chat. The completion is streamed back token by token as it is being
205/// generated by the model instead of waiting for it to be finished first.
1c40de67Krzysztof Cwalina2 years ago206/// </summary>
207/// <remarks>
a330c2e7Jose Arriaga Maldonado1 years ago208/// <see cref="CollectionResult{T}"/> implements the <see cref="IEnumerable{T}"/> interface and can be
13a9c686Jose Arriaga Maldonado1 years ago209/// enumerated over using the <c>await foreach</c> pattern.
1c40de67Krzysztof Cwalina2 years ago210/// </remarks>
13a9c686Jose Arriaga Maldonado1 years ago211/// <param name="messages"> The messages comprising the chat so far. </param>
212/// <param name="options"> The options to configure the chat completion. </param>
213/// <param name="cancellationToken"> A token that can be used to cancel this method call. </param>
214/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
215/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
7bdecfd8Anne Thompson2 years ago216public virtual CollectionResult<StreamingChatCompletionUpdate> CompleteChatStreaming(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
9f9f2936Jose Arriaga Maldonado2 years ago217{
218Argument.AssertNotNull(messages, nameof(messages));
219
220options ??= new();
221CreateChatCompletionOptions(messages, ref options, stream: true);
222
223using BinaryContent content = options.ToBinaryContent();
2ab1a942Jose Arriaga Maldonado1 years ago224ClientResult sendRequest() => CompleteChat(content, cancellationToken.ToRequestOptions(streaming: true));
225return new InternalStreamingChatCompletionUpdateCollection(sendRequest, cancellationToken);
9f9f2936Jose Arriaga Maldonado2 years ago226}
227
1c40de67Krzysztof Cwalina2 years ago228/// <summary>
13a9c686Jose Arriaga Maldonado1 years ago229/// Generates a completion for the given chat. The completion is streamed back token by token as it is being
230/// generated by the model instead of waiting for it to be finished first.
231/// </summary>
232/// <remarks>
233/// <see cref="AsyncCollectionResult{T}"/> implements the <see cref="IAsyncEnumerable{T}"/> interface and can be
234/// enumerated over using the <c>await foreach</c> pattern.
235/// </remarks>
236/// <param name="messages"> The messages comprising the chat so far. </param>
237/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
238/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
239public virtual AsyncCollectionResult<StreamingChatCompletionUpdate> CompleteChatStreamingAsync(params ChatMessage[] messages)
240=> CompleteChatStreamingAsync(messages, default(ChatCompletionOptions));
241
242/// <summary>
243/// Generates a completion for the given chat. The completion is streamed back token by token as it is being
244/// generated by the model instead of waiting for it to be finished first.
1c40de67Krzysztof Cwalina2 years ago245/// </summary>
246/// <remarks>
a330c2e7Jose Arriaga Maldonado1 years ago247/// <see cref="CollectionResult{T}"/> implements the <see cref="IEnumerable{T}"/> interface and can be
13a9c686Jose Arriaga Maldonado1 years ago248/// enumerated over using the <c>await foreach</c> pattern.
1c40de67Krzysztof Cwalina2 years ago249/// </remarks>
13a9c686Jose Arriaga Maldonado1 years ago250/// <param name="messages"> The messages comprising the chat so far. </param>
251/// <exception cref="ArgumentNullException"> <paramref name="messages"/> is null. </exception>
252/// <exception cref="ArgumentException"> <paramref name="messages"/> is an empty collection, and was expected to be non-empty. </exception>
7bdecfd8Anne Thompson2 years ago253public virtual CollectionResult<StreamingChatCompletionUpdate> CompleteChatStreaming(params ChatMessage[] messages)
1c40de67Krzysztof Cwalina2 years ago254=> CompleteChatStreaming(messages, default(ChatCompletionOptions));
255
9f9f2936Jose Arriaga Maldonado2 years ago256private void CreateChatCompletionOptions(IEnumerable<ChatMessage> messages, ref ChatCompletionOptions options, bool stream = false)
257{
258options.Messages = messages.ToList();
259options.Model = _model;
d5b5c604Liudmila Molkova2 years ago260options.Stream = stream
9f9f2936Jose Arriaga Maldonado2 years ago261? true
262: null;
263options.StreamOptions = stream ? options.StreamOptions : null;
264}
265}