Skip to content

Commit 13466b3

Browse files
hkt74abdelkd
andauthoredMar 5, 2025··
feat (file-manager) support upload with buffer (#365)
Co-authored-by: abdelkd <abdelkarimdjelalda@gmail.com>
1 parent 0c8d8cd commit 13466b3

6 files changed

+102
-6
lines changed
 

‎.changeset/fuzzy-cows-approve.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@google/generative-ai": minor
3+
---
4+
5+
added support for buffers in uploadFile

‎common/api-review/generative-ai-server.api.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export interface BooleanSchema extends BaseSchema {
3131
type: typeof SchemaType.BOOLEAN;
3232
}
3333

34+
/// <reference types="node" />
35+
3436
// @public
3537
export interface CachedContent extends CachedContentBase {
3638
createTime?: string;
@@ -373,7 +375,7 @@ export class GoogleAIFileManager {
373375
deleteFile(fileId: string): Promise<void>;
374376
getFile(fileId: string, requestOptions?: SingleRequestOptions): Promise<FileMetadataResponse>;
375377
listFiles(listParams?: ListParams, requestOptions?: SingleRequestOptions): Promise<ListFilesResponse>;
376-
uploadFile(filePath: string, fileMetadata: FileMetadata): Promise<UploadFileResponse>;
378+
uploadFile(fileData: string | Buffer, fileMetadata: FileMetadata): Promise<UploadFileResponse>;
377379
}
378380

379381
// @public

‎docs/reference/server/generative-ai.googleaifilemanager.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ export declare class GoogleAIFileManager
3131
| [deleteFile(fileId)](./generative-ai.googleaifilemanager.deletefile.md) | | Delete file with given ID. |
3232
| [getFile(fileId, requestOptions)](./generative-ai.googleaifilemanager.getfile.md) | | <p>Get metadata for file with given ID.</p><p>Any fields set in the optional [SingleRequestOptions](./generative-ai.singlerequestoptions.md) parameter will take precedence over the [RequestOptions](./generative-ai.requestoptions.md) values provided at the time of the [GoogleAIFileManager](./generative-ai.googleaifilemanager.md) initialization.</p> |
3333
| [listFiles(listParams, requestOptions)](./generative-ai.googleaifilemanager.listfiles.md) | | <p>List all uploaded files.</p><p>Any fields set in the optional [SingleRequestOptions](./generative-ai.singlerequestoptions.md) parameter will take precedence over the [RequestOptions](./generative-ai.requestoptions.md) values provided at the time of the [GoogleAIFileManager](./generative-ai.googleaifilemanager.md) initialization.</p> |
34-
| [uploadFile(filePath, fileMetadata)](./generative-ai.googleaifilemanager.uploadfile.md) | | Upload a file. |
34+
| [uploadFile(fileData, fileMetadata)](./generative-ai.googleaifilemanager.uploadfile.md) | | Upload a file. |
3535

‎docs/reference/server/generative-ai.googleaifilemanager.uploadfile.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ Upload a file.
99
**Signature:**
1010

1111
```typescript
12-
uploadFile(filePath: string, fileMetadata: FileMetadata): Promise<UploadFileResponse>;
12+
uploadFile(fileData: string | Buffer, fileMetadata: FileMetadata): Promise<UploadFileResponse>;
1313
```
1414

1515
## Parameters
1616

1717
| Parameter | Type | Description |
1818
| --- | --- | --- |
19-
| filePath | string | |
19+
| fileData | string \| Buffer | |
2020
| fileMetadata | [FileMetadata](./generative-ai.filemetadata.md) | |
2121

2222
**Returns:**

‎src/server/file-manager.test.ts

+88
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import * as request from "./request";
2323
import { RpcTask } from "./constants";
2424
import { DEFAULT_API_VERSION } from "../requests/request";
2525
import { FileMetadata } from "../../types/server";
26+
import { readFile } from "fs/promises";
2627

2728
use(sinonChai);
2829
use(chaiAsPromised);
@@ -61,6 +62,28 @@ describe("GoogleAIFileManager", () => {
6162
const blobText = await (bodyBlob as Blob).text();
6263
expect(blobText).to.include("Content-Type: image/png");
6364
});
65+
it("passes uploadFile request info reading from buffer", async () => {
66+
const makeRequestStub = stub(request, "makeServerRequest").resolves({
67+
ok: true,
68+
json: fakeUploadJson,
69+
} as Response);
70+
const fileManager = new GoogleAIFileManager("apiKey");
71+
const fileBuffer = await readFile("./test-utils/cat.png");
72+
const result = await fileManager.uploadFile(fileBuffer, {
73+
mimeType: "image/png",
74+
});
75+
expect(result.file.uri).to.equal(FAKE_URI);
76+
expect(makeRequestStub.args[0][0].task).to.equal(RpcTask.UPLOAD);
77+
expect(makeRequestStub.args[0][0].toString()).to.include("/upload/");
78+
expect(makeRequestStub.args[0][1]).to.be.instanceOf(Headers);
79+
expect(makeRequestStub.args[0][1].get("X-Goog-Upload-Protocol")).to.equal(
80+
"multipart",
81+
);
82+
expect(makeRequestStub.args[0][2]).to.be.instanceOf(Blob);
83+
const bodyBlob = makeRequestStub.args[0][2];
84+
const blobText = await (bodyBlob as Blob).text();
85+
expect(blobText).to.include("Content-Type: image/png");
86+
});
6487
it("passes uploadFile request info and metadata", async () => {
6588
const makeRequestStub = stub(request, "makeServerRequest").resolves({
6689
ok: true,
@@ -80,6 +103,26 @@ describe("GoogleAIFileManager", () => {
80103
expect(blobText).to.include("files/customname");
81104
expect(blobText).to.include("mydisplayname");
82105
});
106+
it("passes uploadFile request info and metadata from buffer", async () => {
107+
const makeRequestStub = stub(request, "makeServerRequest").resolves({
108+
ok: true,
109+
json: fakeUploadJson,
110+
} as Response);
111+
const fileManager = new GoogleAIFileManager("apiKey");
112+
const fileBuffer = await readFile("./test-utils/cat.png");
113+
const result = await fileManager.uploadFile(fileBuffer, {
114+
mimeType: "image/png",
115+
name: "files/customname",
116+
displayName: "mydisplayname",
117+
});
118+
expect(result.file.uri).to.equal(FAKE_URI);
119+
expect(makeRequestStub.args[0][2]).to.be.instanceOf(Blob);
120+
const bodyBlob = makeRequestStub.args[0][2];
121+
const blobText = await (bodyBlob as Blob).text();
122+
expect(blobText).to.include("Content-Type: image/png");
123+
expect(blobText).to.include("files/customname");
124+
expect(blobText).to.include("mydisplayname");
125+
});
83126
it("passes uploadFile metadata and formats file name", async () => {
84127
const makeRequestStub = stub(request, "makeServerRequest").resolves({
85128
ok: true,
@@ -95,6 +138,22 @@ describe("GoogleAIFileManager", () => {
95138
const blobText = await (bodyBlob as Blob).text();
96139
expect(blobText).to.include("files/customname");
97140
});
141+
it("passes uploadFile metadata and formats file name from buffer", async () => {
142+
const makeRequestStub = stub(request, "makeServerRequest").resolves({
143+
ok: true,
144+
json: fakeUploadJson,
145+
} as Response);
146+
const fileManager = new GoogleAIFileManager("apiKey");
147+
const fileBuffer = await readFile("./test-utils/cat.png");
148+
await fileManager.uploadFile(fileBuffer, {
149+
mimeType: "image/png",
150+
name: "customname",
151+
displayName: "mydisplayname",
152+
});
153+
const bodyBlob = makeRequestStub.args[0][2];
154+
const blobText = await (bodyBlob as Blob).text();
155+
expect(blobText).to.include("files/customname");
156+
});
98157
it("passes uploadFile request info (with options)", async () => {
99158
const makeRequestStub = stub(request, "makeServerRequest").resolves({
100159
ok: true,
@@ -123,6 +182,35 @@ describe("GoogleAIFileManager", () => {
123182
/^http:\/\/mysite\.com/,
124183
);
125184
});
185+
it("passes uploadFile request info (with options) from buffer", async () => {
186+
const makeRequestStub = stub(request, "makeServerRequest").resolves({
187+
ok: true,
188+
json: fakeUploadJson,
189+
} as Response);
190+
const fileManager = new GoogleAIFileManager("apiKey", {
191+
apiVersion: "v3000",
192+
baseUrl: "http://mysite.com",
193+
});
194+
const fileBuffer = await readFile("./test-utils/cat.png");
195+
const result = await fileManager.uploadFile(fileBuffer, {
196+
mimeType: "image/png",
197+
});
198+
expect(result.file.uri).to.equal(FAKE_URI);
199+
expect(makeRequestStub.args[0][0].task).to.equal(RpcTask.UPLOAD);
200+
expect(makeRequestStub.args[0][0].toString()).to.include("/upload/");
201+
expect(makeRequestStub.args[0][1]).to.be.instanceOf(Headers);
202+
expect(makeRequestStub.args[0][1].get("X-Goog-Upload-Protocol")).to.equal(
203+
"multipart",
204+
);
205+
expect(makeRequestStub.args[0][2]).to.be.instanceOf(Blob);
206+
const bodyBlob = makeRequestStub.args[0][2];
207+
const blobText = await (bodyBlob as Blob).text();
208+
expect(blobText).to.include("Content-Type: image/png");
209+
expect(makeRequestStub.args[0][0].toString()).to.include("v3000/files");
210+
expect(makeRequestStub.args[0][0].toString()).to.match(
211+
/^http:\/\/mysite\.com/,
212+
);
213+
});
126214
it("passes listFiles request info", async () => {
127215
const makeRequestStub = stub(request, "makeServerRequest").resolves({
128216
ok: true,

‎src/server/file-manager.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ export class GoogleAIFileManager {
5151
* Upload a file.
5252
*/
5353
async uploadFile(
54-
filePath: string,
54+
fileData: string | Buffer,
5555
fileMetadata: FileMetadata,
5656
): Promise<UploadFileResponse> {
57-
const file = readFileSync(filePath);
57+
const file = fileData instanceof Buffer ? fileData : readFileSync(fileData);
58+
5859
const url = new FilesRequestUrl(
5960
RpcTask.UPLOAD,
6061
this.apiKey,

0 commit comments

Comments
 (0)
Please sign in to comment.