Skip to content

Commit 7f855b4

Browse files
authored
Merge 5ee53bf into dc3794a
2 parents dc3794a + 5ee53bf commit 7f855b4

File tree

2 files changed

+111
-2
lines changed

2 files changed

+111
-2
lines changed

packages/vertexai/src/methods/chrome-adapter.test.ts

+89-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,59 @@ async function toStringArray(
5252
}
5353

5454
describe('ChromeAdapter', () => {
55+
describe('constructor', () => {
56+
it('sets image as expected input type by default', async () => {
57+
const languageModelProvider = {
58+
availability: () => Promise.resolve(Availability.available)
59+
} as LanguageModel;
60+
const availabilityStub = stub(
61+
languageModelProvider,
62+
'availability'
63+
).resolves(Availability.available);
64+
const adapter = new ChromeAdapter(
65+
languageModelProvider,
66+
'prefer_on_device'
67+
);
68+
await adapter.isAvailable({
69+
contents: [
70+
{
71+
role: 'user',
72+
parts: [{ text: 'hi' }]
73+
}
74+
]
75+
});
76+
expect(availabilityStub).to.have.been.calledWith({
77+
expectedInputs: [{ type: 'image' }]
78+
});
79+
});
80+
it('honors explicitly set expected inputs', async () => {
81+
const languageModelProvider = {
82+
availability: () => Promise.resolve(Availability.available)
83+
} as LanguageModel;
84+
const availabilityStub = stub(
85+
languageModelProvider,
86+
'availability'
87+
).resolves(Availability.available);
88+
const onDeviceParams = {
89+
// Explicitly sets expected inputs.
90+
expectedInputs: [{ type: 'text' }]
91+
} as LanguageModelCreateOptions;
92+
const adapter = new ChromeAdapter(
93+
languageModelProvider,
94+
'prefer_on_device',
95+
onDeviceParams
96+
);
97+
await adapter.isAvailable({
98+
contents: [
99+
{
100+
role: 'user',
101+
parts: [{ text: 'hi' }]
102+
}
103+
]
104+
});
105+
expect(availabilityStub).to.have.been.calledWith(onDeviceParams);
106+
});
107+
});
55108
describe('isAvailable', () => {
56109
it('returns false if mode is only cloud', async () => {
57110
const adapter = new ChromeAdapter(undefined, 'only_in_cloud');
@@ -100,6 +153,33 @@ describe('ChromeAdapter', () => {
100153
})
101154
).to.be.false;
102155
});
156+
it('returns true if request has image with supported mime type', async () => {
157+
const adapter = new ChromeAdapter(
158+
{
159+
availability: async () => Availability.available
160+
} as LanguageModel,
161+
'prefer_on_device'
162+
);
163+
for (const mimeType of ChromeAdapter.SUPPORTED_MIME_TYPES) {
164+
expect(
165+
await adapter.isAvailable({
166+
contents: [
167+
{
168+
role: 'user',
169+
parts: [
170+
{
171+
inlineData: {
172+
mimeType,
173+
data: ''
174+
}
175+
}
176+
]
177+
}
178+
]
179+
})
180+
).to.be.true;
181+
}
182+
});
103183
it('returns true if model is readily available', async () => {
104184
const languageModelProvider = {
105185
availability: () => Promise.resolve(Availability.available)
@@ -110,7 +190,15 @@ describe('ChromeAdapter', () => {
110190
);
111191
expect(
112192
await adapter.isAvailable({
113-
contents: [{ role: 'user', parts: [{ text: 'hi' }] }]
193+
contents: [
194+
{
195+
role: 'user',
196+
parts: [
197+
{ text: 'describe this image' },
198+
{ inlineData: { mimeType: 'image/jpeg', data: 'asd' } }
199+
]
200+
}
201+
]
114202
})
115203
).to.be.true;
116204
});

packages/vertexai/src/methods/chrome-adapter.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,18 @@ import {
3535
* and encapsulates logic for detecting when on-device is possible.
3636
*/
3737
export class ChromeAdapter {
38+
// Visible for testing
39+
static SUPPORTED_MIME_TYPES = ['image/jpeg', 'image/png'];
3840
private isDownloading = false;
3941
private downloadPromise: Promise<LanguageModel | void> | undefined;
4042
private oldSession: LanguageModel | undefined;
4143
constructor(
4244
private languageModelProvider?: LanguageModel,
4345
private mode?: InferenceMode,
4446
private onDeviceParams: LanguageModelCreateOptions = {}
45-
) {}
47+
) {
48+
this.addImageTypeAsExpectedInput();
49+
}
4650

4751
/**
4852
* Checks if a given request can be made on-device.
@@ -140,6 +144,18 @@ export class ChromeAdapter {
140144
if (content.role !== 'user') {
141145
return false;
142146
}
147+
148+
// Returns false if request contains an image with an unsupported mime type.
149+
for (const part of content.parts) {
150+
if (
151+
part.inlineData &&
152+
ChromeAdapter.SUPPORTED_MIME_TYPES.indexOf(
153+
part.inlineData.mimeType
154+
) === -1
155+
) {
156+
return false;
157+
}
158+
}
143159
}
144160

145161
return true;
@@ -236,6 +252,11 @@ export class ChromeAdapter {
236252
return newSession;
237253
}
238254

255+
private addImageTypeAsExpectedInput(): void {
256+
// Defaults to support image inputs for convenience.
257+
this.onDeviceParams.expectedInputs ??= [{ type: 'image' }];
258+
}
259+
239260
/**
240261
* Formats string returned by Chrome as a {@link Response} returned by Vertex.
241262
*/

0 commit comments

Comments
 (0)