Skip to content

Commit

Permalink
com.openai.unity 2.2.4 (#33)
Browse files Browse the repository at this point in the history
- support native texture image variations and edits
  - texture's require the following import settings:
    - no compression
    - read/write enabled 
- made image edit mask optional as long as main texture has transparency
- updated `AuthInfo` to validate `apiKey` and `organizationId` a bit
better
- renamed `OPEN_AI_ORGANIZATION_ID` -> `OPENAI_ORGANIZATION_ID`
- updated dependencies
- updated docs
  • Loading branch information
StephenHodgson authored Feb 17, 2023
1 parent cd70450 commit b7c7863
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 93 deletions.
43 changes: 18 additions & 25 deletions Documentation~/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ There are 4 ways to provide your API keys, in order of precedence:
#### Pass keys directly with constructor

```csharp
var api = new OpenAIClient("sk-mykeyhere");
var api = new OpenAIClient("sk-apiKey");
```

Or create a `OpenAIAuthentication` object manually

```csharp
var api = new OpenAIClient(new OpenAIAuthentication("sk-secretkey"));
var api = new OpenAIClient(new OpenAIAuthentication("sk-apiKey", "org-yourOrganizationId"));
```

#### Unity Scriptable Object
Expand Down Expand Up @@ -140,19 +140,12 @@ var api = new OpenAIClient(OpenAIAuthentication.LoadFromDirectory("your/path/to/
Use your system's environment variables specify an api key and organization to use.

- Use `OPENAI_API_KEY` for your api key.
- Use `OPEN_AI_ORGANIZATION_ID` to specify an organization.
- Use `OPENAI_ORGANIZATION_ID` to specify an organization.

```csharp
var api = new OpenAIClient(OpenAIAuthentication.LoadFromEnv());
```

or

```csharp
var api = new OpenAIClient(OpenAIAuthentication.LoadFromEnv("org-yourOrganizationId"));
```


### [Models](https://beta.openai.com/docs/api-reference/models)

List and describe the various models available in the API. You can refer to the [Models documentation](https://beta.openai.com/docs/models) to understand what models are available and the differences between them.
Expand Down Expand Up @@ -280,12 +273,12 @@ Creates an image given a prompt.
var api = new OpenAIClient();
var results = await api.ImagesEndPoint.GenerateImageAsync("A house riding a velociraptor", 1, ImageSize.Small);

foreach (var result in results)
foreach (var (path, texture) in results)
{
Debug.Log(result.Key);
// result.Key == file://path/to/image.png
Assert.IsNotNull(result.Value);
// result.Value == The preloaded Texture2D
Debug.Log(path);
// path == file://path/to/image.png
Assert.IsNotNull(texture);
// texture == The preloaded Texture2D
}
```

Expand All @@ -297,12 +290,12 @@ Creates an edited or extended image given an original image and a prompt.
var api = new OpenAIClient();
var results = await api.ImagesEndPoint.CreateImageEditAsync(Path.GetFullPath(imageAssetPath), Path.GetFullPath(maskAssetPath), "A sunlit indoor lounge area with a pool containing a flamingo", 1, ImageSize.Small);

foreach (var result in results)
foreach (var (path, texture) in results)
{
Debug.Log(result.Key);
// result.Key == file://path/to/image.png
Assert.IsNotNull(result.Value);
// result.Value == Texture2D
Debug.Log(path);
// path == file://path/to/image.png
Assert.IsNotNull(texture);
// texture == The preloaded Texture2D
}
```

Expand All @@ -314,12 +307,12 @@ Creates a variation of a given image.
var api = new OpenAIClient();
var results = await api.ImagesEndPoint.CreateImageVariationAsync(Path.GetFullPath(imageAssetPath), 1, ImageSize.Small);

foreach (var result in results)
foreach (var (path, texture) in results)
{
Debug.Log(result.Key);
// result.Key == file://path/to/image.png
Assert.IsNotNull(result.Value);
// result.Value == Texture2D
Debug.Log(path);
// path == file://path/to/image.png
Assert.IsNotNull(texture);
// texture == The preloaded Texture2D
}
```

Expand Down
5 changes: 3 additions & 2 deletions Runtime/AuthInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ internal class AuthInfo
{
public AuthInfo(string apiKey, string organizationId = null)
{
if (!apiKey.Contains("sk-"))
if (string.IsNullOrWhiteSpace(apiKey) ||
!apiKey.Contains("sk-"))
{
throw new InvalidCredentialException($"{apiKey} must start with 'sk-'");
}

this.apiKey = apiKey;

if (organizationId != null)
if (!string.IsNullOrWhiteSpace(organizationId))
{
if (!organizationId.Contains("org-"))
{
Expand Down
103 changes: 63 additions & 40 deletions Runtime/Images/ImageEditRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.IO;
using UnityEngine;

namespace OpenAI.Images
{
Expand Down Expand Up @@ -31,46 +32,52 @@ public sealed class ImageEditRequest : IDisposable
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
/// </param>
public ImageEditRequest(string imagePath, string maskPath, string prompt, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
: this(
File.OpenRead(imagePath),
Path.GetFileName(imagePath),
string.IsNullOrWhiteSpace(maskPath) ? null : File.OpenRead(maskPath),
string.IsNullOrWhiteSpace(maskPath) ? null : Path.GetFileName(maskPath),
prompt,
numberOfResults,
size,
user)
{
if (!File.Exists(imagePath))
{
throw new FileNotFoundException($"Could not find the {nameof(imagePath)} file located at {imagePath}");
}

Image = File.OpenRead(imagePath);
ImageName = Path.GetFileName(imagePath);

if (!File.Exists(maskPath))
{
throw new FileNotFoundException($"Could not find the {nameof(maskPath)} file located at {maskPath}");
}

Mask = File.OpenRead(maskPath);
MaskName = Path.GetFileName(maskPath);

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)
};
}

User = user;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="texture">
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
/// If mask is not provided, image must have transparency, which will be used as the mask.
/// </param>
/// <param name="mask">
/// An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where image should be edited.
/// Must be a valid PNG file, less than 4MB, and have the same dimensions as image.
/// </param>
/// <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. Must be one of 256x256, 512x512, or 1024x1024.
/// </param>
/// <param name="user">
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
/// </param>
public ImageEditRequest(Texture2D texture, Texture2D mask, string prompt, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
: this(
new MemoryStream(texture.EncodeToPNG()),
$"{texture.name}.png",
mask != null ? new MemoryStream(mask.EncodeToPNG()) : null,
mask != null ? $"{mask.name}.png" : null,
prompt,
numberOfResults,
size,
user)
{
}

/// <summary>
Expand Down Expand Up @@ -101,9 +108,25 @@ public ImageEditRequest(string imagePath, string maskPath, string prompt, int nu
public ImageEditRequest(Stream image, string imageName, Stream mask, string maskName, string prompt, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
{
Image = image;

if (string.IsNullOrWhiteSpace(imageName))
{
imageName = "image.png";
}

ImageName = imageName;
Mask = mask;
MaskName = maskName;

if (mask != null)
{
Mask = mask;

if (string.IsNullOrWhiteSpace(maskName))
{
maskName = "mask.png";
}

MaskName = maskName;
}

if (prompt.Length > 1000)
{
Expand Down
54 changes: 49 additions & 5 deletions Runtime/Images/ImageVariationRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.IO;
using UnityEngine;

namespace OpenAI.Images
{
Expand All @@ -12,7 +13,6 @@ public sealed class ImageVariationRequest : IDisposable
/// </summary>
/// <param name="imagePath">
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
/// If mask is not provided, image must have transparency, which will be used as the mask.
/// </param>
/// <param name="numberOfResults">
/// The number of images to generate. Must be between 1 and 10.
Expand All @@ -24,14 +24,58 @@ public sealed class ImageVariationRequest : IDisposable
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
/// </param>
public ImageVariationRequest(string imagePath, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
: this(File.OpenRead(imagePath), Path.GetFileName(imagePath), numberOfResults, size, user)
{
if (!File.Exists(imagePath))
}

/// <summary>
/// Constructor.
/// </summary>
/// <param name="texture">
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
/// </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. Must be one of 256x256, 512x512, or 1024x1024.
/// </param>
/// <param name="user">
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
/// </param>
public ImageVariationRequest(Texture2D texture, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
: this(new MemoryStream(texture.EncodeToPNG()), $"{texture.name}.png", numberOfResults, size, user)
{
}

/// <summary>
/// Constructor.
/// </summary>
/// <param name="image">
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
/// </param>
/// <param name="imageName">
/// The name of the image.
/// </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. Must be one of 256x256, 512x512, or 1024x1024.
/// </param>
/// <param name="user">
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
/// </param>
public ImageVariationRequest(Stream image, string imageName, int numberOfResults, ImageSize size, string user)
{
Image = image;

if (string.IsNullOrWhiteSpace(imageName))
{
throw new FileNotFoundException($"Could not find the {nameof(imagePath)} file located at {imagePath}");
imageName = "image.png";
}

Image = File.OpenRead(imagePath);
ImageName = Path.GetFileName(imagePath);
ImageName = imageName;

if (numberOfResults is > 10 or < 1)
{
Expand Down
Loading

0 comments on commit b7c7863

Please sign in to comment.