Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenHodgson committed Jun 20, 2021
1 parent 5934fb6 commit c95decd
Show file tree
Hide file tree
Showing 74 changed files with 2,678 additions and 50 deletions.
Binary file added 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.
2 changes: 1 addition & 1 deletion Editor/AssemblyInfo.cs.meta

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

8 changes: 0 additions & 8 deletions Editor/ExampleEditor.cs

This file was deleted.

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

using System.IO;
using UnityEditor;

namespace OpenAI.Editor
{
[CustomEditor(typeof(OpenAIConfigurationSettings))]
internal class OpenAIConfigurationSettingsInspector : UnityEditor.Editor
{
private void OnEnable()
{
var update = false;
var currentPath = AssetDatabase.GetAssetPath(target);

if (string.IsNullOrWhiteSpace(currentPath))
{
return;
}

if (!Directory.Exists("Assets/Resources"))
{
Directory.CreateDirectory("Assets/Resources");
update = true;
}

if (!currentPath.Contains("Resources"))
{
File.Move(Path.GetFullPath(currentPath), Path.GetFullPath($"Assets/Resources/{target.name}.asset"));
File.Move(Path.GetFullPath($"{currentPath}.meta"), Path.GetFullPath($"Assets/Resources/{target.name}.asset.meta"));
update = true;
}

if (update)
{
EditorApplication.delayCall += () =>
{
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
EditorGUIUtility.PingObject(target);
};
}
}
}
}

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

180 changes: 179 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,182 @@

[![openupm](https://img.shields.io/npm/v/com.openai.unity?label=openupm&registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.openai.unity/)

The OpenAI package.
A [OpenAI](https://openai.com/) package for the [Unity](https://unity.com/) Game Engine.

Based on [OpenAI-DotNet](https://github.com/RageAgainstThePixel/OpenAI-DotNet)

## Installing

### Via Unity Package Manager and OpenUPM

- Open your Unity project settings
- Add the OpenUPM package registry:
- `Name: OpenUPM`
- `URL: https://package.openupm.com`
- `Scope(s):`
- `com.opanai`

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

- Open the Unity Package Manager window
- Change the Registry from Unity to `My Registries`
- Add the `OpenAI` package

### Via Unity Package Manager and Git url

- Open your Unity Package Manager
- Add package from git url: `https://github.com/RageAgainstThePixel/com.openai.unity.git#upm`

## Getting started

### Quick Start

Uses the default authentication from the current directory, the default user directory or system environment variables

```csharp
OpenAI api = new OpenAIClient(Engine.Davinci);
```

### Authentication

There are 3 ways to provide your API keys, in order of precedence:

1. Pass keys directly to `Authentication(string key)` constructor
2. Set environment variables
3. Include a config file in the local directory or in your user directory named `.openai` and containing the line:

```shell
OPENAI_KEY=sk-aaaabbbbbccccddddd
```

You use the `Authentication` when you initialize the API as shown:

#### If you want to provide a key manually

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

#### Create a `Authentication` object manually

```chsarp
OpenAI api = new OpenAIClient(new Authentication("sk-secretkey"));
```

#### Use System Environment Variables

> Use `OPENAI_KEY` or `OPENAI_SECRET_KEY` specify a key defined in the system's local environment:
```chsarp
OpenAI api = new OpenAIClient(Authentication LoadFromEnv());
```

#### Load key from specified directory

> Attempts to load api keys from a configuration file, by default `.openai` in the current directory, optionally traversing up the directory tree.
```chsarp
OpenAI api = new OpenAIClient(Authentication.LoadFromDirectory("C:\\MyProject"));;
```

### Completions

The Completion API is accessed via `OpenAI.CompletionEndpoint`:

```csharp
var result = await api.CompletionEndpoint.CreateCompletionAsync("One Two Three One Two", temperature: 0.1, engine: Engine.Davinci);
Console.WriteLine(result);
```

Get the `CompletionResult` (which is mostly metadata), use its implicit string operator to get the text if all you want is the completion choice.

#### Streaming

Streaming allows you to get results are they are generated, which can help your application feel more responsive, especially on slow models like Davinci.

```csharp
var api = new OpenAIClient();
await api.CompletionEndpoint.StreamCompletionAsync(result =>
{
foreach (var choice in result.Completions)
{
Console.WriteLine(choice);
}
}, "My name is Roger and I am a principal software engineer at Salesforce. This is my resume:", max_tokens: 200, temperature: 0.5, presencePenalty: 0.1, frequencyPenalty: 0.1, engine: Engine.Davinci);
```

The result.Completions

Or if using [`IAsyncEnumerable{T}`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iasyncenumerable-1?view=net-5.0) ([C# 8.0+](https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8))

```csharp
var api = new OpenAIClient();
await foreach (var token in api.CompletionEndpoint.StreamCompletionEnumerableAsync("My name is Roger and I am a principal software engineer at Salesforce. This is my resume:", max_tokens: 200, temperature: 0.5, presencePenalty: 0.1, frequencyPenalty: 0.1, engine: Engine.Davinci))
{
Console.Write(token);
}
```

### Document Search

The Search API is accessed via `OpenAI.SearchEndpoint`:

#### You can get all results as a dictionary using

```csharp
var api = new OpenAIClient();
string query = "Washington DC";
string[] documents = { "Canada", "China", "USA", "Spain" };

Dictionary<string, double> results = await api.SearchEndpoint.GetSearchResultsAsync(query, documents, Engine.Curie);
// result["USA"] == 294.22
// result["Spain"] == 73.81
```

> The returned dictionary maps documents to scores.
#### You can get only the best match using

```csharp
var api = new OpenAIClient();
string query = "Washington DC";
string[] documents = { "Canada", "China", "USA", "Spain" };
string result = await api.SearchEndpoint.GetBestMatchAsync(query, documents, Engine.Curie);
// result == "USA"
```

> The returned document result string.
#### And if you only want the best match but still want to know the score, use

```csharp
var api = new OpenAIClient();
string query = "Washington DC";
string[] documents = { "Canada", "China", "USA", "Spain" };
Tuple<string, double> result = await await api.SearchEndpoint.GetBestMatchWithScoreAsync(query, documents, Engine.Curie);
// (result, score) == "USA", 294.22
```

> returned Tuple result with score
### Classifications

The Classification API is accessed via `OpenAI.ClassificationEndpoint`:

Given a query and a set of labeled examples, the model will predict the most likely label for the query.

```csharp
var api = new OpenAIClient();

string query = "It is a raining day :(";
string[] labels = { "Positive", "Negative", "Neutral" };
Dictionary<string, string> examples = new Dictionary<string, string>
{
{ "A happy moment", "Positive" },
{ "I am sad.", "Negative" },
{ "I am feeling awesome", "Positive"}
};

var result = await api.ClassificationEndpoint.CreateClassificationAsync(new ClassificationRequest(query, examples, labels));
// result.Label == "Negative"
```
8 changes: 8 additions & 0 deletions Runtime/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System.Runtime.CompilerServices;
using UnityEngine.Scripting;

[assembly: Preserve]
[assembly: AlwaysLinkAssembly]
[assembly: InternalsVisibleTo("OpenAI.Editor")]
[assembly: InternalsVisibleTo("OpenAI.Tests")]
2 changes: 1 addition & 1 deletion Runtime/AssemblyInfo.cs.meta

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

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

namespace OpenAI
{
public abstract class BaseEndPoint
{
protected readonly OpenAIClient Api;

/// <summary>
/// Constructor of the api endpoint.
/// Rather than instantiating this yourself, access it through an instance of <see cref="OpenAIClient"/>.
/// </summary>
internal BaseEndPoint(OpenAIClient api) => Api = api;

/// <summary>
/// Gets the basic endpoint url for the API
/// </summary>
/// <param name="engine">Optional, Engine to use for endpoint.</param>
/// <returns>The completed basic url for the endpoint.</returns>
protected abstract string GetEndpoint(Engine engine = null);
}
}

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

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

using System;

namespace OpenAI
{
public abstract class BaseResponse
{
/// <summary>
/// The server-side processing time as reported by the API. This can be useful for debugging where a delay occurs.
/// </summary>
public TimeSpan ProcessingTime { get; internal set; }

/// <summary>
/// The organization associated with the API request, as reported by the API.
/// </summary>
public string Organization { get; internal set; }

/// <summary>
/// The request id of this API call, as reported in the response headers. This may be useful for troubleshooting or when contacting OpenAI support in reference to a specific request.
/// </summary>
public string RequestId { get; internal set; }
}
}
11 changes: 11 additions & 0 deletions Runtime/BaseResponse.cs.meta

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

8 changes: 8 additions & 0 deletions Runtime/Classifications.meta

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

Loading

0 comments on commit c95decd

Please sign in to comment.