Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,27 +1,39 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Unity.Collections;
using UnityEngine;
using Utilities.Extensions;
using OpenAI.Images;
using Utilities.Async;
using System;

#if !PLATFORM_WEBGL
using System.IO;
using Utilities.WebRequestRest;
#endif

namespace OpenAI.Extensions
{
internal static class TextureExtensions
public static class TextureExtensions
{
public static async Task<(Texture2D, string)> ConvertFromBase64Async(string b64, bool debug, CancellationToken cancellationToken)
internal static async Task<(Texture2D, string)> ConvertFromBase64Async(string b64, bool debug, CancellationToken cancellationToken)
{
var imageData = Convert.FromBase64String(b64);
using var imageData = NativeArrayExtensions.FromBase64String(b64, Allocator.Persistent);
#if PLATFORM_WEBGL
var texture = new Texture2D(2, 2);
#if UNITY_6000_0_OR_NEWER
texture.LoadImage(imageData);
#else
texture.LoadImage(imageData.ToArray());
#endif
return await Task.FromResult((texture, string.Empty));
#else
if (!Rest.TryGetDownloadCacheItem(b64, out var localFilePath))
{
await File.WriteAllBytesAsync(localFilePath, imageData, cancellationToken).ConfigureAwait(true);
await using var fs = new FileStream(localFilePath, FileMode.Create, FileAccess.Write);
await fs.WriteAsync(imageData, cancellationToken: cancellationToken);
localFilePath = $"file://{localFilePath}";
}

Expand All @@ -30,5 +42,54 @@ internal static class TextureExtensions
return (texture, cachedPath);
#endif
}

/// <summary>
/// Loads a Texture2D from an ImageResult, handling base64, cached path, or URL.
/// </summary>
/// <param name="imageResult">The <see cref="ImageResult"/> to load the texture for.</param>
/// <param name="debug">Optional, debug flag.</param>
/// <param name="cancellationToken">Optional, <see cref="CancellationToken"/>.</param>
/// <returns>
/// A tuple containing the converted <see cref="Texture2D"/> and the cached file path as a string.
/// </returns>
public static async Task<(Texture2D, Uri)> LoadTextureAsync(this ImageResult imageResult, bool debug = false, CancellationToken cancellationToken = default)
{
await Awaiters.UnityMainThread;

if (imageResult.Texture.IsNull())
{
if (!string.IsNullOrWhiteSpace(imageResult.B64_Json))
{
var (texture, cachedPath) = await ConvertFromBase64Async(imageResult.B64_Json, debug, cancellationToken);
imageResult.Texture = texture;
imageResult.CachedPathUri = new Uri(cachedPath);
}
else
{
Texture2D texture;
Uri cachedPath;

if (imageResult.CachedPathUri != null)
{
texture = await Rest.DownloadTextureAsync(imageResult.CachedPathUri, parameters: new RestParameters(debug: debug), cancellationToken: cancellationToken);
cachedPath = imageResult.CachedPathUri;
}
else if (!string.IsNullOrWhiteSpace(imageResult.Url))
{
texture = await Rest.DownloadTextureAsync(imageResult.Url, parameters: new RestParameters(debug: debug), cancellationToken: cancellationToken);
cachedPath = Rest.TryGetDownloadCacheItem(imageResult.Url, out var path) ? new Uri(path) : null;
}
else
{
throw new System.Exception("ImageResult does not contain valid image data.");
}

imageResult.Texture = texture;
imageResult.CachedPathUri = cachedPath;
}
}

return (imageResult.Texture, imageResult.CachedPathUri);
}
}
}
11 changes: 8 additions & 3 deletions OpenAI/Packages/com.openai.unity/Runtime/Images/ImageResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ internal ImageResult(

[Preserve]
[JsonIgnore]
public string CachedPath { get; internal set; }
[Obsolete("use CachedPathUri")]
public string CachedPath => CachedPathUri?.ToString();

[Preserve]
[JsonIgnore]
public Uri CachedPathUri { get; internal set; }

[Preserve]
[JsonIgnore]
Expand All @@ -75,9 +80,9 @@ internal ImageResult(
[Preserve]
public override string ToString()
{
if (!string.IsNullOrWhiteSpace(CachedPath))
if (CachedPathUri != null)
{
return CachedPath;
return CachedPathUri.ToString();
}

if (!string.IsNullOrWhiteSpace(B64_Json))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using Utilities.Async;
using Utilities.WebRequestRest;

namespace OpenAI.Images
Expand Down Expand Up @@ -180,33 +179,15 @@ private async Task<IReadOnlyList<ImageResult>> DeserializeResponseAsync(Response
}

await Rest.ValidateCacheDirectoryAsync();
var downloads = imagesResponse.Results.Select(DownloadAsync).ToList();

async Task DownloadAsync(ImageResult result)
{
await Awaiters.UnityMainThread;

if (string.IsNullOrWhiteSpace(result.Url))
{
var (texture, cachePath) = await TextureExtensions.ConvertFromBase64Async(result.B64_Json, EnableDebug, cancellationToken);
result.Texture = texture;
result.CachedPath = cachePath;
}
else
{
result.Texture = await Rest.DownloadTextureAsync(result.Url, parameters: new RestParameters(debug: EnableDebug), cancellationToken: cancellationToken);

if (Rest.TryGetDownloadCacheItem(result.Url, out var cachedPath))
{
result.CachedPath = cachedPath;
}
}
}
Task<(Texture2D, Uri)> DownloadAsync(ImageResult result)
=> result.LoadTextureAsync(debug: EnableDebug, cancellationToken);

await Task.WhenAll(downloads).ConfigureAwait(true);
await Task.WhenAll(imagesResponse.Results.Select(DownloadAsync).ToList()).ConfigureAwait(true);

foreach (var result in imagesResponse.Results)
for (var i = 0; i < imagesResponse.Results.Count; i++)
{
var result = imagesResponse.Results[i];
result.CreatedAt = DateTimeOffset.FromUnixTimeSeconds(imagesResponse.CreatedAtUnixSeconds).UtcDateTime;
result.Background = imagesResponse.Background;
result.OutputFormat = imagesResponse.OutputFormat;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal Message(

[Preserve]
public Message(Role role, string text)
: this(role, new TextContent(text))
: this(role, new TextContent(text, role == Role.Assistant ? ResponseContentType.OutputText : ResponseContentType.InputText))
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ internal TextContent(
}

[Preserve]
public TextContent(string text)
public TextContent(string text, ResponseContentType type = ResponseContentType.InputText)
{
Type = ResponseContentType.InputText;
Type = type;
Text = text;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using System.Threading;
using System.Threading.Tasks;
using TMPro;
using Unity.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
Expand Down
41 changes: 15 additions & 26 deletions OpenAI/Packages/com.openai.unity/Tests/TestFixture_05_Images.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,10 @@ public async Task Test_01_01_GenerateImages()
var result = imageResults[i];
Assert.IsNotNull(result);
Assert.IsNotNull(result.Texture);
Assert.IsNotNull(result.CachedPathUri);
Assert.IsFalse(string.IsNullOrWhiteSpace(result.B64_Json));
var imageBytes = Convert.FromBase64String(result.B64_Json);
Assert.IsNotNull(imageBytes);
var path = Path.Combine(testDirectory, $"{nameof(Test_01_01_GenerateImages)}-{i}-{DateTime.UtcNow:yyyyMMddHHmmss}.jpeg");
await using var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
await fileStream.WriteAsync(imageBytes, 0, imageBytes.Length);
File.Copy(result.CachedPathUri.LocalPath, path, true);
}
}
catch (Exception e)
Expand Down Expand Up @@ -82,12 +80,9 @@ public async Task Test_02_01_CreateImageEdit_Path()
var result = imageResults[i];
Assert.IsNotNull(result);
Assert.IsNotNull(result.Texture);
Assert.IsFalse(string.IsNullOrWhiteSpace(result.B64_Json));
var imageBytes = Convert.FromBase64String(result.B64_Json);
Assert.IsNotNull(imageBytes);
Assert.IsNotNull(result.CachedPathUri);
var path = Path.Combine(testDirectory, $"{nameof(Test_02_01_CreateImageEdit_Path)}-{i}-{DateTime.UtcNow:yyyyMMddHHmmss}.png");
await using var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
await fileStream.WriteAsync(imageBytes, 0, imageBytes.Length);
File.Copy(result.CachedPathUri.LocalPath, path, true);
}
}
catch (Exception e)
Expand Down Expand Up @@ -122,12 +117,10 @@ public async Task Test_02_02_CreateImageEdit_Texture()
var result = imageResults[i];
Assert.IsNotNull(result);
Assert.IsNotNull(result.Texture);
Assert.IsNotNull(result.CachedPathUri);
Assert.IsFalse(string.IsNullOrWhiteSpace(result.B64_Json));
var imageBytes = Convert.FromBase64String(result.B64_Json);
Assert.IsNotNull(imageBytes);
var path = Path.Combine(testDirectory, $"{nameof(Test_02_02_CreateImageEdit_Texture)}-{i}-{DateTime.UtcNow:yyyyMMddHHmmss}.png");
await using var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
await fileStream.WriteAsync(imageBytes, 0, imageBytes.Length);
File.Copy(result.CachedPathUri.LocalPath, path, true);
}
}
catch (Exception e)
Expand Down Expand Up @@ -159,12 +152,10 @@ public async Task Test_02_03_CreateImageEdit_MaskAsTransparency()
var result = imageResults[i];
Assert.IsNotNull(result);
Assert.IsNotNull(result.Texture);
Assert.IsNotNull(result.CachedPathUri);
Assert.IsFalse(string.IsNullOrWhiteSpace(result.B64_Json));
var imageBytes = Convert.FromBase64String(result.B64_Json);
Assert.IsNotNull(imageBytes);
var path = Path.Combine(testDirectory, $"{nameof(Test_02_03_CreateImageEdit_MaskAsTransparency)}-{i}-{DateTime.UtcNow:yyyyMMddHHmmss}.png");
await using var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
await fileStream.WriteAsync(imageBytes, 0, imageBytes.Length);
File.Copy(result.CachedPathUri.LocalPath, path, true);
}
}
catch (Exception e)
Expand Down Expand Up @@ -202,12 +193,10 @@ public async Task Test_02_04_CreateImageEdit_MultipleFiles()
var result = imageResults[i];
Assert.IsNotNull(result);
Assert.IsNotNull(result.Texture);
Assert.IsNotNull(result.CachedPathUri);
Assert.IsFalse(string.IsNullOrWhiteSpace(result.B64_Json));
var imageBytes = Convert.FromBase64String(result.B64_Json);
Assert.IsNotNull(imageBytes);
var path = Path.Combine(testDirectory, $"{nameof(Test_02_04_CreateImageEdit_MultipleFiles)}-{i}-{DateTime.UtcNow:yyyyMMddHHmmss}.png");
await using var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
await fileStream.WriteAsync(imageBytes, 0, imageBytes.Length);
File.Copy(result.CachedPathUri.LocalPath, path, true);
}
}
catch (Exception e)
Expand All @@ -232,8 +221,9 @@ public async Task Test_03_01_CreateImageVariation_Path()

foreach (var result in imageResults)
{
Assert.IsNotNull(result.Texture);
Debug.Log(result.ToString());
Assert.IsNotNull(result.Texture);
Assert.IsNull(result.CachedPathUri);
}
}
catch (Exception e)
Expand Down Expand Up @@ -261,6 +251,7 @@ public async Task Test_03_02_CreateImageVariation_Texture()
{
Debug.Log(result.ToString());
Assert.IsNotNull(result.Texture);
Assert.IsNull(result.CachedPathUri);
}
}
catch (Exception e)
Expand Down Expand Up @@ -289,12 +280,10 @@ public async Task Test_03_03_CreateImageVariation_Texture_B64_Json()
var result = imageResults[i];
Assert.IsNotNull(result);
Assert.IsNotNull(result.Texture);
Assert.IsNotNull(result.CachedPathUri);
Assert.IsFalse(string.IsNullOrWhiteSpace(result.B64_Json));
var imageBytes = Convert.FromBase64String(result.B64_Json);
Assert.IsNotNull(imageBytes);
var path = Path.Combine(testDirectory, $"{nameof(Test_03_03_CreateImageVariation_Texture_B64_Json)}-{i}-{DateTime.UtcNow:yyyyMMddHHmmss}.png");
await using var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
await fileStream.WriteAsync(imageBytes, 0, imageBytes.Length);
File.Copy(result.CachedPathUri.LocalPath, path, true);
}
}
catch (Exception e)
Expand Down
4 changes: 2 additions & 2 deletions OpenAI/Packages/com.openai.unity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"displayName": "OpenAI",
"description": "A OpenAI package for the Unity to use though their RESTful API.\n\nIndependently developed, this is not an official library and I am not affiliated with OpenAI.\n\nAn OpenAI API account is required.",
"keywords": [],
"version": "8.8.7",
"version": "8.8.8",
"unity": "2021.3",
"documentationUrl": "https://github.com/RageAgainstThePixel/com.openai.unity#documentation",
"changelogUrl": "https://github.com/RageAgainstThePixel/com.openai.unity/releases",
Expand All @@ -18,7 +18,7 @@
},
"dependencies": {
"com.utilities.encoder.wav": "3.0.2",
"com.utilities.rest": "5.0.4",
"com.utilities.rest": "5.1.0",
"com.utilities.websockets": "2.0.0"
},
"samples": [
Expand Down
Loading