Comparing version 0.0.1 to 0.0.2
{ | ||
"root": true, | ||
"plugins": [ | ||
"@typescript-eslint", | ||
"prettier", | ||
"sort-imports-es6-autofix" | ||
], | ||
"plugins": ["@typescript-eslint", "prettier", "sort-imports-es6-autofix"], | ||
"parser": "@typescript-eslint/parser", | ||
@@ -22,7 +18,3 @@ "parserOptions": { | ||
}, | ||
"ignorePatterns": [ | ||
"dist/*", | ||
"sample/*", | ||
"rollup.config.js" | ||
], | ||
"ignorePatterns": ["dist/*", "sample/*", "rollup.config.js"], | ||
"rules": { | ||
@@ -67,6 +59,3 @@ "no-console": "off", | ||
], | ||
"curly": [ | ||
"error", | ||
"all" | ||
], | ||
"curly": ["error", "all"], | ||
"eqeqeq": "error", | ||
@@ -96,6 +85,3 @@ "max-classes-per-file": "error", | ||
"prefer-promise-reject-errors": "error", | ||
"radix": [ | ||
"error", | ||
"always" | ||
], | ||
"radix": ["error", "always"], | ||
"no-shadow": "off", | ||
@@ -119,6 +105,3 @@ "no-confusing-arrow": [ | ||
], | ||
"@typescript-eslint/consistent-type-definitions": [ | ||
"error", | ||
"interface" | ||
], | ||
"@typescript-eslint/consistent-type-definitions": ["error", "interface"], | ||
"@typescript-eslint/explicit-function-return-type": [ | ||
@@ -140,2 +123,2 @@ "error", | ||
} | ||
} | ||
} |
{ | ||
"name": "openai", | ||
"version": "0.0.1", | ||
"description": "", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "tsc -d --watch", | ||
"build": "tsc -d", | ||
"clean": "rm -rf dist", | ||
"lint": "eslint . --fix --cache", | ||
"lint:nofix": "eslint ." | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/ceifa/openai.git" | ||
}, | ||
"author": "ceifa", | ||
"license": "MIT", | ||
"keywords": [ | ||
"gpt-3", | ||
"gpt", | ||
"ai" | ||
], | ||
"bugs": { | ||
"url": "https://github.com/ceifa/openai/issues" | ||
}, | ||
"homepage": "https://github.com/ceifa/openai#readme", | ||
"devDependencies": { | ||
"@types/node-fetch": "^2.5.12", | ||
"@typescript-eslint/eslint-plugin": "4.28.5", | ||
"@typescript-eslint/parser": "4.28.5", | ||
"eslint": "7.31.0", | ||
"eslint-config-prettier": "8.3.0", | ||
"eslint-plugin-prettier": "3.4.0", | ||
"eslint-plugin-sort-imports-es6-autofix": "0.6.0", | ||
"prettier": "2.3.2", | ||
"tslib": "2.3.0", | ||
"typescript": "4.3.5" | ||
}, | ||
"dependencies": { | ||
"node-fetch": "^2.6.1" | ||
} | ||
"name": "openai", | ||
"version": "0.0.2", | ||
"description": "", | ||
"main": "src/index.ts", | ||
"scripts": { | ||
"start": "tsc -d --watch", | ||
"build": "tsc -d", | ||
"clean": "rm -rf dist", | ||
"lint": "eslint . --fix --cache && prettier --write src", | ||
"lint:nofix": "eslint . && prettier --check src" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/ceifa/openai.git" | ||
}, | ||
"author": "ceifa", | ||
"license": "MIT", | ||
"keywords": [ | ||
"gpt-3", | ||
"gpt", | ||
"ai" | ||
], | ||
"bugs": { | ||
"url": "https://github.com/ceifa/openai/issues" | ||
}, | ||
"homepage": "https://github.com/ceifa/openai#readme", | ||
"devDependencies": { | ||
"@types/node-fetch": "2.5.12", | ||
"@typescript-eslint/eslint-plugin": "4.29.0", | ||
"@typescript-eslint/parser": "4.29.0", | ||
"eslint": "7.32.0", | ||
"eslint-config-prettier": "8.3.0", | ||
"eslint-plugin-prettier": "3.4.0", | ||
"eslint-plugin-sort-imports-es6-autofix": "0.6.0", | ||
"prettier": "2.3.2", | ||
"typescript": "4.3.5" | ||
}, | ||
"dependencies": { | ||
"form-data": "4.0.0", | ||
"node-fetch": "2.6.1", | ||
"tslib": "2.3.0" | ||
} | ||
} |
Not ready for production! | ||
Under intensive development. | ||
Under intensive development. |
@@ -1,4 +0,4 @@ | ||
const { default: OpenAI } = require('../dist'); | ||
const { default: OpenAI } = require('../dist') | ||
const api = new OpenAI(process.env.OPENAI_API_KEY); | ||
api.getEngines().then(console.log) | ||
const api = new OpenAI(process.env.OPENAI_API_KEY) | ||
api.getEngines().then(console.log) |
153
src/index.ts
@@ -0,3 +1,22 @@ | ||
import FormData from 'form-data' | ||
import fetch from 'node-fetch' | ||
import type { DataContainer, Engine } from './types' | ||
import type { | ||
Answer, | ||
AnswerRequest, | ||
Classification, | ||
ClassificationRequest, | ||
Completion, | ||
CompletionRequest, | ||
Engine, | ||
EngineId, | ||
File, | ||
FilePurpose, | ||
FineTune, | ||
FineTuneEvent, | ||
FineTuneRequest, | ||
JsonLines, | ||
List, | ||
SearchDocument, | ||
SearchRequest, | ||
} from './types' | ||
@@ -11,14 +30,11 @@ const baseUrl = 'https://api.openai.com' | ||
constructor( | ||
apiKey: string, | ||
organizationId?: string, | ||
version: string = defaultVersion | ||
) { | ||
constructor(apiKey: string, organizationId?: string, version: string = defaultVersion) { | ||
// https://beta.openai.com/docs/api-reference/authentication | ||
this.headers = { | ||
'Authorization': `Bearer ${apiKey}`, | ||
'Content-Type': 'application/json' | ||
'authorization': `Bearer ${apiKey}`, | ||
'content-type': 'application/json', | ||
} | ||
if (organizationId) { | ||
this.headers['OpenAI-Organization'] = organizationId | ||
this.headers['openai-organization'] = organizationId | ||
} | ||
@@ -29,16 +45,119 @@ | ||
public async getEngines(): Promise<Engine[]> { | ||
const result = await this.request('/engines', 'GET') as DataContainer<Engine[]> | ||
return result.data | ||
// https://beta.openai.com/docs/api-reference/engines/list | ||
public getEngines(): Promise<Engine[]> { | ||
return this.request<List<Engine>>('/engines', 'GET').then((r) => r.data) | ||
} | ||
private async request(path: string, method: string, body?: unknown): Promise<unknown> { | ||
// https://beta.openai.com/docs/api-reference/engines/retrieve | ||
public getEngine(engine: EngineId): Promise<Engine> { | ||
return this.request<Engine>(`/engines/${engine}`, 'GET') | ||
} | ||
// https://beta.openai.com/docs/api-reference/completions/create | ||
public complete(engine: EngineId, options: CompletionRequest): Promise<Completion> { | ||
return this.request<Completion>(`/engines/${engine}/completions`, 'POST', options) | ||
} | ||
// https://beta.openai.com/docs/api-reference/searches/create | ||
public search(engine: EngineId, options: SearchRequest): Promise<SearchDocument[]> { | ||
return this.request<List<SearchDocument>>(`/engines/${engine}/search`, 'POST', options).then((r) => r.data) | ||
} | ||
// https://beta.openai.com/docs/api-reference/classifications/create | ||
public classify(options: ClassificationRequest): Promise<Classification> { | ||
return this.request<Classification>('/classifications', 'POST', options) | ||
} | ||
// https://beta.openai.com/docs/api-reference/answers/create | ||
public answer(options: AnswerRequest): Promise<Answer> { | ||
return this.request<Answer>('/answers', 'POST', options) | ||
} | ||
// https://beta.openai.com/docs/api-reference/files/list | ||
public getFiles(): Promise<File[]> { | ||
return this.request<List<File>>('/files', 'GET').then((r) => r.data) | ||
} | ||
// https://beta.openai.com/docs/api-reference/files/upload | ||
public uploadFile(file: string, jsonlines: JsonLines, purpose: FilePurpose): Promise<File> { | ||
const data = new FormData() | ||
let fileJsonlines: string | ||
if (Array.isArray(jsonlines)) { | ||
if (typeof jsonlines[0] === 'object') { | ||
jsonlines = jsonlines.map((j) => JSON.stringify(j)) | ||
} | ||
fileJsonlines = jsonlines.join('\n') | ||
} else { | ||
fileJsonlines = jsonlines | ||
} | ||
data.append('file', fileJsonlines, file) | ||
data.append('purpose', purpose) | ||
return this.request<File>('/files', 'POST', data) | ||
} | ||
// https://beta.openai.com/docs/api-reference/files/retrieve | ||
public getFile(fileId: string): Promise<File> { | ||
return this.request<File>(`/files/${fileId}`, 'GET') | ||
} | ||
// https://beta.openai.com/docs/api-reference/files/delete | ||
public deleteFile(fileId: string): Promise<void> { | ||
return this.request<void>(`/files/${fileId}`, 'DELETE') | ||
} | ||
// https://beta.openai.com/docs/api-reference/fine-tunes/create | ||
public finetune(options: FineTuneRequest): Promise<FineTune> { | ||
return this.request<FineTune>(`/fine-tunes`, 'POST', options) | ||
} | ||
// https://beta.openai.com/docs/api-reference/fine-tunes/list | ||
public getFinetunes(): Promise<FineTune[]> { | ||
return this.request<List<FineTune>>('/fine-tunes', 'GET').then((r) => r.data) | ||
} | ||
// https://beta.openai.com/docs/api-reference/fine-tunes/retrieve | ||
public getFinetune(finetuneId: string): Promise<FineTune> { | ||
return this.request<FineTune>(`/fine-tunes/${finetuneId}`, 'GET') | ||
} | ||
// https://beta.openai.com/docs/api-reference/fine-tunes/cancel | ||
public cancelFinetune(finetuneId: string): Promise<FineTune> { | ||
return this.request<FineTune>(`/fine-tunes/${finetuneId}/cancel`, 'POST') | ||
} | ||
// https://beta.openai.com/docs/api-reference/fine-tunes/events | ||
public getFinetuneEvents(finetuneId: string): Promise<FineTuneEvent[]> { | ||
return this.request<List<FineTuneEvent>>(`/fine-tunes/${finetuneId}/events`, 'GET').then((r) => r.data) | ||
} | ||
private async request<TResponse>(path: string, method: 'GET' | 'POST' | 'DELETE', body?: any): Promise<TResponse> { | ||
let headers = this.headers | ||
if (body instanceof FormData) { | ||
delete headers['content-type'] | ||
headers = body.getHeaders(headers) | ||
} else if (!['string', 'undefined'].includes(typeof body)) { | ||
body = JSON.stringify(body) | ||
} | ||
const response = await fetch(this.url + path, { | ||
headers: this.headers, | ||
headers, | ||
method, | ||
body: typeof body === 'string' ? body : JSON.stringify(body) | ||
body: body, | ||
}) | ||
if (!response.ok) { | ||
throw new Error(`OpenAI did not return ok: ${response.status}`) | ||
let errorBody | ||
try { | ||
errorBody = await response.text() | ||
} catch { | ||
errorBody = 'Failed to get body as text' | ||
} | ||
throw new Error(`OpenAI did not return ok: ${response.status} ~ Error body: ${errorBody}`) | ||
} | ||
@@ -48,2 +167,2 @@ | ||
} | ||
} | ||
} |
179
src/types.ts
export type EngineId = 'davinci' | 'curie' | 'babbage' | 'ada' | string | ||
// The 'unknowns' it's because I don't actually know | ||
// TODO: Discover these types | ||
export interface Engine { | ||
id: EngineId | ||
object: string | ||
object: 'engine' | ||
created?: Date | ||
@@ -17,5 +15,174 @@ max_replicas?: number | ||
export interface DataContainer<T> { | ||
export interface List<T> { | ||
object: 'list' | ||
data: T[] | ||
} | ||
export interface CompletionRequest { | ||
prompt?: string | string[] | ||
max_tokens?: number | ||
temperature?: number | ||
top_p?: number | ||
n?: number | ||
stream?: boolean | ||
logprobs?: number | ||
echo?: boolean | ||
stop?: string | string[] | ||
presence_penalty?: number | ||
frequency_penalty?: number | ||
best_of?: number | ||
logit_bias?: Record<string, unknown> | ||
} | ||
export interface Choice { | ||
text: string | ||
index: number | ||
logprobes: number | null | ||
finish_reason: string | null | ||
} | ||
export interface Completion { | ||
id: string | ||
object: 'text_completion' | ||
created: number | ||
model: string | ||
choices: Choice[] | ||
} | ||
export interface SearchRequest { | ||
query: string | ||
documents?: string[] | ||
file?: string | ||
max_rerank?: number | ||
return_metadata?: boolean | ||
} | ||
export interface SearchDocument { | ||
document: number | ||
object: 'search_result' | ||
score: number | ||
} | ||
export interface ClassificationRequest { | ||
model: string | ||
query: string | ||
examples?: string[] | ||
file?: string | ||
labels?: string[] | null | ||
search_model?: string | ||
temperature?: number | ||
logprobs?: number | ||
max_examples?: number | ||
logit_bias?: Record<string, unknown> | ||
return_prompt?: boolean | ||
return_metadata?: boolean | ||
expand?: string[] | ||
} | ||
export interface ClassificationExample { | ||
document: number | ||
label: string | ||
text: string | ||
} | ||
export interface Classification { | ||
completion: string | ||
label: string | ||
model: string | ||
object: 'classification' | ||
search_model: string | ||
selected_examples: ClassificationExample[] | ||
} | ||
export interface AnswerRequest { | ||
model: string | ||
question: string | ||
examples: Array<[string, string]> | ||
examples_context: string | ||
documents?: string[] | ||
file?: string | ||
search_model?: string | ||
max_rerank?: number | ||
temperature?: number | ||
logprobs?: number | ||
max_tokens?: number | ||
stop?: string | string[] | ||
n?: number | ||
logit_bias?: Record<string, unknown> | ||
return_metadata?: boolean | ||
return_prompt?: boolean | ||
expand?: string[] | ||
} | ||
export interface AnswerDocument { | ||
document: number | ||
text: string | ||
} | ||
export interface Answer { | ||
answers: string[] | ||
completion: string | Completion | ||
model: string | ||
object: 'answer' | ||
search_model: string | ||
prompt: string | ||
selected_documents: AnswerDocument[] | ||
} | ||
export type FilePurpose = 'search' | 'answers' | 'classifications' | 'fine-tune' | ||
// TODO: Improve jsonlines typing | ||
export type JsonLines = string | string[] | unknown[] | ||
export interface File { | ||
id: string | ||
object: string | ||
data: T | ||
} | ||
bytes: number | ||
created_at: number | ||
filename: string | ||
purpose: FilePurpose | ||
} | ||
export interface Hyperparams { | ||
n_epochs?: number | ||
batch_size?: number | ||
learning_rate_multiplier?: number | ||
use_packing?: boolean | ||
prompt_loss_weight?: number | ||
} | ||
export interface FineTuneRequest extends Hyperparams { | ||
training_file: string | ||
validation_file?: string | ||
model?: string | ||
compute_classification_metrics?: boolean | ||
classification_n_classes?: number | ||
classification_positive_class?: string | ||
classification_betas?: number[] | ||
} | ||
export interface FineTuneEvent { | ||
object: 'fine-tune-event' | ||
created_at: number | ||
// TODO: Improve level typing | ||
level: string | ||
message: string | ||
} | ||
export interface FineTune { | ||
id: string | ||
object: 'fine-tune' | ||
model: string | ||
created_at: number | ||
events: FineTuneEvent[] | ||
fine_tuned_model: string | ||
hyperparams: Hyperparams | ||
organization_id: string | ||
result_files: File[] | ||
// TODO: Improve status typing | ||
status: string | ||
validation_files: File[] | ||
training_files: File[] | ||
updated_at: number | ||
user_id: string | ||
} |
@@ -8,9 +8,7 @@ { | ||
"sourceMap": false, | ||
"target": "ES6", | ||
"target": "ESNext", | ||
"esModuleInterop": true, | ||
"module": "UMD", | ||
"skipLibCheck": true, | ||
"lib": [ | ||
"ESNEXT", | ||
"DOM" | ||
], | ||
"lib": ["ESNEXT", "DOM"], | ||
"forceConsistentCasingInFileNames": true, | ||
@@ -26,8 +24,4 @@ "noImplicitReturns": true, | ||
}, | ||
"include": [ | ||
"src/**/*" | ||
], | ||
"exclude": [ | ||
"node_modules" | ||
], | ||
} | ||
"include": ["src/**/*"], | ||
"exclude": ["node_modules"] | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
18618
9
448
4
1
3
+ Addedform-data@4.0.0
+ Addedtslib@2.3.0
+ Addedasynckit@0.4.0(transitive)
+ Addedcombined-stream@1.0.8(transitive)
+ Addeddelayed-stream@1.0.0(transitive)
+ Addedform-data@4.0.0(transitive)
+ Addedmime-db@1.52.0(transitive)
+ Addedmime-types@2.1.35(transitive)
+ Addednode-fetch@2.6.1(transitive)
+ Addedtslib@2.3.0(transitive)
- Removednode-fetch@2.7.0(transitive)
- Removedtr46@0.0.3(transitive)
- Removedwebidl-conversions@3.0.1(transitive)
- Removedwhatwg-url@5.0.0(transitive)
Updatednode-fetch@2.6.1