openai/openai-dotnet

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
OpenAI_2.1.0-beta.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

examples/Assistants/Example04_AllTheTools.cs

204lines · modecode

1using NUnit.Framework;
2using OpenAI.Assistants;
3using OpenAI.Files;
4using System;
5using System.ClientModel;
6using System.Collections.Generic;
7using System.Text.Json;
8using System.Threading;
9
10namespace OpenAI.Examples;
11
12public partial class AssistantExamples
13{
14 [Test]
15 public void Example04_AllTheTools()
16 {
17 #region Define a function tool
18 static string GetNameOfFamilyMember(string relation)
19 => relation switch
20 {
21 { } when relation.Contains("father") => "John Doe",
22 { } when relation.Contains("mother") => "Jane Doe",
23 _ => throw new ArgumentException(relation, nameof(relation))
24 };
25
26 FunctionToolDefinition getNameOfFamilyMemberTool = new()
27 {
28 FunctionName = nameof(GetNameOfFamilyMember),
29 Description = "Provided a family relation type like 'father' or 'mother', "
30 + "gets the name of the related person from the user.",
31 Parameters = BinaryData.FromString("""
32 {
33 "type": "object",
34 "properties": {
35 "relation": {
36 "type": "string",
37 "description": "The relation to the user to query, e.g. 'mother' or 'father'"
38 }
39 },
40 "required": [ "relation" ]
41 }
42 """),
43 };
44
45 #region Upload a mock file for use with file search
46 OpenAIFileClient fileClient = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
47 OpenAIFile favoriteNumberFile = fileClient.UploadFile(
48 BinaryData.FromString("""
49 This file contains the favorite numbers for individuals.
50
51 John Doe: 14
52 Bob Doe: 32
53 Jane Doe: 44
54 """).ToStream(),
55 "favorite_numbers.txt",
56 FileUploadPurpose.Assistants);
57 #endregion
58
59 #region Create an assistant with functions, file search, and code interpreter all enabled
60 AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
61 Assistant assistant = client.CreateAssistant("gpt-4-turbo", new AssistantCreationOptions()
62 {
63 Instructions = "Use functions to resolve family relations into the names of people. Use file search to "
64 + " look up the favorite numbers of people. Use code interpreter to create graphs of lines.",
65 Tools = { getNameOfFamilyMemberTool, new FileSearchToolDefinition(), new CodeInterpreterToolDefinition() },
66 ToolResources = new()
67 {
68 FileSearch = new()
69 {
70 NewVectorStores =
71 {
72 new VectorStoreCreationHelper([favoriteNumberFile.Id]),
73 },
74 },
75 },
76 });
77 #endregion
78
79 #region Create a new thread and start a run
80 AssistantThread thread = client.CreateThread(new ThreadCreationOptions()
81 {
82 InitialMessages =
83 {
84 "Create a graph of a line with a slope that's my father's favorite number "
85 + "and an offset that's my mother's favorite number.",
86 "Include people's names in your response and cite where you found them."
87 }
88 });
89
90 ThreadRun run = client.CreateRun(thread.Id, assistant.Id);
91 #endregion
92
93 #region Complete the run, calling functions as needed
94 // Poll the run until it is no longer queued or in progress.
95 while (!run.Status.IsTerminal)
96 {
97 Thread.Sleep(TimeSpan.FromSeconds(1));
98 run = client.GetRun(run.ThreadId, run.Id);
99
100 // If the run requires action, resolve them.
101 if (run.Status == RunStatus.RequiresAction)
102 {
103 List<ToolOutput> toolOutputs = [];
104
105 foreach (RequiredAction action in run.RequiredActions)
106 {
107 switch (action.FunctionName)
108 {
109 case nameof(GetNameOfFamilyMember):
110 {
111 using JsonDocument argumentsDocument = JsonDocument.Parse(action.FunctionArguments);
112 string relation = argumentsDocument.RootElement.TryGetProperty("relation", out JsonElement relationProperty)
113 ? relationProperty.GetString()
114 : null;
115 string toolResult = GetNameOfFamilyMember(relation);
116 toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult));
117 break;
118 }
119
120 default:
121 {
122 // Handle other or unexpected calls.
123 throw new NotImplementedException();
124 }
125 }
126 }
127
128 // Submit the tool outputs to the assistant, which returns the run to the queued state.
129 run = client.SubmitToolOutputsToRun(run.ThreadId, run.Id, toolOutputs);
130 }
131 }
132 #endregion
133
134 #region
135 // With the run complete, list the messages and display their content
136 if (run.Status == RunStatus.Completed)
137 {
138 CollectionResult<ThreadMessage> messages
139 = client.GetMessages(run.ThreadId, new MessageCollectionOptions() { Order = MessageCollectionOrder.Ascending });
140 foreach (ThreadMessage message in messages)
141 {
142 Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: ");
143 foreach (MessageContent contentItem in message.Content)
144 {
145 Console.WriteLine($"{contentItem.Text}");
146
147 if (contentItem.ImageFileId is not null)
148 {
149 Console.WriteLine($" <Image File ID> {contentItem.ImageFileId}");
150 }
151
152 // Include annotations, if any.
153 if (contentItem.TextAnnotations.Count > 0)
154 {
155 Console.WriteLine();
156 foreach (TextAnnotation annotation in contentItem.TextAnnotations)
157 {
158 Console.WriteLine($"* File ID used by file_search: {annotation.InputFileId}");
159 Console.WriteLine($"* File ID created by code_interpreter: {annotation.OutputFileId}");
160 Console.WriteLine($"* Text to replace: {annotation.TextToReplace}");
161 Console.WriteLine($"* Message content index range: {annotation.StartIndex}-{annotation.EndIndex}");
162 }
163 }
164
165 }
166 Console.WriteLine();
167 }
168 #endregion
169
170 #region List run steps for details about tool calls
171 CollectionResult<RunStep> runSteps = client.GetRunSteps(
172 run.ThreadId,
173 run.Id,
174 new RunStepCollectionOptions()
175 {
176 Order = RunStepCollectionOrder.Ascending
177 });
178 foreach (RunStep step in runSteps)
179 {
180 Console.WriteLine($"Run step: {step.Status}");
181 foreach (RunStepToolCall toolCall in step.Details.ToolCalls)
182 {
183 Console.WriteLine($" --> Tool call: {toolCall.ToolKind}");
184 foreach (RunStepCodeInterpreterOutput output in toolCall.CodeInterpreterOutputs)
185 {
186 Console.WriteLine($" --> Output: {output.ImageFileId}");
187 }
188 }
189 }
190 #endregion
191 }
192 else
193 {
194 throw new NotImplementedException(run.Status.ToString());
195 }
196 #endregion
197
198 #region Clean up any temporary resources that are no longer needed
199 _ = client.DeleteThread(thread.Id);
200 _ = client.DeleteAssistant(assistant.Id);
201 _ = fileClient.DeleteFile(favoriteNumberFile.Id);
202 #endregion
203 }
204}
205