diff --git a/Runtime/HuggingFaceAuthInfo.cs b/Runtime/HuggingFaceAuthInfo.cs index 7d7ef91..7160c71 100644 --- a/Runtime/HuggingFaceAuthInfo.cs +++ b/Runtime/HuggingFaceAuthInfo.cs @@ -1,3 +1,5 @@ +// Licensed under the MIT License. See LICENSE in the project root for license information. + using System; using System.Security.Authentication; using UnityEngine; diff --git a/Runtime/HuggingFaceAuthentication.cs b/Runtime/HuggingFaceAuthentication.cs index 664ca94..ddd2c94 100644 --- a/Runtime/HuggingFaceAuthentication.cs +++ b/Runtime/HuggingFaceAuthentication.cs @@ -1,3 +1,5 @@ +// Licensed under the MIT License. See LICENSE in the project root for license information. + using System; using System.IO; using System.Linq; diff --git a/Runtime/HuggingFaceBaseEndpoint.cs b/Runtime/HuggingFaceBaseEndpoint.cs index e413d33..49327f8 100644 --- a/Runtime/HuggingFaceBaseEndpoint.cs +++ b/Runtime/HuggingFaceBaseEndpoint.cs @@ -6,9 +6,13 @@ namespace HuggingFace { public abstract class HuggingFaceBaseEndpoint : BaseEndPoint { + private const string HttpPrefix = "https://"; + protected HuggingFaceBaseEndpoint(HuggingFaceClient client) : base(client) { } protected string GetInferenceUrl(string endpoint) - => string.Format(client.Settings.InferenceRequestUrlFormat, $"{Root}/{endpoint}"); + => endpoint.Contains(HttpPrefix) + ? endpoint + : string.Format(client.Settings.InferenceRequestUrlFormat, $"{Root}/{endpoint}"); } } diff --git a/Runtime/HuggingFaceClient.cs b/Runtime/HuggingFaceClient.cs index 450d126..e141ad4 100644 --- a/Runtime/HuggingFaceClient.cs +++ b/Runtime/HuggingFaceClient.cs @@ -1,3 +1,5 @@ +// Licensed under the MIT License. See LICENSE in the project root for license information. + using HuggingFace.Hub; using HuggingFace.Inference; using Newtonsoft.Json; diff --git a/Runtime/HuggingFaceSettings.cs b/Runtime/HuggingFaceSettings.cs index 7a8d5eb..18d0387 100644 --- a/Runtime/HuggingFaceSettings.cs +++ b/Runtime/HuggingFaceSettings.cs @@ -1,3 +1,5 @@ +// Licensed under the MIT License. See LICENSE in the project root for license information. + using System.Linq; using UnityEngine; using Utilities.WebRequestRest.Interfaces; diff --git a/Runtime/HuggingFaceSettingsInfo.cs b/Runtime/HuggingFaceSettingsInfo.cs index 4e96309..c8991be 100644 --- a/Runtime/HuggingFaceSettingsInfo.cs +++ b/Runtime/HuggingFaceSettingsInfo.cs @@ -1,3 +1,5 @@ +// Licensed under the MIT License. See LICENSE in the project root for license information. + using System; using Utilities.WebRequestRest.Interfaces; diff --git a/Runtime/Inference/Audio/AudioToAudio/AudioToAudioResponse.cs b/Runtime/Inference/Audio/AudioToAudio/AudioToAudioResponse.cs index de038f8..06a28fe 100644 --- a/Runtime/Inference/Audio/AudioToAudio/AudioToAudioResponse.cs +++ b/Runtime/Inference/Audio/AudioToAudio/AudioToAudioResponse.cs @@ -1,12 +1,12 @@ // Licensed under the MIT License. See LICENSE in the project root for license information. +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; using UnityEngine; using Utilities.WebRequestRest; @@ -31,13 +31,34 @@ private static async Task DecodeAudioAsync(AudioToAudioResult result, Cancellati { await Rest.ValidateCacheDirectoryAsync(); - if (!Rest.TryGetDownloadCacheItem(result.Blob, out var localFilePath)) + Rest.TryGetDownloadCacheItem(result.Blob, out var guid); + var localFilePath = Path.Combine(Rest.DownloadCacheDirectory, $"{DateTime.UtcNow:yyyy-MM-ddTHH-mm-ssffff}-{guid}.jpg"); + var fileStream = new FileStream(localFilePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); + + try { - await using var fileStream = new FileStream(localFilePath, FileMode.Create, FileAccess.ReadWrite); await fileStream.WriteAsync(Convert.FromBase64String(result.Blob), cancellationToken); + await fileStream.FlushAsync(cancellationToken); + } + catch (Exception e) + { + switch (e) + { + case TaskCanceledException: + case OperationCanceledException: + throw; + default: + Debug.LogError(e); + throw; + } + } + finally + { + fileStream.Close(); + await fileStream.DisposeAsync(); } - result.AudioClip = await Rest.DownloadAudioClipAsync(localFilePath, AudioType.WAV, parameters: null, cancellationToken: cancellationToken); + result.AudioClip = await Rest.DownloadAudioClipAsync($"file://{localFilePath}", AudioType.WAV, parameters: null, cancellationToken: cancellationToken); } } } diff --git a/Runtime/Inference/Audio/TextToSpeech/TextToSpeechResponse.cs b/Runtime/Inference/Audio/TextToSpeech/TextToSpeechResponse.cs index a9f68cb..64c3075 100644 --- a/Runtime/Inference/Audio/TextToSpeech/TextToSpeechResponse.cs +++ b/Runtime/Inference/Audio/TextToSpeech/TextToSpeechResponse.cs @@ -21,7 +21,7 @@ public override async Task DecodeAsync(Stream stream, CancellationToken cancella var filePath = Path.Combine(Rest.DownloadCacheDirectory, $"{DateTime.UtcNow:yyyy-MM-ddTHH-mm-ssffff}.wav"); Debug.Log(filePath); CachedPath = filePath; - var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write, FileShare.None); + var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); try { @@ -37,7 +37,7 @@ public override async Task DecodeAsync(Stream stream, CancellationToken cancella throw; default: Debug.LogError(e); - break; + throw; } } finally diff --git a/Runtime/Inference/B64JsonInferenceTaskResponse.cs b/Runtime/Inference/B64JsonInferenceTaskResponse.cs index 0f18212..7b18719 100644 --- a/Runtime/Inference/B64JsonInferenceTaskResponse.cs +++ b/Runtime/Inference/B64JsonInferenceTaskResponse.cs @@ -1,6 +1,8 @@ +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Newtonsoft.Json; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; namespace HuggingFace.Inference { diff --git a/Runtime/Inference/ComputerVision/ImageSegmentation/ImageSegmentationResponse.cs b/Runtime/Inference/ComputerVision/ImageSegmentation/ImageSegmentationResponse.cs index 5ebe870..1bf25d0 100644 --- a/Runtime/Inference/ComputerVision/ImageSegmentation/ImageSegmentationResponse.cs +++ b/Runtime/Inference/ComputerVision/ImageSegmentation/ImageSegmentationResponse.cs @@ -1,12 +1,13 @@ // Licensed under the MIT License. See LICENSE in the project root for license information. +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; +using UnityEngine; using Utilities.WebRequestRest; namespace HuggingFace.Inference.ComputerVision.ImageSegmentation @@ -26,14 +27,34 @@ public override async Task DecodeAsync(CancellationToken cancellationToken = def private static async Task DecodeImageAsync(ImageSegmentationResult result, CancellationToken cancellationToken) { await Rest.ValidateCacheDirectoryAsync(); + Rest.TryGetDownloadCacheItem(result.Blob, out var guid); + var localFilePath = Path.Combine(Rest.DownloadCacheDirectory, $"{DateTime.UtcNow:yyyy-MM-ddTHH-mm-ssffff}-{guid}.jpg"); + var fileStream = new FileStream(localFilePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); - if (!Rest.TryGetDownloadCacheItem(result.Blob, out var localFilePath)) + try { - await using var fileStream = new FileStream(localFilePath, FileMode.Create, FileAccess.ReadWrite); await fileStream.WriteAsync(Convert.FromBase64String(result.Blob), cancellationToken); + await fileStream.FlushAsync(cancellationToken); + } + catch (Exception e) + { + switch (e) + { + case TaskCanceledException: + case OperationCanceledException: + throw; + default: + Debug.LogError(e); + throw; + } + } + finally + { + fileStream.Close(); + await fileStream.DisposeAsync(); } - result.Mask = await Rest.DownloadTextureAsync(localFilePath, parameters: null, cancellationToken: cancellationToken); + result.Mask = await Rest.DownloadTextureAsync($"file://{localFilePath}", parameters: null, cancellationToken: cancellationToken); } } } diff --git a/Runtime/Inference/ComputerVision/ImageToImage/ImageToImageResponse.cs b/Runtime/Inference/ComputerVision/ImageToImage/ImageToImageResponse.cs index d5b2e90..5862935 100644 --- a/Runtime/Inference/ComputerVision/ImageToImage/ImageToImageResponse.cs +++ b/Runtime/Inference/ComputerVision/ImageToImage/ImageToImageResponse.cs @@ -21,7 +21,7 @@ public override async Task DecodeAsync(Stream stream, CancellationToken cancella var filePath = Path.Combine(Rest.DownloadCacheDirectory, $"{DateTime.UtcNow:yyyy-MM-ddTHH-mm-ssffff}.jpg"); Debug.Log(filePath); CachedPath = filePath; - var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write, FileShare.None); + var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); try { @@ -37,7 +37,7 @@ public override async Task DecodeAsync(Stream stream, CancellationToken cancella throw; default: Debug.LogError(e); - break; + throw; } } finally diff --git a/Runtime/Inference/Multimodal/B64ImageResult.cs b/Runtime/Inference/Multimodal/B64ImageResult.cs new file mode 100644 index 0000000..9abebb4 --- /dev/null +++ b/Runtime/Inference/Multimodal/B64ImageResult.cs @@ -0,0 +1,18 @@ +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Newtonsoft.Json; + +namespace HuggingFace.Inference.Multimodal +{ + public sealed class B64ImageResult + { + [JsonConstructor] + public B64ImageResult([JsonProperty("image")] string blob) + { + Blob = blob; + } + + [JsonProperty("image")] + public string Blob { get; } + } +} diff --git a/Runtime/Inference/Multimodal/B64ImageResult.cs.meta b/Runtime/Inference/Multimodal/B64ImageResult.cs.meta new file mode 100644 index 0000000..543e573 --- /dev/null +++ b/Runtime/Inference/Multimodal/B64ImageResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6a6363d952e2c742ad76e88c6a87b92 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e02b827cb46ed0c45a16c6e7d9469306, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Inference/Multimodal/TextToImage/TextToImageB64Response.cs b/Runtime/Inference/Multimodal/TextToImage/TextToImageB64Response.cs new file mode 100644 index 0000000..6d13b1e --- /dev/null +++ b/Runtime/Inference/Multimodal/TextToImage/TextToImageB64Response.cs @@ -0,0 +1,59 @@ +// Licensed under the MIT License. See LICENSE in the project root for license information. + +using Newtonsoft.Json; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using UnityEngine; +using Utilities.WebRequestRest; + +namespace HuggingFace.Inference.Multimodal.TextToImage +{ + public sealed class TextToImageB64Response : B64JsonInferenceTaskResponse + { + public TextToImageB64Response(string content, JsonSerializerSettings settings) : base(content, settings) + { + Result = JsonConvert.DeserializeObject(content, settings); + } + + public B64ImageResult Result { get; private set; } + + public string CachedPath { get; private set; } + + public Texture2D Image { get; private set; } + + public override async Task DecodeAsync(CancellationToken cancellationToken = default) + { + await Rest.ValidateCacheDirectoryAsync(); + var localFilePath = Path.Combine(Rest.DownloadCacheDirectory, $"{DateTime.UtcNow:yyyy-MM-ddTHH-mm-ssffff}.jpg"); + CachedPath = localFilePath; + var fileStream = new FileStream(localFilePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); + + try + { + await fileStream.WriteAsync(Convert.FromBase64String(Result.Blob), cancellationToken); + await fileStream.FlushAsync(cancellationToken); + } + catch (Exception e) + { + switch (e) + { + case TaskCanceledException: + case OperationCanceledException: + throw; + default: + Debug.LogError(e); + throw; + } + } + finally + { + fileStream.Close(); + await fileStream.DisposeAsync(); + } + + Image = await Rest.DownloadTextureAsync($"file://{localFilePath}", parameters: null, cancellationToken: cancellationToken); + } + } +} diff --git a/Runtime/Inference/Multimodal/TextToImage/TextToImageB64Response.cs.meta b/Runtime/Inference/Multimodal/TextToImage/TextToImageB64Response.cs.meta new file mode 100644 index 0000000..c90a6d9 --- /dev/null +++ b/Runtime/Inference/Multimodal/TextToImage/TextToImageB64Response.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4552f197eea7024fbdffd1977ce5f14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e02b827cb46ed0c45a16c6e7d9469306, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Inference/Multimodal/TextToImage/TextToImageResponse.cs b/Runtime/Inference/Multimodal/TextToImage/TextToImageBinaryResponse.cs similarity index 69% rename from Runtime/Inference/Multimodal/TextToImage/TextToImageResponse.cs rename to Runtime/Inference/Multimodal/TextToImage/TextToImageBinaryResponse.cs index 1e60fd0..34670c9 100644 --- a/Runtime/Inference/Multimodal/TextToImage/TextToImageResponse.cs +++ b/Runtime/Inference/Multimodal/TextToImage/TextToImageBinaryResponse.cs @@ -9,7 +9,7 @@ namespace HuggingFace.Inference.Multimodal.TextToImage { - public sealed class TextToImageResponse : BinaryInferenceTaskResponse + public sealed class TextToImageBinaryResponse : BinaryInferenceTaskResponse { public string CachedPath { get; private set; } @@ -18,10 +18,9 @@ public sealed class TextToImageResponse : BinaryInferenceTaskResponse public override async Task DecodeAsync(Stream stream, CancellationToken cancellationToken = default) { await Rest.ValidateCacheDirectoryAsync(); - var filePath = Path.Combine(Rest.DownloadCacheDirectory, $"{DateTime.UtcNow:yyyy-MM-ddTHH-mm-ssffff}.jpg"); - Debug.Log(filePath); - CachedPath = filePath; - var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write, FileShare.None); + var localFilePath = Path.Combine(Rest.DownloadCacheDirectory, $"{DateTime.UtcNow:yyyy-MM-ddTHH-mm-ssffff}.jpg"); + CachedPath = localFilePath; + var fileStream = new FileStream(localFilePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None); try { @@ -37,7 +36,7 @@ public override async Task DecodeAsync(Stream stream, CancellationToken cancella throw; default: Debug.LogError(e); - break; + throw; } } finally @@ -46,7 +45,7 @@ public override async Task DecodeAsync(Stream stream, CancellationToken cancella await fileStream.DisposeAsync(); } - Image = await Rest.DownloadTextureAsync($"file://{filePath}", parameters: null, cancellationToken: cancellationToken); + Image = await Rest.DownloadTextureAsync($"file://{localFilePath}", parameters: null, cancellationToken: cancellationToken); } } } diff --git a/Runtime/Inference/Multimodal/TextToImage/TextToImageResponse.cs.meta b/Runtime/Inference/Multimodal/TextToImage/TextToImageBinaryResponse.cs.meta similarity index 100% rename from Runtime/Inference/Multimodal/TextToImage/TextToImageResponse.cs.meta rename to Runtime/Inference/Multimodal/TextToImage/TextToImageBinaryResponse.cs.meta diff --git a/Tests/TestFixture_04_Inference_Multimodal.cs b/Tests/TestFixture_04_Inference_Multimodal.cs index d79ada8..fc55953 100644 --- a/Tests/TestFixture_04_Inference_Multimodal.cs +++ b/Tests/TestFixture_04_Inference_Multimodal.cs @@ -28,8 +28,9 @@ public async Task Test_01_TextToImage() Width = 1024, }; var task = new TextToImageTask(inputs); - var response = await api.InferenceEndpoint.RunInferenceTaskAsync(task); + var response = await api.InferenceEndpoint.RunInferenceTaskAsync(task); Assert.IsNotNull(response); + Debug.Log(response.CachedPath); Assert.IsNotNull(response.Image); } diff --git a/package.json b/package.json index 9be7eaa..561911f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "HuggingFace", "description": "A Non-Official HuggingFace Rest Client for Unity (UPM)", "keywords": [], - "version": "1.0.0-preview.10", + "version": "1.0.0-preview.11", "unity": "2021.3", "documentationUrl": "https://github.com/RageAgainstThePixel/com.rest.huggingface#documentation", "changelogUrl": "https://github.com/RageAgainstThePixel/com.rest.huggingface/releases",