Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 17 additions & 16 deletions built-in-ai-extension/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions built-in-ai-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@
"author": "Thomas Steiner (tomac@google.com)",
"license": "Apache-2.0",
"dependencies": {
"built-in-ai-task-apis-polyfills": "^1.4.0",
"prompt-api-polyfill": "^1.10.0"
"built-in-ai-task-apis-polyfills": "^1.5.0",
"prompt-api-polyfill": "^1.11.0"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"eslint": "^10.0.2",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^10.1.8",
"globals": "^17.3.0",
"node-addon-api": "^8.5.0",
"node-addon-api": "^8.6.0",
"node-gyp": "^12.2.0",
"prettier": "^3.8.1",
"vite": "^7.3.1"
Expand Down
16 changes: 8 additions & 8 deletions built-in-ai-task-apis-polyfills/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions built-in-ai-task-apis-polyfills/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@
"homepage": "https://github.com/GoogleChromeLabs/web-ai-demos/tree/main/built-in-ai-task-apis-polyfills#readme",
"bugs": "https://github.com/GoogleChromeLabs/web-ai-demos/issues",
"dependencies": {
"prompt-api-polyfill": "^1.10.0"
"prompt-api-polyfill": "^1.11.0"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"eslint": "^10.0.2",
"eslint-config-prettier": "^10.1.8",
"globals": "^17.3.0",
"node-addon-api": "^8.5.0",
"node-addon-api": "^8.6.0",
"node-gyp": "^12.2.0",
"prettier-plugin-curly": "^0.4.1",
"vite": "^7.3.1"
Expand Down
25 changes: 12 additions & 13 deletions prompt-api-polyfill/backends/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
* Abstract class representing a backend for the LanguageModel polyfill.
*/
export default class PolyfillBackend {
#model;

/**
* @param {string} modelName - The name of the model.
Expand All @@ -18,48 +17,48 @@ export default class PolyfillBackend {

/**
* Checks if the backend is available given the options.
* @param {Object} options - LanguageModel options.
* @param {Object} _options - LanguageModel options.
* @returns {string} 'available', 'unavailable', 'downloadable', or 'downloading'.
*/
static availability(options) {
static availability(_options) {
return 'available';
}

/**
* Creates a model session and stores it.
* @param {Object} options - LanguageModel options.
* @param {Object} sessionParams - Parameters for the cloud or local model.
* @param {EventTarget} [monitorTarget] - The event target to dispatch download progress events to.
* @param {Object} _options - LanguageModel options.
* @param {Object} _sessionParams - Parameters for the cloud or local model.
* @param {EventTarget} [_monitorTarget] - The event target to dispatch download progress events to.
* @returns {any} The created session object.
*/
createSession(options, sessionParams, monitorTarget) {
createSession(_options, _sessionParams, _monitorTarget) {
throw new Error('Not implemented');
}

/**
* Generates content (non-streaming).
* @param {Array} content - The history + new message content.
* @param {Array} _content - The history + new message content.
* @returns {Promise<{text: string, usage: number}>}
*/
async generateContent(content) {
async generateContent(_content) {
throw new Error('Not implemented');
}

/**
* Generates content stream.
* @param {Array} content - The history + new content.
* @param {Array} _content - The history + new content.
* @returns {Promise<AsyncIterable>} Stream of chunks.
*/
async generateContentStream(content) {
async generateContentStream(_content) {
throw new Error('Not implemented');
}

/**
* Counts tokens.
* @param {Array} content - The content to count.
* @param {Array} _content - The content to count.
* @returns {Promise<number>} Total tokens.
*/
async countTokens(content) {
async countTokens(_content) {
throw new Error('Not implemented');
}
}
23 changes: 21 additions & 2 deletions prompt-api-polyfill/backends/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { DEFAULT_MODELS } from './defaults.js';
*/
export default class FirebaseBackend extends PolyfillBackend {
#model;
#sessionParams;

constructor(config) {
const {
Expand Down Expand Up @@ -52,26 +51,46 @@ export default class FirebaseBackend extends PolyfillBackend {
});
}

/**
* Creates a model session and stores it.
* @param {Object} _options - LanguageModel options.
* @param {Object} sessionParams - Parameters for the cloud or local model.
* @returns {any} The created session object.
*/
createSession(_options, sessionParams) {
this.#sessionParams = sessionParams;
this.#model = getGenerativeModel(this.ai, {
mode: InferenceMode.ONLY_IN_CLOUD,
inCloudParams: sessionParams,
});
return this.#model;
}

/**
* Generates content (non-streaming).
* @param {Array} contents - The history + new message content.
* @returns {Promise<{text: string, usage: number}>}
*/
async generateContent(contents) {
const result = await this.#model.generateContent({ contents });
const usage = result.response.usageMetadata?.promptTokenCount || 0;
return { text: result.response.text(), usage };
}

/**
* Generates content stream.
* @param {Array} contents - The history + new content.
* @returns {Promise<AsyncIterable>} Stream of chunks.
*/
async generateContentStream(contents) {
const result = await this.#model.generateContentStream({ contents });
return result.stream;
}

/**
* Counts tokens.
* @param {Array} contents - The content to count.
* @returns {Promise<number>} Total tokens.
*/
async countTokens(contents) {
const { totalTokens } = await this.#model.countTokens({
contents,
Expand Down
21 changes: 21 additions & 0 deletions prompt-api-polyfill/backends/gemini.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,23 @@ export default class GeminiBackend extends PolyfillBackend {
this.#ai = new GoogleGenAI({ apiKey: config.apiKey });
}

/**
* Creates a model session.
* @param {Object} options - LanguageModel options.
* @param {Object} sessionParams - Session parameters.
* @returns {Object} The session object.
*/
createSession(options, sessionParams) {
this.#sessionParams = sessionParams;
this.#modelName = options.modelName || this.modelName;
return { model: this.#modelName, params: sessionParams };
}

/**
* Generates content (non-streaming).
* @param {Array} contents - The history + new message content.
* @returns {Promise<{text: string, usage: number}>}
*/
async generateContent(contents) {
const config = {
systemInstruction: this.#sessionParams.systemInstruction,
Expand All @@ -43,6 +54,11 @@ export default class GeminiBackend extends PolyfillBackend {
return { text: response.text, usage };
}

/**
* Generates content stream.
* @param {Array} contents - The history + new content.
* @returns {Promise<AsyncIterable>} Stream of chunks.
*/
async generateContentStream(contents) {
const config = {
systemInstruction: this.#sessionParams.systemInstruction,
Expand All @@ -69,6 +85,11 @@ export default class GeminiBackend extends PolyfillBackend {
})();
}

/**
* Counts tokens.
* @param {Array} contents - The content to count.
* @returns {Promise<number>} Total tokens.
*/
async countTokens(contents) {
const { totalTokens } = await this.#ai.models.countTokens({
model: this.#modelName,
Expand Down
22 changes: 21 additions & 1 deletion prompt-api-polyfill/backends/openai.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export default class OpenAIBackend extends PolyfillBackend {
return 'available';
}

/**
* Creates a model session and stores it.
* @param {Object} options - LanguageModel options.
* @param {Object} sessionParams - Parameters for the cloud or local model.
* @returns {any} The created session object.
*/
createSession(options, sessionParams) {
// OpenAI doesn't have a "session" object like Gemini, so we return a context object
// tailored for our generate methods.
Expand Down Expand Up @@ -155,6 +161,11 @@ export default class OpenAIBackend extends PolyfillBackend {
return hasAudio ? `${this.modelName}-audio-preview` : this.modelName;
}

/**
* Generates content (non-streaming).
* @param {Array} contents - The history + new message content.
* @returns {Promise<{text: string, usage: number}>}
*/
async generateContent(contents) {
const { messages } = this.#convertContentsToInput(
contents,
Expand Down Expand Up @@ -212,6 +223,11 @@ export default class OpenAIBackend extends PolyfillBackend {
}
}

/**
* Generates content stream.
* @param {Array} contents - The history + new content.
* @returns {Promise<AsyncIterable>} Stream of chunks.
*/
async generateContentStream(contents) {
const { messages } = this.#convertContentsToInput(
contents,
Expand Down Expand Up @@ -249,7 +265,6 @@ export default class OpenAIBackend extends PolyfillBackend {

// Convert OpenAI stream to an AsyncIterable that yields chunks
return (async function* () {
let firstChunk = true;
for await (const chunk of stream) {
let text = chunk.choices[0]?.delta?.content;
if (text) {
Expand All @@ -268,6 +283,11 @@ export default class OpenAIBackend extends PolyfillBackend {
}
}

/**
* Counts tokens.
* @param {Array} contents - The content to count.
* @returns {Promise<number>} Total tokens.
*/
async countTokens(contents) {
// OpenAI does not provide a public API endpoint for counting tokens before generation.
// Implementing countTokens strictly requires a tokenizer like `tiktoken`.
Expand Down
Loading