Skip to content

Commit

Permalink
added image generation api endpoint
Browse files Browse the repository at this point in the history
updated project unity version
  • Loading branch information
StephenHodgson committed Nov 26, 2022
1 parent 5be4784 commit 59a7d3b
Show file tree
Hide file tree
Showing 18 changed files with 318 additions and 6 deletions.
Binary file modified Documentation~/images/package-manager-scopes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Based on [OpenAI-DotNet](https://github.com/RageAgainstThePixel/OpenAI-DotNet)
- `Name: OpenUPM`
- `URL: https://package.openupm.com`
- `Scope(s):`
- `com.opanai`
- `com.openai`
- `com.utilities`

![scoped-registries](Documentation~/images/package-manager-scopes.png)

Expand Down Expand Up @@ -182,3 +183,14 @@ Dictionary<string, string> examples = new Dictionary<string, string>
var result = await api.ClassificationEndpoint.CreateClassificationAsync(new ClassificationRequest(query, examples, labels));
// result.Label == "Negative"
```

### Image Generation

The Image Generation API is accessed via `OpenAI.ImageGenerationEndpoint`:

```csharp
var api = new OpenAIClient();
var results = await api.ImageGenerationEndPoint.GenerateImageAsync("A house riding a velociraptor", 1, ImageSize.Small);
var image = results[0];
// result == Texture2D generated image
```
8 changes: 8 additions & 0 deletions Runtime/ImageGeneration.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 69 additions & 0 deletions Runtime/ImageGeneration/ImageGenerationEndpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Newtonsoft.Json;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using UnityEngine;
using Utilities.WebRequestRest;

namespace OpenAI.Images
{
/// <summary>
/// Creates an image given a prompt.
/// </summary>
public class ImageGenerationEndpoint : BaseEndPoint
{
/// <inheritdoc />
internal ImageGenerationEndpoint(OpenAIClient api) : base(api) { }

/// <inheritdoc />
protected override string GetEndpoint(Engine engine = null) => $"{Api.BaseUrl}images/generations";

/// <summary>
/// Creates an image given a prompt.
/// </summary>
/// <param name="prompt"></param>
/// <param name="numberOfResults"></param>
/// <param name="size"></param>
/// <returns>An array of generated textures.</returns>
public async Task<IReadOnlyList<Texture2D>> GenerateImageAsync(string prompt, int numberOfResults = 1, ImageSize size = ImageSize.Large)
=> await GenerateImageAsync(new ImageGenerationRequest(prompt, numberOfResults, size));

/// <summary>
/// Creates an image given a prompt.
/// </summary>
/// <param name="request"><see cref="ImageGenerationRequest"/></param>
/// <returns>An array of generated textures.</returns>
/// <exception cref="HttpRequestException"></exception>
public async Task<IReadOnlyList<Texture2D>> GenerateImageAsync(ImageGenerationRequest request)
{
var jsonContent = JsonConvert.SerializeObject(request, Api.JsonSerializationOptions);
var response = await Api.Client.PostAsync(GetEndpoint(), jsonContent.ToJsonStringContent());

if (response.IsSuccessStatusCode)
{
var resultAsString = await response.Content.ReadAsStringAsync();
var imageGenerationResponse = JsonConvert.DeserializeObject<ImageGenerationResponse>(resultAsString, Api.JsonSerializationOptions);

if (imageGenerationResponse?.Data == null || imageGenerationResponse.Data.Count == 0)
{
throw new HttpRequestException($"{nameof(GenerateImageAsync)} returned no results! HTTP status code: {response.StatusCode}. Response body: {resultAsString}");
}

imageGenerationResponse.SetResponseData(response.Headers);

var images = new List<Texture2D>(imageGenerationResponse.Data.Count);

foreach (var imageResult in imageGenerationResponse.Data)
{
images.Add(await Rest.DownloadTextureAsync(imageResult.Url));
}

return images;
}

throw new HttpRequestException($"{nameof(GenerateImageAsync)} Failed! HTTP status code: {response.StatusCode}. Request body: {jsonContent}");
}
}
}
11 changes: 11 additions & 0 deletions Runtime/ImageGeneration/ImageGenerationEndpoint.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 69 additions & 0 deletions Runtime/ImageGeneration/ImageGenerationRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using Newtonsoft.Json;

namespace OpenAI.Images
{
/// <summary>
/// Creates an image given a prompt.
/// </summary>
public sealed class ImageGenerationRequest
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="prompt">
/// A text description of the desired image(s). The maximum length is 1000 characters.
/// </param>
/// <param name="numberOfResults">
/// The number of images to generate. Must be between 1 and 10.
/// </param>
/// <param name="size">
/// The size of the generated images.
/// </param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public ImageGenerationRequest(string prompt, int numberOfResults, ImageSize size)
{
if (prompt.Length > 1000)
{
throw new ArgumentOutOfRangeException(nameof(prompt), "The maximum character length for the prompt is 1000 characters.");
}

Prompt = prompt;

if (numberOfResults is > 10 or < 1)
{
throw new ArgumentOutOfRangeException(nameof(numberOfResults), "The number of results must be between 1 and 10");
}

Number = numberOfResults;

Size = size switch
{
ImageSize.Small => "256x256",
ImageSize.Medium => "512x512",
ImageSize.Large => "1024x1024",
_ => throw new ArgumentOutOfRangeException(nameof(size), size, null)
};
}

/// <summary>
/// A text description of the desired image(s). The maximum length is 1000 characters.
/// </summary>
[JsonProperty("prompt")]
public string Prompt { get; }

/// <summary>
/// The number of images to generate. Must be between 1 and 10.
/// </summary>
[JsonProperty("n")]
public int Number { get; }

/// <summary>
/// The size of the generated images.
/// </summary>
[JsonProperty("size")]
public string Size { get; }
}
}
11 changes: 11 additions & 0 deletions Runtime/ImageGeneration/ImageGenerationRequest.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions Runtime/ImageGeneration/ImageGenerationResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System.Collections.Generic;
using Newtonsoft.Json;

namespace OpenAI.Images
{
internal class ImageGenerationResponse : BaseResponse
{
[JsonProperty("created")]
public int Created { get; set; }

[JsonProperty("data")]
public List<ImageResult> Data { get; set; }
}
}
11 changes: 11 additions & 0 deletions Runtime/ImageGeneration/ImageGenerationResponse.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions Runtime/ImageGeneration/ImageResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Newtonsoft.Json;

namespace OpenAI.Images
{
internal class ImageResult
{
[JsonProperty("url")]
public string Url { get; set; }
}
}
11 changes: 11 additions & 0 deletions Runtime/ImageGeneration/ImageResult.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions Runtime/ImageGeneration/ImageSize.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace OpenAI.Images
{
public enum ImageSize
{
/// <summary>
/// 256x256
/// </summary>
Small,
/// <summary>
/// 512x512
/// </summary>
Medium,
/// <summary>
/// 1024x1024
/// </summary>
Large,
}
}
11 changes: 11 additions & 0 deletions Runtime/ImageGeneration/ImageSize.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 15 additions & 2 deletions Runtime/OpenAI.asmdef
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
{
"name": "OpenAI"
}
"name": "OpenAI",
"rootNamespace": "",
"references": [
"GUID:7958db66189566541a6363568aee1575"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
25 changes: 25 additions & 0 deletions Tests/ImagesTestFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using NUnit.Framework;
using OpenAI.Images;
using System.Collections;
using UnityEngine.TestTools;

namespace OpenAI.Tests
{
internal class ImagesTestFixture
{
[UnityTest]
public IEnumerator Test_1_GenerateImage()
{
yield return AwaitTestUtilities.Await(async () =>
{
var api = new OpenAIClient();
var results = await api.ImageGenerationEndPoint.GenerateImageAsync("A house riding a velociraptor", 1, ImageSize.Small);
Assert.IsNotNull(results);
Assert.NotZero(results.Count);
});
}
}
}
11 changes: 11 additions & 0 deletions Tests/ImagesTestFixture.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Tests/OpenAI.Tests.asmdef
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "OpenAI.Tests",
"rootNamespace": "",
"references": [
"GUID:27619889b8ba8c24980f49ee34dbb44a",
"GUID:0acc523941302664db1f4e527237feb3",
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"displayName": "OpenAI",
"description": "An OpenAI package for the Unity Game Engine.",
"keywords": [],
"version": "1.0.0",
"unity": "2020.3",
"version": "2.0.0-preview.1",
"unity": "2021.3",
"license": "MIT",
"repository": {
"type": "git",
Expand All @@ -15,7 +15,8 @@
"url": "https://github.com/StephenHodgson"
},
"dependencies": {
"com.unity.nuget.newtonsoft-json": "3.0.2"
"com.unity.nuget.newtonsoft-json": "3.0.2",
"com.utilities.rest": "1.0.1"
},
"publishConfig": {
"registry": "https://package.openupm.com"
Expand Down

0 comments on commit 59a7d3b

Please sign in to comment.