Skip to content

Commit

Permalink
OpenAI-DotNet 7.3.2 (#177)
Browse files Browse the repository at this point in the history
- Added detail parameter to ImageURL
  • Loading branch information
StephenHodgson authored Nov 22, 2023
1 parent 0dfda4b commit 271c374
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 27 deletions.
57 changes: 41 additions & 16 deletions OpenAI-DotNet-Tests/TestFixture_03_Chat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public async Task Test_01_GetChatCompletion()

foreach (var choice in response.Choices)
{
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice.Message.Content} | Finish Reason: {choice.FinishReason}");
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice} | Finish Reason: {choice.FinishReason}");
}

response.GetUsage();
Expand Down Expand Up @@ -65,8 +65,10 @@ public async Task Test_02_GetChatStreamingCompletion()
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
var choice = response.FirstChoice;
Assert.IsFalse(string.IsNullOrEmpty(choice?.Message?.Content));
Console.WriteLine($"[{choice!.Index}] {choice.Message!.Role}: {choice.Message.Content} | Finish Reason: {choice.FinishReason}");
Assert.IsNotNull(choice);
Assert.IsNotNull(choice.Message);
Assert.IsFalse(string.IsNullOrEmpty(choice.Message.Content));
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice} | Finish Reason: {choice.FinishReason}");
Assert.IsTrue(choice.Message.Role == Role.Assistant);
Assert.IsTrue(choice.Message.Content!.Equals(cumulativeDelta));
Console.WriteLine(response.ToString());
Expand Down Expand Up @@ -149,7 +151,7 @@ public async Task Test_04_GetChatFunctionCompletion()
Assert.IsTrue(response.Choices.Count == 1);
messages.Add(response.FirstChoice.Message);

Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var locationMessage = new Message(Role.User, "I'm in Glasgow, Scotland");
messages.Add(locationMessage);
Expand All @@ -164,7 +166,7 @@ public async Task Test_04_GetChatFunctionCompletion()

if (!string.IsNullOrEmpty(response.FirstChoice.Message.Content))
{
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var unitMessage = new Message(Role.User, "celsius");
messages.Add(unitMessage);
Expand Down Expand Up @@ -259,7 +261,7 @@ public async Task Test_05_GetChatFunctionCompletion_Streaming()

if (!string.IsNullOrEmpty(response.FirstChoice.Message.Content))
{
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var unitMessage = new Message(Role.User, "celsius");
messages.Add(unitMessage);
Expand Down Expand Up @@ -336,7 +338,7 @@ public async Task Test_06_GetChatFunctionForceCompletion()
Assert.IsTrue(response.Choices.Count == 1);
messages.Add(response.FirstChoice.Message);

Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var locationMessage = new Message(Role.User, "I'm in Glasgow, Scotland");
messages.Add(locationMessage);
Expand Down Expand Up @@ -411,7 +413,7 @@ public async Task Test_07_GetChatToolCompletion()
Assert.IsTrue(response.Choices.Count == 1);
messages.Add(response.FirstChoice.Message);

Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var locationMessage = new Message(Role.User, "I'm in Glasgow, Scotland");
messages.Add(locationMessage);
Expand All @@ -424,9 +426,9 @@ public async Task Test_07_GetChatToolCompletion()
Assert.IsTrue(response.Choices.Count == 1);
messages.Add(response.FirstChoice.Message);

if (!string.IsNullOrEmpty(response.FirstChoice.Message.Content))
if (!string.IsNullOrEmpty(response.FirstChoice))
{
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var unitMessage = new Message(Role.User, "celsius");
messages.Add(unitMessage);
Expand Down Expand Up @@ -521,7 +523,7 @@ public async Task Test_08_GetChatToolCompletion_Streaming()

if (!string.IsNullOrEmpty(response.FirstChoice.Message.Content))
{
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var unitMessage = new Message(Role.User, "celsius");
messages.Add(unitMessage);
Expand Down Expand Up @@ -598,7 +600,7 @@ public async Task Test_09_GetChatToolForceCompletion()
Assert.IsTrue(response.Choices.Count == 1);
messages.Add(response.FirstChoice.Message);

Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var locationMessage = new Message(Role.User, "I'm in Glasgow, Scotland");
messages.Add(locationMessage);
Expand Down Expand Up @@ -637,14 +639,14 @@ public async Task Test_10_GetChatVision()
new Message(Role.User, new List<Content>
{
new Content(ContentType.Text, "What's in this image?"),
new Content(ContentType.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")
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)
})
};
var chatRequest = new ChatRequest(messages, model: "gpt-4-vision-preview");
var response = await OpenAIClient.ChatEndpoint.GetCompletionAsync(chatRequest);
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishDetails}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishDetails}");
response.GetUsage();
}

Expand All @@ -658,7 +660,7 @@ public async Task Test_11_GetChatVisionStreaming()
new Message(Role.User, new List<Content>
{
new Content(ContentType.Text, "What's in this image?"),
new Content(ContentType.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")
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)
})
};
var chatRequest = new ChatRequest(messages, model: "gpt-4-vision-preview");
Expand All @@ -670,7 +672,30 @@ public async Task Test_11_GetChatVisionStreaming()
});
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishDetails}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishDetails}");
response.GetUsage();
}

[Test]
public async Task Test_12_JsonMode()
{
Assert.IsNotNull(OpenAIClient.ChatEndpoint);
var messages = new List<Message>
{
new Message(Role.System, "You are a helpful assistant designed to output JSON."),
new Message(Role.User, "Who won the world series in 2020?"),
};
var chatRequest = new ChatRequest(messages, "gpt-4-1106-preview", responseFormat: ChatResponseFormat.Json);
var response = await OpenAIClient.ChatEndpoint.GetCompletionAsync(chatRequest);
Assert.IsNotNull(response);
Assert.IsNotNull(response.Choices);
Assert.IsNotEmpty(response.Choices);

foreach (var choice in response.Choices)
{
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice} | Finish Reason: {choice.FinishReason}");
}

response.GetUsage();
}
}
Expand Down
2 changes: 1 addition & 1 deletion OpenAI-DotNet/Chat/ChatResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public IReadOnlyList<Choice> Choices

public override string ToString() => FirstChoice?.ToString() ?? string.Empty;

public static implicit operator string(ChatResponse response) => response.ToString();
public static implicit operator string(ChatResponse response) => response?.ToString();

internal void CopyFrom(ChatResponse other)
{
Expand Down
8 changes: 8 additions & 0 deletions OpenAI-DotNet/Chat/Content.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public Content(ContentType type, string input)
}
}

public Content(ImageUrl imageUrl)
{
Type = ContentType.ImageUrl;
ImageUrl = imageUrl;
}

[JsonInclude]
[JsonPropertyName("type")]
[JsonConverter(typeof(JsonStringEnumConverter<ContentType>))]
Expand All @@ -36,5 +42,7 @@ public Content(ContentType type, string input)
[JsonPropertyName("image_url")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public ImageUrl ImageUrl { get; private set; }

public static implicit operator Content(ImageUrl imageUrl) => new Content(imageUrl);
}
}
2 changes: 1 addition & 1 deletion OpenAI-DotNet/Chat/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public IReadOnlyList<Tool> ToolCalls

public override string ToString() => Content?.ToString() ?? string.Empty;

public static implicit operator string(Message message) => message.ToString();
public static implicit operator string(Message message) => message?.ToString();

internal void CopyFrom(Delta other)
{
Expand Down
14 changes: 14 additions & 0 deletions OpenAI-DotNet/Common/ImageDetail.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Runtime.Serialization;

namespace OpenAI
{
public enum ImageDetail
{
[EnumMember(Value = "auto")]
Auto,
[EnumMember(Value = "low")]
Low,
[EnumMember(Value = "high")]
High
}
}
11 changes: 10 additions & 1 deletion OpenAI-DotNet/Common/ImageUrl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ namespace OpenAI
public sealed class ImageUrl
{
[JsonConstructor]
public ImageUrl(string url) => Url = url;
public ImageUrl(string url, ImageDetail detail = ImageDetail.Auto)
{
Url = url;
Detail = detail;
}

[JsonInclude]
[JsonPropertyName("url")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public string Url { get; private set; }

[JsonInclude]
[JsonPropertyName("detail")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public ImageDetail Detail { get; private set; }
}
}
6 changes: 4 additions & 2 deletions OpenAI-DotNet/OpenAI-DotNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ More context [on Roger Pincombe's blog](https://rogerpincombe.com/openai-dotnet-
<RepositoryUrl>https://github.com/RageAgainstThePixel/OpenAI-DotNet</RepositoryUrl>
<PackageTags>OpenAI, AI, ML, API, gpt-4, gpt-3.5-tubo, gpt-3, chatGPT, chat-gpt, gpt-2, gpt, dall-e-2, dall-e-3</PackageTags>
<Title>OpenAI API</Title>
<Version>7.3.1</Version>
<PackageReleaseNotes>Version 7.3.1
<Version>7.3.2</Version>
<PackageReleaseNotes>Version 7.3.2
- Added detail parameter to ImageURL
Version 7.3.1
- Fixed json serialization settings when EnableDebug is disabled
Version 7.3.0
- Added AgentsEndpoint
Expand Down
41 changes: 35 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ Install-Package OpenAI-DotNet
- [Streaming](#chat-streaming)
- [Tools](#chat-tools) :new:
- [Vision](#chat-vision) :new:
- [Json Mode](#chat-json-mode) :new:
- [Audio](#audio)
- [Create Speech](#create-speech)
- [Create Transcription](#create-transcription)
Expand Down Expand Up @@ -848,7 +849,8 @@ var messages = new List<Message>
};
var chatRequest = new ChatRequest(messages, Model.GPT4);
var response = await api.ChatEndpoint.GetCompletionAsync(chatRequest);
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content}");
var choice = response.FirstChoice;
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice.Message} | Finish Reason: {choice.FinishReason}");
```

#### [Chat Streaming](https://platform.openai.com/docs/api-reference/chat/create#chat/create-stream)
Expand All @@ -871,7 +873,7 @@ var response = await api.ChatEndpoint.StreamCompletionAsync(chatRequest, partial
}
});
var choice = response.FirstChoice;
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice.Message.Content} | Finish Reason: {choice.FinishReason}");
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice.Message} | Finish Reason: {choice.FinishReason}");
```

Or if using [`IAsyncEnumerable{T}`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iasyncenumerable-1?view=net-5.0) ([C# 8.0+](https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8))
Expand Down Expand Up @@ -943,7 +945,7 @@ var chatRequest = new ChatRequest(messages, tools: tools, toolChoice: "auto");
var response = await api.ChatEndpoint.GetCompletionAsync(chatRequest);
messages.Add(response.FirstChoice.Message);

Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var locationMessage = new Message(Role.User, "I'm in Glasgow, Scotland");
messages.Add(locationMessage);
Expand All @@ -953,9 +955,9 @@ response = await api.ChatEndpoint.GetCompletionAsync(chatRequest);

messages.Add(response.FirstChoice.Message);

if (!string.IsNullOrEmpty(response.FirstChoice.Message.Content))
if (!string.IsNullOrEmpty(response.FirstChoice))
{
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishReason}");
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice} | Finish Reason: {response.FirstChoice.FinishReason}");

var unitMessage = new Message(Role.User, "celsius");
messages.Add(unitMessage);
Expand Down Expand Up @@ -995,14 +997,41 @@ var messages = new List<Message>
new Message(Role.User, new List<Content>
{
new Content(ContentType.Text, "What's in this image?"),
new Content(ContentType.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")
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)
})
};
var chatRequest = new ChatRequest(messages, model: "gpt-4-vision-preview");
var response = await api.ChatEndpoint.GetCompletionAsync(chatRequest);
Console.WriteLine($"{response.FirstChoice.Message.Role}: {response.FirstChoice.Message.Content} | Finish Reason: {response.FirstChoice.FinishDetails}");
```

#### [Chat Json Mode](https://platform.openai.com/docs/guides/text-generation/json-mode)

> :warning: Beta Feature
Important notes:

- When using JSON mode, always instruct the model to produce JSON via some message in the conversation, for example via your system message. If you don't include an explicit instruction to generate JSON, the model may generate an unending stream of whitespace and the request may run continually until it reaches the token limit. To help ensure you don't forget, the API will throw an error if the string "JSON" does not appear somewhere in the context.
- The JSON in the message the model returns may be partial (i.e. cut off) if `finish_reason` is length, which indicates the generation exceeded max_tokens or the conversation exceeded the token limit. To guard against this, check `finish_reason` before parsing the response.
- JSON mode will not guarantee the output matches any specific schema, only that it is valid and parses without errors.

```csharp
var messages = new List<Message>
{
new Message(Role.System, "You are a helpful assistant designed to output JSON."),
new Message(Role.User, "Who won the world series in 2020?"),
};
var chatRequest = new ChatRequest(messages, "gpt-4-1106-preview", responseFormat: ChatResponseFormat.Json);
var response = await OpenAIClient.ChatEndpoint.GetCompletionAsync(chatRequest);

foreach (var choice in response.Choices)
{
Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice} | Finish Reason: {choice.FinishReason}");
}

response.GetUsage();
```

### [Audio](https://platform.openai.com/docs/api-reference/audio)

Converts audio into text.
Expand Down

0 comments on commit 271c374

Please sign in to comment.