Skip to content

Commit

Permalink
Remove all dependencies and create a native and simple http client
Browse files Browse the repository at this point in the history
  • Loading branch information
joyqi committed Mar 17, 2023
1 parent ffbbe46 commit 717f7b4
Show file tree
Hide file tree
Showing 17 changed files with 397 additions and 193 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# node-openai

An elegant Node.js library written in TypeScript for the OpenAI API.
**An elegant Node.js library written in TypeScript for the OpenAI API. Pure JavaScript, no dependencies. Works in Node.js and the browser.**

[![npm](https://img.shields.io/npm/v/node-openai.svg)](https://www.npmjs.com/package/node-openai)
[![npm](https://img.shields.io/npm/dt/node-openai.svg)](https://www.npmjs.com/package/node-openai)
[![GitHub](https://img.shields.io/github/license/joyqi/node-openai.svg)](https://github.com/joyqi/node-openai/blob/master/LICENSE)
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/joyqi/node-openai/ci.yml)
![Libraries.io dependency status for GitHub repo](https://img.shields.io/librariesio/github/joyqi/node-openai)

- [Installation](#installation)
- [Features](#features)
Expand Down
5 changes: 0 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,5 @@
"ts-node": "latest",
"tsc-esm-fix": "latest",
"typescript": "latest"
},
"dependencies": {
"axios": "^1.3.4",
"form-data": "^4.0.0",
"node-fetch": "^3.3.1"
}
}
122 changes: 7 additions & 115 deletions pnpm-lock.yaml

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

45 changes: 18 additions & 27 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import * as v1 from "./v1";
import fetchPolyfill from "./polyfill/fetch";
import FormDataPolyfill from "./polyfill/formdata";
import { RequestInit as NodeRequestInit } from "node-fetch";
import { Init, request } from "./request";

// ApiConfig defines the configuration options for the OpenAI API
export type ApiConfig = {
apiKey: string;
organization?: string;
endpoint?: string;
options?: ApiInit;
};

type RequestConfig = RequestInit & NodeRequestInit & {
data?: any
};
export type ApiInit = Omit<Init, "signal">;

// ApiVersion defines the version of the OpenAI API
export type ApiVersion = "v1" | "v2";

export type ApiClient = (path: string, options: RequestConfig, direct?: boolean) => Promise<any>;
export type ApiClient = (path: string, options: Init, direct?: boolean) => Promise<any>;

// OpenAI is the main class for the OpenAI API
export class OpenAI {

constructor(private config: ApiConfig) {}

v1() {
Expand Down Expand Up @@ -75,37 +73,30 @@ export class OpenAI {

// Generate a client for the given version of the OpenAI API
private makeClient(version: ApiVersion): ApiClient {
return async (path: string, options: RequestConfig, direct = false) => {
const headers: any = {
return async (path: string, options: Init, direct = false) => {
if (this.config.options) {
options = Object.assign(this.config.options, options);
}

const headers: Record<string, string> = {
Authorization: `Bearer ${this.config.apiKey}`,
};

if (options.data) {
options.body = JSON.stringify(options.data);
delete options.data;
headers["Content-Type"] = "application/json";
} else if (options.body && options.body instanceof FormDataPolyfill) {
headers["Content-Type"] = "multipart/form-data";
if (this.config.organization) {
headers["OpenAI-Organization"] = this.config.organization;
}

options.headers = Object.assign(headers, options.headers || {});

const endpoint = this.config.endpoint || "https://api.openai.com";
const url = `${endpoint}/${version}/${path}`;
const response = await fetchPolyfill(url, options);
const response = await request(url, options, direct ? "original" : "json");

if (!direct && !response.headers.get("content-type")?.match(/^application\/json/)) {
throw new Error(`Unexpected Content-Type: ${response.headers.get("content-type")}`);
} else if (direct) {
return response.body;
} else {
const data = await response.json();
if (response.status != 200) {
throw new Error(direct ? response.statusText : data.error.message);
} else {
return data;
}
if (response.status !== 200) {
throw new Error(direct ? response.statusText : response.body.error.message);
}

return response.body;
}
}
}
5 changes: 0 additions & 5 deletions src/polyfill/fetch.ts

This file was deleted.

5 changes: 0 additions & 5 deletions src/polyfill/formdata.ts

This file was deleted.

5 changes: 0 additions & 5 deletions src/polyfill/readfile.ts

This file was deleted.

Loading

0 comments on commit 717f7b4

Please sign in to comment.