30 Commits

Author SHA1 Message Date
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
Theo Kanning 618a097254 Add pom files to publishing steps (#2)
Necessary in order to be added to jcenter
2020-10-05 18:18:51 -05:00
Theo Kanning 0297fe0393 Add build Github Action (#1)
The default action should work fine
2020-10-05 17:54:18 -05:00
Theo Kanning c2044c64f9 Include gradle-wrapper.jar
The default java gitignore doesn't include any jar files, and this missing file caused Github Actions builds to fail
2020-10-05 17:52:21 -05:00
Theo Kanning 00fa073446 Update package names
This matches the library groupId and makes it clear that this is not an OpenAI product
2020-10-05 17:44:18 -05:00
Theo Kanning d15dc718c2 Add builders to request objects
This is so much nicer
2020-10-05 17:41:16 -05:00
Theo Kanning 44ad76258c Add logprobs field 2020-10-05 17:39:34 -05:00
54 changed files with 1727 additions and 183 deletions
+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
View File
@@ -12,6 +12,7 @@
# Package Files #
*.jar
!gradle/wrapper/gradle-wrapper.jar
*.war
*.nar
*.ear
+33 -10
View File
@@ -1,27 +1,50 @@
![Maven Central](https://img.shields.io/maven-central/v/com.theokanning.openai-gpt3-java/client?color=blue)
# 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
- `api` : request/response POJOs for the GPT-3 engine, completion, and search APIs.
- `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
- [Engines](https://beta.openai.com/docs/api-reference/engines)
- [Completions](https://beta.openai.com/docs/api-reference/completions)
- [Edits](https://beta.openai.com/docs/api-reference/edits)
- [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)
- [Files](https://beta.openai.com/docs/api-reference/files)
- [Fine-tunes](https://beta.openai.com/docs/api-reference/fine-tunes)
- [Embeddings](https://beta.openai.com/docs/api-reference/embeddings)
## Usage
If you're looking for the fastest solution, import the `client` and use [OpenAiService](client/src/main/java/openai/OpenAiService.java).
### 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/com/theokanning/openai/OpenAiService.java).
```
OpenAiService service = new OpenAiService(your_token)
CompletionRequest completionRequest = new CompletionRequest();
completionRequest.setPrompt("Somebody once told me the world is gonna roll me");
completionRequest.setEcho(true);
CompletionRequest completionRequest = CompletionRequest.builder()
.prompt("Somebody once told me the world is gonna roll me")
.echo(true)
.build();
service.createCompletion("ada", completionRequest).getChoices().forEach(System.out::println);
```
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))
### Using OpenAiApi Retrofit client
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.
If you want to make your own client, just import the POJOs from the `api` module.
### Using data classes only
If you want to make your own client, just import the POJOs from the `api` module.
Your client will need to use snake case to work with the OpenAI API.
## Running the example project
All the [example](example/src/main/java/example/OpenAiApiExample.java) project requires is your OpenAI api token
@@ -31,4 +54,4 @@ export OPENAI_TOKEN="sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
```
## License
Published under the MIT License
Published under the MIT License
+4 -23
View File
@@ -1,31 +1,12 @@
apply plugin: 'java-library'
apply plugin: 'com.jfrog.bintray'
apply plugin: "com.vanniktech.maven.publish"
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.12'
annotationProcessor 'org.projectlombok:lombok:1.18.12'
}
ext {
libraryVersion = '0.1.0'
compileJava {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
version = libraryVersion
group = 'com.theokanning.openai-gpt3-java'
bintray {
user = System.getenv("BINTRAY_USER")
key = System.getenv("BINTRAY_KEY")
configurations = ['archives']
pkg {
repo = 'openai-gpt3-java'
name = 'api'
vcsUrl = 'https://github.com/TheoKanning/openai-java.git'
licenses = ["MIT"]
publish = true
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;
}
@@ -1,4 +1,4 @@
package openai;
package com.theokanning.openai;
import lombok.Data;
@@ -0,0 +1,140 @@
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
*/
@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,43 @@
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
*/
@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,21 @@
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
*/
@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,120 @@
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
*/
@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,44 @@
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
*/
@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,26 @@
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
*/
@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;
}
@@ -1,11 +1,11 @@
package openai.completion;
package com.theokanning.openai.completion;
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 {
@@ -18,7 +18,11 @@ public class CompletionChoice {
* This index of this completion in the returned list.
*/
Integer index;
// todo add logprobs
/**
* The log probabilities of the chosen tokens and the top {@link CompletionRequest#logprobs} tokens
*/
LogProbResult logprobs;
/**
* The reason why GPT-3 stopped generating, for example "length".
@@ -1,6 +1,9 @@
package openai.completion;
package com.theokanning.openai.completion;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@@ -8,11 +11,19 @@ import java.util.List;
* 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
@AllArgsConstructor
@Data
public class CompletionRequest {
/**
* The name of the model to use, only used if specifying a fine tuned model.
*/
String model;
/**
* An optional prompt to complete from
*/
@@ -29,7 +40,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;
@@ -38,7 +49,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;
@@ -46,7 +57,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;
@@ -74,7 +85,7 @@ public class CompletionRequest {
* Up to 4 sequences where the API will stop generating further tokens.
* The returned text will not contain the stop sequence.
*/
List<String> stop; //todo test this
List<String> stop;
/**
* Number between 0 and 1 (default 0) that penalizes new tokens based on whether they appear in the text so far.
@@ -93,7 +104,7 @@ 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;
@@ -1,4 +1,4 @@
package openai.completion;
package com.theokanning.openai.completion;
import lombok.Data;
@@ -7,12 +7,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 +22,17 @@ 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;
}
@@ -0,0 +1,37 @@
package com.theokanning.openai.completion;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* Log probabilities of different token options
* Returned if {@link CompletionRequest#logprobs} is greater than zero
*
* https://beta.openai.com/docs/api-reference/create-completion
*/
@Data
public class LogProbResult {
/**
* The tokens chosen by the completion api
*/
List<String> tokens;
/**
* The log probability of each token in {@link tokens}
*/
List<Double> tokenLogprobs;
/**
* A map for each index in the completion result.
* The map contains the top {@link CompletionRequest#logprobs} tokens and their probabilities
*/
List<Map<String, Double>> topLogprobs;
/**
* The character offset from the start of the returned text for each of the chosen tokens.
*/
List<Integer> textOffset;
}
@@ -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,43 @@
package com.theokanning.openai.edit;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 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 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"
*/
String instruction;
/**
* 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.
*/
Double topP;
}
@@ -0,0 +1,29 @@
package com.theokanning.openai.edit;
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"
*/
String object;
/**
* The creation time in epoch milliseconds.
*/
long created;
/**
* A list of generated edits.
*/
List<EditChoice> choices;
}
@@ -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,34 @@
package com.theokanning.openai.embedding;
import lombok.*;
import java.util.List;
/**
* Creates an embedding vector representing the input text.
*
* Documentation taken from
* https://beta.openai.com/docs/api-reference/embeddings/create
*/
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class EmbeddingRequest {
/**
* 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,29 @@
package com.theokanning.openai.embedding;
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;
}
@@ -1,4 +1,4 @@
package openai.engine;
package com.theokanning.openai.engine;
import lombok.Data;
@@ -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,109 @@
package com.theokanning.openai.finetune;
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.
*/
Integer classificationNClasses; // todo verify snake case
/**
* 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;
}
@@ -1,6 +1,9 @@
package openai.search;
package com.theokanning.openai.search;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@@ -9,10 +12,14 @@ 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
*/
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class SearchRequest {
/**
* Documents to search over
*/
@@ -1,11 +1,11 @@
package openai.search;
package com.theokanning.openai.search;
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
*/
@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"
}
}
}
+10 -22
View File
@@ -1,33 +1,21 @@
apply plugin: 'java-library'
apply plugin: 'com.jfrog.bintray'
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.1.0'
compileJava {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
version = libraryVersion
group = 'com.theokanning.openai-gpt3-java'
bintray {
user = System.getenv("BINTRAY_USER")
key = System.getenv("BINTRAY_KEY")
configurations = ['archives']
pkg {
repo = 'openai-gpt3-java'
name = 'client'
vcsUrl = 'https://github.com/TheoKanning/openai-java.git'
licenses = ["MIT"]
publish = true
version {
name = libraryVersion
}
}
}
test {
useJUnitPlatform()
}
+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,4 +1,4 @@
package openai;
package com.theokanning.openai;
import okhttp3.Interceptor;
import okhttp3.Request;
@@ -0,0 +1,86 @@
package com.theokanning.openai;
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.search.SearchRequest;
import com.theokanning.openai.search.SearchResult;
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/engines/{engine_id}")
Single<Engine> getEngine(@Path("engine_id") String engineId);
@POST("/v1/engines/{engine_id}/completions")
Single<CompletionResult> createCompletion(@Path("engine_id") String engineId, @Body CompletionRequest request);
@POST("/v1/engines/{engine_id}/edits")
Single<EditResult> createEdit(@Path("engine_id") String engineId, @Body EditRequest request);
@POST("/v1/engines/{engine_id}/search")
Single<OpenAiResponse<SearchResult>> search(@Path("engine_id") String engineId, @Body SearchRequest request);
@POST("v1/classifications")
Single<ClassificationResult> createClassification(@Body ClassificationRequest request);
@POST("v1/answers")
Single<AnswerResult> createAnswer(@Body AnswerRequest 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/engines/{engine_id}/embeddings")
Single<EmbeddingResult> createEmbeddings(@Path("engine_id") String engineId, @Body EmbeddingRequest request);
}
@@ -0,0 +1,159 @@
package com.theokanning.openai;
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.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.search.SearchRequest;
import com.theokanning.openai.search.SearchResult;
import okhttp3.*;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;
import java.util.List;
import java.util.concurrent.TimeUnit;
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);
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
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()
.baseUrl("https://api.openai.com/")
.client(client)
.addConverterFactory(JacksonConverterFactory.create(mapper))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
this.api = retrofit.create(OpenAiApi.class);
}
/**
* Creates a new OpenAiService that wraps OpenAiApi
* @param api OpenAiApi instance to use for all methods
*/
public OpenAiService(OpenAiApi api) {
this.api = api;
}
public List<Engine> getEngines() {
return api.getEngines().blockingGet().data;
}
public Engine getEngine(String engineId) {
return api.getEngine(engineId).blockingGet();
}
public CompletionResult createCompletion(String engineId, CompletionRequest request) {
return api.createCompletion(engineId, request).blockingGet();
}
public EditResult createEdit(String engineId, EditRequest request) {
return api.createEdit(engineId, request).blockingGet();
}
public List<SearchResult> search(String engineId, SearchRequest request) {
return api.search(engineId, request).blockingGet().data;
}
public ClassificationResult createClassification(ClassificationRequest request) {
return api.createClassification(request).blockingGet();
}
public AnswerResult createAnswer(AnswerRequest request) {
return api.createAnswer(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 EmbeddingResult createEmbeddings(String engineId, EmbeddingRequest request) {
return api.createEmbeddings(engineId, request).blockingGet();
}
}
@@ -1,27 +0,0 @@
package openai;
import io.reactivex.Single;
import openai.completion.CompletionRequest;
import openai.completion.CompletionResult;
import openai.engine.Engine;
import openai.search.SearchRequest;
import openai.search.SearchResult;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
public interface OpenAiApi {
@GET("v1/engines")
Single<OpenAiResponse<Engine>> getEngines();
@GET("/v1/engines/{engine_id}")
Single<Engine> getEngine(@Path("engine_id") String engineId);
@POST("/v1/engines/{engine_id}/completions")
Single<CompletionResult> createCompletion(@Path("engine_id") String engineId, @Body CompletionRequest request);
@POST("/v1/engines/{engine_id}/search")
Single<OpenAiResponse<SearchResult>> search(@Path("engine_id") String engineId, @Body SearchRequest request);
}
@@ -1,61 +0,0 @@
package openai;
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 okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import openai.completion.CompletionRequest;
import openai.completion.CompletionResult;
import openai.engine.Engine;
import openai.search.SearchRequest;
import openai.search.SearchResult;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class OpenAiService {
OpenAiApi api;
public OpenAiService(String token) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new AuthenticationInterceptor(token))
.connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS))
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.openai.com/")
.client(client)
.addConverterFactory(JacksonConverterFactory.create(mapper))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
api = retrofit.create(OpenAiApi.class);
}
public List<Engine> getEngines() {
return api.getEngines().blockingGet().data;
}
public Engine getEngine(String engineId) {
return api.getEngine(engineId).blockingGet();
}
public CompletionResult createCompletion(String engineId, CompletionRequest request) {
return api.createCompletion(engineId, request).blockingGet();
}
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,27 @@
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.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()
.prompt("Somebody once told me the world is gonna roll me")
.echo(true)
.build();
List<CompletionChoice> choices = service.createCompletion("ada", completionRequest).getChoices();
assertFalse(choices.isEmpty());
}
}
@@ -0,0 +1,27 @@
package com.theokanning.openai;
import com.theokanning.openai.edit.EditRequest;
import com.theokanning.openai.edit.EditResult;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@Disabled // disabled until edit example CURL works
public class EditTest {
String token = System.getenv("OPENAI_TOKEN");
OpenAiService service = new OpenAiService(token);
@Test
void edit() {
EditRequest request = EditRequest.builder()
.input("What day of the wek is it?")
.instruction("Fix the spelling mistakes")
.build();
EditResult result = service.createEdit("text-ada-001", request);
assertEquals("What day of the week is it?", result.getChoices().get(0).getText());
}
}
@@ -0,0 +1,29 @@
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()
.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,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"}
@@ -1,9 +1,9 @@
package example;
import openai.OpenAiService;
import openai.completion.CompletionRequest;
import openai.engine.Engine;
import openai.search.SearchRequest;
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;
@@ -20,15 +20,17 @@ class OpenAiApiExample {
System.out.println(ada);
System.out.println("\nCreating completion...");
CompletionRequest completionRequest = new CompletionRequest();
completionRequest.setPrompt("Somebody once told me the world is gonna roll me");
completionRequest.setEcho(true);
CompletionRequest completionRequest = CompletionRequest.builder()
.prompt("Somebody once told me the world is gonna roll me")
.echo(true)
.build();
service.createCompletion("ada", completionRequest).getChoices().forEach(System.out::println);
System.out.println("\nSearching documents...");
SearchRequest searchRequest = new SearchRequest();
searchRequest.setDocuments(Arrays.asList("Water", "Earth", "Electricity", "Fire"));
searchRequest.setQuery("Pikachu");
SearchRequest searchRequest = SearchRequest.builder()
.documents(Arrays.asList("Water", "Earth", "Electricity", "Fire"))
.query("Pikachu")
.build();
service.search("ada", searchRequest).forEach(System.out::println);
}
}
+14
View File
@@ -0,0 +1,14 @@
GROUP=com.theokanning.openai-gpt3-java
VERSION_NAME=0.7.0
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
Binary file not shown.
+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