openai/openai-dotnet

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
OpenAI_2.6.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

examples/Responses/Example03_FunctionCalling.cs

165lines · modeblame

d893a79fJose Arriaga Maldonado11 months ago1using NUnit.Framework;
2using OpenAI.Responses;
3using System;
4using System.Collections.Generic;
5using System.Linq;
6using System.Text.Json;
7
8namespace OpenAI.Examples;
9
10// This example uses experimental APIs which are subject to change. To use experimental APIs,
11// please acknowledge their experimental status by suppressing the corresponding warning.
12#pragma warning disable OPENAI001
13
14public partial class ResponseExamples
15{
16#region
17private static string GetCurrentLocation()
18{
19// Call the location API here.
20return "San Francisco";
21}
22
23private static string GetCurrentWeather(string location, string unit = "celsius")
24{
25// Call the weather API here.
26return $"31 {unit}";
27}
28#endregion
29
30#region
31private static readonly FunctionTool getCurrentLocationTool = ResponseTool.CreateFunctionTool(
32functionName: nameof(GetCurrentLocation),
33functionDescription: "Get the user's current location",
34functionParameters: null,
35strictModeEnabled: false
36);
37
38private static readonly FunctionTool getCurrentWeatherTool = ResponseTool.CreateFunctionTool(
39functionName: nameof(GetCurrentWeather),
40functionDescription: "Get the current weather in a given location",
41functionParameters: BinaryData.FromBytes("""
42{
43"type": "object",
44"properties": {
45"location": {
46"type": "string",
47"description": "The city and state, e.g. Boston, MA"
48},
49"unit": {
50"type": "string",
51"enum": [ "celsius", "fahrenheit" ],
52"description": "The temperature unit to use. Infer this from the specified location."
53}
54},
55"required": [ "location" ]
56}
57"""u8.ToArray()),
58strictModeEnabled: false
59);
60#endregion
61
62[Test]
63public void Example03_FunctionCalling()
64{
65OpenAIResponseClient client = new("gpt-5", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
66
67List<ResponseItem> inputItems =
68[
69ResponseItem.CreateUserMessageItem("What's the weather like today for my current location?"),
70];
71
72ResponseCreationOptions options = new()
73{
74Tools = { getCurrentLocationTool, getCurrentWeatherTool },
75};
76
77PrintMessageItems(inputItems.OfType<MessageResponseItem>());
78
79bool requiresAction;
80
81do
82{
83requiresAction = false;
84OpenAIResponse response = client.CreateResponse(inputItems, options);
85
86inputItems.AddRange(response.OutputItems);
87
88foreach (ResponseItem outputItem in response.OutputItems)
89{
90if (outputItem is FunctionCallResponseItem functionCall)
91{
92switch (functionCall.FunctionName)
93{
94case nameof(GetCurrentLocation):
95{
96string functionOutput = GetCurrentLocation();
97inputItems.Add(new FunctionCallOutputResponseItem(functionCall.CallId, functionOutput));
98break;
99}
100
101case nameof(GetCurrentWeather):
102{
103// The arguments that the model wants to use to call the function are specified as a
104// stringified JSON object based on the schema defined in the tool definition. Note that
105// the model may hallucinate arguments too. Consequently, it is important to do the
106// appropriate parsing and validation before calling the function.
107using JsonDocument argumentsJson = JsonDocument.Parse(functionCall.FunctionArguments);
108bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location);
109bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit);
110
111if (!hasLocation)
112{
113throw new ArgumentNullException(nameof(location), "The location argument is required.");
114}
115
116string functionOutput = hasUnit
117? GetCurrentWeather(location.GetString(), unit.GetString())
118: GetCurrentWeather(location.GetString());
119inputItems.Add(new FunctionCallOutputResponseItem(functionCall.CallId, functionOutput));
120break;
121}
122
123default:
124{
125// Handle other unexpected calls.
126throw new NotImplementedException();
127}
128}
129
130requiresAction = true;
131break;
132}
133}
134
135PrintMessageItems(response.OutputItems.OfType<MessageResponseItem>());
136
137} while (requiresAction);
138}
139
140private void PrintMessageItems(IEnumerable<ResponseItem> messageItems)
141{
142foreach (MessageResponseItem messageItem in messageItems)
143{
144switch (messageItem.Role)
145{
146case MessageRole.User:
147Console.WriteLine($"[USER]:");
148Console.WriteLine($"{messageItem.Content[0].Text}");
149Console.WriteLine();
150break;
151
152case MessageRole.Assistant:
153Console.WriteLine($"[ASSISTANT]:");
154Console.WriteLine($"{messageItem.Content[0].Text}");
155Console.WriteLine();
156break;
157
158default:
159break;
160}
161}
162}
163}
164
165#pragma warning restore OPENAI001