Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a3d869b
Define HybridParams
erikeldridge Mar 24, 2025
14eee16
Copy over most types from @types package
erikeldridge Mar 24, 2025
b242749
Trim unused AI types
erikeldridge Mar 25, 2025
5e97457
Assert HybridParams sets the model name
erikeldridge Mar 25, 2025
1fe8a08
Use dom-chromium-ai package directly
erikeldridge Mar 26, 2025
869fee7
Define ChromeAdapter class
erikeldridge Mar 25, 2025
ff31b42
Implement ChromeAdapter class
erikeldridge Apr 2, 2025
1e487d5
Integrate with e2e test app
erikeldridge Apr 2, 2025
8307fe5
Parameterize default in-cloud model name
erikeldridge Mar 28, 2025
291c53b
Use type for inference mode and update docs
erikeldridge Apr 2, 2025
fe2bebc
Remove stray ai.ts
erikeldridge Apr 3, 2025
d4286d6
Run yarn format
erikeldridge Apr 3, 2025
b898cd0
Test request-based availability checks
erikeldridge Apr 4, 2025
2fb2795
Remove request.systemInstruction validation
erikeldridge Apr 4, 2025
ef893c9
Integrate chrome adapter into stream methods
erikeldridge Apr 7, 2025
4c37859
Refactor to emulate Vertex response
erikeldridge Apr 8, 2025
eb25fec
Group response formatting methods together
erikeldridge Apr 8, 2025
b8d849c
Run docgen
erikeldridge Apr 18, 2025
1b9c98d
Re-remove isChrome
erikeldridge Apr 18, 2025
5092bd8
Re-remove dom-chromium-ai
erikeldridge Apr 18, 2025
025b786
Unit test stream method
erikeldridge Apr 18, 2025
34c658e
Remove redundant ondevice suffix
erikeldridge Apr 18, 2025
7af0f8d
Merge remote-tracking branch 'public/vaihi-exp' into erikeldridge-ver…
erikeldridge Apr 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions common/api-review/util.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ export function isBrowser(): boolean;
// @public (undocumented)
export function isBrowserExtension(): boolean;

// Warning: (ae-missing-release-tag) "isChrome" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function isChrome(): boolean;

// Warning: (ae-missing-release-tag) "isCloudflareWorker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
Expand Down
16 changes: 8 additions & 8 deletions e2e/sample-apps/modular.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,7 @@ import {
onValue,
off
} from 'firebase/database';
import {
getGenerativeModel,
getVertexAI,
InferenceMode,
VertexAI
} from 'firebase/vertexai';
import { getGenerativeModel, getVertexAI } from 'firebase/vertexai';
import { getDataConnect, DataConnect } from 'firebase/data-connect';

/**
Expand Down Expand Up @@ -318,8 +313,13 @@ function callPerformance(app) {
async function callVertexAI(app) {
console.log('[VERTEXAI] start');
const vertexAI = getVertexAI(app);
const model = getGenerativeModel(vertexAI, { model: 'gemini-1.5-flash' });
const result = await model.countTokens('abcdefg');
const model = getGenerativeModel(vertexAI, {
mode: 'prefer_in_cloud'
});
const result = await model.generateContentStream("What is Roko's Basalisk?");
for await (const chunk of result.stream) {
console.log(chunk.text());
}
console.log(`[VERTEXAI] counted tokens: ${result.totalTokens}`);
}

Expand Down
6 changes: 6 additions & 0 deletions packages/util/src/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ export function isSafari(): boolean {
);
}

export function isChrome(): boolean {
return (
!isNode() && !!navigator.userAgent && navigator.userAgent.includes('Chrome')
);
}

/**
* This method checks if indexedDB is supported by current browser/service worker context
* @return true if indexedDB is supported by current browser/service worker context
Expand Down
1 change: 1 addition & 0 deletions packages/vertexai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"devDependencies": {
"@firebase/app": "0.11.4",
"@rollup/plugin-json": "6.1.0",
"@types/dom-chromium-ai": "0.0.6",
"rollup": "2.79.2",
"rollup-plugin-replace": "2.2.0",
"rollup-plugin-typescript2": "0.36.0",
Expand Down
1 change: 1 addition & 0 deletions packages/vertexai/src/methods/chat-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export class ChatSession {
this._apiSettings,
this.model,
generateContentRequest,
this.chromeAdapter,
this.requestOptions
);

Expand Down
71 changes: 55 additions & 16 deletions packages/vertexai/src/methods/chrome-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,23 +103,19 @@ export class ChromeAdapter {
);
const messages = ChromeAdapter.toLanguageModelMessages(request.contents);
const text = await session.prompt(messages);
return {
json: () =>
Promise.resolve({
candidates: [
{
content: {
parts: [{ text }]
}
}
]
})
} as Response;
return ChromeAdapter.toResponse(text);
}
async generateContentStreamOnDevice(
request: GenerateContentRequest
): Promise<Response> {
const session = await this.createSession(
// TODO: normalize on-device params during construction.
this.onDeviceParams || {}
);
const messages = ChromeAdapter.toLanguageModelMessages(request.contents);
const stream = await session.promptStreaming(messages);
return ChromeAdapter.toStreamResponse(stream);
}

/**
* Asserts inference for the given request can be performed by an on-device model.
*/
private static isOnDeviceRequest(request: GenerateContentRequest): boolean {
// Returns false if the prompt is empty.
if (request.contents.length === 0) {
Expand Down Expand Up @@ -224,4 +220,47 @@ export class ChromeAdapter {
this.oldSession = newSession;
return newSession;
}

/**
* Formats string returned by Chrome as a {@link Response} returned by Vertex.
*/
private static toResponse(text: string): Response {
return {
json: async () => ({
candidates: [
{
content: {
parts: [{ text }]
}
}
]
})
} as Response;
}

/**
* Formats string stream returned by Chrome as SSE returned by Vertex.
*/
private static toStreamResponse(stream: ReadableStream<string>): Response {
const encoder = new TextEncoder();
return {
body: stream.pipeThrough(
new TransformStream({
transform(chunk, controller) {
const json = JSON.stringify({
candidates: [
{
content: {
role: 'model',
parts: [{ text: chunk }]
}
}
]
});
controller.enqueue(encoder.encode(`data: ${json}\n\n`));
}
})
)
} as Response;
}
}
26 changes: 23 additions & 3 deletions packages/vertexai/src/methods/generate-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,40 @@ import { processStream } from '../requests/stream-reader';
import { ApiSettings } from '../types/internal';
import { ChromeAdapter } from './chrome-adapter';

export async function generateContentStream(
async function generateContentStreamOnCloud(
apiSettings: ApiSettings,
model: string,
params: GenerateContentRequest,
requestOptions?: RequestOptions
): Promise<GenerateContentStreamResult> {
const response = await makeRequest(
): Promise<Response> {
return makeRequest(
model,
Task.STREAM_GENERATE_CONTENT,
apiSettings,
/* stream */ true,
JSON.stringify(params),
requestOptions
);
}

export async function generateContentStream(
apiSettings: ApiSettings,
model: string,
params: GenerateContentRequest,
chromeAdapter: ChromeAdapter,
requestOptions?: RequestOptions
): Promise<GenerateContentStreamResult> {
let response;
if (await chromeAdapter.isAvailable(params)) {
response = await chromeAdapter.generateContentStreamOnDevice(params);
} else {
response = await generateContentStreamOnCloud(
apiSettings,
model,
params,
requestOptions
);
}
return processStream(response);
}

Expand Down
1 change: 1 addition & 0 deletions packages/vertexai/src/models/generative-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export class GenerativeModel extends VertexAIModel {
systemInstruction: this.systemInstruction,
...formattedParams
},
this.chromeAdapter,
this.requestOptions
);
}
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2947,6 +2947,11 @@
resolved "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd"
integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==

"@types/[email protected]":
version "0.0.6"
resolved "https://registry.npmjs.org/@types/dom-chromium-ai/-/dom-chromium-ai-0.0.6.tgz#0c9e5712d8db3d26586cd9f175001b509cd2e514"
integrity sha512-/jUGe9a3BLzsjjg18Olk/Ul64PZ0P4aw8uNxrXeXVTni5PSxyCfyhHb4UohsXNVByOnwYGzlqUcb3vYKVsG4mg==

"@types/eslint-scope@^3.7.7":
version "3.7.7"
resolved "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5"
Expand Down
Loading