Skip to content

Commit 6f86c58

Browse files
committed
Reject image input for Count Token on device
1 parent 43a69d5 commit 6f86c58

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

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

+50-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18+
import { VertexAIError } from '../errors';
1819
import { expect, use } from 'chai';
1920
import sinonChai from 'sinon-chai';
2021
import chaiAsPromised from 'chai-as-promised';
@@ -26,7 +27,7 @@ import {
2627
LanguageModelMessageContent
2728
} from '../types/language-model';
2829
import { match, stub } from 'sinon';
29-
import { GenerateContentRequest } from '../types';
30+
import { GenerateContentRequest, VertexAIErrorCode } from '../types';
3031

3132
use(sinonChai);
3233
use(chaiAsPromised);
@@ -414,6 +415,54 @@ describe('ChromeAdapter', () => {
414415
totalTokens: expectedCount
415416
});
416417
});
418+
it('count tokens for image based input should throw', async () => {
419+
// setting up stubs
420+
const languageModelProvider = {
421+
create: () => Promise.resolve({})
422+
} as LanguageModel;
423+
const languageModel = {
424+
measureInputUsage: _i => Promise.resolve(123)
425+
} as LanguageModel;
426+
const createStub = stub(languageModelProvider, 'create').resolves(
427+
languageModel
428+
);
429+
430+
const countTokenRequestWithImagePart = {
431+
contents: [
432+
{
433+
role: 'user',
434+
parts: [
435+
{ text: 'test' },
436+
{
437+
inlineData: {
438+
data: sampleBase64EncodedImage,
439+
mimeType: 'image/jpeg'
440+
}
441+
}
442+
]
443+
}
444+
]
445+
} as GenerateContentRequest;
446+
447+
const adapter = new ChromeAdapter(
448+
languageModelProvider,
449+
'only_on_device'
450+
);
451+
452+
try {
453+
await adapter.countTokens(countTokenRequestWithImagePart);
454+
} catch (e) {
455+
// the call to countToken should be rejected with Error
456+
expect((e as VertexAIError).code).to.equal(
457+
VertexAIErrorCode.INVALID_CONTENT
458+
);
459+
expect((e as VertexAIError).message).includes('image input');
460+
}
461+
462+
// Asserts that create stub was not called - error happens before this
463+
// step is reached
464+
expect(createStub).not.called;
465+
});
417466
});
418467
describe('generateContentStream', () => {
419468
it('generates content stream', async () => {

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

+15-2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515
* limitations under the License.
1616
*/
1717

18+
import { VertexAIError } from '../errors';
1819
import {
1920
CountTokensRequest,
2021
GenerateContentRequest,
2122
InferenceMode,
22-
Part
23+
Part,
24+
VertexAIErrorCode
2325
} from '../types';
2426
import {
2527
Availability,
@@ -130,7 +132,18 @@ export class ChromeAdapter {
130132
}
131133

132134
async countTokens(request: CountTokensRequest): Promise<Response> {
133-
// TODO: Check if the request contains an image, and if so, throw.
135+
// validated that no input is of image type. The current on-device
136+
// implementation doesn't support image input for the `measureInputUsage` API.
137+
for (const part of request.contents[0].parts) {
138+
// console.log(part);
139+
if (part.inlineData) {
140+
throw new VertexAIError(
141+
VertexAIErrorCode.INVALID_CONTENT,
142+
'Support for image input is not yet available for the Count Tokens API when running on-device.'
143+
);
144+
}
145+
}
146+
134147
const session = await this.createSession(
135148
// TODO: normalize on-device params during construction.
136149
this.onDeviceParams || {}

0 commit comments

Comments
 (0)