Skip to content

Commit 57018ca

Browse files
authored
Port code from GoogleAI repo (#283)
1 parent c1aca52 commit 57018ca

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+3842
-27
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,6 @@ toc/
9898
.terraform.lock.hcl
9999
*.tfstate
100100
*.tfstate.*
101+
102+
# generated test case text data
103+
mocks-lookup.ts

packages/vertexai/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# @firebase/vertexai
22

3+
This is the Firebase Vertex AI component of the Firebase JS SDK.
34

4-
5+
**This package is not intended for direct usage, and should only be used via the officially supported [firebase](https://www.npmjs.com/package/firebase) package.**

packages/vertexai/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@
3434
"lint": "eslint -c .eslintrc.js '**/*.ts' --ignore-path '../../.gitignore'",
3535
"lint:fix": "eslint --fix -c .eslintrc.js '**/*.ts' --ignore-path '../../.gitignore'",
3636
"build": "rollup -c",
37-
"build:deps": "lerna run --scope @firebase/template --include-dependencies build",
37+
"build:deps": "lerna run --scope @firebase/vertexai --include-dependencies build",
3838
"dev": "rollup -c -w",
39+
"pretest": "yarn ts-node ./test-utils/convert-mocks.ts",
3940
"test": "run-p --npm-path npm lint test:all",
4041
"test:ci": "node ../../scripts/run_tests_in_ci.js -s test:all",
4142
"test:all": "run-p --npm-path npm test:browser test:node",
@@ -55,7 +56,7 @@
5556
},
5657
"license": "Apache-2.0",
5758
"devDependencies": {
58-
"@firebase/app": "0.9.28",
59+
"@firebase/app": "0.9.29",
5960
"@rollup/plugin-json": "4.1.0",
6061
"rollup": "2.79.1",
6162
"rollup-plugin-replace": "2.2.0",

packages/vertexai/src/api.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @license
3+
* Copyright 2024 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import { ModelParams } from './types';
18+
import { getGenerativeModel } from './api';
19+
import { expect } from 'chai';
20+
import { Vertex } from './public-types';
21+
import { GenerativeModel } from './models/generative-model';
22+
import { VertexError } from './errors';
23+
24+
const fakeVertex: Vertex = {
25+
app: {
26+
name: 'DEFAULT',
27+
automaticDataCollectionEnabled: true,
28+
options: {
29+
apiKey: 'key',
30+
projectId: 'my-project'
31+
}
32+
},
33+
region: 'us-central1'
34+
};
35+
36+
describe('Top level API', () => {
37+
it('getGenerativeModel throws if no model is provided', () => {
38+
expect(() => getGenerativeModel(fakeVertex, {} as ModelParams)).to.throw(
39+
VertexError.NO_MODEL
40+
);
41+
});
42+
it('getGenerativeModel throws if no apiKey is provided', () => {
43+
const fakeVertexNoApiKey = {
44+
...fakeVertex,
45+
app: { options: { projectId: 'my-project' } }
46+
} as Vertex;
47+
expect(() =>
48+
getGenerativeModel(fakeVertexNoApiKey, { model: 'my-model' })
49+
).to.throw(VertexError.NO_API_KEY);
50+
});
51+
it('getGenerativeModel throws if no projectId is provided', () => {
52+
const fakeVertexNoProject = {
53+
...fakeVertex,
54+
app: { options: { apiKey: 'my-key' } }
55+
} as Vertex;
56+
expect(() =>
57+
getGenerativeModel(fakeVertexNoProject, { model: 'my-model' })
58+
).to.throw(VertexError.NO_PROJECT_ID);
59+
});
60+
it('getGenerativeModel gets a GenerativeModel', () => {
61+
const genModel = getGenerativeModel(fakeVertex, { model: 'my-model' });
62+
expect(genModel).to.be.an.instanceOf(GenerativeModel);
63+
expect(genModel.model).to.equal('publishers/google/models/my-model');
64+
});
65+
});

packages/vertexai/src/api.ts

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ import { getModularInstance } from '@firebase/util';
2121
import { VERTEX_TYPE } from './constants';
2222
import { VertexService } from './factory';
2323
import { Vertex } from './public-types';
24+
import { ERROR_FACTORY, VertexError } from './errors';
25+
import { ModelParams, RequestOptions } from './types';
26+
import { GenerativeModel } from './models/generative-model';
27+
28+
export { ChatSession } from './methods/chat-session';
29+
30+
export { GenerativeModel };
2431

2532
declare module '@firebase/component' {
2633
interface NameServiceMapping {
@@ -47,24 +54,13 @@ export function getVertex(app: FirebaseApp = getApp()): Vertex {
4754
return vertexProvider.initialize();
4855
}
4956

50-
export function getGenerativeModel(vertex: Vertex): GenerativeModel {
51-
return new GenerativeModel(vertex, {});
52-
}
53-
54-
// Just a stub
55-
class GenerativeModel {
56-
private _apiKey?: string;
57-
constructor(vertex: Vertex, modelParams: {}) {
58-
if (!vertex.app.options.apiKey) {
59-
// throw error
60-
} else {
61-
this._apiKey = vertex.app.options.apiKey;
62-
//TODO: remove when we use this
63-
console.log(this._apiKey);
64-
}
65-
//TODO: do something with modelParams
66-
console.log(modelParams);
57+
export function getGenerativeModel(
58+
vertex: Vertex,
59+
modelParams: ModelParams,
60+
requestOptions?: RequestOptions
61+
): GenerativeModel {
62+
if (!modelParams.model) {
63+
throw ERROR_FACTORY.create(VertexError.NO_MODEL);
6764
}
65+
return new GenerativeModel(vertex, modelParams, requestOptions);
6866
}
69-
70-
//TODO: add all top-level exportable methods and classes

packages/vertexai/src/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@
1616
*/
1717

1818
export const VERTEX_TYPE = 'vertex';
19+
20+
export const DEFAULT_REGION = 'us-central1';

packages/vertexai/src/errors.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* @license
3+
* Copyright 2024 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { ErrorFactory, ErrorMap } from '@firebase/util';
19+
import { GenerateContentResponse } from './types';
20+
21+
export const enum VertexError {
22+
FETCH_ERROR = 'fetch-error',
23+
INVALID_CONTENT = 'invalid-content',
24+
NO_API_KEY = 'no-api-key',
25+
NO_MODEL = 'no-model',
26+
NO_PROJECT_ID = 'no-project-id',
27+
PARSE_FAILED = 'parse-failed',
28+
RESPONSE_ERROR = 'response-error'
29+
}
30+
31+
const ERRORS: ErrorMap<VertexError> = {
32+
[VertexError.FETCH_ERROR]: `Error fetching from {$url}: {$message}`,
33+
[VertexError.INVALID_CONTENT]: `Content formatting error: {$message}`,
34+
[VertexError.NO_API_KEY]:
35+
`The "apiKey" field is empty in the local Firebase config. Firebase VertexAI requires this field to` +
36+
`contain a valid API key.`,
37+
[VertexError.NO_PROJECT_ID]:
38+
`The "projectId" field is empty in the local Firebase config. Firebase VertexAI requires this field to` +
39+
`contain a valid project ID.`,
40+
[VertexError.NO_MODEL]:
41+
`Must provide a model name. ` +
42+
`Example: genai.getGenerativeModel({ model: 'my-model-name' })`,
43+
[VertexError.PARSE_FAILED]: `Parsing failed: {$message}`,
44+
[VertexError.RESPONSE_ERROR]:
45+
`Response error: {$message}. Response body stored in ` +
46+
`error.customData.response`
47+
};
48+
49+
interface ErrorParams {
50+
[VertexError.FETCH_ERROR]: { url: string; message: string };
51+
[VertexError.INVALID_CONTENT]: { message: string };
52+
[VertexError.PARSE_FAILED]: { message: string };
53+
[VertexError.RESPONSE_ERROR]: {
54+
message: string;
55+
response: GenerateContentResponse;
56+
};
57+
}
58+
59+
export const ERROR_FACTORY = new ErrorFactory<VertexError, ErrorParams>(
60+
'vertex',
61+
'Vertex',
62+
ERRORS
63+
);

packages/vertexai/src/factory.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
FirebaseAppCheckInternal
2323
} from '@firebase/app-check-interop-types';
2424
import { Provider } from '@firebase/component';
25+
import { DEFAULT_REGION } from './constants';
2526

2627
export function factory(
2728
app: FirebaseApp,
@@ -33,6 +34,7 @@ export function factory(
3334

3435
export class VertexService implements Vertex, _FirebaseService {
3536
appCheck: FirebaseAppCheckInternal | null;
37+
region: string;
3638

3739
constructor(
3840
public app: FirebaseApp,
@@ -41,10 +43,7 @@ export class VertexService implements Vertex, _FirebaseService {
4143
) {
4244
const appCheck = appCheckProvider?.getImmediate({ optional: true });
4345
this.appCheck = appCheck || null;
44-
// This needs to go into the url
45-
if (this.options?.region) {
46-
console.log(this.options?.region);
47-
}
46+
this.region = this.options?.region || DEFAULT_REGION;
4847
}
4948

5049
_delete(): Promise<void> {

0 commit comments

Comments
 (0)