-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Vertex AI] Add code snippets for use in docs (#13653)
- Loading branch information
1 parent
78a181d
commit 1f1f308
Showing
3 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
FirebaseVertexAI/Tests/Unit/Snippets/FirebaseAppSnippetsUtil.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import FirebaseCore | ||
import Foundation | ||
import XCTest | ||
|
||
extension FirebaseApp { | ||
static let projectIDEnvVar = "PROJECT_ID" | ||
static let appIDEnvVar = "APP_ID" | ||
static let apiKeyEnvVar = "API_KEY" | ||
|
||
static func configureForSnippets() throws { | ||
let environment = ProcessInfo.processInfo.environment | ||
guard let projectID = environment[projectIDEnvVar] else { | ||
throw XCTSkip("No Firebase Project ID specified in environment variable \(projectIDEnvVar).") | ||
} | ||
guard let appID = environment[appIDEnvVar] else { | ||
throw XCTSkip("No Google App ID specified in environment variable \(appIDEnvVar).") | ||
} | ||
guard let apiKey = environment[apiKeyEnvVar] else { | ||
throw XCTSkip("No API key specified in environment variable \(apiKeyEnvVar).") | ||
} | ||
|
||
let options = FirebaseOptions(googleAppID: appID, gcmSenderID: "") | ||
options.projectID = projectID | ||
options.apiKey = apiKey | ||
|
||
FirebaseApp.configure(options: options) | ||
guard FirebaseApp.isDefaultAppConfigured() else { | ||
XCTFail("Default Firebase app not configured.") | ||
return | ||
} | ||
} | ||
} |
109 changes: 109 additions & 0 deletions
109
FirebaseVertexAI/Tests/Unit/Snippets/FunctionCallingSnippets.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import FirebaseCore | ||
import FirebaseVertexAI | ||
import XCTest | ||
|
||
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) | ||
final class FunctionCallingSnippets: XCTestCase { | ||
override func setUpWithError() throws { | ||
try FirebaseApp.configureForSnippets() | ||
} | ||
|
||
override func tearDown() async throws { | ||
if let app = FirebaseApp.app() { | ||
await app.delete() | ||
} | ||
} | ||
|
||
func testFunctionCalling() async throws { | ||
// This function calls a hypothetical external API that returns | ||
// a collection of weather information for a given location on a given date. | ||
func fetchWeather(city: String, state: String, date: String) -> JSONObject { | ||
// TODO(developer): Write a standard function that would call an external weather API. | ||
|
||
// For demo purposes, this hypothetical response is hardcoded here in the expected format. | ||
return [ | ||
"temperature": .number(38), | ||
"chancePrecipitation": .string("56%"), | ||
"cloudConditions": .string("partlyCloudy"), | ||
] | ||
} | ||
|
||
let fetchWeatherTool = FunctionDeclaration( | ||
name: "fetchWeather", | ||
description: "Get the weather conditions for a specific city on a specific date.", | ||
parameters: [ | ||
"location": .object( | ||
properties: [ | ||
"city": .string(description: "The city of the location."), | ||
"state": .string(description: "The US state of the location."), | ||
], | ||
description: """ | ||
The name of the city and its state for which to get the weather. Only cities in the | ||
USA are supported. | ||
""" | ||
), | ||
"date": .string( | ||
description: """ | ||
The date for which to get the weather. Date must be in the format: YYYY-MM-DD. | ||
""" | ||
), | ||
] | ||
) | ||
|
||
// Initialize the Vertex AI service and the generative model. | ||
// Use a model that supports function calling, like a Gemini 1.5 model. | ||
let model = VertexAI.vertexAI().generativeModel( | ||
modelName: "gemini-1.5-flash", | ||
// Provide the function declaration to the model. | ||
tools: [.functionDeclarations([fetchWeatherTool])] | ||
) | ||
|
||
let chat = model.startChat() | ||
let prompt = "What was the weather in Boston on October 17, 2024?" | ||
|
||
// Send the user's question (the prompt) to the model using multi-turn chat. | ||
let response = try await chat.sendMessage(prompt) | ||
|
||
var functionResponses = [FunctionResponsePart]() | ||
|
||
// When the model responds with one or more function calls, invoke the function(s). | ||
for functionCall in response.functionCalls { | ||
if functionCall.name == "fetchWeather" { | ||
// TODO(developer): Handle invalid arguments. | ||
guard case let .object(location) = functionCall.args["location"] else { fatalError() } | ||
guard case let .string(city) = location["city"] else { fatalError() } | ||
guard case let .string(state) = location["state"] else { fatalError() } | ||
guard case let .string(date) = functionCall.args["date"] else { fatalError() } | ||
|
||
functionResponses.append(FunctionResponsePart( | ||
name: functionCall.name, | ||
response: fetchWeather(city: city, state: state, date: date) | ||
)) | ||
} | ||
// TODO(developer): Handle other potential function calls, if any. | ||
} | ||
|
||
// Send the response(s) from the function back to the model so that the model can use it | ||
// to generate its final response. | ||
let finalResponse = try await chat.sendMessage( | ||
[ModelContent(role: "function", parts: functionResponses)] | ||
) | ||
|
||
// Log the text response. | ||
print(finalResponse.text ?? "No text in response.") | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
FirebaseVertexAI/Tests/Unit/Snippets/StructuredOutputSnippets.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright 2024 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import FirebaseCore | ||
import FirebaseVertexAI | ||
import XCTest | ||
|
||
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) | ||
final class StructuredOutputSnippets: XCTestCase { | ||
override func setUpWithError() throws { | ||
try FirebaseApp.configureForSnippets() | ||
} | ||
|
||
override func tearDown() async throws { | ||
if let app = FirebaseApp.app() { | ||
await app.delete() | ||
} | ||
} | ||
|
||
func testStructuredOutputJSONBasic() async throws { | ||
// Provide a JSON schema object using a standard format. | ||
// Later, pass this schema object into `responseSchema` in the generation config. | ||
let jsonSchema = Schema.object( | ||
properties: [ | ||
"characters": Schema.array( | ||
items: .object( | ||
properties: [ | ||
"name": .string(), | ||
"age": .integer(), | ||
"species": .string(), | ||
"accessory": .enumeration(values: ["hat", "belt", "shoes"]), | ||
], | ||
optionalProperties: ["accessory"] | ||
) | ||
), | ||
] | ||
) | ||
|
||
// Initialize the Vertex AI service and the generative model. | ||
// Use a model that supports `responseSchema`, like one of the Gemini 1.5 models. | ||
let model = VertexAI.vertexAI().generativeModel( | ||
modelName: "gemini-1.5-flash", | ||
// In the generation config, set the `responseMimeType` to `application/json` | ||
// and pass the JSON schema object into `responseSchema`. | ||
generationConfig: GenerationConfig( | ||
responseMIMEType: "application/json", | ||
responseSchema: jsonSchema | ||
) | ||
) | ||
|
||
let prompt = "For use in a children's card game, generate 10 animal-based characters." | ||
|
||
let response = try await model.generateContent(prompt) | ||
print(response.text ?? "No text in response.") | ||
} | ||
|
||
func testStructuredOutputEnumBasic() async throws { | ||
// Provide an enum schema object using a standard format. | ||
// Later, pass this schema object into `responseSchema` in the generation config. | ||
let enumSchema = Schema.enumeration(values: ["drama", "comedy", "documentary"]) | ||
|
||
// Initialize the Vertex AI service and the generative model. | ||
// Use a model that supports `responseSchema`, like one of the Gemini 1.5 models. | ||
let model = VertexAI.vertexAI().generativeModel( | ||
modelName: "gemini-1.5-flash", | ||
// In the generation config, set the `responseMimeType` to `text/x.enum` | ||
// and pass the enum schema object into `responseSchema`. | ||
generationConfig: GenerationConfig( | ||
responseMIMEType: "text/x.enum", | ||
responseSchema: enumSchema | ||
) | ||
) | ||
|
||
let prompt = """ | ||
The film aims to educate and inform viewers about real-life subjects, events, or people. | ||
It offers a factual record of a particular topic by combining interviews, historical footage, | ||
and narration. The primary purpose of a film is to present information and provide insights | ||
into various aspects of reality. | ||
""" | ||
|
||
let response = try await model.generateContent(prompt) | ||
print(response.text ?? "No text in response.") | ||
} | ||
} |