-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
.Net Kernel Contents Graduation (#6319)
### Motivation and Context⚠️ Breaking changes on non-experimental types **ImageContent** Resolves #5625 Resolves #5295 For a brief time this changes will keep the content below as experimental. - BinaryContent - AudioContent - ImageContent - FunctionCallContent - FunctionResultContent Changes: ### **BinaryContent** - Removed providers for lazy loading content, simplifying its usage and APIs. - Removed `Stream` constructor to avoid IDisposable resource consumption or bad practices. - Added `Uri` dedicated for Referenced Uri information - Added `DataUri` property which can be set or get dynamically (auto generated if you created the content using byte array with a mime type) Setting a `DataUri` will automatically update the `MimeType` property and add any extra metadata that may be available in the data scheme definition. - Added a required `mimeType` property to the ByteArray constructor, to encourage passing the mimeType when creating BinaryContent directly or from specializations. - Added `Data` property which can be set or get dynamically (auto generated if you created the content using a data uri format) Setting a Data on an existing BinaryContent will also reflect on the getter of `DataUri` for the given content. - Added DataUri and Base64 validation when setting DataUri on the contents. - When using DataUri parameters those merge with the current content metadata. i.e: `data:image/jpeg;parameter1=value1;parameter2=value2;base64,binary==` ###⚠️ **ImageContent** Fixes bugs and inconsistency behavior: - Setting the Data of an image doesn't change the current data uri and vice versa, allowing the sema image content instance to have different binary data to representations. - When an Image could not have DataUri and Uri in the same instance, this limits scenarios where you have the image data but want to have a reference to where that content is from. - Wasn't possible to create an Image from a data uri greater than the size limit of .Net System.Uri type here: [dotnet/runtime#96544. ### **FunctionResultContent** - Update `Id` property to `CallId`.
- Loading branch information
1 parent
f1f53f4
commit 737385c
Showing
38 changed files
with
2,123 additions
and
278 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
dotnet/samples/Concepts/Agents/OpenAIAssistant_MultipleContents.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
using Azure.AI.OpenAI.Assistants; | ||
using Microsoft.SemanticKernel; | ||
using Microsoft.SemanticKernel.Agents; | ||
using Microsoft.SemanticKernel.Agents.OpenAI; | ||
using Microsoft.SemanticKernel.ChatCompletion; | ||
using Microsoft.SemanticKernel.Connectors.OpenAI; | ||
using Resources; | ||
|
||
namespace Agents; | ||
|
||
/// <summary> | ||
/// Demonstrate using retrieval on <see cref="OpenAIAssistantAgent"/> . | ||
/// </summary> | ||
public class OpenAIAssistant_MultipleContents(ITestOutputHelper output) : BaseTest(output) | ||
{ | ||
/// <summary> | ||
/// Retrieval tool not supported on Azure OpenAI. | ||
/// </summary> | ||
protected override bool ForceOpenAI => true; | ||
|
||
[Fact] | ||
public async Task RunAsync() | ||
{ | ||
OpenAIFileService fileService = new(TestConfiguration.OpenAI.ApiKey); | ||
|
||
BinaryContent[] files = [ | ||
// Audio is not supported by Assistant API | ||
// new AudioContent(await EmbeddedResource.ReadAllAsync("test_audio.wav")!, mimeType:"audio/wav", innerContent: "test_audio.wav"), | ||
new ImageContent(await EmbeddedResource.ReadAllAsync("sample_image.jpg")!, mimeType: "image/jpeg") { InnerContent = "sample_image.jpg" }, | ||
new ImageContent(await EmbeddedResource.ReadAllAsync("test_image.jpg")!, mimeType: "image/jpeg") { InnerContent = "test_image.jpg" }, | ||
new BinaryContent(data: await EmbeddedResource.ReadAllAsync("travelinfo.txt"), mimeType: "text/plain") | ||
{ | ||
InnerContent = "travelinfo.txt" | ||
} | ||
]; | ||
|
||
var fileIds = new List<string>(); | ||
foreach (var file in files) | ||
{ | ||
try | ||
{ | ||
var uploadFile = await fileService.UploadContentAsync(file, | ||
new OpenAIFileUploadExecutionSettings(file.InnerContent!.ToString()!, Microsoft.SemanticKernel.Connectors.OpenAI.OpenAIFilePurpose.Assistants)); | ||
|
||
fileIds.Add(uploadFile.Id); | ||
} | ||
catch (HttpOperationException hex) | ||
{ | ||
Console.WriteLine(hex.ResponseContent); | ||
Assert.Fail($"Failed to upload file: {hex.Message}"); | ||
} | ||
} | ||
|
||
// Define the agent | ||
OpenAIAssistantAgent agent = | ||
await OpenAIAssistantAgent.CreateAsync( | ||
kernel: new(), | ||
config: new(this.ApiKey, this.Endpoint), | ||
new() | ||
{ | ||
EnableRetrieval = true, // Enable retrieval | ||
ModelId = this.Model, | ||
// FileIds = fileIds Currently Assistant API only supports text files, no images or audio. | ||
FileIds = [fileIds.Last()] | ||
}); | ||
|
||
// Create a chat for agent interaction. | ||
var chat = new AgentGroupChat(); | ||
|
||
// Respond to user input | ||
try | ||
{ | ||
await InvokeAgentAsync("Where did sam go?"); | ||
await InvokeAgentAsync("When does the flight leave Seattle?"); | ||
await InvokeAgentAsync("What is the hotel contact info at the destination?"); | ||
} | ||
finally | ||
{ | ||
await agent.DeleteAsync(); | ||
} | ||
|
||
// Local function to invoke agent and display the conversation messages. | ||
async Task InvokeAgentAsync(string input) | ||
{ | ||
chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, input)); | ||
|
||
Console.WriteLine($"# {AuthorRole.User}: '{input}'"); | ||
|
||
await foreach (var content in chat.InvokeAsync(agent)) | ||
{ | ||
Console.WriteLine($"# {content.Role} - {content.AuthorName ?? "*"}: '{content.Content}'"); | ||
} | ||
} | ||
} | ||
|
||
[Fact] | ||
public async Task SendingAndRetrievingFilesAsync() | ||
{ | ||
var openAIClient = new AssistantsClient(TestConfiguration.OpenAI.ApiKey); | ||
OpenAIFileService fileService = new(TestConfiguration.OpenAI.ApiKey); | ||
|
||
BinaryContent[] files = [ | ||
new AudioContent(await EmbeddedResource.ReadAllAsync("test_audio.wav")!, mimeType: "audio/wav") { InnerContent = "test_audio.wav" }, | ||
new ImageContent(await EmbeddedResource.ReadAllAsync("sample_image.jpg")!, mimeType: "image/jpeg") { InnerContent = "sample_image.jpg" }, | ||
new ImageContent(await EmbeddedResource.ReadAllAsync("test_image.jpg")!, mimeType: "image/jpeg") { InnerContent = "test_image.jpg" }, | ||
new BinaryContent(data: await EmbeddedResource.ReadAllAsync("travelinfo.txt"), mimeType: "text/plain") { InnerContent = "travelinfo.txt" } | ||
]; | ||
|
||
var fileIds = new Dictionary<string, BinaryContent>(); | ||
foreach (var file in files) | ||
{ | ||
var result = await openAIClient.UploadFileAsync(new BinaryData(file.Data), Azure.AI.OpenAI.Assistants.OpenAIFilePurpose.FineTune); | ||
fileIds.Add(result.Value.Id, file); | ||
} | ||
|
||
foreach (var file in (await openAIClient.GetFilesAsync(Azure.AI.OpenAI.Assistants.OpenAIFilePurpose.FineTune)).Value) | ||
{ | ||
if (!fileIds.ContainsKey(file.Id)) | ||
{ | ||
continue; | ||
} | ||
|
||
var data = (await openAIClient.GetFileContentAsync(file.Id)).Value; | ||
|
||
var mimeType = fileIds[file.Id].MimeType; | ||
var fileName = fileIds[file.Id].InnerContent!.ToString(); | ||
var metadata = new Dictionary<string, object?> { ["id"] = file.Id }; | ||
var uri = new Uri($"https://api.openai.com/v1/files/{file.Id}/content"); | ||
var content = mimeType switch | ||
{ | ||
"image/jpeg" => new ImageContent(data, mimeType) { Uri = uri, InnerContent = fileName, Metadata = metadata }, | ||
"audio/wav" => new AudioContent(data, mimeType) { Uri = uri, InnerContent = fileName, Metadata = metadata }, | ||
_ => new BinaryContent(data, mimeType) { Uri = uri, InnerContent = fileName, Metadata = metadata } | ||
}; | ||
|
||
Console.WriteLine($"File: {fileName} - {mimeType}"); | ||
|
||
// Images tostring are different from the graduated contents for retrocompatibility | ||
Console.WriteLine(content.ToString()); | ||
|
||
// Delete the test file remotely | ||
await openAIClient.DeleteFileAsync(file.Id); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
dotnet/src/Connectors/Connectors.OpenAI/CompatibilitySuppressions.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids --> | ||
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | ||
<Suppression> | ||
<DiagnosticId>CP0002</DiagnosticId> | ||
<Target>M:Microsoft.SemanticKernel.Connectors.OpenAI.OpenAIFileService.GetFileContent(System.String,System.Threading.CancellationToken)</Target> | ||
<Left>lib/net8.0/Microsoft.SemanticKernel.Connectors.OpenAI.dll</Left> | ||
<Right>lib/net8.0/Microsoft.SemanticKernel.Connectors.OpenAI.dll</Right> | ||
<IsBaselineSuppression>true</IsBaselineSuppression> | ||
</Suppression> | ||
<Suppression> | ||
<DiagnosticId>CP0002</DiagnosticId> | ||
<Target>M:Microsoft.SemanticKernel.Connectors.OpenAI.OpenAIFileService.GetFileContent(System.String,System.Threading.CancellationToken)</Target> | ||
<Left>lib/netstandard2.0/Microsoft.SemanticKernel.Connectors.OpenAI.dll</Left> | ||
<Right>lib/netstandard2.0/Microsoft.SemanticKernel.Connectors.OpenAI.dll</Right> | ||
<IsBaselineSuppression>true</IsBaselineSuppression> | ||
</Suppression> | ||
</Suppressions> |
Oops, something went wrong.