Skip to content

Commit 669810c

Browse files
com.openai.unity 7.7.7 (#217)
- Updated static models list - Added gpt-4-turbo - Marked some models as deprecated since they are no longer available - Added temperature to CreateRunRequest and CreateThreadAndRunRequest - Fixed temperature to string conversion to be invariant culture for audio requests - Fixed type checking built in function tool calls
1 parent 8fb7881 commit 669810c

15 files changed

+152
-64
lines changed

Documentation~/README.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ Create an assistant with a model and instructions.
398398

399399
```csharp
400400
var api = new OpenAIClient();
401-
var request = new CreateAssistantRequest("gpt-3.5-turbo");
401+
var request = new CreateAssistantRequest(Model.GPT4_Turbo);
402402
var assistant = await api.AssistantsEndpoint.CreateAssistantAsync(request);
403403
```
404404

@@ -418,9 +418,9 @@ Modifies an assistant.
418418

419419
```csharp
420420
var api = new OpenAIClient();
421-
var createRequest = new CreateAssistantRequest("gpt-3.5-turbo");
421+
var createRequest = new CreateAssistantRequest(Model.GPT3_5_Turbo);
422422
var assistant = await api.AssistantsEndpoint.CreateAssistantAsync(createRequest);
423-
var modifyRequest = new CreateAssistantRequest("gpt-4-turbo-preview");
423+
var modifyRequest = new CreateAssistantRequest(Model.GPT4_Turbo);
424424
var modifiedAssistant = await api.AssistantsEndpoint.ModifyAssistantAsync(assistant.Id, modifyRequest);
425425
// OR AssistantExtension for easier use!
426426
var modifiedAssistantEx = await assistant.ModifyAsync(modifyRequest);
@@ -550,7 +550,7 @@ var assistant = await api.AssistantsEndpoint.CreateAssistantAsync(
550550
new CreateAssistantRequest(
551551
name: "Math Tutor",
552552
instructions: "You are a personal math tutor. Answer questions briefly, in a sentence or less.",
553-
model: "gpt-4-turbo-preview"));
553+
model: Model.GPT4_Turbo));
554554
var messages = new List<Message> { "I need to solve the equation `3x + 11 = 14`. Can you help me?" };
555555
var threadRequest = new CreateThreadRequest(messages);
556556
var run = await assistant.CreateThreadAndRunAsync(threadRequest);
@@ -726,7 +726,7 @@ var assistant = await api.AssistantsEndpoint.CreateAssistantAsync(
726726
new CreateAssistantRequest(
727727
name: "Math Tutor",
728728
instructions: "You are a personal math tutor. Answer questions briefly, in a sentence or less.",
729-
model: "gpt-4-turbo-preview"));
729+
model: Model.GPT4_Turbo));
730730
var thread = await api.ThreadsEndpoint.CreateThreadAsync();
731731
var message = await thread.CreateMessageAsync("I need to solve the equation `3x + 11 = 14`. Can you help me?");
732732
var run = await thread.CreateRunAsync(assistant);
@@ -868,7 +868,7 @@ var messages = new List<Message>
868868
new Message(Role.Assistant, "The Los Angeles Dodgers won the World Series in 2020."),
869869
new Message(Role.User, "Where was it played?"),
870870
};
871-
var chatRequest = new ChatRequest(messages, Model.GPT4);
871+
var chatRequest = new ChatRequest(messages, Model.GPT4_Turbo);
872872
var response = await api.ChatEndpoint.GetCompletionAsync(chatRequest);
873873
var choice = response.FirstChoice;
874874
Debug.Log($"[{choice.Index}] {choice.Message.Role}: {choice.Message} | Finish Reason: {choice.FinishReason}");
@@ -970,7 +970,6 @@ foreach (var toolCall in response.FirstChoice.Message.ToolCalls)
970970
#### [Chat Vision](https://platform.openai.com/docs/guides/vision)
971971

972972
> :warning: Beta Feature
973-
> Currently, GPT-4 with vision does not support the `message.name` parameter, functions/tools, nor the `response_format` parameter.
974973
975974
```csharp
976975
var api = new OpenAIClient();
@@ -983,7 +982,7 @@ var messages = new List<Message>
983982
new ImageUrl("https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg", ImageDetail.Low)
984983
})
985984
};
986-
var chatRequest = new ChatRequest(messages, model: "gpt-4-vision-preview");
985+
var chatRequest = new ChatRequest(messages, model: Model.GPT4_Turbo);
987986
var response = await api.ChatEndpoint.GetCompletionAsync(chatRequest);
988987
Debug.Log($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishDetails}");
989988
```
@@ -1001,7 +1000,7 @@ var messages = new List<Message>
10011000
texture
10021001
})
10031002
};
1004-
var chatRequest = new ChatRequest(messages, model: "gpt-4-vision-preview");
1003+
var chatRequest = new ChatRequest(messages, model: Model.GPT4_Turbo);
10051004
var result = await apiChatEndpoint.GetCompletionAsync(chatRequest);
10061005
Debug.Log($"{result.FirstChoice.Message.Role}: {result.FirstChoice} | Finish Reason: {result.FirstChoice.FinishDetails}");
10071006
```
@@ -1022,7 +1021,7 @@ var messages = new List<Message>
10221021
new Message(Role.System, "You are a helpful assistant designed to output JSON."),
10231022
new Message(Role.User, "Who won the world series in 2020?"),
10241023
};
1025-
var chatRequest = new ChatRequest(messages, "gpt-4-turbo-preview", responseFormat: ChatResponseFormat.Json);
1024+
var chatRequest = new ChatRequest(messages, Model.GPT4_Turbo, responseFormat: ChatResponseFormat.Json);
10261025
var response = await api.ChatEndpoint.GetCompletionAsync(chatRequest);
10271026

10281027
foreach (var choice in response.Choices)

Runtime/Assistants/AssistantExtensions.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,13 @@ public static async Task<bool> DeleteFileAsync(this AssistantResponse assistant,
187187
/// <returns>Tool output result as <see cref="string"/></returns>
188188
public static string InvokeToolCall(this AssistantResponse assistant, ToolCall toolCall)
189189
{
190-
var tool = assistant.Tools.FirstOrDefault(tool => toolCall.Type == "function" && tool.Function.Name == toolCall.FunctionCall.Name) ??
191-
throw new InvalidOperationException($"Failed to find a valid tool for [{toolCall.Id}] {toolCall.Type}");
190+
if (toolCall.Type != "function")
191+
{
192+
throw new InvalidOperationException($"Cannot invoke built in tool {toolCall.Type}");
193+
}
194+
195+
var tool = assistant.Tools.FirstOrDefault(tool => tool.Type == "function" && tool.Function.Name == toolCall.FunctionCall.Name) ??
196+
throw new InvalidOperationException($"Failed to find a valid tool for [{toolCall.Id}] {toolCall.Type}");
192197
tool.Function.Arguments = toolCall.FunctionCall.Arguments;
193198
return tool.InvokeFunction();
194199
}
@@ -202,8 +207,13 @@ public static string InvokeToolCall(this AssistantResponse assistant, ToolCall t
202207
/// <returns>Tool output result as <see cref="string"/></returns>
203208
public static async Task<string> InvokeToolCallAsync(this AssistantResponse assistant, ToolCall toolCall, CancellationToken cancellationToken = default)
204209
{
205-
var tool = assistant.Tools.FirstOrDefault(tool => toolCall.Type == "function" && tool.Function.Name == toolCall.FunctionCall.Name) ??
206-
throw new InvalidOperationException($"Failed to find a valid tool for [{toolCall.Id}] {toolCall.Type}");
210+
if (toolCall.Type != "function")
211+
{
212+
throw new InvalidOperationException($"Cannot invoke built in tool {toolCall.Type}");
213+
}
214+
215+
var tool = assistant.Tools.FirstOrDefault(tool => tool.Type == "function" && tool.Function.Name == toolCall.FunctionCall.Name) ??
216+
throw new InvalidOperationException($"Failed to find a valid tool for [{toolCall.Id}] {toolCall.Type}");
207217
tool.Function.Arguments = toolCall.FunctionCall.Arguments;
208218
return await tool.InvokeFunctionAsync(cancellationToken);
209219
}

Runtime/Audio/AudioEndpoint.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using Newtonsoft.Json;
44
using System;
5+
using System.Globalization;
56
using System.IO;
67
using System.Threading;
78
using System.Threading.Tasks;
@@ -169,7 +170,7 @@ private async Task<string> Internal_CreateTranscriptionAsync(AudioTranscriptionR
169170

170171
if (request.Temperature.HasValue)
171172
{
172-
form.AddField("temperature", request.Temperature.ToString());
173+
form.AddField("temperature", request.Temperature.Value.ToString(CultureInfo.InvariantCulture));
173174
}
174175

175176
if (!string.IsNullOrWhiteSpace(request.Language))
@@ -246,7 +247,7 @@ private async Task<string> Internal_CreateTranslationAsync(AudioTranslationReque
246247

247248
if (request.Temperature.HasValue)
248249
{
249-
form.AddField("temperature", request.Temperature.ToString());
250+
form.AddField("temperature", request.Temperature.Value.ToString(CultureInfo.InvariantCulture));
250251
}
251252

252253
request.Dispose();

Runtime/Common/Function.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public Function(string name, string description = null, JToken parameters = null
4747
throw new ArgumentException($"The name of the function does not conform to naming standards: {NameRegex}");
4848
}
4949

50+
if (functionCache.ContainsKey(name))
51+
{
52+
throw new ArgumentException($"The function \"{name}\" is already registered.");
53+
}
54+
5055
Name = name;
5156
Description = description;
5257
Parameters = parameters;
@@ -74,6 +79,11 @@ public Function(string name, string description, string parameters)
7479
throw new ArgumentException($"The name of the function does not conform to naming standards: {NameRegex}");
7580
}
7681

82+
if (functionCache.ContainsKey(name))
83+
{
84+
throw new ArgumentException($"The function \"{name}\" is already registered.");
85+
}
86+
7787
Name = name;
7888
Description = description;
7989
Parameters = new JObject(parameters);
@@ -88,6 +98,11 @@ internal Function(string name, string description, MethodInfo method, object ins
8898
throw new ArgumentException($"The name of the function does not conform to naming standards: {NameRegex}");
8999
}
90100

101+
if (functionCache.ContainsKey(name))
102+
{
103+
throw new ArgumentException($"The function \"{name}\" is already registered.");
104+
}
105+
91106
Name = name;
92107
Description = description;
93108
MethodInfo = method;
@@ -96,6 +111,11 @@ internal Function(string name, string description, MethodInfo method, object ins
96111
functionCache[Name] = this;
97112
}
98113

114+
internal static Function GetOrCreateFunction(string name, string description, MethodInfo method, object instance = null)
115+
=> functionCache.TryGetValue(name, out var function)
116+
? function
117+
: new Function(name, description, method, instance);
118+
99119
#region Func<,> Overloads
100120

101121
public static Function FromFunc<TResult>(string name, Func<TResult> function, string description = null)
@@ -246,6 +266,8 @@ internal void CopyFrom(Function other)
246266

247267
private static readonly ConcurrentDictionary<string, Function> functionCache = new();
248268

269+
internal static void ClearFunctionCache() => functionCache.Clear();
270+
249271
/// <summary>
250272
/// Invokes the function and returns the result as json.
251273
/// </summary>

Runtime/Common/Tool.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ public async Task<T> InvokeFunctionAsync<T>(CancellationToken cancellationToken
132132
public static void ClearRegisteredTools()
133133
{
134134
toolCache.Clear();
135+
Function.ClearFunctionCache();
135136
toolCache.Add(CodeInterpreter);
136137
toolCache.Add(Retrieval);
137138
}
@@ -260,7 +261,7 @@ public static Tool GetOrCreateTool(Type type, string methodName, string descript
260261
return tool;
261262
}
262263

263-
tool = new Tool(new Function(functionName, description ?? string.Empty, method));
264+
tool = new Tool(Function.GetOrCreateFunction(functionName, description ?? string.Empty, method));
264265
toolCache.Add(tool);
265266
return tool;
266267
}

Runtime/Models/Model.cs

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -101,18 +101,32 @@ public Model(
101101
/// More capable than any GPT-3.5 model, able to do more complex tasks, and optimized for chat.
102102
/// Will be updated with our latest model iteration.
103103
/// </summary>
104+
/// <remarks>
105+
/// Context Window: 8,192 tokens
106+
/// </remarks>
104107
public static Model GPT4 { get; } = new("gpt-4", "openai");
105108

109+
/// <summary>
110+
/// The latest GPT-4 Turbo model with vision capabilities. Vision requests can now use JSON mode and function calling.
111+
/// </summary>
112+
/// <remarks>
113+
/// Context Window: 128,000 tokens
114+
/// </remarks>
115+
public static Model GPT4_Turbo { get; } = new("gpt-4-turbo", "openai");
116+
106117
/// <summary>
107118
/// Same capabilities as the base gpt-4 mode but with 4x the context length.
108119
/// Will be updated with our latest model iteration. Tokens are 2x the price of gpt-4.
109120
/// </summary>
110121
public static Model GPT4_32K { get; } = new("gpt-4-32k", "openai");
111122

112123
/// <summary>
113-
/// Because gpt-3.5-turbo performs at a similar capability to text-davinci-003 but at 10%
114-
/// the price per token, we recommend gpt-3.5-turbo for most use cases.
124+
/// GPT-3.5 Turbo models can understand and generate natural language or code and have been optimized for chat
125+
/// using the Chat Completions API but work well for non-chat tasks as well.
115126
/// </summary>
127+
/// <remarks>
128+
/// Context Window: 4,096 tokens
129+
/// </remarks>
116130
public static Model GPT3_5_Turbo { get; } = new("gpt-3.5-turbo", "openai");
117131

118132
/// <summary>
@@ -122,71 +136,84 @@ public Model(
122136
public static Model GPT3_5_Turbo_16K { get; } = new("gpt-3.5-turbo-16k", "openai");
123137

124138
/// <summary>
125-
/// The most powerful, largest engine available, although the speed is quite slow.<para/>
126-
/// Good at: Complex intent, cause and effect, summarization for audience
139+
/// Replacement for the GPT-3 curie and davinci base models.
127140
/// </summary>
128-
public static Model Davinci { get; } = new("text-davinci-003", "openai");
141+
public static Model Davinci { get; } = new("davinci-002", "openai");
129142

130143
/// <summary>
131-
/// For edit requests.
144+
/// Replacement for the GPT-3 ada and babbage base models.
132145
/// </summary>
133-
public static Model DavinciEdit { get; } = new("text-davinci-edit-001", "openai");
146+
public static Model Babbage { get; } = new("babbage-002", "openai");
134147

135148
/// <summary>
136-
/// The 2nd most powerful engine, a bit faster than <see cref="Davinci"/>, and a bit faster.<para/>
137-
/// Good at: Language translation, complex classification, text sentiment, summarization.
149+
/// The default model for <see cref="Embeddings.EmbeddingsEndpoint"/>.
138150
/// </summary>
139-
public static Model Curie { get; } = new("text-curie-001", "openai");
151+
public static Model Embedding_Ada_002 { get; } = new("text-embedding-ada-002", "openai");
140152

141153
/// <summary>
142-
/// The 2nd fastest engine, a bit more powerful than <see cref="Ada"/>, and a bit slower.<para/>
143-
/// Good at: Moderate classification, semantic search classification
154+
/// A highly efficient model which provides a significant upgrade over its predecessor, the text-embedding-ada-002 model.
144155
/// </summary>
145-
public static Model Babbage { get; } = new("text-babbage-001", "openai");
156+
public static Model Embedding_3_Small { get; } = new("text-embedding-3-small", "openai");
146157

147158
/// <summary>
148-
/// The smallest, fastest engine available, although the quality of results may be poor.<para/>
149-
/// Good at: Parsing text, simple classification, address correction, keywords
159+
/// Most capable embedding model for both english and non-english tasks with embeddings of up to 3072 dimensions.
150160
/// </summary>
151-
public static Model Ada { get; } = new("text-ada-001", "openai");
161+
public static Model Embedding_3_Large { get; } = new("text-embedding-3-large", "openai");
152162

153163
/// <summary>
154-
/// The default model for <see cref="Embeddings.EmbeddingsEndpoint"/>.
164+
/// The default model for <see cref="Moderations.ModerationsEndpoint"/>.
155165
/// </summary>
156-
public static Model Embedding_Ada_002 { get; } = new("text-embedding-ada-002", "openai");
166+
public static Model Moderation_Latest { get; } = new("text-moderation-latest", "openai");
167+
168+
public static Model Moderation_Stable { get; } = new("text-moderation-stable", "openai");
157169

158170
/// <summary>
159-
/// A highly efficient model which provides a significant upgrade over its predecessor, the text-embedding-ada-002 model.
171+
/// The latest text to speech model, optimized for speed.
160172
/// </summary>
161-
public static Model Embedding_3_Small { get; } = new("text-embedding-3-small", "openai");
173+
/// <remarks>
174+
/// The default model for <see cref="Audio.SpeechRequest"/>s.
175+
/// </remarks>
176+
public static Model TTS_1 { get; } = new("tts-1", "openai");
162177

163178
/// <summary>
164-
/// A next generation larger model with embeddings of up to 3072 dimensions.
179+
/// The latest text to speech model, optimized for quality.
165180
/// </summary>
166-
public static Model Embedding_3_Large { get; } = new("text-embedding-3-large", "openai");
181+
public static Model TTS_1HD { get; } = new("tts-1-hd", "openai");
167182

168183
/// <summary>
169184
/// The default model for <see cref="Audio.AudioEndpoint"/>.
170185
/// </summary>
171186
public static Model Whisper1 { get; } = new("whisper-1", "openai");
172187

173188
/// <summary>
174-
/// The default model for <see cref="Moderations.ModerationsEndpoint"/>.
189+
/// The default model for <see cref="Images.ImagesEndpoint"/>.
175190
/// </summary>
176-
public static Model Moderation_Latest { get; } = new("text-moderation-latest", "openai");
191+
public static Model DallE_2 { get; } = new("dall-e-2", "openai");
192+
193+
public static Model DallE_3 { get; } = new("dall-e-3", "openai");
194+
195+
#region Obsolete
177196

178197
/// <summary>
179-
/// The default model for <see cref="Audio.SpeechRequest"/>s.
198+
/// For edit requests.
180199
/// </summary>
181-
public static Model TTS_1 { get; } = new("tts-1", "openai");
200+
[Obsolete("Removed")]
201+
public static Model DavinciEdit { get; } = new("text-davinci-edit-001", "openai");
182202

183-
public static Model TTS_1HD { get; } = new("tts-1-hd", "openai");
203+
/// <summary>
204+
/// The 2nd most powerful engine, a bit faster than <see cref="Davinci"/>, and a bit faster.<para/>
205+
/// Good at: Language translation, complex classification, text sentiment, summarization.
206+
/// </summary>
207+
[Obsolete("Removed")]
208+
public static Model Curie { get; } = new("text-curie-001", "openai");
184209

185210
/// <summary>
186-
/// The default model for <see cref="Images.ImagesEndpoint"/>.
211+
/// The smallest, fastest engine available, although the quality of results may be poor.<para/>
212+
/// Good at: Parsing text, simple classification, address correction, keywords
187213
/// </summary>
188-
public static Model DallE_2 { get; } = new("dall-e-2", "openai");
214+
[Obsolete("Removed")]
215+
public static Model Ada { get; } = new("text-ada-001", "openai");
189216

190-
public static Model DallE_3 { get; } = new("dall-e-3", "openai");
217+
#endregion Obsolete
191218
}
192219
}

0 commit comments

Comments
 (0)