Skip to content

Commit 329eb3e

Browse files
amirai21asafgardin
authored andcommitted
feat: add upload file object override
1 parent d68e935 commit 329eb3e

File tree

4 files changed

+75
-12
lines changed

4 files changed

+75
-12
lines changed

examples/studio/conversational-rag/rag-engine.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ async function uploadQueryUpdateDelete() {
4747

4848
async function listFiles() {
4949
const client = new AI21({ apiKey: process.env.AI21_API_KEY });
50-
const files = await client.ragEngine.list({ limit: 10 });
50+
const files = await client.ragEngine.list({ limit: 4 });
5151
console.log(files);
5252
}
5353

src/APIClient.ts

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,36 @@ const validatePositiveInteger = (name: string, n: unknown): number => {
2626
return n;
2727
};
2828

29+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
30+
const appendBodyToFormData = (formData: FormData, body: Record<string, any>): void => {
31+
for (const [key, value] of Object.entries(body)) {
32+
if (Array.isArray(value)) {
33+
value.forEach(item => formData.append(key, item));
34+
} else {
35+
formData.append(key, value);
36+
}
37+
}
38+
}
39+
40+
export type FilePathOrFileObject =
41+
| string
42+
| File;
43+
44+
function makeFormDataFromFilePath(filePath: string): FormData {
45+
const formData = new FormData();
46+
const fileStream = createReadStream(filePath);
47+
const fileName = getBasename(filePath);
48+
49+
formData.append('file', fileStream, fileName);
50+
return formData;
51+
}
52+
53+
function makeFormDataFromFileObject(file: File): FormData {
54+
const formData = new FormData();
55+
formData.append('file', file);
56+
return formData;
57+
}
58+
2959
export abstract class APIClient {
3060
protected baseURL: string;
3161
protected maxRetries: number;
@@ -64,10 +94,41 @@ export abstract class APIClient {
6494
return this.makeRequest('delete', path, opts);
6595
}
6696

67-
async upload<Req, Rsp>(path: string, filePath: string, opts?: RequestOptions<Req>): Promise<Rsp> {
68-
const formDataRequest = this.makeFormDataRequest(path, filePath, opts);
69-
const response = await this.performRequest(formDataRequest);
70-
return this.fetch.handleResponse<Rsp>(response) as Rsp;
97+
upload<Req, Rsp>(path: string, file: string, opts?: RequestOptions<Req>): Promise<Rsp>;
98+
upload<Req, Rsp>(path: string, file: File, opts?: RequestOptions<Req>): Promise<Rsp>;
99+
100+
101+
upload<Req, Rsp>(path: string, file: FilePathOrFileObject, opts?: RequestOptions<Req>): Promise<Rsp> {
102+
let formData: FormData;
103+
104+
if (typeof file === 'string') {
105+
formData = makeFormDataFromFilePath(file);
106+
} else if (file instanceof File) {
107+
formData = makeFormDataFromFileObject(file);
108+
} else {
109+
throw new AI21Error('Invalid file type for upload');
110+
}
111+
112+
if (opts?.body) {
113+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
114+
appendBodyToFormData(formData, opts.body as Record<string, any>);
115+
}
116+
117+
const headers = {
118+
...opts?.headers,
119+
'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`
120+
};
121+
122+
const options: FinalRequestOptions = {
123+
method: 'post',
124+
path: path,
125+
body: formData,
126+
headers,
127+
};
128+
129+
return this.performRequest(options).then(
130+
(response) => this.fetch.handleResponse<Rsp>(response) as Rsp,
131+
);
71132
}
72133

73134
protected makeFormDataRequest<Req>(
@@ -133,6 +194,7 @@ export abstract class APIClient {
133194
const options = {
134195
method,
135196
path,
197+
136198
...opts,
137199
};
138200

@@ -145,7 +207,8 @@ export abstract class APIClient {
145207
let url = `${this.baseURL}${options.path}`;
146208

147209
if (options.query) {
148-
const queryString = new URLSearchParams(options.query as Record<string, string>).toString();
210+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
211+
const queryString = new URLSearchParams(options.query as Record<string, any>).toString();
149212
url += `?${queryString}`;
150213
}
151214

src/resources/chat/completions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export class Completions extends APIResource {
2424
{
2525
body,
2626
...options,
27-
stream: body.stream ?? false,
27+
stream: body.stream ?? false,
2828
} as Models.RequestOptions<Models.ChatCompletionCreateParams>,
2929
) as Promise<Models.ChatCompletionResponse> | Promise<Stream<Models.ChatCompletionChunk>>;
3030
}

src/resources/rag/ragEngine.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,35 @@ import { FileResponse } from 'types/rag/FileResponse';
66
const RAG_ENGINE_PATH = '/library/files';
77

88
export class RAGEngine extends APIResource {
9-
create(filePath: string, body: UploadFileRequest, options?: Models.RequestOptions) {
9+
create(filePath: string, body: UploadFileRequest, options?: Models.RequestOptions): Promise<UploadFileResponse> {
1010
return this.client.upload<UploadFileRequest, UploadFileResponse>(RAG_ENGINE_PATH, filePath, {
1111
body: body,
1212
...options,
1313
} as Models.RequestOptions<UploadFileRequest>) as Promise<UploadFileResponse>;
1414
}
1515

16-
get(fileId: string, options?: Models.RequestOptions) {
16+
get(fileId: string, options?: Models.RequestOptions): Promise<FileResponse> {
1717
return this.client.get<string, FileResponse>(
1818
`${RAG_ENGINE_PATH}/${fileId}`,
1919
options as Models.RequestOptions<string>,
2020
) as Promise<FileResponse>;
2121
}
2222

23-
delete(fileId: string, options?: Models.RequestOptions) {
23+
delete(fileId: string, options?: Models.RequestOptions): Promise<null> {
2424
return this.client.delete<string, null>(
2525
`${RAG_ENGINE_PATH}/${fileId}`,
2626
options as Models.RequestOptions<string>,
2727
) as Promise<null>;
2828
}
2929

30-
list(body: ListFilesFilters | null, options?: Models.RequestOptions) {
30+
list(body: ListFilesFilters | null, options?: Models.RequestOptions): Promise<FileResponse[]> {
3131
return this.client.get<ListFilesFilters | null, FileResponse[]>(RAG_ENGINE_PATH, {
3232
query: body,
3333
...options,
3434
} as Models.RequestOptions<ListFilesFilters | null>) as Promise<FileResponse[]>;
3535
}
3636

37-
update(fileId: string, body: UpdateFileRequest, options?: Models.RequestOptions) {
37+
update(fileId: string, body: UpdateFileRequest, options?: Models.RequestOptions): Promise<null> {
3838
return this.client.put<UpdateFileRequest, null>(`${RAG_ENGINE_PATH}/${fileId}`, {
3939
body,
4040
...options,

0 commit comments

Comments
 (0)