38 Commits

Author SHA1 Message Date
Theo Kanning 48cd7272f7 Bump version to 0.8.1 (#43) 2022-12-04 13:41:14 -06:00
Theo Kanning 1600841a58 Update lombok to 1.18.24 (#42)
Not sure why I never had compiling issues and others did, but I see no reason not to update this.
2022-12-04 12:55:17 -06:00
Theo Kanning 8d7f240010 Add logit bias parameter to CompletionRequest (#41) 2022-12-04 12:49:26 -06:00
Theo Kanning c76923926e Remove deprecated endpoints from example project (#40)
The engine APIs are deprecated, and OpenAI will shut them down eventually
2022-12-04 12:44:30 -06:00
Robin Glauser 0caab13666 Updating example to not use new api (#33) 2022-12-04 12:39:31 -06:00
Theo Kanning 5e14d4f62b Add usage data to Completion and Embedding APIs (#39)
Also changed EditResult to use the new shared object
2022-12-04 12:37:28 -06:00
Theo Kanning 83df513ddc Bump version to 0.8.0 (#29) 2022-08-22 14:32:40 -05:00
Theo Kanning 515a5fc47d Add deprecation info to README (#28)
Answers, Classifications, Searchs, and old v1/engine endpoints are all deprecated.
2022-08-22 14:29:42 -05:00
Theo Kanning 553e22fea2 Add Model support and new v1 endpoints (#27)
The old endpoints are marked as deprecated
Also marked response fields as public for easier access
2022-08-22 13:55:20 -05:00
Theo Kanning 252db27577 Update EditResult and fix the Edit test (#26)
OpenAI's example curl used an invalid engine, and the api returned a confusing error message.
Now everything works with text-davinci-edit-001
2022-08-19 11:05:12 -05:00
Theo Kanning ff06ffb309 Mark Answer, Completion, and Search APIs as deprecated (#25)
OpenAI has officially deprecated these APIs, but I'll leave them in as long as the endpoints still work
The engines api is also deprecated, but I'll get to that when I add
model support.
2022-08-19 10:49:22 -05:00
Theo Kanning d1f274800a Add moderation support (#24)
Adding support for the new Moderations api https://beta.openai.com/docs/guides/moderation

Fixes https://github.com/TheoKanning/openai-java/issues/20
2022-08-19 10:32:33 -05:00
Theo Kanning 77219d497b Add user to CompletionRequest (#23)
Fixes https://github.com/TheoKanning/openai-java/issues/19
2022-08-19 09:44:38 -05:00
Jacek Lipiec 1391f4074d Fix typo in the LICENSE.md (#22)
As I assume it was by mistake; functionally it wasn't a MIT license :)
2022-08-19 09:31:56 -05:00
Theo Kanning 6f5a4ada76 Update version to 0.7.0 (#18) 2022-06-29 11:54:30 -05:00
Theo Kanning 4d5878db07 Add OpenAiService constructor that takes timeout parameter (#17)
If certain engines are timing out regularly, then OpenAiService needs a timeout parameter.
I also added a constructor that takes an OpenAiApi, and this will allow users to customize their api settings much more easily.

If we need more parameters later, I might add a builder for OpenAiService.

Based on feedback in https://github.com/TheoKanning/openai-java/issues/5
2022-06-29 11:43:29 -05:00
Theo Kanning 9e0a26b576 Update to version 0.6.0 (#16) 2022-04-28 16:53:41 -05:00
Theo Kanning bcfb5da378 Add supported apis to readme (#15) 2022-04-28 16:50:15 -05:00
Theo Kanning 7f39df6e0b Add Edit request functionality (#14) 2022-04-28 16:48:33 -05:00
Theo Kanning 900e13bbda Add embeddings support (#13) 2022-04-28 16:42:13 -05:00
Theo Kanning 9f5b64b151 Add answer support (#12) 2022-04-28 16:20:15 -05:00
Theo Kanning 103c34da94 Add classification support (#11) 2022-04-28 15:55:27 -05:00
Theo Kanning ed2f1152e8 Add more tests and run them before each merge (#10)
These tests are very basic sanity checks
2022-04-28 14:49:54 -05:00
Theo Kanning d3074e113e Fix build action trigger (#9) 2022-04-28 14:19:42 -05:00
Theo Kanning 4dd974cf98 Switch to publishing plugin (#8)
This should make publishing from CI easier from now on
2022-04-28 14:19:36 -05:00
Theo Kanning 9a05c6ac77 Add file and fine-tune api support (#6) 2022-04-19 18:50:44 -05:00
Theo Kanning d410abe1b5 Update badge to show maven central 2021-03-09 21:31:03 -06:00
Theo Kanning b10b9c30f2 Fix CI build
Failed because everything in gradle.properties is only available locally
2021-03-09 21:28:16 -06:00
Theo Kanning 217116b819 Publish to OSSRH instead of Bintray (#4) 2021-03-09 20:52:48 -06:00
Theo Kanning cdfceb0783 Fix readme links 2021-03-01 09:31:39 -06:00
Theo Kanning c14c98c915 Update Readme
Fixed typo
2020-10-07 09:47:48 -05:00
Theo Kanning 9529928f0a Update Readme
Changed badge color from that ugly orange to a nice green
2020-10-07 09:43:04 -05:00
Theo Kanning 70019fa7bb Update Readme
Added version badge and download instructions
2020-10-07 09:38:16 -05:00
Theo Kanning fe48e8cfc3 Add sources and javadocs jars to published artifacts
JCenter requires these
2020-10-06 18:14:35 -05:00
Theo Kanning a893f80b75 Use release tag without prefixes
https://github.community/t/getting-release-details-from-within-an-actions-run/17552
Also fixed BINTRAY_KEY secret
2020-10-05 19:02:04 -05:00
Theo Kanning 4141fb942a Send library version via command line 2020-10-05 18:49:57 -05:00
Theo Kanning 3fdc96d6a5 Fix publish.yml
Now it will call the correct task and only fire once per release
2020-10-05 18:35:44 -05:00
Theo Kanning 4e070027c4 Add github action to publish artifacts after a release 2020-10-05 18:26:56 -05:00
60 changed files with 2120 additions and 208 deletions
-26
View File
@@ -1,26 +0,0 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Java CI with Gradle
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
+31
View File
@@ -0,0 +1,31 @@
name: Publish
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Test
run: ./gradlew test
env:
OPENAI_TOKEN: ${{ secrets.OPENAI_TOKEN }}
- name: Publish
run: ./gradlew build publish
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_KEY_PASSWORD }}
+24
View File
@@ -0,0 +1,24 @@
name: Test
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Test
run: ./gradlew test --stacktrace
env:
OPENAI_TOKEN: ${{ secrets.OPENAI_TOKEN }}
+1 -1
View File
@@ -1,4 +1,4 @@
T License
MIT License
Copyright (c) [year] [fullname]
+45 -7
View File
@@ -1,27 +1,58 @@
![Maven Central](https://img.shields.io/maven-central/v/com.theokanning.openai-gpt3-java/client?color=blue)
> ⚠️The [Answers](https://help.openai.com/en/articles/6233728-answers-transition-guide),
>[Classifications](https://help.openai.com/en/articles/6272941-classifications-transition-guide),
>and [Searches](https://help.openai.com/en/articles/6272952-search-transition-guide) APIs are deprecated,
>and will stop working on December 3rd, 2022.
> ⚠️OpenAI has deprecated all Engine-based APIs. See [Deprecated Endpoints](https://github.com/TheoKanning/openai-java#deprecated-endpoints) below for more info.
# OpenAI-Java
Java libraries for using OpenAI's GPT-3 api.
Includes the following artifacts:
- `api` : request/response POJOs for the GPT-3 engine, completion, and search APIs.
- `client` : a basic retrofit client for the GPT-3 endpoints
- `client` : a basic retrofit client for the GPT-3 endpoints, includes the `api` module
as well as an example project using the client.
## Supported APIs
- [Models](https://beta.openai.com/docs/api-reference/models)
- [Completions](https://beta.openai.com/docs/api-reference/completions)
- [Edits](https://beta.openai.com/docs/api-reference/edits)
- [Embeddings](https://beta.openai.com/docs/api-reference/embeddings)
- [Files](https://beta.openai.com/docs/api-reference/files)
- [Fine-tunes](https://beta.openai.com/docs/api-reference/fine-tunes)
- [Moderations](https://beta.openai.com/docs/api-reference/moderations)
#### Deprecated by OpenAI
- [Searches](https://beta.openai.com/docs/api-reference/searches)
- [Classifications](https://beta.openai.com/docs/api-reference/classifications)
- [Answers](https://beta.openai.com/docs/api-reference/answers)
- [Engines](https://beta.openai.com/docs/api-reference/engines)
## Usage
### Importing into a gradle project
`implementation 'com.theokanning.openai-gpt3-java:api:<version>'`
or
`implementation 'com.theokanning.openai-gpt3-java:client:<version>'`
### Using OpenAiService
If you're looking for the fastest solution, import the `client` and use [OpenAiService](client/src/main/java/openai/OpenAiService.java).
If you're looking for the fastest solution, import the `client` and use [OpenAiService](client/src/main/java/com/theokanning/openai/OpenAiService.java).
```
OpenAiService service = new OpenAiService(your_token)
OpenAiService service = new OpenAiService("your_token");
CompletionRequest completionRequest = CompletionRequest.builder()
.prompt("Somebody once told me the world is gonna roll me")
.model("ada")
.echo(true)
.build();
service.createCompletion("ada", completionRequest).getChoices().forEach(System.out::println);
service.createCompletion(completionRequest).getChoices().forEach(System.out::println);
```
### Using OpenAiApi Retrofit client
If you're using retrofit, you can import the `client` module and use the [OpenAiApi](client/src/main/java/openai/OpenAiApi.java).
You'll have to add your auth token as a header (see [AuthenticationInterceptor](client/src/main/java/openai/AuthenticationInterceptor.java))
If you're using retrofit, you can import the `client` module and use the [OpenAiApi](client/src/main/java/com/theokanning/openai/OpenAiApi.java).
You'll have to add your auth token as a header (see [AuthenticationInterceptor](client/src/main/java/com/theokanning/openai/AuthenticationInterceptor.java))
and set your converter factory to use snake case and only include non-null fields.
### Using data classes only
@@ -35,5 +66,12 @@ export OPENAI_TOKEN="sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
./gradlew example:run
```
## Deprecated Endpoints
OpenAI has deprecated engine-based endpoints in favor of model-based endpoints.
For example, instead of using `v1/engines/{engine_id}/completions`, switch to `v1/completions` and specify the model in the `CompletionRequest`.
The code includes upgrade instructions for all deprecated endpoints.
I won't remove the old endpoints from this library until OpenAI shuts them down.
## License
Published under the MIT License
Published under the MIT License
+7 -59
View File
@@ -1,65 +1,13 @@
apply plugin: 'java-library'
apply plugin: 'com.jfrog.bintray'
apply plugin: 'maven-publish'
apply plugin: "com.vanniktech.maven.publish"
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.12'
annotationProcessor 'org.projectlombok:lombok:1.18.12'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.9.0'
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
}
ext {
libraryVersion = '0.2.0'
compileJava {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
version = libraryVersion
group = 'com.theokanning.openai-gpt3-java'
publishing {
publications {
ApiPublication(MavenPublication) {
from components.java
groupId project.group
artifactId 'api'
version libraryVersion
pom {
description = 'POJOs for the OpenAI GPT-3 API'
name = 'api'
url = 'https://github.com/theokanning/openai-java'
developers {
developer {
id = "theokanning"
name = "Theo Kanning"
email = "theokanning@gmail.com"
}
}
scm {
url = "https://github.com/theokanning/openai-java"
}
licenses {
license {
name = "The MIT License"
url = "https://www.mit.edu/~amini/LICENSE.md"
distribution = "repo"
}
}
}
}
}
}
bintray {
user = System.getenv("BINTRAY_USER")
key = System.getenv("BINTRAY_KEY")
publications = ['ApiPublication']
pkg {
repo = 'openai-gpt3-java'
name = 'api'
vcsUrl = 'https://github.com/TheoKanning/openai-java.git'
licenses = ["MIT"]
publish = false
version {
name = libraryVersion
}
}
}
+3
View File
@@ -0,0 +1,3 @@
POM_ARTIFACT_ID=api
POM_NAME=api
POM_DESCRIPTION=Basic java objects for the OpenAI GPT-3 API
@@ -0,0 +1,24 @@
package com.theokanning.openai;
import lombok.Data;
/**
* A response when deleting an object
*/
@Data
public class DeleteResult {
/**
* The id of the object.
*/
String id;
/**
* The type of object deleted, for example "file" or "model"
*/
String object;
/**
* True if successfully deleted
*/
boolean deleted;
}
@@ -0,0 +1,24 @@
package com.theokanning.openai;
import lombok.Data;
/**
* The OpenAI resources used by a request
*/
@Data
public class Usage {
/**
* The number of prompt tokens used.
*/
long promptTokens;
/**
* The number of completion tokens used.
*/
long completionTokens;
/**
* The number of total tokens used
*/
long totalTokens;
}
@@ -0,0 +1,141 @@
package com.theokanning.openai.answer;
import lombok.*;
import java.util.List;
import java.util.Map;
/**
* Given a question, a set of documents, and some examples, the API generates an answer to the question based
* on the information in the set of documents. This is useful for question-answering applications on sources of truth,
* like company documentation or a knowledge base.
*
* Documentation taken from
* https://beta.openai.com/docs/api-reference/answers/create
*/
@Deprecated
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class AnswerRequest {
/**
* ID of the engine to use for completion.
*/
@NonNull
String model;
/**
* Question to get answered.
*/
@NonNull
String question;
/**
* List of (question, answer) pairs that will help steer the model towards the tone and answer format you'd like.
* We recommend adding 2 to 3 examples.
*/
@NonNull
List<List<String>> examples;
/**
* A text snippet containing the contextual information used to generate the answers for the examples you provide.
*/
@NonNull
String examplesContext;
/**
* List of documents from which the answer for the input question should be derived.
* If this is an empty list, the question will be answered based on the question-answer examples.
*
* You should specify either documents or a file, but not both.
*/
List<String> documents;
/**
* The ID of an uploaded file that contains documents to search over.
* See upload file for how to upload a file of the desired format and purpose.
*
* You should specify either documents or file, but not both.
*/
String file;
/**
* ID of the engine to use for Search. You can select one of ada, babbage, curie, or davinci.
*/
String searchModel;
/**
* The maximum number of documents to be ranked by Search when using file.
* Setting it to a higher value leads to improved accuracy but with increased latency and cost.
*/
Integer maxRerank;
/**
* What sampling temperature to use. Higher values means the model will take more risks.
* Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer.
*
* We generally recommend using this or {@link top_p} but not both.
*/
Double temperature;
/**
* Include the log probabilities on the logprobs most likely tokens, as well the chosen tokens.
* For example, if logprobs is 10, the API will return a list of the 10 most likely tokens.
* The API will always return the logprob of the sampled token,
* so there may be up to logprobs+1 elements in the response.
*/
Integer logprobs;
/**
* The maximum number of tokens allowed for the generated answer.
*/
Integer maxTokens;
/**
* Up to 4 sequences where the API will stop generating further tokens.
* The returned text will not contain the stop sequence.
*/
List<String> stop;
/**
* How many answers to generate for each question.
*/
Integer n;
/**
* Modify the likelihood of specified tokens appearing in the completion.
*
* Accepts a json object that maps tokens (specified by their token ID in the GPT tokenizer) to an
* associated bias value from -100 to 100.
*/
Map<String, Double> logitBias;
/**
* A special boolean flag for showing metadata.
* If set to true, each document entry in the returned JSON will contain a "metadata" field.
*
* This flag only takes effect when file is set.
*/
Boolean returnMetadata;
/**
* If set to true, the returned JSON will include a "prompt" field containing the final prompt that was
* used to request a completion. This is mainly useful for debugging purposes.
*/
Boolean returnPrompt;
/**
* If an object name is in the list, we provide the full information of the object;
* otherwise, we only provide the object ID.
*
* Currently we support completion and file objects for expansion.
*/
List<String> expand;
/**
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
*/
String user;
}
@@ -0,0 +1,44 @@
package com.theokanning.openai.answer;
import lombok.Data;
import java.util.List;
/**
* An object containing a response from the answer api
*
* https://beta.openai.com/docs/api-reference/answers/create
*/
@Deprecated
@Data
public class AnswerResult {
/**
* A list of generated answers to the provided question/
*/
List<String> answers;
/**
* A unique id assigned to this completion
*/
String completion;
/**
* The GPT-3 model used for completion
*/
String model;
/**
* The type of object returned, should be "answer"
*/
String object;
/**
* The GPT-3 model used for search
*/
String searchModel;
/**
* A list of the most relevant documents for the question.
*/
List<Document> selectedDocuments;
}
@@ -0,0 +1,22 @@
package com.theokanning.openai.answer;
import lombok.Data;
/**
* Represents an example returned by the classification api
*
* https://beta.openai.com/docs/api-reference/classifications/create
*/
@Deprecated
@Data
public class Document {
/**
* The position of this example in the example list
*/
Integer document;
/**
* The text of the example
*/
String text;
}
@@ -0,0 +1,121 @@
package com.theokanning.openai.classification;
import lombok.*;
import java.util.List;
import java.util.Map;
/**
* A request for OpenAi to classify text based on provided examples
* All fields are nullable.
*
* Documentation taken from
* https://beta.openai.com/docs/api-reference/classifications/create
*/
@Deprecated
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class ClassificationRequest {
/**
* ID of the engine to use for completion
*/
@NonNull
String model;
/**
* Query to be classified
*/
@NonNull
String query;
/**
* A list of examples with labels, in the following format:
*
* [["The movie is so interesting.", "Positive"], ["It is quite boring.", "Negative"], ...]
*
* All the label strings will be normalized to be capitalized.
*
* You should specify either examples or file, but not both.
*/
List<List<String>> examples;
/**
* The ID of the uploaded file that contains training examples.
* See upload file for how to upload a file of the desired format and purpose.
*
* You should specify either examples or file, but not both.
*/
String file;
/**
* The set of categories being classified.
* If not specified, candidate labels will be automatically collected from the examples you provide.
* All the label strings will be normalized to be capitalized.
*/
List<String> labels;
/**
* ID of the engine to use for Search. You can select one of ada, babbage, curie, or davinci.
*/
String searchModel;
/**
* What sampling temperature to use. Higher values means the model will take more risks.
* Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer.
*
* We generally recommend using this or {@link top_p} but not both.
*/
Double temperature;
/**
* Include the log probabilities on the logprobs most likely tokens, as well the chosen tokens.
* For example, if logprobs is 10, the API will return a list of the 10 most likely tokens.
* The API will always return the logprob of the sampled token,
* so there may be up to logprobs+1 elements in the response.
*/
Integer logprobs;
/**
* The maximum number of examples to be ranked by Search when using file.
* Setting it to a higher value leads to improved accuracy but with increased latency and cost.
*/
Integer maxExamples;
/**
* Modify the likelihood of specified tokens appearing in the completion.
*
* Accepts a json object that maps tokens (specified by their token ID in the GPT tokenizer) to an
* associated bias value from -100 to 100.
*/
Map<String, Double> logitBias;
/**
* If set to true, the returned JSON will include a "prompt" field containing the final prompt that was
* used to request a completion. This is mainly useful for debugging purposes.
*/
Boolean returnPrompt;
/**
* A special boolean flag for showing metadata.
* If set to true, each document entry in the returned JSON will contain a "metadata" field.
*
* This flag only takes effect when file is set.
*/
Boolean returnMetadata;
/**
* If an object name is in the list, we provide the full information of the object;
* otherwise, we only provide the object ID.
*
* Currently we support completion and file objects for expansion.
*/
List<String> expand;
/**
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
*/
String user;
}
@@ -0,0 +1,45 @@
package com.theokanning.openai.classification;
import lombok.Data;
import java.util.List;
/**
* An object containing a response from the classification api
* <
* https://beta.openai.com/docs/api-reference/classifications/create
*/
@Deprecated
@Data
public class ClassificationResult {
/**
* A unique id assigned to this completion
*/
String completion;
/**
* The predicted label for the query text.
*/
String label;
/**
* The GPT-3 model used for completion
*/
String model;
/**
* The type of object returned, should be "classification"
*/
String object;
/**
* The GPT-3 model used for search
*/
String searchModel;
/**
* A list of the most relevant examples for the query text.
*/
List<Example> selectedExamples;
}
@@ -0,0 +1,27 @@
package com.theokanning.openai.classification;
import lombok.Data;
/**
* Represents an example returned by the classification api
*
* https://beta.openai.com/docs/api-reference/classifications/create
*/
@Deprecated
@Data
public class Example {
/**
* The position of this example in the example list
*/
Integer document;
/**
* The label of the example
*/
String label;
/**
* The text of the example
*/
String text;
}
@@ -5,7 +5,7 @@ import lombok.Data;
/**
* A completion generated by GPT-3
*
* https://beta.openai.com/docs/api-reference/create-completion
* https://beta.openai.com/docs/api-reference/completions/create
*/
@Data
public class CompletionChoice {
@@ -6,13 +6,13 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
/**
* A request for OpenAi to generate a predicted completion for a prompt.
* All fields are nullable.
*
* Documentation taken from
* https://beta.openai.com/docs/api-reference/create-completion
* https://beta.openai.com/docs/api-reference/completions/create
*/
@Builder
@NoArgsConstructor
@@ -20,6 +20,12 @@ import java.util.List;
@Data
public class CompletionRequest {
/**
* The name of the model to use.
* Required if specifying a fine tuned model or if using the new v1/completions endpoint.
*/
String model;
/**
* An optional prompt to complete from
*/
@@ -36,7 +42,7 @@ public class CompletionRequest {
* What sampling temperature to use. Higher values means the model will take more risks.
* Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer.
*
* We generally recommend using this or {@link top_p} but not both.
* We generally recommend using this or {@link CompletionRequest#topP} but not both.
*/
Double temperature;
@@ -45,7 +51,7 @@ public class CompletionRequest {
* the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are
* considered.
*
* We generally recommend using this or {@link temperature} but not both.
* We generally recommend using this or {@link CompletionRequest#temperature} but not both.
*/
Double topP;
@@ -53,7 +59,7 @@ public class CompletionRequest {
* How many completions to generate for each prompt.
*
* Because this parameter generates many completions, it can quickly consume your token quota.
* Use carefully and ensure that you have reasonable settings for {@link max_tokens} and {@link stop}.
* Use carefully and ensure that you have reasonable settings for {@link CompletionRequest#maxTokens} and {@link CompletionRequest#stop}.
*/
Integer n;
@@ -100,8 +106,22 @@ public class CompletionRequest {
* (the one with the lowest log probability per token).
* Results cannot be streamed.
*
* When used with {@link n}, best_of controls the number of candidate completions and n specifies how many to return,
* When used with {@link CompletionRequest#n}, best_of controls the number of candidate completions and n specifies how many to return,
* best_of must be greater than n.
*/
Integer bestOf;
/**
* Modify the likelihood of specified tokens appearing in the completion.
*
* Maps tokens (specified by their token ID in the GPT tokenizer) to an associated bias value from -100 to 100.
*
* https://beta.openai.com/docs/api-reference/completions/create#completions/create-logit_bias
*/
Map<String, Integer> logitBias;
/**
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
*/
String user;
}
@@ -1,5 +1,6 @@
package com.theokanning.openai.completion;
import com.theokanning.openai.Usage;
import lombok.Data;
import java.util.List;
@@ -7,12 +8,12 @@ import java.util.List;
/**
* An object containing a response from the completion api
*
* https://beta.openai.com/docs/api-reference/create-completion
* https://beta.openai.com/docs/api-reference/completions/create
*/
@Data
public class CompletionResult {
/**
* A unique id assigned to this completion
* A unique id assigned to this completion.
*/
String id;
@@ -22,17 +23,22 @@ public class CompletionResult {
String object;
/**
* The creation time in epoch milliseconds.
* The creation time in epoch seconds.
*/
long created;
/**
* The GPT-3 model used
* The GPT-3 model used.
*/
String model;
/**
* A list of generated completions
* A list of generated completions.
*/
List<CompletionChoice> choices;
/**
* The API usage for this request
*/
Usage usage;
}
@@ -0,0 +1,22 @@
package com.theokanning.openai.edit;
import lombok.Data;
/**
* An edit generated by GPT-3
*
* https://beta.openai.com/docs/api-reference/edits/create
*/
@Data
public class EditChoice {
/**
* The edited text.
*/
String text;
/**
* This index of this completion in the returned list.
*/
Integer index;
}
@@ -0,0 +1,57 @@
package com.theokanning.openai.edit;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
/**
* Given a prompt and an instruction, OpenAi will return an edited version of the prompt
*
* https://beta.openai.com/docs/api-reference/edits/create
*/
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class EditRequest {
/**
* The name of the model to use.
* Required if using the new v1/edits endpoint.
*/
String model;
/**
* The input text to use as a starting point for the edit.
*/
String input;
/**
* The instruction that tells the model how to edit the prompt.
* For example, "Fix the spelling mistakes"
*/
@NonNull
String instruction;
/**
* How many edits to generate for the input and instruction.
*/
Integer n;
/**
* What sampling temperature to use. Higher values means the model will take more risks.
* Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer.
*
* We generally recommend altering this or {@link EditRequest#topP} but not both.
*/
Double temperature;
/**
* An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of
* the tokens with top_p probability mass.So 0.1 means only the tokens comprising the top 10% probability mass are
* considered.
*
* We generally recommend altering this or {@link EditRequest#temperature} but not both.
*/
@JsonProperty("top_p")
Double topP;
}
@@ -0,0 +1,35 @@
package com.theokanning.openai.edit;
import com.theokanning.openai.Usage;
import lombok.Data;
import java.util.List;
/**
* A list of edits generated by GPT-3
*
* https://beta.openai.com/docs/api-reference/edits/create
*/
@Data
public class EditResult {
/**
* The type of object returned, should be "edit"
*/
public String object;
/**
* The creation time in epoch milliseconds.
*/
public long created;
/**
* A list of generated edits.
*/
public List<EditChoice> choices;
/**
* The API usage for this request
*/
public Usage usage;
}
@@ -0,0 +1,30 @@
package com.theokanning.openai.edit;
import lombok.Data;
/**
* An object containing the API usage for an edit request
*
* Deprecated, use {@link com.theokanning.openai.Usage} instead
*
* https://beta.openai.com/docs/api-reference/edits/create
*/
@Data
@Deprecated
public class EditUsage {
/**
* The number of prompt tokens consumed.
*/
String promptTokens;
/**
* The number of completion tokens consumed.
*/
String completionTokens;
/**
* The number of total tokens consumed.
*/
String totalTokens;
}
@@ -0,0 +1,29 @@
package com.theokanning.openai.embedding;
import lombok.Data;
import java.util.List;
/**
* Represents an embedding returned by the embedding api
*
* https://beta.openai.com/docs/api-reference/classifications/create
*/
@Data
public class Embedding {
/**
* The type of object returned, should be "embedding"
*/
String object;
/**
* The embedding vector
*/
List<Double> embedding;
/**
* The position of this embedding in the list
*/
Integer index;
}
@@ -0,0 +1,39 @@
package com.theokanning.openai.embedding;
import lombok.*;
import java.util.List;
/**
* Creates an embedding vector representing the input text.
*
* https://beta.openai.com/docs/api-reference/embeddings/create
*/
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class EmbeddingRequest {
/**
* The name of the model to use.
* Required if using the new v1/embeddings endpoint.
*/
String model;
/**
* Input text to get embeddings for, encoded as a string or array of tokens.
* To get embeddings for multiple inputs in a single request, pass an array of strings or array of token arrays.
* Each input must not exceed 2048 tokens in length.
* <p>
* Unless your are embedding code, we suggest replacing newlines (\n) in your input with a single space,
* as we have observed inferior results when newlines are present.
*/
@NonNull
List<String> input;
/**
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
*/
String user;
}
@@ -0,0 +1,35 @@
package com.theokanning.openai.embedding;
import com.theokanning.openai.Usage;
import lombok.Data;
import java.util.List;
/**
* An object containing a response from the answer api
*
* https://beta.openai.com/docs/api-reference/embeddings/create
*/
@Data
public class EmbeddingResult {
/**
* The GPT-3 model used for generating embeddings
*/
String model;
/**
* The type of object returned, should be "list"
*/
String object;
/**
* A list of the calculated embeddings
*/
List<Embedding> data;
/**
* The API usage for this request
*/
Usage usage;
}
@@ -7,6 +7,7 @@ import lombok.Data;
*
* https://beta.openai.com/docs/api-reference/retrieve-engine
*/
@Deprecated
@Data
public class Engine {
/**
@@ -0,0 +1,42 @@
package com.theokanning.openai.file;
import lombok.Data;
/**
* A file uploaded to OpenAi
*
* https://beta.openai.com/docs/api-reference/files
*/
@Data
public class File {
/**
* The unique id of this file.
*/
String id;
/**
* The type of object returned, should be "file".
*/
String object;
/**
* File size in bytes.
*/
Long bytes;
/**
* The creation time in epoch seconds.
*/
Long createdAt;
/**
* The name of the file.
*/
String filename;
/**
* Description of the file's purpose.
*/
String purpose;
}
@@ -0,0 +1,31 @@
package com.theokanning.openai.finetune;
import lombok.Data;
/**
* An object representing an event in the lifecycle of a fine-tuning job
*
* https://beta.openai.com/docs/api-reference/fine-tunes
*/
@Data
public class FineTuneEvent {
/**
* The type of object returned, should be "fine-tune-event".
*/
String object;
/**
* The creation time in epoch seconds.
*/
Long createdAt;
/**
* The log level of this message.
*/
String level;
/**
* The event message.
*/
String message;
}
@@ -0,0 +1,111 @@
package com.theokanning.openai.finetune;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import java.util.List;
/**
* A request for OpenAi to create a fine-tuned model
* All fields except trainingFile are nullable.
*
* https://beta.openai.com/docs/api-reference/fine-tunes/create
*/
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class FineTuneRequest {
/**
* The ID of an uploaded file that contains training data.
*/
@NonNull
String trainingFile;
/**
* The ID of an uploaded file that contains validation data.
*/
String validationFile;
/**
* The name of the base model to fine-tune. You can select one of "ada", "babbage", "curie", or "davinci".
* To learn more about these models, see the Engines documentation.
*/
String model;
/**
* The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset.
*/
Integer nEpochs;
/**
* The batch size to use for training.
* The batch size is the number of training examples used to train a single forward and backward pass.
*
* By default, the batch size will be dynamically configured to be ~0.2% of the number of examples in the training
* set, capped at 256 - in general, we've found that larger batch sizes tend to work better for larger datasets.
*/
Integer batchSize;
/**
* The learning rate multiplier to use for training.
* The fine-tuning learning rate is the original learning rate used for pretraining multiplied by this value.
*
* By default, the learning rate multiplier is the 0.05, 0.1, or 0.2 depending on final batch_size
* (larger learning rates tend to perform better with larger batch sizes).
* We recommend experimenting with values in the range 0.02 to 0.2 to see what produces the best results.
*/
Double learningRateMultiplier;
/**
* The weight to use for loss on the prompt tokens.
* This controls how much the model tries to learn to generate the prompt
* (as compared to the completion which always has a weight of 1.0),
* and can add a stabilizing effect to training when completions are short.
*
* If prompts are extremely long (relative to completions), it may make sense to reduce this weight so as to
* avoid over-prioritizing learning the prompt.
*/
Double promptLossWeight;
/**
* If set, we calculate classification-specific metrics such as accuracy and F-1 score using the validation set
* at the end of every epoch. These metrics can be viewed in the results file.
*
* In order to compute classification metrics, you must provide a validation_file.
* Additionally, you must specify {@link FineTuneRequest#classificationNClasses} for multiclass
* classification or {@link FineTuneRequest#classificationPositiveClass} for binary classification.
*/
Boolean computeClassificationMetrics;
/**
* The number of classes in a classification task.
*
* This parameter is required for multiclass classification.
*/
@JsonProperty("classification_n_classes")
Integer classificationNClasses;
/**
* The positive class in binary classification.
*
* This parameter is needed to generate precision, recall, and F1 metrics when doing binary classification.
*/
String classificationPositiveClass;
/**
* If this is provided, we calculate F-beta scores at the specified beta values.
* The F-beta score is a generalization of F-1 score. This is only used for binary classification.
*
* With a beta of 1 (i.e. the F-1 score), precision and recall are given the same weight.
* A larger beta score puts more weight on recall and less on precision.
* A smaller beta score puts more weight on precision and less on recall.
*/
List<Double> classificationBetas;
/**
* A string of up to 40 characters that will be added to your fine-tuned model name.
*/
String suffix;
}
@@ -0,0 +1,80 @@
package com.theokanning.openai.finetune;
import com.theokanning.openai.file.File;
import lombok.Data;
import java.util.List;
/**
* An object describing an fine-tuned model. Returned by multiple fine-tune requests.
*
* https://beta.openai.com/docs/api-reference/fine-tunes
*/
@Data
public class FineTuneResult {
/**
* The ID of the fine-tuning job.
*/
String id;
/**
* The type of object returned, should be "fine-tune".
*/
String object;
/**
* The name of the base model.
*/
String model;
/**
* The creation time in epoch seconds.
*/
Long createdAt;
/**
* List of events in this job's lifecycle. Null when getting a list of fine-tune jobs.
*/
List<FineTuneEvent> events;
/**
* The ID of the fine-tuned model, null if tuning job is not finished.
* This is the id used to call the model.
*/
String fineTunedModel;
/**
* The specified hyper-parameters for the tuning job.
*/
HyperParameters hyperparams;
/**
* The ID of the organization this model belongs to.
*/
String organizationId;
/**
* Result files for this fine-tune job.
*/
List<File> resultFiles;
/**
* The status os the fine-tune job. "pending", "succeeded", or "cancelled"
*/
String status;
/**
* Training files for this fine-tune job.
*/
List<File> trainingFiles;
/**
* The last update time in epoch seconds.
*/
Long updatedAt;
/**
* Validation files for this fine-tune job.
*/
List<File> validationFiles;
}
@@ -0,0 +1,32 @@
package com.theokanning.openai.finetune;
import lombok.Data;
/**
* Fine-tuning job hyperparameters
*
* https://beta.openai.com/docs/api-reference/fine-tunes
*/
@Data
public class HyperParameters {
/**
* The batch size to use for training.
*/
String batchSize;
/**
* The learning rate multiplier to use for training.
*/
Double learningRateMultiplier;
/**
* The number of epochs to train the model for.
*/
Integer nEpochs;
/**
* The weight to use for loss on the prompt tokens.
*/
Double promptLossWeight;
}
@@ -0,0 +1,43 @@
package com.theokanning.openai.model;
import lombok.Data;
import java.util.List;
/**
* GPT-3 model details
*
* https://beta.openai.com/docs/api-reference/models
*/
@Data
public class Model {
/**
* An identifier for this model, used to specify the model when making completions, etc
*/
public String id;
/**
* The type of object returned, should be "model"
*/
public String object;
/**
* The owner of the GPT-3 model, typically "openai"
*/
public String ownedBy;
/**
* List of permissions for this model
*/
public List<Permission> permission;
/**
* The root model that this and its parent (if applicable) are based on
*/
public String root;
/**
* The parent model that this is based on
*/
public String parent;
}
@@ -0,0 +1,47 @@
package com.theokanning.openai.model;
import lombok.Data;
/**
* GPT-3 model permissions
* I couldn't find documentation for the specific permissions, and I've elected to leave them undocumented rather than
* write something incorrect.
*
* https://beta.openai.com/docs/api-reference/models
*/
@Data
public class Permission {
/**
* An identifier for this model permission
*/
public String id;
/**
* The type of object returned, should be "model_permission"
*/
public String object;
/**
* The creation time in epoch seconds.
*/
public long created;
public boolean allowCreateEngine;
public boolean allowSampling;
public boolean allowLogProbs;
public boolean allowSearchIndices;
public boolean allowView;
public boolean allowFineTuning;
public String organization;
public String group;
public boolean isBlocking;
}
@@ -0,0 +1,30 @@
package com.theokanning.openai.moderation;
import lombok.Data;
/**
* An object containing the moderation data for a single input string
*
* https://beta.openai.com/docs/api-reference/moderations/create
*/
@Data
public class Moderation {
/**
* Set to true if the model classifies the content as violating OpenAI's content policy, false otherwise
*/
public boolean flagged;
/**
* Object containing per-category binary content policy violation flags.
* For each category, the value is true if the model flags the corresponding category as violated, false otherwise.
*/
public ModerationCategories categories;
/**
* Object containing per-category raw scores output by the model, denoting the model's confidence that the
* input violates the OpenAI's policy for the category.
* The value is between 0 and 1, where higher values denote higher confidence.
* The scores should not be interpreted as probabilities.
*/
public ModerationCategoryScores categoryScores;
}
@@ -0,0 +1,34 @@
package com.theokanning.openai.moderation;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.theokanning.openai.completion.CompletionChoice;
import lombok.Data;
import java.util.List;
/**
* An object containing the flags for each moderation category
*
* https://beta.openai.com/docs/api-reference/moderations/create
*/
@Data
public class ModerationCategories {
public boolean hate;
@JsonProperty("hate/threatening")
public boolean hateThreatening;
@JsonProperty("self-harm")
public boolean selfHarm;
public boolean sexual;
@JsonProperty("sexual/minors")
public boolean sexualMinors;
public boolean violence;
@JsonProperty("violence/graphic")
public boolean violenceGraphic;
}
@@ -0,0 +1,31 @@
package com.theokanning.openai.moderation;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* An object containing the scores for each moderation category
*
* https://beta.openai.com/docs/api-reference/moderations/create
*/
@Data
public class ModerationCategoryScores {
public double hate;
@JsonProperty("hate/threatening")
public double hateThreatening;
@JsonProperty("self-harm")
public double selfHarm;
public double sexual;
@JsonProperty("sexual/minors")
public double sexualMinors;
public double violence;
@JsonProperty("violence/graphic")
public double violenceGraphic;
}
@@ -0,0 +1,28 @@
package com.theokanning.openai.moderation;
import lombok.*;
import java.util.List;
/**
* A request for OpenAi to detect if text violates OpenAi's content policy.
*
* https://beta.openai.com/docs/api-reference/moderations/create
*/
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class ModerationRequest {
/**
* The input text to classify.
*/
@NonNull
String input;
/**
* The name of the model to use, defaults to text-moderation-stable.
*/
String model;
}
@@ -0,0 +1,28 @@
package com.theokanning.openai.moderation;
import lombok.Data;
import java.util.List;
/**
* An object containing a response from the moderation api
*
* https://beta.openai.com/docs/api-reference/moderations/create
*/
@Data
public class ModerationResult {
/**
* A unique id assigned to this moderation.
*/
public String id;
/**
* The GPT-3 model used.
*/
public String model;
/**
* A list of moderation scores.
*/
public List<Moderation> results;
}
@@ -12,8 +12,9 @@ import java.util.List;
* GPT-3 will perform a semantic search over the documents and score them based on how related they are to the query.
* Higher scores indicate a stronger relation.
*
* https://beta.openai.com/docs/api-reference/search
* https://beta.openai.com/docs/api-reference/searches
*/
@Deprecated
@Builder
@NoArgsConstructor
@AllArgsConstructor
@@ -5,8 +5,9 @@ import lombok.Data;
/**
* A search result for a single document.
*
* https://beta.openai.com/docs/api-reference/search
* https://beta.openai.com/docs/api-reference/searches
*/
@Deprecated
@Data
public class SearchResult {
/**
+11 -5
View File
@@ -1,15 +1,21 @@
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4"
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.19.0'
}
}
allprojects {
repositories {
jcenter()
mavenCentral()
}
}
plugins.withId("com.vanniktech.maven.publish") {
mavenPublish {
sonatypeHost = "S01"
}
}
}
+9 -55
View File
@@ -1,67 +1,21 @@
apply plugin: 'java-library'
apply plugin: 'com.jfrog.bintray'
apply plugin: 'maven-publish'
apply plugin: "com.vanniktech.maven.publish"
dependencies {
api project(":api")
api 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
implementation 'com.squareup.retrofit2:converter-jackson:2.9.0'
testImplementation(platform('org.junit:junit-bom:5.8.2'))
testImplementation('org.junit.jupiter:junit-jupiter')
}
ext {
libraryVersion = '0.2.0'
compileJava {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
version = libraryVersion
group = 'com.theokanning.openai-gpt3-java'
publishing {
publications {
ClientPublication(MavenPublication) {
from components.java
groupId project.group
artifactId 'client'
version libraryVersion
pom {
description = 'Basic retrofit client for OpenAI\'s GPT-3 API'
name = 'client'
url = 'https://github.com/theokanning/openai-java'
developers {
developer {
id = "theokanning"
name = "Theo Kanning"
email = "theokanning@gmail.com"
}
}
scm {
url = "https://github.com/theokanning/openai-java"
}
licenses {
license {
name = "The MIT License"
url = "https://www.mit.edu/~amini/LICENSE.md"
distribution = "repo"
}
}
}
}
}
test {
useJUnitPlatform()
}
bintray {
user = System.getenv("BINTRAY_USER")
key = System.getenv("BINTRAY_KEY")
publications = ['ClientPublication']
pkg {
repo = 'openai-gpt3-java'
name = 'client'
vcsUrl = 'https://github.com/TheoKanning/openai-java.git'
licenses = ["MIT"]
publish = false
version {
name = libraryVersion
}
}
}
+3
View File
@@ -0,0 +1,3 @@
POM_ARTIFACT_ID=client
POM_NAME=client
POM_DESCRIPTION=Basic retrofit client for OpenAI's GPT-3 API
@@ -1,27 +1,113 @@
package com.theokanning.openai;
import com.theokanning.openai.engine.Engine;
import com.theokanning.openai.search.SearchRequest;
import io.reactivex.Single;
import com.theokanning.openai.answer.AnswerRequest;
import com.theokanning.openai.answer.AnswerResult;
import com.theokanning.openai.classification.ClassificationRequest;
import com.theokanning.openai.classification.ClassificationResult;
import com.theokanning.openai.completion.CompletionRequest;
import com.theokanning.openai.completion.CompletionResult;
import com.theokanning.openai.edit.EditRequest;
import com.theokanning.openai.edit.EditResult;
import com.theokanning.openai.embedding.EmbeddingRequest;
import com.theokanning.openai.embedding.EmbeddingResult;
import com.theokanning.openai.engine.Engine;
import com.theokanning.openai.file.File;
import com.theokanning.openai.finetune.FineTuneEvent;
import com.theokanning.openai.finetune.FineTuneRequest;
import com.theokanning.openai.finetune.FineTuneResult;
import com.theokanning.openai.model.Model;
import com.theokanning.openai.moderation.ModerationRequest;
import com.theokanning.openai.moderation.ModerationResult;
import com.theokanning.openai.search.SearchRequest;
import com.theokanning.openai.search.SearchResult;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import io.reactivex.Single;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.http.*;
public interface OpenAiApi {
@GET("v1/engines")
Single<OpenAiResponse<Engine>> getEngines();
@GET("v1/models")
Single<OpenAiResponse<Model>> listModels();
@GET("/v1/engines/{engine_id}")
Single<Engine> getEngine(@Path("engine_id") String engineId);
@GET("/v1/models/{model_id}")
Single<Model> getModel(@Path("model_id") String modelId);
@POST("/v1/completions")
Single<CompletionResult> createCompletion(@Body CompletionRequest request);
@Deprecated
@POST("/v1/engines/{engine_id}/completions")
Single<CompletionResult> createCompletion(@Path("engine_id") String engineId, @Body CompletionRequest request);
@POST("/v1/edits")
Single<EditResult> createEdit(@Body EditRequest request);
@Deprecated
@POST("/v1/engines/{engine_id}/edits")
Single<EditResult> createEdit(@Path("engine_id") String engineId, @Body EditRequest request);
@POST("/v1/embeddings")
Single<EmbeddingResult> createEmbeddings(@Body EmbeddingRequest request);
@Deprecated
@POST("/v1/engines/{engine_id}/embeddings")
Single<EmbeddingResult> createEmbeddings(@Path("engine_id") String engineId, @Body EmbeddingRequest request);
@GET("/v1/files")
Single<OpenAiResponse<File>> listFiles();
@Multipart
@POST("/v1/files")
Single<File> uploadFile(@Part("purpose") RequestBody purpose, @Part MultipartBody.Part file);
@DELETE("/v1/files/{file_id}")
Single<DeleteResult> deleteFile(@Path("file_id") String fileId);
@GET("/v1/files/{file_id}")
Single<File> retrieveFile(@Path("file_id") String fileId);
@POST("/v1/fine-tunes")
Single<FineTuneResult> createFineTune(@Body FineTuneRequest request);
@POST("/v1/completions")
Single<CompletionResult> createFineTuneCompletion(@Body CompletionRequest request);
@GET("/v1/fine-tunes")
Single<OpenAiResponse<FineTuneResult>> listFineTunes();
@GET("/v1/fine-tunes/{fine_tune_id}")
Single<FineTuneResult> retrieveFineTune(@Path("fine_tune_id") String fineTuneId);
@POST("/v1/fine-tunes/{fine_tune_id}/cancel")
Single<FineTuneResult> cancelFineTune(@Path("fine_tune_id") String fineTuneId);
@GET("/v1/fine-tunes/{fine_tune_id}/events")
Single<OpenAiResponse<FineTuneEvent>> listFineTuneEvents(@Path("fine_tune_id") String fineTuneId);
@DELETE("/v1/models/{fine_tune_id}")
Single<DeleteResult> deleteFineTune(@Path("fine_tune_id") String fineTuneId);
@POST("/v1/moderations")
Single<ModerationResult> createModeration(@Body ModerationRequest request);
@Deprecated
@GET("v1/engines")
Single<OpenAiResponse<Engine>> getEngines();
@Deprecated
@GET("/v1/engines/{engine_id}")
Single<Engine> getEngine(@Path("engine_id") String engineId);
@Deprecated
@POST("v1/answers")
Single<AnswerResult> createAnswer(@Body AnswerRequest request);
@Deprecated
@POST("v1/classifications")
Single<ClassificationResult> createClassification(@Body ClassificationRequest request);
@Deprecated
@POST("/v1/engines/{engine_id}/search")
Single<OpenAiResponse<SearchResult>> search(@Path("engine_id") String engineId, @Body SearchRequest request);
}
@@ -4,13 +4,27 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.theokanning.openai.search.SearchRequest;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import com.theokanning.openai.answer.AnswerRequest;
import com.theokanning.openai.answer.AnswerResult;
import com.theokanning.openai.classification.ClassificationRequest;
import com.theokanning.openai.classification.ClassificationResult;
import com.theokanning.openai.completion.CompletionRequest;
import com.theokanning.openai.completion.CompletionResult;
import com.theokanning.openai.edit.EditRequest;
import com.theokanning.openai.edit.EditResult;
import com.theokanning.openai.embedding.EmbeddingRequest;
import com.theokanning.openai.embedding.EmbeddingResult;
import com.theokanning.openai.engine.Engine;
import com.theokanning.openai.file.File;
import com.theokanning.openai.finetune.FineTuneEvent;
import com.theokanning.openai.finetune.FineTuneRequest;
import com.theokanning.openai.finetune.FineTuneResult;
import com.theokanning.openai.model.Model;
import com.theokanning.openai.moderation.ModerationRequest;
import com.theokanning.openai.moderation.ModerationResult;
import com.theokanning.openai.search.SearchRequest;
import com.theokanning.openai.search.SearchResult;
import okhttp3.*;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;
@@ -22,7 +36,20 @@ public class OpenAiService {
OpenAiApi api;
/**
* Creates a new OpenAiService that wraps OpenAiApi
* @param token OpenAi token string "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
*/
public OpenAiService(String token) {
this(token, 10);
}
/**
* Creates a new OpenAiService that wraps OpenAiApi
* @param token OpenAi token string "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
* @param timeout http read timeout in seconds, 0 means no timeout
*/
public OpenAiService(String token, int timeout) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
@@ -31,6 +58,7 @@ public class OpenAiService {
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new AuthenticationInterceptor(token))
.connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS))
.readTimeout(timeout, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
@@ -40,21 +68,129 @@ public class OpenAiService {
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
api = retrofit.create(OpenAiApi.class);
this.api = retrofit.create(OpenAiApi.class);
}
public List<Engine> getEngines() {
return api.getEngines().blockingGet().data;
/**
* Creates a new OpenAiService that wraps OpenAiApi
* @param api OpenAiApi instance to use for all methods
*/
public OpenAiService(OpenAiApi api) {
this.api = api;
}
public Engine getEngine(String engineId) {
return api.getEngine(engineId).blockingGet();
public List<Model> listModels() {
return api.listModels().blockingGet().data;
}
public Model getModel(String modelId) {
return api.getModel(modelId).blockingGet();
}
public CompletionResult createCompletion(CompletionRequest request) {
return api.createCompletion(request).blockingGet();
}
/** Use {@link OpenAiService#createCompletion(CompletionRequest)} and {@link CompletionRequest#model}instead */
@Deprecated
public CompletionResult createCompletion(String engineId, CompletionRequest request) {
return api.createCompletion(engineId, request).blockingGet();
}
public EditResult createEdit(EditRequest request) {
return api.createEdit(request).blockingGet();
}
/** Use {@link OpenAiService#createEdit(EditRequest)} and {@link EditRequest#model}instead */
@Deprecated
public EditResult createEdit(String engineId, EditRequest request) {
return api.createEdit(engineId, request).blockingGet();
}
public EmbeddingResult createEmbeddings(EmbeddingRequest request) {
return api.createEmbeddings(request).blockingGet();
}
/** Use {@link OpenAiService#createEmbeddings(EmbeddingRequest)} and {@link EmbeddingRequest#model}instead */
@Deprecated
public EmbeddingResult createEmbeddings(String engineId, EmbeddingRequest request) {
return api.createEmbeddings(engineId, request).blockingGet();
}
public List<File> listFiles() {
return api.listFiles().blockingGet().data;
}
public File uploadFile(String purpose, String filepath) {
java.io.File file = new java.io.File(filepath);
RequestBody purposeBody = RequestBody.create(okhttp3.MultipartBody.FORM, purpose);
RequestBody fileBody = RequestBody.create(MediaType.parse("text"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("file", filepath, fileBody);
return api.uploadFile(purposeBody, body).blockingGet();
}
public DeleteResult deleteFile(String fileId) {
return api.deleteFile(fileId).blockingGet();
}
public File retrieveFile(String fileId) {
return api.retrieveFile(fileId).blockingGet();
}
public FineTuneResult createFineTune(FineTuneRequest request) {
return api.createFineTune(request).blockingGet();
}
public CompletionResult createFineTuneCompletion(CompletionRequest request) {
return api.createFineTuneCompletion(request).blockingGet();
}
public List<FineTuneResult> listFineTunes() {
return api.listFineTunes().blockingGet().data;
}
public FineTuneResult retrieveFineTune(String fineTuneId) {
return api.retrieveFineTune(fineTuneId).blockingGet();
}
public FineTuneResult cancelFineTune(String fineTuneId) {
return api.cancelFineTune(fineTuneId).blockingGet();
}
public List<FineTuneEvent> listFineTuneEvents(String fineTuneId) {
return api.listFineTuneEvents(fineTuneId).blockingGet().data;
}
public DeleteResult deleteFineTune(String fineTuneId) {
return api.deleteFineTune(fineTuneId).blockingGet();
}
public ModerationResult createModeration(ModerationRequest request) {
return api.createModeration(request).blockingGet();
}
@Deprecated
public List<Engine> getEngines() {
return api.getEngines().blockingGet().data;
}
@Deprecated
public Engine getEngine(String engineId) {
return api.getEngine(engineId).blockingGet();
}
@Deprecated
public AnswerResult createAnswer(AnswerRequest request) {
return api.createAnswer(request).blockingGet();
}
@Deprecated
public ClassificationResult createClassification(ClassificationRequest request) {
return api.createClassification(request).blockingGet();
}
@Deprecated
public List<SearchResult> search(String engineId, SearchRequest request) {
return api.search(engineId, request).blockingGet().data;
}
@@ -0,0 +1,37 @@
package com.theokanning.openai;
import com.theokanning.openai.answer.AnswerRequest;
import com.theokanning.openai.answer.AnswerResult;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class AnswerTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void createAnswer() {
AnswerRequest answerRequest = AnswerRequest.builder()
.documents(Arrays.asList("Puppy A is happy.", "Puppy B is sad."))
.question("which puppy is happy?")
.searchModel("ada")
.model("curie")
.examplesContext("In 2017, U.S. life expectancy was 78.6 years.")
.examples(Collections.singletonList(
Arrays.asList("What is human life expectancy in the United States?", "78 years.")
))
.maxTokens(5)
.stop(Arrays.asList("\n", "<|endoftext|>"))
.build();
AnswerResult result = service.createAnswer(answerRequest);
assertNotNull(result.getAnswers().get(0));
}
}
@@ -0,0 +1,39 @@
package com.theokanning.openai;
import com.theokanning.openai.classification.ClassificationRequest;
import com.theokanning.openai.classification.ClassificationResult;
import com.theokanning.openai.completion.CompletionChoice;
import com.theokanning.openai.completion.CompletionRequest;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class ClassificationTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void createCompletion() {
ClassificationRequest classificationRequest = ClassificationRequest.builder()
.examples(Arrays.asList(
Arrays.asList("A happy moment", "Positive"),
Arrays.asList("I am sad.", "Negative"),
Arrays.asList("I am feeling awesome", "Positive")
))
.query("It is a raining day :(")
.model("curie")
.searchModel("ada")
.labels(Arrays.asList("Positive", "Negative", "Neutral"))
.build();
ClassificationResult result = service.createClassification(classificationRequest);
assertNotNull(result.getCompletion());
}
}
@@ -0,0 +1,43 @@
package com.theokanning.openai;
import com.theokanning.openai.completion.CompletionChoice;
import com.theokanning.openai.completion.CompletionRequest;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertFalse;
public class CompletionTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void createCompletion() {
CompletionRequest completionRequest = CompletionRequest.builder()
.model("ada")
.prompt("Somebody once told me the world is gonna roll me")
.echo(true)
.user("testing")
.logitBias(new HashMap<>())
.build();
List<CompletionChoice> choices = service.createCompletion(completionRequest).getChoices();
assertFalse(choices.isEmpty());
}
@Test
void createCompletionDeprecated() {
CompletionRequest completionRequest = CompletionRequest.builder()
.prompt("Somebody once told me the world is gonna roll me")
.echo(true)
.user("testing")
.build();
List<CompletionChoice> choices = service.createCompletion("ada", completionRequest).getChoices();
assertFalse(choices.isEmpty());
}
}
@@ -0,0 +1,38 @@
package com.theokanning.openai;
import com.theokanning.openai.edit.EditRequest;
import com.theokanning.openai.edit.EditResult;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class EditTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void edit() {
EditRequest request = EditRequest.builder()
.model("text-davinci-edit-001")
.input("What day of the wek is it?")
.instruction("Fix the spelling mistakes")
.build();
EditResult result = service.createEdit( request);
assertNotNull(result.getChoices().get(0).getText());
}
@Test
void editDeprecated() {
EditRequest request = EditRequest.builder()
.input("What day of the wek is it?")
.instruction("Fix the spelling mistakes")
.build();
EditResult result = service.createEdit("text-davinci-edit-001", request);
assertNotNull(result.getChoices().get(0).getText());
}
}
@@ -0,0 +1,42 @@
package com.theokanning.openai;
import com.theokanning.openai.embedding.Embedding;
import com.theokanning.openai.embedding.EmbeddingRequest;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertFalse;
public class EmbeddingTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void createEmbeddings() {
EmbeddingRequest embeddingRequest = EmbeddingRequest.builder()
.model("text-similarity-babbage-001")
.input(Collections.singletonList("The food was delicious and the waiter..."))
.build();
List<Embedding> embeddings = service.createEmbeddings(embeddingRequest).getData();
assertFalse(embeddings.isEmpty());
assertFalse(embeddings.get(0).getEmbedding().isEmpty());
}
@Test
void createEmbeddingsDeprecated() {
EmbeddingRequest embeddingRequest = EmbeddingRequest.builder()
.input(Collections.singletonList("The food was delicious and the waiter..."))
.build();
List<Embedding> embeddings = service.createEmbeddings("text-similarity-babbage-001", embeddingRequest).getData();
assertFalse(embeddings.isEmpty());
assertFalse(embeddings.get(0).getEmbedding().isEmpty());
}
}
@@ -0,0 +1,30 @@
package com.theokanning.openai;
import com.theokanning.openai.engine.Engine;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
public class EngineTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void getEngines() {
List<Engine> engines = service.getEngines();
assertFalse(engines.isEmpty());
}
@Test
void getEngine() {
Engine ada = service.getEngine("ada");
assertEquals("ada", ada.id);
}
}
@@ -0,0 +1,55 @@
package com.theokanning.openai;
import com.theokanning.openai.file.File;
import org.junit.jupiter.api.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class FileTest {
static String filePath = "src/test/resources/fine-tuning-data.jsonl";
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
static String fileId;
@Test
@Order(1)
void uploadFile() throws Exception {
File file = service.uploadFile("fine-tune", filePath);
fileId = file.getId();
assertEquals("fine-tune", file.getPurpose());
assertEquals(filePath, file.getFilename());
// wait for file to be processed
TimeUnit.SECONDS.sleep(10);
}
@Test
@Order(2)
void listFiles() {
List<File> files = service.listFiles();
assertTrue(files.stream().anyMatch(file -> file.getId().equals(fileId)));
}
@Test
@Order(3)
void retrieveFile() {
File file = service.retrieveFile(fileId);
assertEquals(filePath, file.getFilename());
}
@Test
@Order(4)
void deleteFile() {
DeleteResult result = service.deleteFile(fileId);
assertTrue(result.isDeleted());
}
}
@@ -0,0 +1,80 @@
package com.theokanning.openai;
import com.theokanning.openai.finetune.FineTuneRequest;
import com.theokanning.openai.finetune.FineTuneEvent;
import com.theokanning.openai.finetune.FineTuneResult;
import org.junit.jupiter.api.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class FineTuneTest {
static OpenAiService service;
static String fileId;
static String fineTuneId;
@BeforeAll
static void setup() throws Exception {
String token = System.getenv("OPENAI_TOKEN");
service = new OpenAiService(token);
fileId = service.uploadFile("fine-tune", "src/test/resources/fine-tuning-data.jsonl").getId();
// wait for file to be processed
TimeUnit.SECONDS.sleep(10);
}
@AfterAll
static void teardown() {
service.deleteFile(fileId);
}
@Test
@Order(1)
void createFineTune() {
FineTuneRequest request = FineTuneRequest.builder()
.trainingFile(fileId)
.model("ada")
.build();
FineTuneResult fineTune = service.createFineTune(request);
fineTuneId = fineTune.getId();
assertEquals("pending", fineTune.getStatus());
}
@Test
@Order(2)
void listFineTunes() {
List<FineTuneResult> fineTunes = service.listFineTunes();
assertTrue(fineTunes.stream().anyMatch(fineTune -> fineTune.getId().equals(fineTuneId)));
}
@Test
@Order(3)
void listFineTuneEvents() {
List<FineTuneEvent> events = service.listFineTuneEvents(fineTuneId);
assertFalse(events.isEmpty());
}
@Test
@Order(3)
void retrieveFineTune() {
FineTuneResult fineTune = service.retrieveFineTune(fineTuneId);
assertEquals("ada", fineTune.getModel());
}
@Test
@Order(4)
void cancelFineTune() {
FineTuneResult fineTune = service.cancelFineTune(fineTuneId);
assertEquals("cancelled", fineTune.getStatus());
}
}
@@ -0,0 +1,31 @@
package com.theokanning.openai;
import com.theokanning.openai.model.Model;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class ModelTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void listModels() {
List<Model> models = service.listModels();
assertFalse(models.isEmpty());
}
@Test
void getModel() {
Model ada = service.getModel("ada");
assertEquals("ada", ada.id);
assertEquals("openai", ada.ownedBy);
assertFalse(ada.permission.isEmpty());
}
}
@@ -0,0 +1,26 @@
package com.theokanning.openai;
import com.theokanning.openai.moderation.ModerationRequest;
import com.theokanning.openai.moderation.Moderation;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ModerationTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void createModeration() {
ModerationRequest moderationRequest = ModerationRequest.builder()
.input("I want to kill them")
.model("text-moderation-latest")
.build();
Moderation moderationScore = service.createModeration(moderationRequest).getResults().get(0);
assertTrue(moderationScore.isFlagged());
}
}
@@ -0,0 +1,28 @@
package com.theokanning.openai;
import com.theokanning.openai.search.SearchRequest;
import com.theokanning.openai.search.SearchResult;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertFalse;
public class SearchTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void search() {
SearchRequest searchRequest = SearchRequest.builder()
.documents(Arrays.asList("Water", "Earth", "Electricity", "Fire"))
.query("Pikachu")
.build();
List<SearchResult> results = service.search("ada", searchRequest);
assertFalse(results.isEmpty());
}
}
@@ -0,0 +1,2 @@
{"prompt": "prompt", "completion": "text"}
{"prompt": "prompt", "completion": "text"}
@@ -2,36 +2,19 @@ package example;
import com.theokanning.openai.OpenAiService;
import com.theokanning.openai.completion.CompletionRequest;
import com.theokanning.openai.engine.Engine;
import com.theokanning.openai.search.SearchRequest;
import java.util.Arrays;
class OpenAiApiExample {
public static void main(String... args) {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
System.out.println("\nGetting available engines...");
service.getEngines().forEach(System.out::println);
System.out.println("\nGetting ada engine...");
Engine ada = service.getEngine("ada");
System.out.println(ada);
System.out.println("\nCreating completion...");
CompletionRequest completionRequest = CompletionRequest.builder()
.model("ada")
.prompt("Somebody once told me the world is gonna roll me")
.echo(true)
.user("testing")
.build();
service.createCompletion("ada", completionRequest).getChoices().forEach(System.out::println);
System.out.println("\nSearching documents...");
SearchRequest searchRequest = SearchRequest.builder()
.documents(Arrays.asList("Water", "Earth", "Electricity", "Fire"))
.query("Pikachu")
.build();
service.search("ada", searchRequest).forEach(System.out::println);
service.createCompletion(completionRequest).getChoices().forEach(System.out::println);
}
}
}
+14
View File
@@ -0,0 +1,14 @@
GROUP=com.theokanning.openai-gpt3-java
VERSION_NAME=0.8.1
POM_URL=https://github.com/theokanning/openai-java
POM_SCM_URL=https://github.com/theokanning/openai-java
POM_SCM_CONNECTION=https://github.com/theokanning/openai-java.git
POM_SCM_DEV_CONNECTION=https://github.com/theokanning/openai-java.git
POM_LICENSE_NAME=The MIT License
POM_LICENSE_URL=https://www.mit.edu/~amini/LICENSE.md
POM_LICENSE_DIST=repo
POM_DEVELOPER_ID=theokanning
POM_DEVELOPER_NAME=Theo Kanning
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists