Skip to content

Commit

Permalink
fix text() and add FileState (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
hsubox76 authored May 8, 2024
1 parent bc79f48 commit c39015c
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 40 deletions.
5 changes: 5 additions & 0 deletions .changeset/two-queens-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@google/generative-ai": patch
---

Fixed a bug where `text()` did not handle multiple `TextPart`s in a single candidate. Added `state` field to `FileMetadataResponse`.
1 change: 1 addition & 0 deletions docs/reference/files/generative-ai.filemetadataresponse.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface FileMetadataResponse
| [name](./generative-ai.filemetadataresponse.name.md) | | string | |
| [sha256Hash](./generative-ai.filemetadataresponse.sha256hash.md) | | string | |
| [sizeBytes](./generative-ai.filemetadataresponse.sizebytes.md) | | string | |
| [state](./generative-ai.filemetadataresponse.state.md) | | [FileState](./generative-ai.filestate.md) | |
| [updateTime](./generative-ai.filemetadataresponse.updatetime.md) | | string | |
| [uri](./generative-ai.filemetadataresponse.uri.md) | | string | |

11 changes: 11 additions & 0 deletions docs/reference/files/generative-ai.filemetadataresponse.state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@google/generative-ai](./generative-ai.md) &gt; [FileMetadataResponse](./generative-ai.filemetadataresponse.md) &gt; [state](./generative-ai.filemetadataresponse.state.md)

## FileMetadataResponse.state property

**Signature:**

```typescript
state: FileState;
```
23 changes: 23 additions & 0 deletions docs/reference/files/generative-ai.filestate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@google/generative-ai](./generative-ai.md) &gt; [FileState](./generative-ai.filestate.md)

## FileState enum

Processing state of the `File`<!-- -->.

**Signature:**

```typescript
export declare enum FileState
```

## Enumeration Members

| Member | Value | Description |
| --- | --- | --- |
| ACTIVE | <code>2</code> | |
| FAILED | <code>10</code> | |
| PROCESSING | <code>1</code> | |
| STATE\_UNSPECIFIED | <code>0</code> | |

6 changes: 6 additions & 0 deletions docs/reference/files/generative-ai.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
| --- | --- |
| [GoogleAIFileManager](./generative-ai.googleaifilemanager.md) | Class for managing GoogleAI file uploads. |

## Enumerations

| Enumeration | Description |
| --- | --- |
| [FileState](./generative-ai.filestate.md) | Processing state of the <code>File</code>. |

## Interfaces

| Interface | Description |
Expand Down
16 changes: 16 additions & 0 deletions packages/main/src/files/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface FileMetadataResponse {
expirationTime: string;
sha256Hash: string;
uri: string;
state: FileState;
}

/**
Expand All @@ -66,3 +67,18 @@ export interface ListFilesResponse {
export interface UploadFileResponse {
file: FileMetadataResponse;
}

/**
* Processing state of the `File`.
* @public
*/
export enum FileState {
// The default value. This value is used if the state is omitted.
STATE_UNSPECIFIED = 0,
// File is being processed and cannot be used for inference yet.
PROCESSING = 1,
// File is processed and available for inference.
ACTIVE = 2,
// File failed processing.
FAILED = 10,
}
125 changes: 90 additions & 35 deletions packages/main/src/requests/response-helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,54 +40,85 @@ const fakeResponseText: GenerateContentResponse = {
],
};

const functionCallPart1 = {
functionCall: {
name: "find_theaters",
args: {
location: "Mountain View, CA",
movie: "Barbie",
},
},
};

const functionCallPart2 = {
functionCall: {
name: "find_times",
args: {
location: "Mountain View, CA",
movie: "Barbie",
time: "20:00",
},
},
};

const fakeResponseFunctionCall: GenerateContentResponse = {
candidates: [
{
index: 0,
content: {
role: "model",
parts: [
{
functionCall: {
name: "find_theaters",
args: {
location: "Mountain View, CA",
movie: "Barbie",
},
},
},
],
parts: [functionCallPart1],
},
},
],
};

const fakeResponseFunctionCalls: GenerateContentResponse = {
candidates: [
{
index: 0,
content: {
role: "model",
parts: [functionCallPart1, functionCallPart2],
},
},
],
};

const fakeResponseMixed1: GenerateContentResponse = {
candidates: [
{
index: 0,
content: {
role: "model",
parts: [{ text: "some text" }, functionCallPart2],
},
},
],
};

const fakeResponseMixed2: GenerateContentResponse = {
candidates: [
{
index: 0,
content: {
role: "model",
parts: [functionCallPart1, { text: "some text" }],
},
},
],
};

const fakeResponseMixed3: GenerateContentResponse = {
candidates: [
{
index: 0,
content: {
role: "model",
parts: [
{
functionCall: {
name: "find_theaters",
args: {
location: "Mountain View, CA",
movie: "Barbie",
},
},
},
{
functionCall: {
name: "find_times",
args: {
location: "Mountain View, CA",
movie: "Barbie",
time: "20:00",
},
},
},
{ text: "some text" },
functionCallPart1,
{ text: " and more text" },
],
},
},
Expand All @@ -109,19 +140,43 @@ describe("response-helpers methods", () => {
it("good response text", async () => {
const enhancedResponse = addHelpers(fakeResponseText);
expect(enhancedResponse.text()).to.equal("Some text and some more text");
expect(enhancedResponse.functionCalls()).to.be.undefined;
});
it("good response functionCall", async () => {
const enhancedResponse = addHelpers(fakeResponseFunctionCall);
expect(enhancedResponse.functionCall()).to.deep.equal(
fakeResponseFunctionCall.candidates[0].content.parts[0].functionCall,
);
expect(enhancedResponse.text()).to.equal("");
expect(enhancedResponse.functionCalls()).to.deep.equal([
functionCallPart1.functionCall,
]);
});
it("good response functionCalls", async () => {
const enhancedResponse = addHelpers(fakeResponseFunctionCalls);
expect(enhancedResponse.text()).to.equal("");
expect(enhancedResponse.functionCalls()).to.deep.equal([
functionCallPart1.functionCall,
functionCallPart2.functionCall,
]);
});
it("good response text/functionCall", async () => {
const enhancedResponse = addHelpers(fakeResponseMixed1);
expect(enhancedResponse.functionCalls()).to.deep.equal([
functionCallPart2.functionCall,
]);
expect(enhancedResponse.text()).to.equal("some text");
});
it("good response functionCall/text", async () => {
const enhancedResponse = addHelpers(fakeResponseMixed2);
expect(enhancedResponse.functionCalls()).to.deep.equal([
functionCallPart1.functionCall,
]);
expect(enhancedResponse.text()).to.equal("some text");
});
it("good response text/functionCall/text", async () => {
const enhancedResponse = addHelpers(fakeResponseMixed3);
expect(enhancedResponse.functionCalls()).to.deep.equal([
fakeResponseFunctionCalls.candidates[0].content.parts[0].functionCall,
fakeResponseFunctionCalls.candidates[0].content.parts[1].functionCall,
functionCallPart1.functionCall,
]);
expect(enhancedResponse.text()).to.equal("some text and more text");
});
it("bad response safety", async () => {
const enhancedResponse = addHelpers(badFakeResponse);
Expand Down
16 changes: 11 additions & 5 deletions packages/main/src/requests/response-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,19 @@ export function addHelpers(
}

/**
* Returns text of first candidate.
* Returns all text found in all parts of first candidate.
*/
export function getText(response: GenerateContentResponse): string {
if (response.candidates?.[0].content?.parts?.[0]?.text) {
return response.candidates[0].content.parts
.map(({ text }) => text)
.join("");
const textStrings = [];
if (response.candidates?.[0].content?.parts) {
for (const part of response.candidates?.[0].content?.parts) {
if (part.text) {
textStrings.push(part.text);
}
}
}
if (textStrings.length > 0) {
return textStrings.join("");
} else {
return "";
}
Expand Down

0 comments on commit c39015c

Please sign in to comment.