openai/openai-dotnet

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
OpenAI_2.3.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

examples/Chat/Example04_FunctionCallingStreamingAsync.cs

171lines · modeblame

9f9f2936Jose Arriaga Maldonado2 years ago1using NUnit.Framework;
2using OpenAI.Chat;
3using System;
4using System.ClientModel;
5using System.Collections.Generic;
6using System.Text;
7using System.Text.Json;
8using System.Threading.Tasks;
9
8cc6643fJose Arriaga Maldonado2 years ago10namespace OpenAI.Examples;
9f9f2936Jose Arriaga Maldonado2 years ago11
8cc6643fJose Arriaga Maldonado2 years ago12public partial class ChatExamples
9f9f2936Jose Arriaga Maldonado2 years ago13{
8cc6643fJose Arriaga Maldonado2 years ago14// See Example03_FunctionCalling.cs for the tool and function definitions.
9f9f2936Jose Arriaga Maldonado2 years ago15
16[Test]
8cc6643fJose Arriaga Maldonado2 years ago17public async Task Example04_FunctionCallingStreamingAsync()
9f9f2936Jose Arriaga Maldonado2 years ago18{
8cc6643fJose Arriaga Maldonado2 years ago19ChatClient client = new("gpt-4-turbo", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
9f9f2936Jose Arriaga Maldonado2 years ago20
21#region
31c2ba63Jose Arriaga Maldonado1 years ago22List<ChatMessage> messages =
23[
9f9f2936Jose Arriaga Maldonado2 years ago24new UserChatMessage("What's the weather like today?"),
25];
26
27ChatCompletionOptions options = new()
28{
29Tools = { getCurrentLocationTool, getCurrentWeatherTool },
30};
31#endregion
32
33#region
34bool requiresAction;
35
36do
37{
38requiresAction = false;
39StringBuilder contentBuilder = new();
31c2ba63Jose Arriaga Maldonado1 years ago40StreamingChatToolCallsBuilder toolCallsBuilder = new();
9f9f2936Jose Arriaga Maldonado2 years ago41
31c2ba63Jose Arriaga Maldonado1 years ago42AsyncCollectionResult<StreamingChatCompletionUpdate> completionUpdates = client.CompleteChatStreamingAsync(messages, options);
43
44await foreach (StreamingChatCompletionUpdate completionUpdate in completionUpdates)
9f9f2936Jose Arriaga Maldonado2 years ago45{
46// Accumulate the text content as new updates arrive.
31c2ba63Jose Arriaga Maldonado1 years ago47foreach (ChatMessageContentPart contentPart in completionUpdate.ContentUpdate)
9f9f2936Jose Arriaga Maldonado2 years ago48{
49contentBuilder.Append(contentPart.Text);
50}
51
52// Build the tool calls as new updates arrive.
31c2ba63Jose Arriaga Maldonado1 years ago53foreach (StreamingChatToolCallUpdate toolCallUpdate in completionUpdate.ToolCallUpdates)
9f9f2936Jose Arriaga Maldonado2 years ago54{
31c2ba63Jose Arriaga Maldonado1 years ago55toolCallsBuilder.Append(toolCallUpdate);
9f9f2936Jose Arriaga Maldonado2 years ago56}
57
31c2ba63Jose Arriaga Maldonado1 years ago58switch (completionUpdate.FinishReason)
9f9f2936Jose Arriaga Maldonado2 years ago59{
60case ChatFinishReason.Stop:
61{
62// Add the assistant message to the conversation history.
63messages.Add(new AssistantChatMessage(contentBuilder.ToString()));
64break;
65}
66
67case ChatFinishReason.ToolCalls:
68{
69// First, collect the accumulated function arguments into complete tool calls to be processed
31c2ba63Jose Arriaga Maldonado1 years ago70IReadOnlyList<ChatToolCall> toolCalls = toolCallsBuilder.Build();
9f9f2936Jose Arriaga Maldonado2 years ago71
72// Next, add the assistant message with tool calls to the conversation history.
31c2ba63Jose Arriaga Maldonado1 years ago73AssistantChatMessage assistantMessage = new(toolCalls);
74
75if (contentBuilder.Length > 0)
2ab1a942Jose Arriaga Maldonado1 years ago76{
31c2ba63Jose Arriaga Maldonado1 years ago77assistantMessage.Content.Add(ChatMessageContentPart.CreateTextPart(contentBuilder.ToString()));
2ab1a942Jose Arriaga Maldonado1 years ago78}
31c2ba63Jose Arriaga Maldonado1 years ago79
80messages.Add(assistantMessage);
9f9f2936Jose Arriaga Maldonado2 years ago81
82// Then, add a new tool message for each tool call to be resolved.
83foreach (ChatToolCall toolCall in toolCalls)
84{
85switch (toolCall.FunctionName)
86{
87case nameof(GetCurrentLocation):
88{
89string toolResult = GetCurrentLocation();
90messages.Add(new ToolChatMessage(toolCall.Id, toolResult));
91break;
92}
93
94case nameof(GetCurrentWeather):
95{
96// The arguments that the model wants to use to call the function are specified as a
97// stringified JSON object based on the schema defined in the tool definition. Note that
98// the model may hallucinate arguments too. Consequently, it is important to do the
99// appropriate parsing and validation before calling the function.
100using JsonDocument argumentsJson = JsonDocument.Parse(toolCall.FunctionArguments);
101bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location);
102bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit);
103
104if (!hasLocation)
105{
106throw new ArgumentNullException(nameof(location), "The location argument is required.");
107}
108
109string toolResult = hasUnit
110? GetCurrentWeather(location.GetString(), unit.GetString())
111: GetCurrentWeather(location.GetString());
112messages.Add(new ToolChatMessage(toolCall.Id, toolResult));
113break;
114}
115
116default:
117{
118// Handle other unexpected calls.
119throw new NotImplementedException();
120}
121}
122}
123
124requiresAction = true;
125break;
126}
127
128case ChatFinishReason.Length:
129throw new NotImplementedException("Incomplete model output due to MaxTokens parameter or token limit exceeded.");
130
131case ChatFinishReason.ContentFilter:
132throw new NotImplementedException("Omitted content due to a content filter flag.");
133
134case ChatFinishReason.FunctionCall:
135throw new NotImplementedException("Deprecated in favor of tool calls.");
136
137case null:
138break;
139}
140}
141} while (requiresAction);
142#endregion
143
144#region
7a8bc8beJose Arriaga Maldonado1 years ago145foreach (ChatMessage message in messages)
9f9f2936Jose Arriaga Maldonado2 years ago146{
7a8bc8beJose Arriaga Maldonado1 years ago147switch (message)
9f9f2936Jose Arriaga Maldonado2 years ago148{
149case UserChatMessage userMessage:
150Console.WriteLine($"[USER]:");
151Console.WriteLine($"{userMessage.Content[0].Text}");
152Console.WriteLine();
153break;
154
155case AssistantChatMessage assistantMessage when assistantMessage.Content.Count > 0:
156Console.WriteLine($"[ASSISTANT]:");
157Console.WriteLine($"{assistantMessage.Content[0].Text}");
158Console.WriteLine();
159break;
160
161case ToolChatMessage:
162// Do not print any tool messages; let the assistant summarize the tool results instead.
163break;
164
165default:
166break;
167}
168}
169#endregion
170}
171}