Skip to content

Commit b7c7863

Browse files
com.openai.unity 2.2.4 (#33)
- 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
1 parent cd70450 commit b7c7863

10 files changed

+280
-93
lines changed

Documentation~/README.md

+18-25
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,13 @@ There are 4 ways to provide your API keys, in order of precedence:
8888
#### Pass keys directly with constructor
8989

9090
```csharp
91-
var api = new OpenAIClient("sk-mykeyhere");
91+
var api = new OpenAIClient("sk-apiKey");
9292
```
9393

9494
Or create a `OpenAIAuthentication` object manually
9595

9696
```csharp
97-
var api = new OpenAIClient(new OpenAIAuthentication("sk-secretkey"));
97+
var api = new OpenAIClient(new OpenAIAuthentication("sk-apiKey", "org-yourOrganizationId"));
9898
```
9999

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

142142
- Use `OPENAI_API_KEY` for your api key.
143-
- Use `OPEN_AI_ORGANIZATION_ID` to specify an organization.
143+
- Use `OPENAI_ORGANIZATION_ID` to specify an organization.
144144

145145
```csharp
146146
var api = new OpenAIClient(OpenAIAuthentication.LoadFromEnv());
147147
```
148148

149-
or
150-
151-
```csharp
152-
var api = new OpenAIClient(OpenAIAuthentication.LoadFromEnv("org-yourOrganizationId"));
153-
```
154-
155-
156149
### [Models](https://beta.openai.com/docs/api-reference/models)
157150

158151
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.
@@ -280,12 +273,12 @@ Creates an image given a prompt.
280273
var api = new OpenAIClient();
281274
var results = await api.ImagesEndPoint.GenerateImageAsync("A house riding a velociraptor", 1, ImageSize.Small);
282275

283-
foreach (var result in results)
276+
foreach (var (path, texture) in results)
284277
{
285-
Debug.Log(result.Key);
286-
// result.Key == file://path/to/image.png
287-
Assert.IsNotNull(result.Value);
288-
// result.Value == The preloaded Texture2D
278+
Debug.Log(path);
279+
// path == file://path/to/image.png
280+
Assert.IsNotNull(texture);
281+
// texture == The preloaded Texture2D
289282
}
290283
```
291284

@@ -297,12 +290,12 @@ Creates an edited or extended image given an original image and a prompt.
297290
var api = new OpenAIClient();
298291
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);
299292

300-
foreach (var result in results)
293+
foreach (var (path, texture) in results)
301294
{
302-
Debug.Log(result.Key);
303-
// result.Key == file://path/to/image.png
304-
Assert.IsNotNull(result.Value);
305-
// result.Value == Texture2D
295+
Debug.Log(path);
296+
// path == file://path/to/image.png
297+
Assert.IsNotNull(texture);
298+
// texture == The preloaded Texture2D
306299
}
307300
```
308301

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

317-
foreach (var result in results)
310+
foreach (var (path, texture) in results)
318311
{
319-
Debug.Log(result.Key);
320-
// result.Key == file://path/to/image.png
321-
Assert.IsNotNull(result.Value);
322-
// result.Value == Texture2D
312+
Debug.Log(path);
313+
// path == file://path/to/image.png
314+
Assert.IsNotNull(texture);
315+
// texture == The preloaded Texture2D
323316
}
324317
```
325318

Runtime/AuthInfo.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ internal class AuthInfo
1212
{
1313
public AuthInfo(string apiKey, string organizationId = null)
1414
{
15-
if (!apiKey.Contains("sk-"))
15+
if (string.IsNullOrWhiteSpace(apiKey) ||
16+
!apiKey.Contains("sk-"))
1617
{
1718
throw new InvalidCredentialException($"{apiKey} must start with 'sk-'");
1819
}
1920

2021
this.apiKey = apiKey;
2122

22-
if (organizationId != null)
23+
if (!string.IsNullOrWhiteSpace(organizationId))
2324
{
2425
if (!organizationId.Contains("org-"))
2526
{

Runtime/Images/ImageEditRequest.cs

+63-40
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using System;
44
using System.IO;
5+
using UnityEngine;
56

67
namespace OpenAI.Images
78
{
@@ -31,46 +32,52 @@ public sealed class ImageEditRequest : IDisposable
3132
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
3233
/// </param>
3334
public ImageEditRequest(string imagePath, string maskPath, string prompt, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
35+
: this(
36+
File.OpenRead(imagePath),
37+
Path.GetFileName(imagePath),
38+
string.IsNullOrWhiteSpace(maskPath) ? null : File.OpenRead(maskPath),
39+
string.IsNullOrWhiteSpace(maskPath) ? null : Path.GetFileName(maskPath),
40+
prompt,
41+
numberOfResults,
42+
size,
43+
user)
3444
{
35-
if (!File.Exists(imagePath))
36-
{
37-
throw new FileNotFoundException($"Could not find the {nameof(imagePath)} file located at {imagePath}");
38-
}
39-
40-
Image = File.OpenRead(imagePath);
41-
ImageName = Path.GetFileName(imagePath);
42-
43-
if (!File.Exists(maskPath))
44-
{
45-
throw new FileNotFoundException($"Could not find the {nameof(maskPath)} file located at {maskPath}");
46-
}
47-
48-
Mask = File.OpenRead(maskPath);
49-
MaskName = Path.GetFileName(maskPath);
50-
51-
if (prompt.Length > 1000)
52-
{
53-
throw new ArgumentOutOfRangeException(nameof(prompt), "The maximum character length for the prompt is 1000 characters.");
54-
}
55-
56-
Prompt = prompt;
57-
58-
if (numberOfResults is > 10 or < 1)
59-
{
60-
throw new ArgumentOutOfRangeException(nameof(numberOfResults), "The number of results must be between 1 and 10");
61-
}
62-
63-
Number = numberOfResults;
64-
65-
Size = size switch
66-
{
67-
ImageSize.Small => "256x256",
68-
ImageSize.Medium => "512x512",
69-
ImageSize.Large => "1024x1024",
70-
_ => throw new ArgumentOutOfRangeException(nameof(size), size, null)
71-
};
45+
}
7246

73-
User = user;
47+
/// <summary>
48+
/// Constructor.
49+
/// </summary>
50+
/// <param name="texture">
51+
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
52+
/// If mask is not provided, image must have transparency, which will be used as the mask.
53+
/// </param>
54+
/// <param name="mask">
55+
/// An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where image should be edited.
56+
/// Must be a valid PNG file, less than 4MB, and have the same dimensions as image.
57+
/// </param>
58+
/// <param name="prompt">
59+
/// A text description of the desired image(s). The maximum length is 1000 characters.
60+
/// </param>
61+
/// <param name="numberOfResults">
62+
/// The number of images to generate. Must be between 1 and 10.
63+
/// </param>
64+
/// <param name="size">
65+
/// The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024.
66+
/// </param>
67+
/// <param name="user">
68+
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
69+
/// </param>
70+
public ImageEditRequest(Texture2D texture, Texture2D mask, string prompt, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
71+
: this(
72+
new MemoryStream(texture.EncodeToPNG()),
73+
$"{texture.name}.png",
74+
mask != null ? new MemoryStream(mask.EncodeToPNG()) : null,
75+
mask != null ? $"{mask.name}.png" : null,
76+
prompt,
77+
numberOfResults,
78+
size,
79+
user)
80+
{
7481
}
7582

7683
/// <summary>
@@ -101,9 +108,25 @@ public ImageEditRequest(string imagePath, string maskPath, string prompt, int nu
101108
public ImageEditRequest(Stream image, string imageName, Stream mask, string maskName, string prompt, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
102109
{
103110
Image = image;
111+
112+
if (string.IsNullOrWhiteSpace(imageName))
113+
{
114+
imageName = "image.png";
115+
}
116+
104117
ImageName = imageName;
105-
Mask = mask;
106-
MaskName = maskName;
118+
119+
if (mask != null)
120+
{
121+
Mask = mask;
122+
123+
if (string.IsNullOrWhiteSpace(maskName))
124+
{
125+
maskName = "mask.png";
126+
}
127+
128+
MaskName = maskName;
129+
}
107130

108131
if (prompt.Length > 1000)
109132
{

Runtime/Images/ImageVariationRequest.cs

+49-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using System;
44
using System.IO;
5+
using UnityEngine;
56

67
namespace OpenAI.Images
78
{
@@ -12,7 +13,6 @@ public sealed class ImageVariationRequest : IDisposable
1213
/// </summary>
1314
/// <param name="imagePath">
1415
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
15-
/// If mask is not provided, image must have transparency, which will be used as the mask.
1616
/// </param>
1717
/// <param name="numberOfResults">
1818
/// The number of images to generate. Must be between 1 and 10.
@@ -24,14 +24,58 @@ public sealed class ImageVariationRequest : IDisposable
2424
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
2525
/// </param>
2626
public ImageVariationRequest(string imagePath, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
27+
: this(File.OpenRead(imagePath), Path.GetFileName(imagePath), numberOfResults, size, user)
2728
{
28-
if (!File.Exists(imagePath))
29+
}
30+
31+
/// <summary>
32+
/// Constructor.
33+
/// </summary>
34+
/// <param name="texture">
35+
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
36+
/// </param>
37+
/// <param name="numberOfResults">
38+
/// The number of images to generate. Must be between 1 and 10.
39+
/// </param>
40+
/// <param name="size">
41+
/// The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024.
42+
/// </param>
43+
/// <param name="user">
44+
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
45+
/// </param>
46+
public ImageVariationRequest(Texture2D texture, int numberOfResults = 1, ImageSize size = ImageSize.Large, string user = null)
47+
: this(new MemoryStream(texture.EncodeToPNG()), $"{texture.name}.png", numberOfResults, size, user)
48+
{
49+
}
50+
51+
/// <summary>
52+
/// Constructor.
53+
/// </summary>
54+
/// <param name="image">
55+
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
56+
/// </param>
57+
/// <param name="imageName">
58+
/// The name of the image.
59+
/// </param>
60+
/// <param name="numberOfResults">
61+
/// The number of images to generate. Must be between 1 and 10.
62+
/// </param>
63+
/// <param name="size">
64+
/// The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024.
65+
/// </param>
66+
/// <param name="user">
67+
/// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.
68+
/// </param>
69+
public ImageVariationRequest(Stream image, string imageName, int numberOfResults, ImageSize size, string user)
70+
{
71+
Image = image;
72+
73+
if (string.IsNullOrWhiteSpace(imageName))
2974
{
30-
throw new FileNotFoundException($"Could not find the {nameof(imagePath)} file located at {imagePath}");
75+
imageName = "image.png";
3176
}
3277

33-
Image = File.OpenRead(imagePath);
34-
ImageName = Path.GetFileName(imagePath);
78+
ImageName = imageName;
3579

3680
if (numberOfResults is > 10 or < 1)
3781
{

0 commit comments

Comments
 (0)