.Net: Added support for BinaryData for ImageContent.#4919
.Net: Added support for BinaryData for ImageContent.#4919dersia wants to merge 0 commit intomicrosoft:mainfrom
Conversation
|
@microsoft-github-policy-service agree [company="Sia Consulting GmbH"] |
|
@microsoft-github-policy-service agree company="Sia Consulting GmbH" |
There was a problem hiding this comment.
In general I don't think this is a good solution. If we were to introduce base64 support it would probably be better to create a new class like ImageBinaryContent. I'm not sure the SK team will agree to this change. By the way, if you make any changes create a new branch instead working on a copy of the main.
And to implement this, a fix in the implementation of the openai connector would be required....
| /// </summary> | ||
| public BinaryData? Data { get; } | ||
|
|
||
| /// <summary> |
There was a problem hiding this comment.
But which has higher priority uri or base64 and why?
There was a problem hiding this comment.
As the ToString override suggests, Data has priority. This is also assured by Tests
There was a problem hiding this comment.
ToString() rather will not used in connectors. We should clearly explain to others that they should prioritize a BinaryData over an Uri. For example by adding additional information to the doc comment in ImageContent class.
There was a problem hiding this comment.
I was also looking at an issue opened in runtime asking to remove the length limitation on Uri. I think this is in general a good idea, but this won't be GA before net9 and this is way too late. SK and AI development is moving so quickly right now, that most wouldn't want to wait for that change.
But even with that change, I think BinaryData gives developers a lot of comfortable possibilities and they don't have to do all the base64 encoding and serialization themselfs. So maybe once the limit on Uri is removed, we could in the implementation just switch back to Uri as an implementation detail. I really hope the issue on Azure.AI.OpenAI is moving forward sooner rather than later, so we can finally merge this change.
| Assert.Throws<ArgumentNullException>(() => new ImageContent((BinaryData)null!)); | ||
| Assert.Throws<ArgumentNullException>(() => new ImageContent(data)); | ||
| Assert.Throws<ArgumentNullException>(() => new ImageContent(data2)); | ||
| Assert.Throws<ArgumentNullException>(() => new ImageContent(data3)); |
There was a problem hiding this comment.
You should use [Theory] and inline data in such cases.
| // Assert throws if mediatype is null | ||
| Assert.Throws<ArgumentNullException>(() => new ImageContent(BinaryData.FromBytes(bytes, null))); | ||
| Assert.Throws<ArgumentNullException>(() => new ImageContent(BinaryData.FromBytes(bytes, string.Empty))); | ||
| Assert.Throws<ArgumentNullException>(() => new ImageContent(BinaryData.FromBytes(bytes, " "))); |
There was a problem hiding this comment.
Same [Theory] and [InlineData] and throws assertions should be in another test.
| { | ||
| // Arrange | ||
| var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes("this is a test")); | ||
| try |
There was a problem hiding this comment.
tests projects support c#11 so you can do it simpler.
instead System.Text.Encoding.UTF8.GetBytes("this is a test")
you can write "this is a test"u8
There was a problem hiding this comment.
Unfortunately the MemoryStream ctor does not take a ROS<byte> and u8 gives back a ROS<byte>.
I could do "this is a test"u8.ToArray() not sure if is any better, though
I usually create branches for features, I am not sure, why this happend this time. My Fault, Sorry. Regarding the issue with the OpenAI Connector, you are totally correct, I thought that it would use the I have commented on an open issue regarding this and also referenced this issue. Once this is fixed, I will adjust the implementation to the Connectors. |
|
@dersia You can leave this PR with main branch as is. It doesn't matter for PR, only for your convenience. |
| public Uri? Uri { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// The Data used as DataUri for the image. |
There was a problem hiding this comment.
@dersia Thanks for the changes.
I would remove the DataUri from the comment on this field and move it to the ToString.
| /// The Data used as DataUri for the image. | |
| /// The image binary data. |
| this.Data = data; | ||
| } | ||
|
|
||
| /// <inheritdoc/> |
There was a problem hiding this comment.
| /// <inheritdoc/> | |
| /// <summary> | |
| /// Returns the string representation of the image. | |
| /// BinaryData images will be represented as DataUri | |
| /// Remote Uri images will be represented as is | |
| /// </summary> |
| public void ToStringForDataUriFromStreamReturnsDataUriString() | ||
| { | ||
| // Arrange | ||
| var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes("this is a test")); |
There was a problem hiding this comment.
Any special reason why are you manually handling the disposal of MemoryStream in the test?
Can be simplified with the using var
| var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes("this is a test")); | |
| using var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes("this is a test")); |
There was a problem hiding this comment.
I remember having the using pattern implemented and than having early disposal in some test, but I don't have those test anymore. I will see if I can replicate it and if not, revert back to using the using pattern here
|
@dersia btw. new class was introduced to kernel BinaryContent I know this news may not be relevant to this PR, but it is worth taking a view. |
|
I didn't mean to close this PR. I will open a new one and reference this PR |
Reopend PR. See #4919 for previous PR. Reopening this PR from another feature branch makes rebasing easier. ### Motivation and Context As Described in #4781 right now there is no possibility in SK to add Images as DataUris to ChatCompletion APIs, although the Azure OpenAI API and the Open AI API both support this. Fixes #4781 ### Description As per Discussion added overload to the ImageContent ctor that takes BinaryData. For backward Compat we kept the ctor that takes an URI. Also the new ctor throws, if the BinaryData is null, empty or if there is not MediaType provided. I thought about allowing plain, non base64 encoded DataUris with BinaryData. The Idea was to not encode to base64, if the MediaType is set to "text/plain", but then I decided, that this is not needed, since `Uri` in general allows for DataUris like `new Uri("data:text/plain;http://exmpaledomain.com")` just not for DataUris that are longer than 65520 bytes. I feel like that is ok, for plain DataUris. We can still add this if needed. Also as per discussion in the issue, I did not add additional overloads for direct Streams support. ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄 --------- Co-authored-by: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com>
Reopend PR. See microsoft#4919 for previous PR. Reopening this PR from another feature branch makes rebasing easier. ### Motivation and Context As Described in microsoft#4781 right now there is no possibility in SK to add Images as DataUris to ChatCompletion APIs, although the Azure OpenAI API and the Open AI API both support this. Fixes microsoft#4781 ### Description As per Discussion added overload to the ImageContent ctor that takes BinaryData. For backward Compat we kept the ctor that takes an URI. Also the new ctor throws, if the BinaryData is null, empty or if there is not MediaType provided. I thought about allowing plain, non base64 encoded DataUris with BinaryData. The Idea was to not encode to base64, if the MediaType is set to "text/plain", but then I decided, that this is not needed, since `Uri` in general allows for DataUris like `new Uri("data:text/plain;http://exmpaledomain.com")` just not for DataUris that are longer than 65520 bytes. I feel like that is ok, for plain DataUris. We can still add this if needed. Also as per discussion in the issue, I did not add additional overloads for direct Streams support. ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄 --------- Co-authored-by: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com>
Reopend PR. See microsoft#4919 for previous PR. Reopening this PR from another feature branch makes rebasing easier. ### Motivation and Context As Described in microsoft#4781 right now there is no possibility in SK to add Images as DataUris to ChatCompletion APIs, although the Azure OpenAI API and the Open AI API both support this. Fixes microsoft#4781 ### Description As per Discussion added overload to the ImageContent ctor that takes BinaryData. For backward Compat we kept the ctor that takes an URI. Also the new ctor throws, if the BinaryData is null, empty or if there is not MediaType provided. I thought about allowing plain, non base64 encoded DataUris with BinaryData. The Idea was to not encode to base64, if the MediaType is set to "text/plain", but then I decided, that this is not needed, since `Uri` in general allows for DataUris like `new Uri("data:text/plain;http://exmpaledomain.com")` just not for DataUris that are longer than 65520 bytes. I feel like that is ok, for plain DataUris. We can still add this if needed. Also as per discussion in the issue, I did not add additional overloads for direct Streams support. ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄 --------- Co-authored-by: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com>
Added Tests
Motivation and Context
As Described in #4781 right now there is no possibility in SK to add Images as DataUris to ChatCompletion APIs, although the Azure OpenAI API and the Open AI API both support this.
Fixes #4781
Description
As per Discussion added overload to the ImageContent ctor that takes BinaryData.
For backward Compat we kept the ctor that takes an URI.
Also the new ctor throws, if the BinaryData is null, empty or if there is not MediaType provided.
I thought about allowing plain, non base64 encoded DataUris with BinaryData.
The Idea was to not encode to base64, if the MediaType is set to "text/plain", but then I decided, that this is not needed, since
Uriin general allows for DataUris likenew Uri("data:text/plain;http://exmpaledomain.com")just not for DataUris that are longer than 65520 bytes. I feel like that is ok, for plain DataUris.We can still add this if needed.
Also as per discussion in the issue, I did not add additional overloads for direct Streams support.
Contribution Checklist