Skip to content

Commit

Permalink
com.openai.unity 6.0.0 (#133)
Browse files Browse the repository at this point in the history
- Updated FilesEndpoint.ListFilesAsync with optional purpose filter query parameter
- Refactored list responses with a more generic ListQuery and ListResponse<TObject> pattern
  - EventList -> ListResponse<EventResponse>
  - FineTuneJobList -> ListResponse<FineTuneJobResponse>
- Standardized names for timestamps to have suffix: UnixTimeSeconds
- Standardized response class names (existing classes depreciated)
  - FileData -> FileResponse
  - CompletionResult -> CompletonResponse
  - Event -> EventResponse
  - FineTuneJob -> FineTuneJobResponse
- Added detail parameter to ImageURL
- Added GetModerationChunkedAsync method in ModerationsEndpoint
- Fixed streaming function tool serialization
- Fixed multiple function tool usages
- Added additional implicit operators for Chat.Content
- Added warnings to default auth and setting constructors to improve init speed
- Updated authentication
- Updated unit tests
- Updated docs
  • Loading branch information
StephenHodgson authored Nov 29, 2023
1 parent d4e690b commit f9ed115
Show file tree
Hide file tree
Showing 90 changed files with 1,860 additions and 1,191 deletions.
338 changes: 185 additions & 153 deletions OpenAI/Packages/com.openai.unity/Documentation~/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class FineTuningWindow : EditorWindow

private static readonly List<Model> organizationModels = new List<Model>();

private static readonly ConcurrentDictionary<string, FineTuneJob> fineTuneJobs = new ConcurrentDictionary<string, FineTuneJob>();
private static readonly ConcurrentDictionary<string, FineTuneJobResponse> fineTuneJobs = new ConcurrentDictionary<string, FineTuneJobResponse>();

private static OpenAIClient openAI;

Expand Down Expand Up @@ -298,7 +298,7 @@ private static void RenderTrainingDataSets()
(int)JobStatus.Cancelled or
(int)JobStatus.Succeeded)
{
FineTuneJob fineTuneJob = null;
FineTuneJobResponse fineTuneJob = null;

if (jobStatus.intValue == (int)JobStatus.Succeeded)
{
Expand Down Expand Up @@ -506,7 +506,7 @@ private static void RenderTrainingJobQueue()

if (fineTuneJobList is { HasMore: true } && GUILayout.Button("Next Page", defaultColumnWidthOption))
{
EditorApplication.delayCall += () => FetchTrainingJobs(fineTuneJobList.Jobs.LastOrDefault());
EditorApplication.delayCall += () => FetchTrainingJobs(fineTuneJobList.Items.LastOrDefault());
}

if (GUILayout.Button(refreshContent, defaultColumnWidthOption))
Expand Down Expand Up @@ -588,7 +588,7 @@ private static void RenderTrainingJobQueue()
EditorGUI.indentLevel--;
}

private static FineTuneJobList fineTuneJobList;
private static ListResponse<FineTuneJobResponse> fineTuneJobList;
private static int trainingJobCount = 25;
private static readonly Stack<string> trainingJobIds = new Stack<string>();

Expand Down Expand Up @@ -622,12 +622,12 @@ private static async void FetchTrainingJobs(string trainingJobId = null)
}

fineTuneJobList = null;
var list = await openAI.FineTuningEndpoint.ListJobsAsync(limit: trainingJobCount, after: trainingJobId);
var list = await openAI.FineTuningEndpoint.ListJobsAsync(new ListQuery(limit: trainingJobCount, after: trainingJobId));
fineTuneJobs.Clear();
await Task.WhenAll(list.Jobs.Select(SyncJobDataAsync));
await Task.WhenAll(list.Items.Select(SyncJobDataAsync));
fineTuneJobList = list;

static async Task SyncJobDataAsync(FineTuneJob job)
static async Task SyncJobDataAsync(FineTuneJobResponse job)
{
var jobDetails = await openAI.FineTuningEndpoint.GetJobInfoAsync(job);
fineTuneJobs.TryAdd(jobDetails.Id, jobDetails);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using Newtonsoft.Json;
using OpenAI.Extensions;
using System;
using System.IO;
using System.Threading;
Expand Down
8 changes: 8 additions & 0 deletions OpenAI/Packages/com.openai.unity/Runtime/Authentication.meta

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

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace OpenAI
/// <summary>
/// Represents authentication for OpenAI
/// </summary>
public sealed class OpenAIAuthentication : AbstractAuthentication<OpenAIAuthentication, OpenAIAuthInfo>
public sealed class OpenAIAuthentication : AbstractAuthentication<OpenAIAuthentication, OpenAIAuthInfo, OpenAIConfiguration>
{
internal const string CONFIG_FILE = ".openai";
private const string OPENAI_KEY = nameof(OPENAI_KEY);
Expand All @@ -29,24 +29,19 @@ public sealed class OpenAIAuthentication : AbstractAuthentication<OpenAIAuthenti
public static implicit operator OpenAIAuthentication(string key) => new OpenAIAuthentication(key);

/// <summary>
/// Instantiates a new Authentication object that will load the default config.
/// Instantiates an empty Authentication object.
/// </summary>
public OpenAIAuthentication()
{
if (cachedDefault != null) { return; }

cachedDefault = (LoadFromAsset<OpenAIConfiguration>() ??
LoadFromDirectory()) ??
LoadFromDirectory(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)) ??
LoadFromEnvironment();
Info = cachedDefault?.Info;
}
public OpenAIAuthentication() { }

/// <summary>
/// Instantiates a new Authentication object with the given <paramref name="apiKey"/>, which may be <see langword="null"/>.
/// </summary>
/// <param name="apiKey">The API key, required to access the API endpoint.</param>
public OpenAIAuthentication(string apiKey) => Info = new OpenAIAuthInfo(apiKey);
public OpenAIAuthentication(string apiKey)
{
Info = new OpenAIAuthInfo(apiKey);
cachedDefault = this;
}

/// <summary>
/// Instantiates a new Authentication object with the given <paramref name="apiKey"/>, which may be <see langword="null"/>.
Expand All @@ -56,13 +51,27 @@ public OpenAIAuthentication()
/// For users who belong to multiple organizations, you can pass a header to specify which organization is used for an API request.
/// Usage from these API requests will count against the specified organization's subscription quota.
/// </param>
public OpenAIAuthentication(string apiKey, string organization) => Info = new OpenAIAuthInfo(apiKey, organization);
public OpenAIAuthentication(string apiKey, string organization)
{
Info = new OpenAIAuthInfo(apiKey, organization);
cachedDefault = this;
}

/// <summary>
/// Instantiates a new Authentication object with the given <paramref name="authInfo"/>, which may be <see langword="null"/>.
/// </summary>
/// <param name="authInfo"></param>
public OpenAIAuthentication(OpenAIAuthInfo authInfo) => Info = authInfo;
public OpenAIAuthentication(OpenAIAuthInfo authInfo)
{
Info = authInfo;
cachedDefault = this;
}

/// <summary>
/// Instantiates a new Authentication object with the given <see cref="configuration"/>.
/// </summary>
/// <param name="configuration"><see cref="OpenAIConfiguration"/>.</param>
public OpenAIAuthentication(OpenAIConfiguration configuration) : this(configuration.ApiKey, configuration.organizationId) { }

/// <inheritdoc />
public override OpenAIAuthInfo Info { get; }
Expand All @@ -76,20 +85,21 @@ public OpenAIAuthentication()
/// </summary>
public static OpenAIAuthentication Default
{
get => cachedDefault ?? new OpenAIAuthentication();
get => cachedDefault ??= new OpenAIAuthentication().LoadDefault();
internal set => cachedDefault = value;
}

/// <inheritdoc />
public override OpenAIAuthentication LoadFromAsset<T>()
=> Resources.LoadAll<T>(string.Empty)
.Where(asset => asset != null)
.Where(asset => asset is OpenAIConfiguration config &&
!string.IsNullOrWhiteSpace(config.ApiKey))
.Select(asset => asset is OpenAIConfiguration config
? new OpenAIAuthentication(config.ApiKey, config.OrganizationId)
: null)
.FirstOrDefault();
public override OpenAIAuthentication LoadFromAsset(OpenAIConfiguration configuration = null)
{
if (configuration == null)
{
Debug.LogWarning($"You can speed this up by passing a {nameof(OpenAIConfiguration)} to the {nameof(OpenAIAuthentication)}.ctr");
configuration = Resources.LoadAll<OpenAIConfiguration>(string.Empty).FirstOrDefault(o => o != null);
}

return configuration != null ? new OpenAIAuthentication(configuration) : null;
}

/// <inheritdoc />
public override OpenAIAuthentication LoadFromEnvironment()
Expand Down Expand Up @@ -130,13 +140,21 @@ public override OpenAIAuthentication LoadFromEnvironment()
/// ReSharper disable once OptionalParameterHierarchyMismatch
public override OpenAIAuthentication LoadFromDirectory(string directory = null, string filename = CONFIG_FILE, bool searchUp = true)
{
directory ??= Environment.CurrentDirectory;
if (string.IsNullOrWhiteSpace(directory))
{
directory = Environment.CurrentDirectory;
}

if (string.IsNullOrWhiteSpace(filename))
{
filename = CONFIG_FILE;
}

OpenAIAuthInfo tempAuth = null;

var currentDirectory = new DirectoryInfo(directory);

while (tempAuth == null && currentDirectory.Parent != null)
while (tempAuth == null && currentDirectory?.Parent != null)
{
var filePath = Path.Combine(currentDirectory.FullName, filename);

Expand Down Expand Up @@ -195,13 +213,7 @@ public override OpenAIAuthentication LoadFromDirectory(string directory = null,
}
}

if (tempAuth == null ||
string.IsNullOrEmpty(tempAuth.ApiKey))
{
return null;
}

return new OpenAIAuthentication(tempAuth);
return string.IsNullOrEmpty(tempAuth?.ApiKey) ? null : new OpenAIAuthentication(tempAuth);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,63 @@ namespace OpenAI
public sealed class OpenAISettings : ISettings<OpenAISettingsInfo>
{
/// <summary>
/// Creates a new instance of <see cref="OpenAISettings"/> for use with OpenAI.
/// Creates a new instance of <see cref="OpenAISettings"/> with default <see cref="OpenAISettingsInfo"/>.
/// </summary>
public OpenAISettings()
{
if (cachedDefault != null) { return; }
Info = new OpenAISettingsInfo();
cachedDefault = this;
}

var config = Resources.LoadAll<OpenAIConfiguration>(string.Empty)
.FirstOrDefault(asset => asset != null);
/// <summary>
/// Creates a new instance of <see cref="OpenAISettings"/> with provided <see cref="configuration"/>.
/// </summary>
/// <param name="configuration"><see cref="OpenAIConfiguration"/>.</param>
public OpenAISettings(OpenAIConfiguration configuration)
{
if (configuration == null)
{
Debug.LogWarning($"You can speed this up by passing a {nameof(OpenAIConfiguration)} to the {nameof(OpenAISettings)}.ctr");
configuration = Resources.LoadAll<OpenAIConfiguration>(string.Empty).FirstOrDefault(asset => asset != null);
}

if (config != null)
if (configuration == null)
{
if (config.UseAzureOpenAI)
{
Info = new OpenAISettingsInfo(config.ResourceName, config.DeploymentId, config.ApiVersion, config.UseAzureActiveDirectory);
cachedDefault = new OpenAISettings(Info);
}
else
{
Info = new OpenAISettingsInfo(domain: config.ProxyDomain, apiVersion: config.ApiVersion);
cachedDefault = new OpenAISettings(Info);
}
throw new MissingReferenceException($"Failed to find a valid {nameof(OpenAIConfiguration)}!");
}

if (configuration.UseAzureOpenAI)
{
Info = new OpenAISettingsInfo(configuration.ResourceName, configuration.DeploymentId, configuration.ApiVersion, configuration.UseAzureActiveDirectory);
cachedDefault = this;
}
else
{
Info = new OpenAISettingsInfo();
cachedDefault = new OpenAISettings(Info);
Info = new OpenAISettingsInfo(domain: configuration.ProxyDomain, apiVersion: configuration.ApiVersion);
cachedDefault = this;
}
}

/// <summary>
/// Creates a new instance of <see cref="OpenAISettings"/> with the provided <see cref="OpenAISettingsInfo"/>.
/// Creates a new instance of <see cref="OpenAISettings"/> with the provided <see cref="settingsInfo"/>.
/// </summary>
/// <param name="settingsInfo"></param>
/// <param name="settingsInfo"><see cref="OpenAISettingsInfo"/>.</param>
public OpenAISettings(OpenAISettingsInfo settingsInfo)
=> Info = settingsInfo;
{
Info = settingsInfo;
cachedDefault = this;
}

/// <summary>
/// Creates a new instance of <see cref="OpenAISettings"/> for use with OpenAI.
/// Creates a new instance of <see cref="OpenAISettings"/>.
/// </summary>
/// <param name="domain">Base api domain.</param>
/// <param name="apiVersion">The version of the OpenAI api you want to use.</param>
public OpenAISettings(string domain, string apiVersion = OpenAISettingsInfo.DefaultOpenAIApiVersion)
=> Info = new OpenAISettingsInfo(domain, apiVersion);
{
Info = new OpenAISettingsInfo(domain, apiVersion);
cachedDefault = this;
}

/// <summary>
/// Creates a new instance of the <see cref="OpenAISettings"/> for use with Azure OpenAI.<br/>
Expand All @@ -70,13 +84,16 @@ public OpenAISettings(string domain, string apiVersion = OpenAISettingsInfo.Defa
/// Optional, set to true if you want to use Azure Active Directory for Authentication.
/// </param>
public OpenAISettings(string resourceName, string deploymentId, string apiVersion = OpenAISettingsInfo.DefaultAzureApiVersion, bool useActiveDirectoryAuthentication = false)
=> Info = new OpenAISettingsInfo(resourceName, deploymentId, apiVersion, useActiveDirectoryAuthentication);
{
Info = new OpenAISettingsInfo(resourceName, deploymentId, apiVersion, useActiveDirectoryAuthentication);
cachedDefault = this;
}

private static OpenAISettings cachedDefault;

public static OpenAISettings Default
{
get => cachedDefault ?? new OpenAISettings();
get => cachedDefault ??= new OpenAISettings(configuration: null);
internal set => cachedDefault = value;
}

Expand Down
24 changes: 0 additions & 24 deletions OpenAI/Packages/com.openai.unity/Runtime/BaseResponse.cs

This file was deleted.

4 changes: 2 additions & 2 deletions OpenAI/Packages/com.openai.unity/Runtime/Chat/ChatEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public async Task<ChatResponse> GetCompletionAsync(ChatRequest chatRequest, Canc

var response = await Rest.PostAsync(GetUrl("/completions"), payload, new RestParameters(client.DefaultRequestHeaders), cancellationToken);
response.Validate(EnableDebug);
return response.DeserializeResponse<ChatResponse>(response.Body);
return response.Deserialize<ChatResponse>(response.Body, client);
}

/// <summary>
Expand Down Expand Up @@ -83,7 +83,7 @@ public async Task<ChatResponse> StreamCompletionAsync(ChatRequest chatRequest, A
}, new RestParameters(client.DefaultRequestHeaders), cancellationToken);
response?.Validate(EnableDebug);
if (chatResponse == null) { return null; }
chatResponse.SetResponseData(response);
chatResponse.SetResponseData(response, client);
resultHandler?.Invoke(chatResponse);
return chatResponse;
}
Expand Down
2 changes: 1 addition & 1 deletion OpenAI/Packages/com.openai.unity/Runtime/Chat/Choice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public Choice() { }
public override string ToString() => Message?.Content?.ToString() ?? Delta?.Content ?? string.Empty;

[Preserve]
public static implicit operator string(Choice choice) => choice.ToString();
public static implicit operator string(Choice choice) => choice?.ToString();

[Preserve]
internal void CopyFrom(Choice other)
Expand Down
Loading

0 comments on commit f9ed115

Please sign in to comment.