Skip to content

Instantly share code, notes, and snippets.

@AmazingTurtle
Created July 7, 2021 11:17
Show Gist options
  • Save AmazingTurtle/d10db1ec3b02efd81d358b652762ee9f to your computer and use it in GitHub Desktop.
Save AmazingTurtle/d10db1ec3b02efd81d358b652762ee9f to your computer and use it in GitHub Desktop.
openai client
export const DEFAULT_ENGINE = 'davinci';
export const ENGINE_LIST = ['ada', 'babbage', 'curie', 'davinci', 'davinci-instruct-beta', 'curie-instruct-beta'];
export const ORIGIN = 'https://api.openai.com';
export const DEFAULT_API_VERSION = 'v1';
export const DEFAULT_OPEN_AI_URL = `${ORIGIN}/${DEFAULT_API_VERSION}`;
export interface EngineResponse {
id: string;
object: 'engine';
owner: string;
ready: boolean;
}
export interface EnginesListResponse {
data: Array<EngineResponse>;
object: 'list';
}
export interface CreateCompletionRequest {
/**
* string or array Optional Defaults to <|endoftext|>
*
* The prompt(s) to generate completions for, encoded as a string, a list of strings, or a list of token lists.
* Note that <|endoftext|> is the document separator that the model sees during training, so if a prompt is not specified the model will generate as if from the beginning of a new document.
*/
prompt?: string | string[];
/**
* integer Optional Defaults to 16
*
* The maximum number of tokens to generate. Requests can use up to 2048 tokens shared between prompt and completion. (One token is roughly 4 characters for normal English text)
*/
max_tokens?: number;
/**
* number Optional Defaults to 1
*
* 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 top_p but not both.
*/
temperature?: number;
/**
* number Optional Defaults to 1
*
* 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 temperature but not both.
*/
top_p?: number;
/**
* integer Optional Defaults to 1
*
* How many completions to generate for each prompt.
* Note: Because this parameter generates many completions, it can quickly consume your token quota. Use carefully and ensure that you have reasonable settings for max_tokens and stop.
*/
n?: number;
/**
* boolean Optional Defaults to false
*
* Whether to stream back partial progress. If set, tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message.
*/
stream?: boolean;
/**
* integer Optional Defaults to null
*
* 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.
*/
logprobs?: number;
/**
* boolean Optional Defaults to false
*
* Echo back the prompt in addition to the completion
*/
echo?: boolean;
/**
* string or array Optional Defaults to null
*
* Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence.
*/
stop?: string | string[];
/**
* number Optional Defaults to 0
*
* Number between 0 and 1 that penalizes new tokens based on whether they appear in the text so far. Increases the model's likelihood to talk about new topics.
*/
presence_penalty?: number;
/**
* number Optional Defaults to 0
*
* Number between 0 and 1 that penalizes new tokens based on their existing frequency in the text so far. Decreases the model's likelihood to repeat the same line verbatim.
*/
frequency_penalty?: number;
/**
* integer Optional Defaults to 1
*
* Generates best_of completions server-side and returns the "best" (the one with the lowest log probability per token). Results cannot be streamed.
* When used with n, best_of controls the number of candidate completions and n specifies how many to return – best_of must be greater than n.
* Note: Because this parameter generates many completions, it can quickly consume your token quota. Use carefully and ensure that you have reasonable settings for max_tokens and stop.
*/
best_of?: number;
/**
* map Optional Defaults to null
*
* 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. You can use this tokenizer tool (which works for both GPT-2 and GPT-3) to convert text to token IDs. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token.
* As an example, you can pass {"50256": -100} to prevent the <|endoftext|> token from being generated.
*/
logit_bias?: {[tokenId: string]: number};
}
export interface CreateCompletionViaGetRequest {
/**
* string or array Optional Defaults to <|endoftext|>
*
* The prompt(s) to generate completions for, encoded as a string, a list of strings, or a list of token lists.
* Note that <|endoftext|> is the document separator that the model sees during training, so if a prompt is not specified the model will generate as if from the beginning of a new document.
*/
prompt?: string | string[];
/**
* integer Optional Defaults to 16
*
* The maximum number of tokens to generate. Requests can use up to 2048 tokens shared between prompt and completion. (One token is roughly 4 characters for normal English text)
*/
max_tokens?: number;
/**
* number Optional Defaults to 1
*
* 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 top_p but not both.
*/
temperature?: number;
/**
* number Optional Defaults to 1
*
* 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 temperature but not both.
*/
top_p?: number;
/**
* integer Optional Defaults to 1
*
* How many completions to generate for each prompt.
* Note: Because this parameter generates many completions, it can quickly consume your token quota. Use carefully and ensure that you have reasonable settings for max_tokens and stop.
*/
n?: number;
/**
* integer Optional Defaults to null
*
* 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.
*/
logprobs?: number;
/**
* boolean Optional Defaults to false
*
* Echo back the prompt in addition to the completion
*/
echo?: boolean;
/**
* string or array Optional Defaults to null
*
* Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence.
*/
stop?: string | string[];
/**
* number Optional Defaults to 0
*
* Number between 0 and 1 that penalizes new tokens based on whether they appear in the text so far. Increases the model's likelihood to talk about new topics.
*/
presence_penalty?: number;
/**
* number Optional Defaults to 0
*
* Number between 0 and 1 that penalizes new tokens based on their existing frequency in the text so far. Decreases the model's likelihood to repeat the same line verbatim.
*/
frequency_penalty?: number;
/**
* integer Optional Defaults to 1
*
* Generates best_of completions server-side and returns the "best" (the one with the lowest log probability per token). Results cannot be streamed.
* When used with n, best_of controls the number of candidate completions and n specifies how many to return – best_of must be greater than n.
* Note: Because this parameter generates many completions, it can quickly consume your token quota. Use carefully and ensure that you have reasonable settings for max_tokens and stop.
*/
best_of?: number;
/**
* map Optional Defaults to null
*
* 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. You can use this tokenizer tool (which works for both GPT-2 and GPT-3) to convert text to token IDs. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token.
* As an example, you can pass {"50256": -100} to prevent the <|endoftext|> token from being generated.
*/
logit_bias?: {[tokenId: string]: number};
}
export interface Choice {
text: string;
index: number;
logprobs: any;
finish_reason: string;
}
export interface CreateCompletionResponse {
id: string;
object: 'text_completion';
created: number;
model: string;
choices: Array<Choice>;
}
export interface CreateSearchRequestBase {
/**
* string Required
* Query to search against the documents.
*/
query: string;
/**
* Integer Optional Defaults to 200
*
* The maximum number of documents to be re-ranked and returned by search.
* This flag only takes effect when file is set.
*/
max_rerank?: number;
/**
* boolean Optional Defaults to false
*
* 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.
*/
return_metadata?: boolean;
}
export interface CreateSearchRequestViaDocuments extends CreateSearchRequestBase {
/**
* string Required
*
* Up to 200 documents to search over, provided as a list of strings.
* The maximum document length (in tokens) is 2034 minus the number of tokens in the query.
*/
documents: Array<string>;
}
export interface CreateSearchRequestViaFile extends CreateSearchRequestBase {
/**
* string Required
*
* The ID of an uploaded file that contains documents to search over.
*/
file: string;
}
export interface CreateSearchResponse {
data: Array<{
document: number;
object: 'search_result';
score: number;
}>;
object: 'list';
}
export interface CreateClassificationRequestBase {
/**
* string Required
*
* ID of the engine to use for completion.
*/
model: string;
/**
* string Required
*
* Query to be classified.
*/
query: string;
/**
* array Optional Defaults to null
*
* 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.
*/
labels?: string[];
/**
* string Optional Defaults to ada
*
* ID of the engine to use for Search.
*/
search_model?: string;
/**
* Optional Defaults to 0
*
* What sampling temperature to use. Higher values mean the model will take more risks. Try 0.9 for more creative applications, and 0 (argmax sampling) for ones with a well-defined answer.
*/
temperature?: number;
/**
* Optional Defaults to null
*
* 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.
* When logprobs is set, completion will be automatically added into expand to get the logprobs.
*/
logprobs?: number;
/**
* map Optional Defaults to null
*
* 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. You can use this tokenizer tool (which works for both GPT-2 and GPT-3) to convert text to token IDs. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token.
* As an example, you can pass {"50256": -100} to prevent the <|endoftext|> token from being generated.
*/
logit_bias?: {[tokenId: string]: number};
/**
* boolean Optional Defaults to false
*
* 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.
*/
return_prompt?: boolean;
/**
* boolean Optional Defaults to false
*
* 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.
*/
return_metadata?: boolean;
/**
* Optional Defaults to []
*
* 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.
*/
expand?: Array<string>;
}
export interface CreateClassificationRequestViaExamples extends CreateClassificationRequestBase {
/**
* array Required
*
* A list of examples with labels, in the follwing format:
* [["The movie is so interesting.", "Positive"], ["It is quite boring.", "Negative"], ...]
* All the label strings will be normalized to be capitalized.
*/
examples: Array<string>;
}
export interface CreateClassificationRequestViaFile extends CreateClassificationRequestBase {
/**
* string Required
*
* The ID of an uploaded file that contains documents to search over.
*/
file: string;
/**
* integer Optional defaults to 200
*
* 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.
*/
max_examples?: number;
}
export interface CreateClassificationResponse {
completion: string;
label: string;
model: string;
object: 'classification';
search_model: string;
selected_examples?: Array<{
document: number;
text: string;
}>;
selected_documents?: Array<{
document: number;
text: string;
}>;
}
export interface CreateAnswerRequestBase {
/**
* string Required
*
* ID of the engine to use for completion.
*/
model: string;
/**
* string Required
*
* Question to get answered.
*/
question: string;
/**
* array Required
*
* 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.
*/
examples: Array<string>;
/**
* string Required
*
* A text snippet containing the contextual information used to generate the answers for the examples you provide.
*/
examples_context: string;
/**
* string Optional Defaults to ada
*
* ID of the engine to use for Search.
*/
search_model?: string;
/**
* number Optional Defaults to 1
*
* 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 top_p but not both.
*/
temperature?: number;
/**
* integer Optional Defaults to null
*
* 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.
*/
logprobs?: number;
/**
* integer Optional Defaults to 16
*
* The maximum number of tokens to generate. Requests can use up to 2048 tokens shared between prompt and completion. (One token is roughly 4 characters for normal English text)
*/
max_tokens?: number;
/**
* string or array Optional Defaults to null
*
* Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence.
*/
stop?: string | string[];
/**
* integer Optional Defaults to 1
*
* How many completions to generate for each prompt.
* Note: Because this parameter generates many completions, it can quickly consume your token quota. Use carefully and ensure that you have reasonable settings for max_tokens and stop.
*/
n?: number;
/**
* map Optional Defaults to null
*
* 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. You can use this tokenizer tool (which works for both GPT-2 and GPT-3) to convert text to token IDs. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token.
* As an example, you can pass {"50256": -100} to prevent the <|endoftext|> token from being generated.
*/
logit_bias?: {[tokenId: string]: number};
/**
* boolean Optional Defaults to false
*
* 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.
*/
return_metadata?: boolean;
/**
* boolean Optional Defaults to false
*
* 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.
*/
return_prompt?: boolean;
/**
* Optional Defaults to []
*
* 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.
*/
expand?: Array<string>;
}
export interface CreateAnswerRequestViaDocuments extends CreateAnswerRequestBase {
/**
* array Required
*
* 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.
*/
documents: Array<string>;
}
export interface CreateAnswerRequestViaFile extends CreateAnswerRequestBase {
/**
* string Required
*
* The ID of an uploaded file that contains documents to search over.
*/
file: string;
/**
* Integer Optional Defaults to 200
*
* The maximum number of documents to be re-ranked and returned by search.
* This flag only takes effect when file is set.
*/
max_rerank?: number;
}
export interface CreateAnswerResponse {
answers: Array<string>;
completion: string;
model: string;
object: 'answer';
search_model: string;
selected_documents: Array<{
document: number;
text: string;
}>;
}
export type Purpose = 'search' | 'answers' | 'classifications';
export interface OpenAIFile {
id: string;
object: 'file';
bytes: number;
created_at: number;
filename: string;
purpose: Purpose;
}
export interface ListFilesResponse {
data: Array<OpenAIFile>;
object: 'list';
}
export type UploadFileResponse = OpenAIFile;
export type RetrieveFileResponse = OpenAIFile;
import axios, {AxiosPromise, AxiosRequestConfig, Method} from 'axios';
import FormData from 'form-data';
import stream from 'stream';
import {DEFAULT_API_VERSION, ORIGIN} from './config';
import {
CreateAnswerRequestViaDocuments,
CreateAnswerRequestViaFile,
CreateAnswerResponse,
CreateClassificationRequestViaExamples,
CreateClassificationRequestViaFile,
CreateClassificationResponse,
CreateCompletionRequest,
CreateCompletionResponse,
CreateCompletionViaGetRequest,
CreateSearchRequestViaDocuments,
CreateSearchRequestViaFile,
CreateSearchResponse,
EngineResponse,
EnginesListResponse,
ListFilesResponse,
Purpose,
RetrieveFileResponse,
UploadFileResponse
} from './types';
export class OpenAI {
constructor(private readonly apiKey: string, private readonly apiVersion: string = DEFAULT_API_VERSION) {
}
protected wrapAuthenticatedRequest<T = any>(url: string, method: Method, data: {} | FormData | undefined = undefined, axiosConfig: AxiosRequestConfig = {}): AxiosPromise<T> {
function camelToUnderscore(key) {
let result = key.replace(/([A-Z])/g, ' $1');
return result.split(' ').join('_').toLowerCase();
}
return axios({
...axiosConfig,
url,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
...(axiosConfig.headers || {})
},
data,
method,
});
}
protected assembleRequestUrl(relativeAddress: string): string {
return `${ORIGIN}/${this.apiVersion}/${relativeAddress}`;
}
public engines = {
_client: this,
list(): AxiosPromise<EnginesListResponse> {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl('engines'),
'GET',
{}
);
},
retrieve(engineId: string): AxiosPromise<EngineResponse> {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl(`engines/${engineId}`),
'GET',
{}
);
}
};
public completions = {
_client: this,
create(engineId: string, body: CreateCompletionRequest): AxiosPromise<CreateCompletionResponse> {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl(`engines/${engineId}/completions`),
'POST',
body
);
},
createViaGet(engineId: string, body: CreateCompletionViaGetRequest): AxiosPromise<CreateCompletionResponse> {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl(`engines/${engineId}/completions/browser_stream`),
'GET',
body
);
},
};
public searches = {
_client: this,
create(engineId: string, body: CreateSearchRequestViaDocuments | CreateSearchRequestViaFile): AxiosPromise<CreateSearchResponse> {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl(`engines/${engineId}/search`),
'POST',
body
);
}
};
public classifications = {
_client: this,
create(body: CreateClassificationRequestViaExamples | CreateClassificationRequestViaFile): AxiosPromise<CreateClassificationResponse> {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl('classifications'),
'POST',
body
);
}
};
public answers = {
_client: this,
create(body: CreateAnswerRequestViaDocuments | CreateAnswerRequestViaFile): AxiosPromise<CreateAnswerResponse> {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl('answers'),
'POST',
body
);
}
};
public files = {
_client: this,
list(): AxiosPromise<ListFilesResponse> {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl('files'),
'GET'
);
},
upload(body: {
file: string,
purpose: Purpose
}): AxiosPromise<UploadFileResponse> {
const formData = new FormData();
const file = new stream.Readable();
file.push(body.file);
file.push(null);
(file as any).path = 'file.jsonl';
formData.append('purpose', body.purpose);
formData.append('file', file);
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl('files'),
'POST',
formData,
{
headers: formData.getHeaders()
}
);
},
retrieve(fileId: string): AxiosPromise<RetrieveFileResponse> {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl(`files/${fileId}`),
'GET'
);
},
delete(fileId: string): AxiosPromise {
return this._client.wrapAuthenticatedRequest(
this._client.assembleRequestUrl(`files/${fileId}`),
'DELETE'
);
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment