From b719369df97b0321b8c90bd5b8bf9be7cbfe85b9 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Mon, 6 May 2024 16:23:42 +0530 Subject: [PATCH 01/15] feat: beta.vectorStores beta.Chats updated assistant and threads --- package-lock.json | 14 +- package.json | 2 +- src/apis/assistants.ts | 115 -------- src/apis/betaChat.ts | 128 +++++++++ src/apis/files.ts | 24 ++ src/apis/index.ts | 3 +- src/apis/threads.ts | 282 ++++++++++++++---- src/apis/vectorStores.ts | 606 +++++++++++++++++++++++++++++++++++++++ src/client.ts | 12 +- 9 files changed, 995 insertions(+), 191 deletions(-) create mode 100644 src/apis/betaChat.ts create mode 100644 src/apis/vectorStores.ts diff --git a/package-lock.json b/package-lock.json index 151d345..662cc0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "agentkeepalive": "^4.5.0", "dotenv": "^16.3.1", - "openai": "4.36.0" + "openai": "^4.41.0" }, "devDependencies": { "@babel/core": "^7.23.3", @@ -5564,9 +5564,9 @@ } }, "node_modules/openai": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.36.0.tgz", - "integrity": "sha512-AtYrhhWY64LhB9P6f3H0nV8nTSaQJ89mWPnfNU5CnYg81zlYaV8nkyO+aTNfprdqP/9xv10woNNUgefXINT4Dg==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.41.0.tgz", + "integrity": "sha512-fiV+RvUGRW+PXxycqeDYuOwsL3TxNqT/LcM6vlqyLz9ACmfSUGg1qviQrHuuNKL7gFOvfzgEJRVVFdqmv/sjxg==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -5582,9 +5582,9 @@ } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.17.tgz", - "integrity": "sha512-SzyGKgwPzuWp2SHhlpXKzCX0pIOfcI4V2eF37nNBJOhwlegQ83omtVQ1XxZpDE06V/d6AQvfQdPfnw0tRC//Ng==", + "version": "18.19.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", + "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", "dependencies": { "undici-types": "~5.26.4" } diff --git a/package.json b/package.json index f29ad02..b730c18 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,6 @@ "dependencies": { "agentkeepalive": "^4.5.0", "dotenv": "^16.3.1", - "openai": "4.36.0" + "openai": "4.41.0" } } diff --git a/src/apis/assistants.ts b/src/apis/assistants.ts index f9a8eb5..1a54a32 100644 --- a/src/apis/assistants.ts +++ b/src/apis/assistants.ts @@ -47,13 +47,6 @@ export interface AssistantUpdateParams { export class Assistants extends ApiResource { - - files: Files; - - constructor(client:any) { - super(client); - this.files = new Files(client); - } async create( _body: AssistantCreateParams, @@ -181,111 +174,3 @@ export class Assistants extends ApiResource { } } - -export class Files extends ApiResource{ - - async create( - assistantId: string, - _body: FileCreateParams, - params?: ApiClientInterface, - opts?: RequestOptions - ): Promise { - const body: FileCreateParams = _body; - if (params) { - const config = overrideConfig(this.client.config, params.config); - this.client.customHeaders = { - ...this.client.customHeaders, - ...createHeaders({ ...params, config }), - }; - } - - - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); - - const result = await OAIclient.beta.assistants.files.create(assistantId, body, opts).withResponse(); - - return finalResponse(result); - } - - async list( - assistantId: string, - _query?: FileListParams, - params?: ApiClientInterface, - opts?: RequestOptions - ): Promise { - const query: FileListParams | undefined = _query; - if (params) { - const config = overrideConfig(this.client.config, params.config); - this.client.customHeaders = { - ...this.client.customHeaders, - ...createHeaders({ ...params, config }), - }; - } - - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const result = await OAIclient.beta.assistants.files.list(assistantId, query, opts).withResponse(); - - return finalResponse(result); - } - - async retrieve( - assistantId: string, - fileId: string, - params?: ApiClientInterface, - opts?: RequestOptions - ): Promise { - if (params) { - const config = overrideConfig(this.client.config, params.config); - this.client.customHeaders = { - ...this.client.customHeaders, - ...createHeaders({ ...params, config }), - }; - } - - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); - - const result = await OAIclient.beta.assistants.files.retrieve(assistantId, fileId, opts).withResponse(); - - return finalResponse(result); - } - - async del( - assistantId: string, - fileId: string, - params?: ApiClientInterface, - opts?: RequestOptions - ): Promise { - if (params) { - const config = overrideConfig(this.client.config, params.config); - this.client.customHeaders = { - ...this.client.customHeaders, - ...createHeaders({ ...params, config }), - }; - } - - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); - - const result = await OAIclient.beta.assistants.files.del(assistantId, fileId, opts).withResponse(); - - return finalResponse(result); - } - -} \ No newline at end of file diff --git a/src/apis/betaChat.ts b/src/apis/betaChat.ts new file mode 100644 index 0000000..b89a879 --- /dev/null +++ b/src/apis/betaChat.ts @@ -0,0 +1,128 @@ +import { ChatCompletionStreamParams } from "openai/lib/ChatCompletionStream"; +import { ApiClientInterface } from "../_types/generalTypes"; +import { ApiResource } from "../apiResource"; +import { RequestOptions } from "../baseClient"; +import { OPEN_AI_API_KEY } from "../constants"; +import { defaultHeadersBuilder, overrideConfig } from "../utils"; +import { createHeaders } from "./createHeaders"; +import OpenAI from "openai"; +import { + ChatCompletionFunctionRunnerParams, + ChatCompletionToolRunnerParams, +} from "openai/lib/ChatCompletionRunner"; +import { + ChatCompletionStreamingFunctionRunnerParams, + ChatCompletionStreamingToolRunnerParams, +} from "openai/lib/ChatCompletionStreamingRunner"; + +export class BetaChat extends ApiResource { + completions: Completions; + + constructor(client: any) { + super(client); + this.completions = new Completions(client); + } +} + +export class Completions extends ApiResource { + + async runFunctions( + body: ChatCompletionFunctionRunnerParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise; + async runFunctions( + body: ChatCompletionStreamingFunctionRunnerParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise; + async runFunctions( + _body: + ChatCompletionFunctionRunnerParams + | ChatCompletionStreamingFunctionRunnerParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: any = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.chat.completions.runFunctions( + body, + opts + ); + return result; + } + + async runTools( + body: ChatCompletionToolRunnerParams, + params?: ApiClientInterface, + opts?: RequestOptions, + ): Promise; + async runTools( + body: ChatCompletionStreamingToolRunnerParams, + params?: ApiClientInterface, + opts?: RequestOptions, + ): Promise; + async runTools( + _body: + | ChatCompletionToolRunnerParams + | ChatCompletionStreamingToolRunnerParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: any = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.chat.completions.runTools(body, opts); + return result; + } + + async stream( + _body:ChatCompletionStreamParams, + params?: ApiClientInterface, + opts?: RequestOptions): Promise { + const body: ChatCompletionStreamParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.chat.completions.stream(body, opts); + return result; + } +} + +export type BaseFunctionsArgs = readonly (object | string)[]; diff --git a/src/apis/files.ts b/src/apis/files.ts index dd9b69b..51ab26b 100644 --- a/src/apis/files.ts +++ b/src/apis/files.ts @@ -108,6 +108,30 @@ export class MainFiles extends ApiResource { return finalResponse(result); } + async content( + fileId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.files.content(fileId, opts).withResponse(); + + return finalResponse(result); + } + async retrieveContent( fileId: string, params?: ApiClientInterface, diff --git a/src/apis/index.ts b/src/apis/index.ts index ab53264..17c2fed 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -10,4 +10,5 @@ export { Assistants } from "./assistants"; export { Threads } from "./threads"; export { MainFiles } from "./files"; export { Models } from "./models"; - +export { VectorStores } from "./vectorStores" +export { BetaChat } from "./betaChat" diff --git a/src/apis/threads.ts b/src/apis/threads.ts index 3e9d6ee..06964f4 100644 --- a/src/apis/threads.ts +++ b/src/apis/threads.ts @@ -143,18 +143,60 @@ export class Threads extends ApiResource { return finalResponse(result); } + async createAndRunPoll( + _body: ThreadCreateAndRunParamsNonStreaming, + params?: ApiClientInterface, + opts?: RequestOptions & {pollIntervalMs?: number} + ): Promise { + const body: ThreadCreateAndRunParamsNonStreaming = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.threads.createAndRunPoll(body, opts) + return result; + + } + + async createAndRunStream( + _body: ThreadCreateAndRunParamsBaseStream, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: ThreadCreateAndRunParamsBaseStream = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.threads.createAndRunStream(body, opts); + return result; + } + } export class Messages extends ApiResource{ - files: Files; - - constructor(client:any) { - super(client); - this.files = new Files(client); - } - async create( threadId: string, _body: MessageCreateParams, @@ -265,16 +307,23 @@ export class Messages extends ApiResource{ } -export class Files extends ApiResource{ - async list( +export class Runs extends ApiResource{ + + steps: Steps; + + constructor(client:any) { + super(client); + this.steps = new Steps(client); + } + + async create( threadId: string, - messageId: string, - _query?: FileListParams, + _body: RunCreateParams, params?: ApiClientInterface, opts?: RequestOptions ): Promise { - const query: FileListParams | undefined = _query; + const body: RunCreateParams = _body; if (params) { const config = overrideConfig(this.client.config, params.config); this.client.customHeaders = { @@ -282,26 +331,25 @@ export class Files extends ApiResource{ ...createHeaders({ ...params, config }), }; } - + const OAIclient = new OpenAI({ apiKey: OPEN_AI_API_KEY, baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const result = await OAIclient.beta.threads.messages.files.list(threadId, messageId, query, opts).withResponse(); + + const result = await OAIclient.beta.threads.runs.create(threadId, body, opts).withResponse(); return finalResponse(result); } - async retrieve( + async list( threadId: string, - messageId: string, - fileId: string, + _query?: RunListParams, params?: ApiClientInterface, opts?: RequestOptions ): Promise { + const query: RunListParams | undefined = _query; if (params) { const config = overrideConfig(this.client.config, params.config); this.client.customHeaders = { @@ -309,37 +357,25 @@ export class Files extends ApiResource{ ...createHeaders({ ...params, config }), }; } - + const OAIclient = new OpenAI({ apiKey: OPEN_AI_API_KEY, baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); - - const result = await OAIclient.beta.threads.messages.files.retrieve(threadId, messageId, fileId, opts).withResponse(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const result = await OAIclient.beta.threads.runs.list(threadId, query, opts).withResponse(); return finalResponse(result); } -} - - -export class Runs extends ApiResource{ - - steps: Steps; - - constructor(client:any) { - super(client); - this.steps = new Steps(client); - } - - async create( + async retrieve( threadId: string, - _body: RunCreateParams, + runId: string, params?: ApiClientInterface, opts?: RequestOptions ): Promise { - const body: RunCreateParams = _body; if (params) { const config = overrideConfig(this.client.config, params.config); this.client.customHeaders = { @@ -347,25 +383,26 @@ export class Runs extends ApiResource{ ...createHeaders({ ...params, config }), }; } - + const OAIclient = new OpenAI({ apiKey: OPEN_AI_API_KEY, baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); - const result = await OAIclient.beta.threads.runs.create(threadId, body, opts).withResponse(); + const result = await OAIclient.beta.threads.runs.retrieve(threadId, runId, opts).withResponse(); return finalResponse(result); } - async list( + async update( threadId: string, - _query?: RunListParams, + runId: string, + _body: RunUpdateParams, params?: ApiClientInterface, opts?: RequestOptions ): Promise { - const query: RunListParams | undefined = _query; + const body: RunUpdateParams = _body; if (params) { const config = overrideConfig(this.client.config, params.config); this.client.customHeaders = { @@ -379,19 +416,20 @@ export class Runs extends ApiResource{ baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const result = await OAIclient.beta.threads.runs.list(threadId, query, opts).withResponse(); + + const result = await OAIclient.beta.threads.runs.update(threadId, runId, body, opts).withResponse(); return finalResponse(result); } - async retrieve( + async submitToolOutputs( threadId: string, runId: string, + _body: RunSubmitToolOutputsParams, params?: ApiClientInterface, opts?: RequestOptions ): Promise { + const body: RunSubmitToolOutputsParams = _body; if (params) { const config = overrideConfig(this.client.config, params.config); this.client.customHeaders = { @@ -406,19 +444,19 @@ export class Runs extends ApiResource{ defaultHeaders: defaultHeadersBuilder(this.client), }); - const result = await OAIclient.beta.threads.runs.retrieve(threadId, runId, opts).withResponse(); + const result = await OAIclient.beta.threads.runs.submitToolOutputs(threadId, runId, body, opts).withResponse(); return finalResponse(result); } - async update( + async submitToolOutputsAndPoll( threadId: string, runId: string, - _body: RunUpdateParams, + _body: RunSubmitToolOutputsParamsNonStreaming, params?: ApiClientInterface, - opts?: RequestOptions - ): Promise { - const body: RunUpdateParams = _body; + opts?: RequestOptions & {pollIntervalMs?: number} + ): Promise { + const body: RunSubmitToolOutputsParamsNonStreaming = _body; if (params) { const config = overrideConfig(this.client.config, params.config); this.client.customHeaders = { @@ -433,19 +471,18 @@ export class Runs extends ApiResource{ defaultHeaders: defaultHeadersBuilder(this.client), }); - const result = await OAIclient.beta.threads.runs.update(threadId, runId, body, opts).withResponse(); - - return finalResponse(result); + const result = await OAIclient.beta.threads.runs.submitToolOutputsAndPoll(threadId, runId, body, opts); + return result; } - async submitToolOutputs( + async submitToolOutputsStream( threadId: string, runId: string, - _body: RunSubmitToolOutputsParams, + _body: RunSubmitToolOutputsParamsStreaming, params?: ApiClientInterface, opts?: RequestOptions - ): Promise { - const body: RunSubmitToolOutputsParams = _body; + ): Promise { + const body: RunSubmitToolOutputsParamsStreaming = _body; if (params) { const config = overrideConfig(this.client.config, params.config); this.client.customHeaders = { @@ -460,9 +497,8 @@ export class Runs extends ApiResource{ defaultHeaders: defaultHeadersBuilder(this.client), }); - const result = await OAIclient.beta.threads.runs.submitToolOutputs(threadId, runId, body, opts).withResponse(); - - return finalResponse(result); + const result = await OAIclient.beta.threads.runs.submitToolOutputsStream(threadId, runId, body, opts); + return result; } async cancel( @@ -490,6 +526,105 @@ export class Runs extends ApiResource{ return finalResponse(result); } + async createAndPoll( + threadId: string, + _body: RunCreateParamsNonStreaming, + params?: ApiClientInterface, + opts?: RequestOptions & {pollIntervalMs?: number}, + ): Promise { + const body: RunCreateParamsNonStreaming = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.threads.runs.createAndPoll(threadId, body, opts); + return result; + } + + async createAndStream( + threadId: string, + _body: RunCreateParamsBaseStream, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: RunCreateParamsBaseStream = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.threads.runs.createAndStream(threadId, body, opts); + return result; + } + + async poll( + threadId: string, + runId: string, + params?: ApiClientInterface, + opts?: RequestOptions & {pollIntervalMs?: number} + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.threads.runs.poll(threadId, runId, opts); + return result + } + + async stream( + threadId: string, + _body: RunCreateParamsBaseStream, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: RunCreateParamsBaseStream = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.threads.runs.stream(threadId, body, opts); + return result; + } + } export class Steps extends ApiResource{ @@ -605,6 +740,9 @@ export interface RunCreateParams { tools?: Array | null; } +export interface RunCreateParamsNonStreaming extends RunCreateParams { + stream?: false | null; +} export interface ThreadCreateAndRunParams { assistant_id: string; @@ -615,6 +753,14 @@ export interface ThreadCreateAndRunParams { tools?: Array | null; } +export interface ThreadCreateAndRunParamsNonStreaming extends ThreadCreateAndRunParams{ + stream?: false | null; +} + +export type ThreadCreateAndRunParamsBaseStream = Omit & { + stream?: true; +}; + export interface RunListParams extends CursorPageParams { before?: string; order?: string; @@ -638,3 +784,15 @@ export interface ToolOutput { output?: string; tool_call_id?: string; } + +export type RunCreateParamsBaseStream = Omit & { + stream?: true; +}; + +export interface RunSubmitToolOutputsParamsNonStreaming extends RunSubmitToolOutputsParams { + stream?: false | null; +} + +export interface RunSubmitToolOutputsParamsStreaming extends RunSubmitToolOutputsParams { + stream: true; +} \ No newline at end of file diff --git a/src/apis/vectorStores.ts b/src/apis/vectorStores.ts new file mode 100644 index 0000000..022c7b3 --- /dev/null +++ b/src/apis/vectorStores.ts @@ -0,0 +1,606 @@ +import { Uploadable } from "openai/uploads"; +import { ApiClientInterface } from "../_types/generalTypes"; +import { ApiResource } from "../apiResource"; +import { RequestOptions } from "../baseClient"; +import { OPEN_AI_API_KEY } from "../constants"; +import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { createHeaders } from "./createHeaders"; +import OpenAI from "openai"; + +export class VectorStores extends ApiResource { + files: Files; + fileBatches: FileBatches + + constructor(client: any) { + super(client); + this.files = new Files(client); + this.fileBatches = new FileBatches(client); + } + + async create( + _body: VectorStoreCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: VectorStoreCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const result = await OAIclient.beta.vectorStores + .create(body, opts) + .withResponse(); + + return finalResponse(result); + } + + async retrieve( + vectorStoreId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores + .retrieve(vectorStoreId, opts) + .withResponse(); + + return finalResponse(result); + } + + async update( + vectorStoreId: string, + _body: VectorStoreUpdateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: VectorStoreUpdateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores + .update(vectorStoreId, body, opts) + .withResponse(); + + return finalResponse(result); + } + + async list( + _query?: VectorStoreListParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const query: VectorStoreListParams | undefined = _query; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores + .list(query, opts) + .withResponse(); + return finalResponse(result); + } + + async del( + vectorStoreId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores + .del(vectorStoreId, opts) + .withResponse(); + + return finalResponse(result); + + } + +} + +export class Files extends ApiResource{ + + + async create( + vectorStoreId: string, + _body: FileCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: FileCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores + .files.create(vectorStoreId, body, opts) + .withResponse(); + + return finalResponse(result); + } + + async retrieve( + vectorStoreId: string, + fileId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores.files.retrieve(vectorStoreId, fileId, opts).withResponse(); + + return finalResponse(result); + } + + async list( + vectorStoreId: string, + _query?: FileListParams | RequestOptions, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const query: FileListParams | RequestOptions| undefined = _query; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const result = await OAIclient.beta.vectorStores.files.list(vectorStoreId, query, opts).withResponse(); + + return finalResponse(result); + } + + async del( + vectorStoreId: string, + fileId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores.files.del(vectorStoreId, fileId, opts).withResponse(); + + return finalResponse(result); + } + + async createAndPoll( + vectorStoreId: string, + _body: FileCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: FileCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores + .files.createAndPoll(vectorStoreId, body, opts); + + return result; + } + + async poll( + vectorStoreId: string, + fileId: string, + params?: ApiClientInterface, + opts?: RequestOptions & { pollIntervalMs?: number } + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores.files.poll(vectorStoreId, fileId, opts); + + return result; + } + + async upload( + vectorStoreId: string, + file: Uploadable, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores.files.upload(vectorStoreId, file, opts); + + return result; + } + + async uploadAndPoll( + vectorStoreId: string, + file: Uploadable, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores.files.uploadAndPoll(vectorStoreId, file, opts); + + return result; + + } +} + +export class FileBatches extends ApiResource{ + + async create( + vectorStoreId: string, + _body: FileBatchCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: FileBatchCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores + .fileBatches.create(vectorStoreId, body, opts) + .withResponse(); + + return finalResponse(result); + } + + async retrieve( + vectorStoreId: string, + batchId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores.fileBatches.retrieve(vectorStoreId, batchId, opts).withResponse(); + + return finalResponse(result); + } + + async cancel( + vectorStoreId: string, + batchId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores.fileBatches.cancel(vectorStoreId, batchId, opts).withResponse(); + + return finalResponse(result); + + } + + async createAndPoll( + vectorStoreId: string, + _body: FileBatchCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: FileBatchCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores + .fileBatches.createAndPoll(vectorStoreId, body, opts); + + return result; + } + + async listFiles( + vectorStoreId: string, + batchId: string, + _query?: FileBatchListFilesParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const query: FileBatchListFilesParams | undefined = _query; + + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const result = await OAIclient.beta.vectorStores.fileBatches.listFiles(vectorStoreId, batchId, query, opts).withResponse(); + + return finalResponse(result); + } + + async poll( + vectorStoreId: string, + batchId: string, + params?: ApiClientInterface, + opts?: RequestOptions & { pollIntervalMs?: number } + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores.fileBatches.poll(vectorStoreId, batchId, opts); + + return result; + } + + async uploadAndPoll( + vectorStoreId: string, + { files, fileIds = [] }: { files: Uploadable[]; fileIds?: string[] }, + params?: ApiClientInterface, + opts?: RequestOptions & { pollIntervalMs?: number; maxConcurrency?: number }, + ): Promise { + if(params){ + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + } + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, { files, fileIds }, opts); + return result; + } +} + + + +export interface ExpiresAfter { + anchor: "last_active_at"; + days: number; +} + +export interface VectorStoreCreateParams { + expires_after?: ExpiresAfter; + file_ids?: Array; + metadata?: unknown | null; + name?: string; +} + +export interface VectorStoreUpdateParams { + expires_after?: ExpiresAfter | null; + metadata?: unknown | null; + name?: string | null; +} + +export interface VectorStoreListParams extends CursorPageParams { + before?: string; + order?: "asc" | "desc"; +} + +export interface CursorPageParams { + after?: string; + + limit?: number; +} + + +export interface FileCreateParams { + file_id: string; +} + +export interface FileListParams extends CursorPageParams { + before?: string; + filter?: 'in_progress' | 'completed' | 'failed' | 'cancelled'; + order?: 'asc' | 'desc'; + } + + export interface FileBatchCreateParams { + file_ids: Array; + } + + export interface FileBatchListFilesParams extends CursorPageParams { + before?: string; + filter?: 'in_progress' | 'completed' | 'failed' | 'cancelled'; + order?: 'asc' | 'desc'; + } \ No newline at end of file diff --git a/src/client.ts b/src/client.ts index 23559d5..1869a3e 100644 --- a/src/client.ts +++ b/src/client.ts @@ -62,16 +62,18 @@ export class Portkey extends ApiClient { completions: API.Completions = new API.Completions(this); chat = new API.Chat(this); - generations = new API.Generations(this); - prompts = new API.Prompt(this); - feedback = new API.Feedback(this); embeddings = new API.Embeddings(this); - images = new API.Images(this); files = new API.MainFiles(this); + images = new API.Images(this); models = new API.Models(this); + generations = new API.Generations(this); + prompts = new API.Prompt(this); + feedback = new API.Feedback(this); beta = { assistants: new API.Assistants(this), - threads: new API.Threads(this) + threads: new API.Threads(this), + vectorStores: new API.VectorStores(this), + chat: new API.BetaChat(this), }; From d0f9e406164534b15efe7ce428a7e61d350a9532 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Mon, 6 May 2024 16:42:03 +0530 Subject: [PATCH 02/15] feat: batches support added --- src/apis/batches.ts | 106 ++++++++++++++++++++++++++++++++++++++++++++ src/apis/index.ts | 1 + src/client.ts | 1 + 3 files changed, 108 insertions(+) create mode 100644 src/apis/batches.ts diff --git a/src/apis/batches.ts b/src/apis/batches.ts new file mode 100644 index 0000000..fa898f9 --- /dev/null +++ b/src/apis/batches.ts @@ -0,0 +1,106 @@ +import { BatchCreateParams, BatchListParams } from "openai/resources/batches"; +import { ApiClientInterface } from "../_types/generalTypes"; +import { ApiResource } from "../apiResource"; +import { RequestOptions } from "../baseClient"; +import { OPEN_AI_API_KEY } from "../constants"; +import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { createHeaders } from "./createHeaders"; +import OpenAI from "openai"; + +export class Batches extends ApiResource{ + + async create( + _body: BatchCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: BatchCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.batches.create(body, opts).withResponse(); + return finalResponse(result); + } + + async retrieve( + batchId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.batches.retrieve(batchId, opts).withResponse(); + return finalResponse(result); + } + + async list( + _query?: BatchListParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const query: BatchListParams | undefined = _query; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.batches.list(query, opts).withResponse(); + return finalResponse(result); + } + + async cancel( + batchId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.batches.cancel(batchId, opts).withResponse(); + return finalResponse(result); + } +} + diff --git a/src/apis/index.ts b/src/apis/index.ts index 17c2fed..7820354 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -10,5 +10,6 @@ export { Assistants } from "./assistants"; export { Threads } from "./threads"; export { MainFiles } from "./files"; export { Models } from "./models"; +export { Batches } from "./batches"; export { VectorStores } from "./vectorStores" export { BetaChat } from "./betaChat" diff --git a/src/client.ts b/src/client.ts index 1869a3e..04682ab 100644 --- a/src/client.ts +++ b/src/client.ts @@ -69,6 +69,7 @@ export class Portkey extends ApiClient { generations = new API.Generations(this); prompts = new API.Prompt(this); feedback = new API.Feedback(this); + batches = new API.Batches(this); beta = { assistants: new API.Assistants(this), threads: new API.Threads(this), From 0dd83064387d6a18c61735a1a3f02bec55c017c5 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Mon, 6 May 2024 16:58:19 +0530 Subject: [PATCH 03/15] feat: finetune support added --- src/apis/fineTuning.ts | 172 +++++++++++++++++++++++++++++++++++++++++ src/apis/index.ts | 1 + src/client.ts | 1 + 3 files changed, 174 insertions(+) create mode 100644 src/apis/fineTuning.ts diff --git a/src/apis/fineTuning.ts b/src/apis/fineTuning.ts new file mode 100644 index 0000000..107930c --- /dev/null +++ b/src/apis/fineTuning.ts @@ -0,0 +1,172 @@ +import { JobCreateParams, JobListEventsParams, JobListParams } from "openai/resources/fine-tuning/jobs/jobs"; +import { ApiClientInterface } from "../_types/generalTypes"; +import { ApiResource } from "../apiResource"; +import { RequestOptions } from "../baseClient"; +import { OPEN_AI_API_KEY } from "../constants"; +import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { createHeaders } from "./createHeaders"; +import OpenAI from "openai"; +import { CheckpointListParams } from "openai/resources/fine-tuning/jobs/checkpoints"; + + +export class FineTuning extends ApiResource{ + jobs: Jobs; + constructor(client:any) { + super(client); + this.jobs = new Jobs(client); + } +} + +export class Jobs extends ApiResource { + checkpoints: Checkpoints; + constructor(client:any) { + super(client); + this.checkpoints = new Checkpoints(client); + } + + async create( + _body: JobCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: JobCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.fineTuning.jobs.create(body, opts).withResponse(); + return finalResponse(result); + } + + async retrieve( + fineTuningJobId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.fineTuning.jobs.retrieve(fineTuningJobId, opts).withResponse(); + return finalResponse(result); + } + + async list( + _query?: JobListParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const query: JobListParams | undefined = _query; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.fineTuning.jobs.list(query, opts).withResponse(); + return finalResponse(result); + } + + async cancel( + fineTuningJobId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.fineTuning.jobs.cancel(fineTuningJobId, opts).withResponse(); + return finalResponse(result); + } + + async listEvents( + fineTuningJobId: string, + _query?: JobListEventsParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const query: JobListEventsParams | undefined = _query; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.fineTuning.jobs.listEvents(fineTuningJobId, query, opts).withResponse(); + return finalResponse(result); + } +} + +export class Checkpoints extends ApiResource { + async list( + fineTuningJobId: string, + _query?: CheckpointListParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const query: CheckpointListParams | undefined = _query; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.fineTuning.jobs.checkpoints.list(fineTuningJobId, query, opts).withResponse(); + return finalResponse(result); + } +} \ No newline at end of file diff --git a/src/apis/index.ts b/src/apis/index.ts index 7820354..9363a5d 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -11,5 +11,6 @@ export { Threads } from "./threads"; export { MainFiles } from "./files"; export { Models } from "./models"; export { Batches } from "./batches"; +export { FineTuning } from "./fineTuning" export { VectorStores } from "./vectorStores" export { BetaChat } from "./betaChat" diff --git a/src/client.ts b/src/client.ts index 04682ab..1904233 100644 --- a/src/client.ts +++ b/src/client.ts @@ -70,6 +70,7 @@ export class Portkey extends ApiClient { prompts = new API.Prompt(this); feedback = new API.Feedback(this); batches = new API.Batches(this); + fineTuning = new API.FineTuning(this); beta = { assistants: new API.Assistants(this), threads: new API.Threads(this), From f6e25eee43f523a9a7f286220cd22bf6c6e3af0f Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Mon, 6 May 2024 17:03:21 +0530 Subject: [PATCH 04/15] feat: moderations support added --- src/apis/index.ts | 1 + src/apis/moderations.ts | 34 ++++++++++++++++++++++++++++++++++ src/client.ts | 1 + 3 files changed, 36 insertions(+) create mode 100644 src/apis/moderations.ts diff --git a/src/apis/index.ts b/src/apis/index.ts index 9363a5d..4bb9e98 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -12,5 +12,6 @@ export { MainFiles } from "./files"; export { Models } from "./models"; export { Batches } from "./batches"; export { FineTuning } from "./fineTuning" +export { Moderations } from "./moderations" export { VectorStores } from "./vectorStores" export { BetaChat } from "./betaChat" diff --git a/src/apis/moderations.ts b/src/apis/moderations.ts new file mode 100644 index 0000000..f147faf --- /dev/null +++ b/src/apis/moderations.ts @@ -0,0 +1,34 @@ +import { ModerationCreateParams } from "openai/resources"; +import { ApiClientInterface } from "../_types/generalTypes"; +import { ApiResource } from "../apiResource"; +import { RequestOptions } from "../baseClient"; +import { OPEN_AI_API_KEY } from "../constants"; +import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { createHeaders } from "./createHeaders"; +import OpenAI from "openai"; + + +export class Moderations extends ApiResource{ + async create(_body: ModerationCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: ModerationCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + + const result = await OAIclient.moderations.create(body, opts).withResponse(); + return finalResponse(result); + } +} \ No newline at end of file diff --git a/src/client.ts b/src/client.ts index 1904233..25021d7 100644 --- a/src/client.ts +++ b/src/client.ts @@ -71,6 +71,7 @@ export class Portkey extends ApiClient { feedback = new API.Feedback(this); batches = new API.Batches(this); fineTuning = new API.FineTuning(this); + moderations = new API.Moderations(this); beta = { assistants: new API.Assistants(this), threads: new API.Threads(this), From a2539e3e6a2668276c098aa567d43f8f339686d7 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Mon, 6 May 2024 17:40:28 +0530 Subject: [PATCH 05/15] feat: audio support added --- src/apis/audio.ts | 97 +++++++++++++++++++++++++++++++++++++++++++++++ src/apis/index.ts | 1 + src/client.ts | 1 + 3 files changed, 99 insertions(+) create mode 100644 src/apis/audio.ts diff --git a/src/apis/audio.ts b/src/apis/audio.ts new file mode 100644 index 0000000..0269d6c --- /dev/null +++ b/src/apis/audio.ts @@ -0,0 +1,97 @@ +import { TranscriptionCreateParams } from "openai/resources/audio/transcriptions"; +import { ApiClientInterface } from "../_types/generalTypes"; +import { ApiResource } from "../apiResource"; +import { RequestOptions } from "../baseClient"; +import { OPEN_AI_API_KEY } from "../constants"; +import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { createHeaders } from "./createHeaders"; +import OpenAI from "openai"; +import { TranslationCreateParams } from "openai/resources/audio/translations"; +import { SpeechCreateParams } from "openai/resources/audio/speech"; + +export class Audio extends ApiResource { + transcriptions: transcriptions; + translations: translations; + speech: speech; + + constructor(client: any) { + super(client); + this.transcriptions = new transcriptions(client); + this.translations = new translations(client); + this.speech = new speech(client); + } +} + +export class transcriptions extends ApiResource{ + async create( + _body: TranscriptionCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: TranscriptionCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + const response = await OAIclient.audio.transcriptions.create(body, opts).withResponse(); + return finalResponse(response); + } +} + + +export class translations extends ApiResource{ + async create( + _body: TranslationCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: TranslationCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + const response = await OAIclient.audio.translations.create(body, opts).withResponse(); + return finalResponse(response); + } +} + + +export class speech extends ApiResource{ + async create( + _body: SpeechCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: SpeechCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + const response = await OAIclient.audio.speech.create(body, opts).withResponse(); + return finalResponse(response); + } +} diff --git a/src/apis/index.ts b/src/apis/index.ts index 4bb9e98..63dd659 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -13,5 +13,6 @@ export { Models } from "./models"; export { Batches } from "./batches"; export { FineTuning } from "./fineTuning" export { Moderations } from "./moderations" +export { Audio } from "./audio" export { VectorStores } from "./vectorStores" export { BetaChat } from "./betaChat" diff --git a/src/client.ts b/src/client.ts index 25021d7..0dd0bd8 100644 --- a/src/client.ts +++ b/src/client.ts @@ -72,6 +72,7 @@ export class Portkey extends ApiClient { batches = new API.Batches(this); fineTuning = new API.FineTuning(this); moderations = new API.Moderations(this); + audio = new API.audio(this); beta = { assistants: new API.Assistants(this), threads: new API.Threads(this), From 713eeddf3b473b5c2f17254e1902f3acd22c0167 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Mon, 6 May 2024 17:41:17 +0530 Subject: [PATCH 06/15] fix: audio typo --- src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index 0dd0bd8..2a8a7a9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -72,7 +72,7 @@ export class Portkey extends ApiClient { batches = new API.Batches(this); fineTuning = new API.FineTuning(this); moderations = new API.Moderations(this); - audio = new API.audio(this); + audio = new API.Audio(this); beta = { assistants: new API.Assistants(this), threads: new API.Threads(this), From 4a1e47c9591d4052f3ba3abca02ee028cfe48c30 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Sat, 18 May 2024 11:57:58 -0400 Subject: [PATCH 07/15] fix: assistant response type --- src/apis/assistants.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/apis/assistants.ts b/src/apis/assistants.ts index 1a54a32..4152530 100644 --- a/src/apis/assistants.ts +++ b/src/apis/assistants.ts @@ -9,11 +9,15 @@ import OpenAI from "openai"; export interface AssistantCreateParams { model: string; description?: string | null; - file_ids?: Array; instructions?: string | null; metadata?: unknown | null; name?: string | null; tools?: Array; + response_format?: any | null; + temperature?: number | null; + tool_resources?: any | null; + top_p?: number | null; + } export interface FileCreateParams { From aa8eff0652cd783443c0264d2af557ae55b2a9b1 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Sat, 18 May 2024 17:22:33 -0400 Subject: [PATCH 08/15] feat: added audio and moderations test cases --- package-lock.json | 2 +- src/apis/audio.ts | 4 +-- tests/audio/openai.test.ts | 45 +++++++++++++++++++++++++++++++ tests/audio/speech.mp3 | Bin 0 -> 53280 bytes tests/moderations/openai.test.ts | 21 +++++++++++++++ 5 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 tests/audio/openai.test.ts create mode 100644 tests/audio/speech.mp3 create mode 100644 tests/moderations/openai.test.ts diff --git a/package-lock.json b/package-lock.json index 662cc0e..fde7784 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "agentkeepalive": "^4.5.0", "dotenv": "^16.3.1", - "openai": "^4.41.0" + "openai": "4.41.0" }, "devDependencies": { "@babel/core": "^7.23.3", diff --git a/src/apis/audio.ts b/src/apis/audio.ts index 0269d6c..ca47c12 100644 --- a/src/apis/audio.ts +++ b/src/apis/audio.ts @@ -91,7 +91,7 @@ export class speech extends ApiResource{ baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); - const response = await OAIclient.audio.speech.create(body, opts).withResponse(); - return finalResponse(response); + const response = await OAIclient.audio.speech.create(body, opts); + return response; } } diff --git a/tests/audio/openai.test.ts b/tests/audio/openai.test.ts new file mode 100644 index 0000000..eefc864 --- /dev/null +++ b/tests/audio/openai.test.ts @@ -0,0 +1,45 @@ +import { config } from "dotenv"; +import { Portkey } from "portkey-ai"; +import fs from "fs"; +import path from "path"; + +config({ override: true }); +const client = new Portkey({ + apiKey: process.env["PORTKEY_API_KEY"] ?? "", + virtualKey: process.env["OPENAI_VIRTUAL_KEY"] ?? "" +}); + +describe("Openai Audio APIs", () => { + test("Speech: only required params", async () => { + + const speechFile = path.resolve("./speech.mp3"); + const response = await client.audio.speech.create({ + model:"tts-1", + voice:"alloy", + input:"The quick brown fox jumps over the lazy dog" + }); + const buffer = Buffer.from(await response.arrayBuffer()); + await fs.promises.writeFile(speechFile, buffer); + expect(response).toBeDefined(); + }); + + + test("Transcription: only required params", async () => { + const transcription = await client.audio.transcriptions.create({ + file: fs.createReadStream("./speech.mp3"), + model: "whisper-1", + }); + expect(transcription).toBeDefined(); + expect(transcription.text).toBeDefined(); + }); + + test("Translation: only required params", async () => { + const transcription = await client.audio.translations.create({ + file: fs.createReadStream("./speech.mp3"), + model: "whisper-1", + }); + expect(transcription).toBeDefined(); + expect(transcription.text).toBeDefined(); + }); + +}); diff --git a/tests/audio/speech.mp3 b/tests/audio/speech.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..9eb4623a83fbb14bf1c416fbc2f2a6225ee14555 GIT binary patch literal 53280 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≀eC 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%0A8dKp2)==OD|g)P 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 H{}cExgVI|g literal 0 HcmV?d00001 diff --git a/tests/moderations/openai.test.ts b/tests/moderations/openai.test.ts new file mode 100644 index 0000000..257ad44 --- /dev/null +++ b/tests/moderations/openai.test.ts @@ -0,0 +1,21 @@ +import { config } from 'dotenv'; +import { Portkey } from 'portkey-ai'; + +config({ override: true }) +const client = new Portkey({ + apiKey: process.env["PORTKEY_API_KEY"] ?? "", + virtualKey: process.env["OPENAI_VIRTUAL_KEY"] ?? "" +}); + +describe('OpenAI Moderations APIs', () => { + test('assistant: create: documentation', async () => { + const moderation = await client.moderations.create({ + input: "I want to kill them.", + model: "text-moderation-stable", + }); + expect(moderation).toBeDefined(); + expect(moderation.id).toBeDefined(); + expect(moderation.results.length).toBeGreaterThan(0); + }); + +}); \ No newline at end of file From a33c6c63bcf1d151f10e0f66784d4607ae243935 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Fri, 9 Aug 2024 19:43:47 +0530 Subject: [PATCH 09/15] feat: matching oai4.55.3 --- .gitignore | 4 +- package-lock.json | 27 ++++---- package.json | 2 +- src/_types/portkeyConstructs.ts | 1 + src/apis/betaChat.ts | 58 ++++++++++++----- src/apis/chatCompletions.ts | 17 ++++- src/apis/completions.ts | 13 +++- src/apis/index.ts | 1 + src/apis/uploads.ts | 110 ++++++++++++++++++++++++++++++++ src/client.ts | 1 + 10 files changed, 200 insertions(+), 34 deletions(-) create mode 100644 src/apis/uploads.ts diff --git a/.gitignore b/.gitignore index 6a7d6d8..f3f691e 100644 --- a/.gitignore +++ b/.gitignore @@ -127,4 +127,6 @@ dist .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz -.pnp.* \ No newline at end of file +.pnp.* + +.DS_Store \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index fde7784..6ff3f60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "agentkeepalive": "^4.5.0", "dotenv": "^16.3.1", - "openai": "4.41.0" + "openai": "4.55.3" }, "devDependencies": { "@babel/core": "^7.23.3", @@ -5564,9 +5564,9 @@ } }, "node_modules/openai": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.41.0.tgz", - "integrity": "sha512-fiV+RvUGRW+PXxycqeDYuOwsL3TxNqT/LcM6vlqyLz9ACmfSUGg1qviQrHuuNKL7gFOvfzgEJRVVFdqmv/sjxg==", + "version": "4.55.3", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.55.3.tgz", + "integrity": "sha512-/IUDdK5w3aB1Kd88Ml7w5F+EkVM5aXlrY+lSpWXdIPL18CmGkC7lV9HFJ7beR0OUSFLFT0qmWvMynqtbMF06/Q==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -5574,11 +5574,18 @@ "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "web-streams-polyfill": "^3.2.1" + "node-fetch": "^2.6.7" }, "bin": { "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } } }, "node_modules/openai/node_modules/@types/node": { @@ -6650,14 +6657,6 @@ "makeerror": "1.0.12" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } - }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index b730c18..156ddce 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,6 @@ "dependencies": { "agentkeepalive": "^4.5.0", "dotenv": "^16.3.1", - "openai": "4.41.0" + "openai": "4.55.3" } } diff --git a/src/_types/portkeyConstructs.ts b/src/_types/portkeyConstructs.ts index 9bbe1d4..6e39c82 100644 --- a/src/_types/portkeyConstructs.ts +++ b/src/_types/portkeyConstructs.ts @@ -30,6 +30,7 @@ export interface ModelParams { logit_bias?: Record; user?: string; organization?: string; + seed?: number; } export interface Message { diff --git a/src/apis/betaChat.ts b/src/apis/betaChat.ts index b89a879..d6a7919 100644 --- a/src/apis/betaChat.ts +++ b/src/apis/betaChat.ts @@ -14,6 +14,8 @@ import { ChatCompletionStreamingFunctionRunnerParams, ChatCompletionStreamingToolRunnerParams, } from "openai/lib/ChatCompletionStreamingRunner"; +import { ChatCompletionParseParams, ParsedChatCompletion } from "openai/resources/beta/chat/completions"; +import { ExtractParsedContentFromParams } from "openai/lib/parser"; export class BetaChat extends ApiResource { completions: Completions; @@ -25,6 +27,32 @@ export class BetaChat extends ApiResource { } export class Completions extends ApiResource { + + async parse> + ( + _body: Params, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: Params = _body; + + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }) + + const result = await OAIclient.beta.chat.completions.parse(body, opts); + return result; + } async runFunctions( body: ChatCompletionFunctionRunnerParams, @@ -105,23 +133,23 @@ export class Completions extends ApiResource { _body:ChatCompletionStreamParams, params?: ApiClientInterface, opts?: RequestOptions): Promise { - const body: ChatCompletionStreamParams = _body; - if (params) { - const config = overrideConfig(this.client.config, params.config); - this.client.customHeaders = { - ...this.client.customHeaders, - ...createHeaders({ ...params, config }), - }; - } + const body: ChatCompletionStreamParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); - const result = await OAIclient.beta.chat.completions.stream(body, opts); - return result; + const result = await OAIclient.beta.chat.completions.stream(body, opts).toReadableStream(); + return result; } } diff --git a/src/apis/chatCompletions.ts b/src/apis/chatCompletions.ts index a878f92..127ffe1 100644 --- a/src/apis/chatCompletions.ts +++ b/src/apis/chatCompletions.ts @@ -1,3 +1,4 @@ +import { ChatCompletionMessageToolCall, ChatCompletionStreamOptions, ChatCompletionTokenLogprob } from "openai/resources/chat/completions"; import { APIResponseType, ApiClientInterface } from "../_types/generalTypes"; import { ModelParams } from "../_types/portkeyConstructs"; import { ApiResource } from "../apiResource"; @@ -53,6 +54,7 @@ export interface ChatCompletionsBodyBase extends ModelParams { export interface ChatCompletionsBodyStreaming extends ChatCompletionsBodyBase { stream?: true; + stream_options?: ChatCompletionStreamOptions } export interface ChatCompletionsBodyNonStreaming extends ChatCompletionsBodyBase { @@ -68,15 +70,24 @@ interface Usage { } interface Message { - role: string - content: string + role: string; + content: string; + refusal?: string; + function_call?: any; + tool_calls?: Array; } +export interface Logprobs { + content: Array | null; + refusal: Array | null; + } + interface Choices { index?: number; message?: Message; delta?: Message finish_reason?: string; + logprobs?: Logprobs } interface ChatCompletion extends APIResponseType { @@ -86,4 +97,6 @@ interface ChatCompletion extends APIResponseType { model: string; choices: Array; usage: Usage; + service_tier?: string; + system_fingerprint?: string; } \ No newline at end of file diff --git a/src/apis/completions.ts b/src/apis/completions.ts index 81e5e1f..ae40037 100644 --- a/src/apis/completions.ts +++ b/src/apis/completions.ts @@ -64,10 +64,20 @@ interface Usage { total_tokens?: number; } +interface Logprobs { + text_offset?: Array; + + token_logprobs?: Array; + + tokens?: Array; + + top_logprobs?: Array>; + } + interface Choices { index?: number; text?: string; - logprobs: any; + logprobs: Logprobs; finish_reason?: string; } @@ -78,4 +88,5 @@ interface TextCompletion extends APIResponseType { model: string; choices: Array; usage?: Usage; + system_fingerprint?: string; } \ No newline at end of file diff --git a/src/apis/index.ts b/src/apis/index.ts index 63dd659..ea1cad9 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -16,3 +16,4 @@ export { Moderations } from "./moderations" export { Audio } from "./audio" export { VectorStores } from "./vectorStores" export { BetaChat } from "./betaChat" +export { Uploads } from "./uploads" \ No newline at end of file diff --git a/src/apis/uploads.ts b/src/apis/uploads.ts new file mode 100644 index 0000000..4da523d --- /dev/null +++ b/src/apis/uploads.ts @@ -0,0 +1,110 @@ +import { ApiClientInterface } from "../_types/generalTypes"; +import { ApiResource } from "../apiResource"; +import { RequestOptions } from "../baseClient"; +import { OPEN_AI_API_KEY } from "../constants"; +import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { createHeaders } from "./createHeaders"; +import OpenAI from "openai"; +import { PartCreateParams } from "openai/resources/uploads/parts"; +import { UploadCompleteParams, UploadCreateParams } from "openai/resources"; + +export class Uploads extends ApiResource { + parts: Parts + + constructor(client: any) { + super(client); + this.parts = new Parts(client); + } + + + async create( + _body: UploadCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: UploadCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + const response = await OAIclient.uploads.create(body, opts).withResponse(); + return finalResponse(response); + } + + async cancel( + uploadId: string, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + const response = await OAIclient.uploads.cancel(uploadId, opts).withResponse(); + return finalResponse(response); + } + + async complete( + uploadId: string, + _body: UploadCompleteParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: UploadCompleteParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + const response = await OAIclient.uploads.complete(uploadId, body, opts).withResponse(); + return finalResponse(response); + } +} + +export class Parts extends ApiResource{ + async create( + uploadId: string, + _body: PartCreateParams, + params?: ApiClientInterface, + opts?: RequestOptions + ): Promise { + const body: PartCreateParams = _body; + if (params) { + const config = overrideConfig(this.client.config, params.config); + this.client.customHeaders = { + ...this.client.customHeaders, + ...createHeaders({ ...params, config }), + }; + } + const OAIclient = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + baseURL: this.client.baseURL, + defaultHeaders: defaultHeadersBuilder(this.client), + }); + const response = await OAIclient.uploads.parts.create(uploadId ,body, opts).withResponse(); + return finalResponse(response); + } +} \ No newline at end of file diff --git a/src/client.ts b/src/client.ts index 2a8a7a9..256e86d 100644 --- a/src/client.ts +++ b/src/client.ts @@ -73,6 +73,7 @@ export class Portkey extends ApiClient { fineTuning = new API.FineTuning(this); moderations = new API.Moderations(this); audio = new API.Audio(this); + uploads = new API.Uploads(this); beta = { assistants: new API.Assistants(this), threads: new API.Threads(this), From 4076059380c6d76318238ca085ceeb7cb1bea8d7 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Sat, 10 Aug 2024 13:02:07 +0530 Subject: [PATCH 10/15] feat: upload and part request interface --- src/_types/portkeyConstructs.ts | 4 ++++ src/apis/betaChat.ts | 2 +- src/apis/uploads.ts | 15 +++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/_types/portkeyConstructs.ts b/src/_types/portkeyConstructs.ts index 6e39c82..3099b0b 100644 --- a/src/_types/portkeyConstructs.ts +++ b/src/_types/portkeyConstructs.ts @@ -31,6 +31,10 @@ export interface ModelParams { user?: string; organization?: string; seed?: number; + response_format?: any; + service_tier?: string; + top_logprobs?: number | null; + parallel_tool_calls?: boolean } export interface Message { diff --git a/src/apis/betaChat.ts b/src/apis/betaChat.ts index d6a7919..bc3eb69 100644 --- a/src/apis/betaChat.ts +++ b/src/apis/betaChat.ts @@ -14,7 +14,7 @@ import { ChatCompletionStreamingFunctionRunnerParams, ChatCompletionStreamingToolRunnerParams, } from "openai/lib/ChatCompletionStreamingRunner"; -import { ChatCompletionParseParams, ParsedChatCompletion } from "openai/resources/beta/chat/completions"; +import { ChatCompletionParseParams } from "openai/resources/beta/chat/completions"; import { ExtractParsedContentFromParams } from "openai/lib/parser"; export class BetaChat extends ApiResource { diff --git a/src/apis/uploads.ts b/src/apis/uploads.ts index 4da523d..b9936e7 100644 --- a/src/apis/uploads.ts +++ b/src/apis/uploads.ts @@ -5,8 +5,8 @@ import { OPEN_AI_API_KEY } from "../constants"; import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; import { createHeaders } from "./createHeaders"; import OpenAI from "openai"; -import { PartCreateParams } from "openai/resources/uploads/parts"; -import { UploadCompleteParams, UploadCreateParams } from "openai/resources"; +import { UploadCompleteParams } from "openai/resources"; +import { Uploadable } from "openai/uploads"; export class Uploads extends ApiResource { parts: Parts @@ -107,4 +107,15 @@ export class Parts extends ApiResource{ const response = await OAIclient.uploads.parts.create(uploadId ,body, opts).withResponse(); return finalResponse(response); } +} + +export interface UploadCreateParams { + bytes: number; + filename: string; + mime_type: string; + purpose: 'assistants' | 'batch' | 'fine-tune' | 'vision'; +} + +export interface PartCreateParams { + data: Uploadable; } \ No newline at end of file From 49379eba841cd2556755c9f3eacb004b8aa85262 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Sat, 10 Aug 2024 19:22:56 +0530 Subject: [PATCH 11/15] feat: handling POST without body --- src/apis/batches.ts | 4 +++- src/apis/fineTuning.ts | 4 +++- src/apis/threads.ts | 4 +++- src/apis/uploads.ts | 4 +++- src/apis/vectorStores.ts | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/apis/batches.ts b/src/apis/batches.ts index fa898f9..2e298c1 100644 --- a/src/apis/batches.ts +++ b/src/apis/batches.ts @@ -98,8 +98,10 @@ export class Batches extends ApiResource{ baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); + const body = {} + const options = { body, ...opts } - const result = await OAIclient.batches.cancel(batchId, opts).withResponse(); + const result = await OAIclient.batches.cancel(batchId, options).withResponse(); return finalResponse(result); } } diff --git a/src/apis/fineTuning.ts b/src/apis/fineTuning.ts index 107930c..0351c0b 100644 --- a/src/apis/fineTuning.ts +++ b/src/apis/fineTuning.ts @@ -113,8 +113,10 @@ export class Jobs extends ApiResource { baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); + const body = {} + const options = { body, ...opts } - const result = await OAIclient.fineTuning.jobs.cancel(fineTuningJobId, opts).withResponse(); + const result = await OAIclient.fineTuning.jobs.cancel(fineTuningJobId, options).withResponse(); return finalResponse(result); } diff --git a/src/apis/threads.ts b/src/apis/threads.ts index 06964f4..ecb9964 100644 --- a/src/apis/threads.ts +++ b/src/apis/threads.ts @@ -520,8 +520,10 @@ export class Runs extends ApiResource{ baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); + const body = {} + const options = { body, ...opts } - const result = await OAIclient.beta.threads.runs.cancel(threadId, runId, opts).withResponse(); + const result = await OAIclient.beta.threads.runs.cancel(threadId, runId, options).withResponse(); return finalResponse(result); } diff --git a/src/apis/uploads.ts b/src/apis/uploads.ts index b9936e7..e119c0e 100644 --- a/src/apis/uploads.ts +++ b/src/apis/uploads.ts @@ -56,7 +56,9 @@ export class Uploads extends ApiResource { baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); - const response = await OAIclient.uploads.cancel(uploadId, opts).withResponse(); + const body = {} + const options = { body, ...opts } + const response = await OAIclient.uploads.cancel(uploadId, options).withResponse(); return finalResponse(response); } diff --git a/src/apis/vectorStores.ts b/src/apis/vectorStores.ts index 022c7b3..6096a4e 100644 --- a/src/apis/vectorStores.ts +++ b/src/apis/vectorStores.ts @@ -440,8 +440,10 @@ export class FileBatches extends ApiResource{ baseURL: this.client.baseURL, defaultHeaders: defaultHeadersBuilder(this.client), }); + const body = {} + const options = { body, ...opts } - const result = await OAIclient.beta.vectorStores.fileBatches.cancel(vectorStoreId, batchId, opts).withResponse(); + const result = await OAIclient.beta.vectorStores.fileBatches.cancel(vectorStoreId, batchId, options).withResponse(); return finalResponse(result); From ff384d2002afac2a7f189601c660e7c65e115854 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Sat, 10 Aug 2024 19:50:27 +0530 Subject: [PATCH 12/15] feat: initalising openai from utils --- src/apis/audio.ts | 22 ++----- src/apis/batches.ts | 28 ++------- src/apis/betaChat.ts | 28 ++------- src/apis/files.ts | 6 +- src/apis/fineTuning.ts | 40 +++---------- src/apis/moderations.ts | 10 +--- src/apis/uploads.ts | 28 ++------- src/apis/vectorStores.ts | 124 +++++++-------------------------------- src/utils.ts | 4 +- 9 files changed, 52 insertions(+), 238 deletions(-) diff --git a/src/apis/audio.ts b/src/apis/audio.ts index ca47c12..77b4560 100644 --- a/src/apis/audio.ts +++ b/src/apis/audio.ts @@ -2,10 +2,8 @@ import { TranscriptionCreateParams } from "openai/resources/audio/transcriptions import { ApiClientInterface } from "../_types/generalTypes"; import { ApiResource } from "../apiResource"; import { RequestOptions } from "../baseClient"; -import { OPEN_AI_API_KEY } from "../constants"; -import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { finalResponse, initOpenAIClient, overrideConfig } from "../utils"; import { createHeaders } from "./createHeaders"; -import OpenAI from "openai"; import { TranslationCreateParams } from "openai/resources/audio/translations"; import { SpeechCreateParams } from "openai/resources/audio/speech"; @@ -36,11 +34,7 @@ export class transcriptions extends ApiResource{ ...createHeaders({ ...params, config }), }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const response = await OAIclient.audio.transcriptions.create(body, opts).withResponse(); return finalResponse(response); } @@ -61,11 +55,7 @@ export class translations extends ApiResource{ ...createHeaders({ ...params, config }), }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const response = await OAIclient.audio.translations.create(body, opts).withResponse(); return finalResponse(response); } @@ -86,11 +76,7 @@ export class speech extends ApiResource{ ...createHeaders({ ...params, config }), }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const response = await OAIclient.audio.speech.create(body, opts); return response; } diff --git a/src/apis/batches.ts b/src/apis/batches.ts index 2e298c1..9bc4245 100644 --- a/src/apis/batches.ts +++ b/src/apis/batches.ts @@ -2,10 +2,8 @@ import { BatchCreateParams, BatchListParams } from "openai/resources/batches"; import { ApiClientInterface } from "../_types/generalTypes"; import { ApiResource } from "../apiResource"; import { RequestOptions } from "../baseClient"; -import { OPEN_AI_API_KEY } from "../constants"; -import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { finalResponse, initOpenAIClient, overrideConfig } from "../utils"; import { createHeaders } from "./createHeaders"; -import OpenAI from "openai"; export class Batches extends ApiResource{ @@ -23,11 +21,7 @@ export class Batches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.batches.create(body, opts).withResponse(); return finalResponse(result); @@ -46,11 +40,7 @@ export class Batches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.batches.retrieve(batchId, opts).withResponse(); return finalResponse(result); @@ -70,11 +60,7 @@ export class Batches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.batches.list(query, opts).withResponse(); return finalResponse(result); @@ -93,11 +79,7 @@ export class Batches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const body = {} const options = { body, ...opts } diff --git a/src/apis/betaChat.ts b/src/apis/betaChat.ts index bc3eb69..3264f0c 100644 --- a/src/apis/betaChat.ts +++ b/src/apis/betaChat.ts @@ -2,10 +2,8 @@ import { ChatCompletionStreamParams } from "openai/lib/ChatCompletionStream"; import { ApiClientInterface } from "../_types/generalTypes"; import { ApiResource } from "../apiResource"; import { RequestOptions } from "../baseClient"; -import { OPEN_AI_API_KEY } from "../constants"; -import { defaultHeadersBuilder, overrideConfig } from "../utils"; +import { initOpenAIClient, overrideConfig } from "../utils"; import { createHeaders } from "./createHeaders"; -import OpenAI from "openai"; import { ChatCompletionFunctionRunnerParams, ChatCompletionToolRunnerParams, @@ -44,11 +42,7 @@ export class Completions extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }) + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.chat.completions.parse(body, opts); return result; @@ -80,11 +74,7 @@ export class Completions extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.chat.completions.runFunctions( body, @@ -119,11 +109,7 @@ export class Completions extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.chat.completions.runTools(body, opts); return result; @@ -142,11 +128,7 @@ export class Completions extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.chat.completions.stream(body, opts).toReadableStream(); return result; diff --git a/src/apis/files.ts b/src/apis/files.ts index 80697c2..98009b9 100644 --- a/src/apis/files.ts +++ b/src/apis/files.ts @@ -103,11 +103,7 @@ export class MainFiles extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.files.content(fileId, opts).withResponse(); diff --git a/src/apis/fineTuning.ts b/src/apis/fineTuning.ts index 0351c0b..9efbf62 100644 --- a/src/apis/fineTuning.ts +++ b/src/apis/fineTuning.ts @@ -2,10 +2,8 @@ import { JobCreateParams, JobListEventsParams, JobListParams } from "openai/reso import { ApiClientInterface } from "../_types/generalTypes"; import { ApiResource } from "../apiResource"; import { RequestOptions } from "../baseClient"; -import { OPEN_AI_API_KEY } from "../constants"; -import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { finalResponse, initOpenAIClient, overrideConfig } from "../utils"; import { createHeaders } from "./createHeaders"; -import OpenAI from "openai"; import { CheckpointListParams } from "openai/resources/fine-tuning/jobs/checkpoints"; @@ -38,11 +36,7 @@ export class Jobs extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.fineTuning.jobs.create(body, opts).withResponse(); return finalResponse(result); @@ -61,11 +55,7 @@ export class Jobs extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.fineTuning.jobs.retrieve(fineTuningJobId, opts).withResponse(); return finalResponse(result); @@ -85,11 +75,7 @@ export class Jobs extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.fineTuning.jobs.list(query, opts).withResponse(); return finalResponse(result); @@ -108,11 +94,7 @@ export class Jobs extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const body = {} const options = { body, ...opts } @@ -135,11 +117,7 @@ export class Jobs extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.fineTuning.jobs.listEvents(fineTuningJobId, query, opts).withResponse(); return finalResponse(result); @@ -162,11 +140,7 @@ export class Checkpoints extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.fineTuning.jobs.checkpoints.list(fineTuningJobId, query, opts).withResponse(); return finalResponse(result); diff --git a/src/apis/moderations.ts b/src/apis/moderations.ts index f147faf..df1fc43 100644 --- a/src/apis/moderations.ts +++ b/src/apis/moderations.ts @@ -2,10 +2,8 @@ import { ModerationCreateParams } from "openai/resources"; import { ApiClientInterface } from "../_types/generalTypes"; import { ApiResource } from "../apiResource"; import { RequestOptions } from "../baseClient"; -import { OPEN_AI_API_KEY } from "../constants"; -import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { finalResponse, initOpenAIClient, overrideConfig } from "../utils"; import { createHeaders } from "./createHeaders"; -import OpenAI from "openai"; export class Moderations extends ApiResource{ @@ -22,11 +20,7 @@ export class Moderations extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.moderations.create(body, opts).withResponse(); return finalResponse(result); diff --git a/src/apis/uploads.ts b/src/apis/uploads.ts index e119c0e..46d369a 100644 --- a/src/apis/uploads.ts +++ b/src/apis/uploads.ts @@ -1,10 +1,8 @@ import { ApiClientInterface } from "../_types/generalTypes"; import { ApiResource } from "../apiResource"; import { RequestOptions } from "../baseClient"; -import { OPEN_AI_API_KEY } from "../constants"; -import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { finalResponse, initOpenAIClient, overrideConfig } from "../utils"; import { createHeaders } from "./createHeaders"; -import OpenAI from "openai"; import { UploadCompleteParams } from "openai/resources"; import { Uploadable } from "openai/uploads"; @@ -30,11 +28,7 @@ export class Uploads extends ApiResource { ...createHeaders({ ...params, config }), }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const response = await OAIclient.uploads.create(body, opts).withResponse(); return finalResponse(response); } @@ -51,11 +45,7 @@ export class Uploads extends ApiResource { ...createHeaders({ ...params, config }), }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const body = {} const options = { body, ...opts } const response = await OAIclient.uploads.cancel(uploadId, options).withResponse(); @@ -76,11 +66,7 @@ export class Uploads extends ApiResource { ...createHeaders({ ...params, config }), }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const response = await OAIclient.uploads.complete(uploadId, body, opts).withResponse(); return finalResponse(response); } @@ -101,11 +87,7 @@ export class Parts extends ApiResource{ ...createHeaders({ ...params, config }), }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const response = await OAIclient.uploads.parts.create(uploadId ,body, opts).withResponse(); return finalResponse(response); } diff --git a/src/apis/vectorStores.ts b/src/apis/vectorStores.ts index 6096a4e..f6a7e38 100644 --- a/src/apis/vectorStores.ts +++ b/src/apis/vectorStores.ts @@ -2,10 +2,8 @@ import { Uploadable } from "openai/uploads"; import { ApiClientInterface } from "../_types/generalTypes"; import { ApiResource } from "../apiResource"; import { RequestOptions } from "../baseClient"; -import { OPEN_AI_API_KEY } from "../constants"; -import { defaultHeadersBuilder, finalResponse, overrideConfig } from "../utils"; +import { finalResponse, initOpenAIClient, overrideConfig } from "../utils"; import { createHeaders } from "./createHeaders"; -import OpenAI from "openai"; export class VectorStores extends ApiResource { files: Files; @@ -31,11 +29,7 @@ export class VectorStores extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const result = await OAIclient.beta.vectorStores @@ -58,11 +52,7 @@ export class VectorStores extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores .retrieve(vectorStoreId, opts) @@ -86,11 +76,7 @@ export class VectorStores extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores .update(vectorStoreId, body, opts) @@ -113,11 +99,7 @@ export class VectorStores extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores .list(query, opts) @@ -138,11 +120,7 @@ export class VectorStores extends ApiResource { }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores .del(vectorStoreId, opts) @@ -172,11 +150,7 @@ export class Files extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores .files.create(vectorStoreId, body, opts) @@ -199,11 +173,7 @@ export class Files extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores.files.retrieve(vectorStoreId, fileId, opts).withResponse(); @@ -225,11 +195,7 @@ export class Files extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const result = await OAIclient.beta.vectorStores.files.list(vectorStoreId, query, opts).withResponse(); @@ -251,11 +217,7 @@ export class Files extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores.files.del(vectorStoreId, fileId, opts).withResponse(); @@ -277,11 +239,7 @@ export class Files extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores .files.createAndPoll(vectorStoreId, body, opts); @@ -303,11 +261,7 @@ export class Files extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores.files.poll(vectorStoreId, fileId, opts); @@ -328,11 +282,7 @@ export class Files extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores.files.upload(vectorStoreId, file, opts); @@ -353,11 +303,7 @@ export class Files extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores.files.uploadAndPoll(vectorStoreId, file, opts); @@ -383,11 +329,7 @@ export class FileBatches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores .fileBatches.create(vectorStoreId, body, opts) @@ -410,11 +352,7 @@ export class FileBatches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores.fileBatches.retrieve(vectorStoreId, batchId, opts).withResponse(); @@ -435,11 +373,7 @@ export class FileBatches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const body = {} const options = { body, ...opts } @@ -464,11 +398,7 @@ export class FileBatches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores .fileBatches.createAndPoll(vectorStoreId, body, opts); @@ -493,11 +423,7 @@ export class FileBatches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const result = await OAIclient.beta.vectorStores.fileBatches.listFiles(vectorStoreId, batchId, query, opts).withResponse(); @@ -519,11 +445,7 @@ export class FileBatches extends ApiResource{ }; } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores.fileBatches.poll(vectorStoreId, batchId, opts); @@ -544,11 +466,7 @@ export class FileBatches extends ApiResource{ } } - const OAIclient = new OpenAI({ - apiKey: OPEN_AI_API_KEY, - baseURL: this.client.baseURL, - defaultHeaders: defaultHeadersBuilder(this.client), - }); + const OAIclient = initOpenAIClient(this.client); const result = await OAIclient.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, { files, fileIds }, opts); return result; diff --git a/src/utils.ts b/src/utils.ts index 249dd41..3a718c0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import { PORTKEY_HEADER_PREFIX } from "./constants"; +import { OPEN_AI_API_KEY, PORTKEY_HEADER_PREFIX } from "./constants"; import { createResponseHeaders } from "./streaming"; import OpenAI from "openai"; import type { Portkey } from "./index"; @@ -124,7 +124,7 @@ export function defaultHeadersBuilder(client: any){ export function initOpenAIClient(client: Portkey){ return new OpenAI({ - apiKey: client.apiKey || readEnv("OPENAI_API_KEY"), + apiKey: client.apiKey || readEnv("OPENAI_API_KEY") || OPEN_AI_API_KEY, baseURL: client.baseURL, defaultHeaders: defaultHeadersBuilder(client), maxRetries: 0 From 7d56324d410b4a0ca15a7ed878670dfbaf1f0114 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Mon, 2 Sep 2024 13:51:25 +0530 Subject: [PATCH 13/15] feat: streaming for beta chat completions --- src/apis/betaChat.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apis/betaChat.ts b/src/apis/betaChat.ts index 3264f0c..998474f 100644 --- a/src/apis/betaChat.ts +++ b/src/apis/betaChat.ts @@ -130,7 +130,7 @@ export class Completions extends ApiResource { const OAIclient = initOpenAIClient(this.client); - const result = await OAIclient.beta.chat.completions.stream(body, opts).toReadableStream(); + const result = await OAIclient.beta.chat.completions.stream(body, opts); return result; } } From cd7b8915d3ad1d4f5984e5707b9fa89942ed07d3 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Wed, 4 Sep 2024 13:15:04 +0530 Subject: [PATCH 14/15] feat: chat Completion tool type in request --- src/_types/portkeyConstructs.ts | 9 ++++++++- src/apis/chatCompletions.ts | 15 ++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/_types/portkeyConstructs.ts b/src/_types/portkeyConstructs.ts index 3099b0b..12080e5 100644 --- a/src/_types/portkeyConstructs.ts +++ b/src/_types/portkeyConstructs.ts @@ -34,10 +34,17 @@ export interface ModelParams { response_format?: any; service_tier?: string; top_logprobs?: number | null; - parallel_tool_calls?: boolean + parallel_tool_calls?: boolean; + tools?: Array; + tool_choice?: any; } export interface Message { role: string content: string } + +export interface Tool { + type?: string; + function?: Record +} \ No newline at end of file diff --git a/src/apis/chatCompletions.ts b/src/apis/chatCompletions.ts index 8c28e92..be77078 100644 --- a/src/apis/chatCompletions.ts +++ b/src/apis/chatCompletions.ts @@ -73,19 +73,7 @@ interface Usage { interface FunctionType { arguments?: string; name?: string; - } - -interface ToolCall { - index?: number; - id?: string; - function?: FunctionType; - type?: 'function'; - } - -interface FunctionCall { - arguments?: string; - name?: string; - } +} interface Message { role: string; @@ -93,6 +81,7 @@ interface Message { refusal?: string; function_call?: any; tool_calls?: Array; + tool_call_id?: string; } export interface Logprobs { From b7f305e7a9f7dd13500e3a4a77f5b82d6dd1cea9 Mon Sep 17 00:00:00 2001 From: csgulati09 Date: Wed, 4 Sep 2024 16:26:18 +0530 Subject: [PATCH 15/15] fix: remove chat completion type --- src/apis/chatCompletions.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/apis/chatCompletions.ts b/src/apis/chatCompletions.ts index be77078..a68de8d 100644 --- a/src/apis/chatCompletions.ts +++ b/src/apis/chatCompletions.ts @@ -70,11 +70,6 @@ interface Usage { total_tokens?: number; } -interface FunctionType { - arguments?: string; - name?: string; -} - interface Message { role: string; content: string;