Skip to content

Commit 4a331a9

Browse files
authored
Merge pull request #393 from firebase/mc/vertex
add ci build and function calling
2 parents 81bd5ee + 7909a49 commit 4a331a9

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed

.github/workflows/vertexai.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
on:
2+
pull_request:
3+
paths:
4+
- 'VertexAISnippets/**'
5+
- '.github/workflows/vertexai.yml'
6+
name: VertexAI
7+
jobs:
8+
snippets-build:
9+
name: snippets build
10+
runs-on: macOS-latest
11+
strategy:
12+
matrix:
13+
destination: ['platform=iOS Simulator,OS=latest,name=iPhone 15', 'platform=OS X']
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@master
17+
- name: Build Swift snippets
18+
run: |
19+
cd VertexAISnippets
20+
xcodebuild -project VertexAISnippets.xcodeproj -scheme VertexAISnippets clean build -destination "${destination}" CODE_SIGNING_REQUIRED=NO
21+
env:
22+
destination: ${{ matrix.destination }}

VertexAISnippets/VertexAISnippets/VertexAISnippets.swift

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,4 +326,120 @@ class Snippets {
326326
// [END set_safety_settings]
327327
}
328328

329+
// MARK: - Function Calling
330+
331+
func functionCalling() async throws {
332+
// [START create_function]
333+
func makeAPIRequest(currencyFrom: String, currencyTo: String) -> JSONObject {
334+
// This hypothetical API returns a JSON such as:
335+
// {"base":"USD","rates":{"SEK": 10.99}}
336+
return [
337+
"base": .string(currencyFrom),
338+
"rates": .object([currencyTo: .number(10.99)]),
339+
]
340+
}
341+
// [END create_function]
342+
343+
// [START create_function_metadata]
344+
let getExchangeRate = FunctionDeclaration(
345+
name: "getExchangeRate",
346+
description: "Get the exchange rate for currencies between countries",
347+
parameters: [
348+
"currencyFrom": Schema(
349+
type: .string,
350+
description: "The currency to convert from."
351+
),
352+
"currencyTo": Schema(
353+
type: .string,
354+
description: "The currency to convert to."
355+
),
356+
],
357+
requiredParameters: ["currencyFrom", "currencyTo"]
358+
)
359+
// [END create_function_metadata]
360+
361+
// [START initialize_model_function]
362+
// Initialize the Vertex AI service
363+
let vertex = VertexAI.vertexAI()
364+
365+
// Initialize the generative model
366+
// Use a model that supports function calling, like Gemini 1.0 Pro.
367+
let model = vertex.generativeModel(
368+
modelName: "gemini-1.0-pro",
369+
// Specify the function declaration.
370+
tools: [Tool(functionDeclarations: [getExchangeRate])]
371+
)
372+
// [END initialize_model_function]
373+
374+
// [START generate_function_call]
375+
let chat = model.startChat()
376+
377+
let prompt = "How much is 50 US dollars worth in Swedish krona?"
378+
379+
// Send the message to the generative model
380+
let response1 = try await chat.sendMessage(prompt)
381+
382+
// Check if the model responded with a function call
383+
guard let functionCall = response1.functionCalls.first else {
384+
fatalError("Model did not respond with a function call.")
385+
}
386+
// Print an error if the returned function was not declared
387+
guard functionCall.name == "getExchangeRate" else {
388+
fatalError("Unexpected function called: \(functionCall.name)")
389+
}
390+
// Verify that the names and types of the parameters match the declaration
391+
guard case let .string(currencyFrom) = functionCall.args["currencyFrom"] else {
392+
fatalError("Missing argument: currencyFrom")
393+
}
394+
guard case let .string(currencyTo) = functionCall.args["currencyTo"] else {
395+
fatalError("Missing argument: currencyTo")
396+
}
397+
398+
// Call the hypothetical API
399+
let apiResponse = makeAPIRequest(currencyFrom: currencyFrom, currencyTo: currencyTo)
400+
401+
// Send the API response back to the model so it can generate a text response that can be
402+
// displayed to the user.
403+
let response = try await chat.sendMessage([ModelContent(
404+
role: "function",
405+
parts: [.functionResponse(FunctionResponse(
406+
name: functionCall.name,
407+
response: apiResponse
408+
))]
409+
)])
410+
411+
// Log the text response.
412+
guard let modelResponse = response.text else {
413+
fatalError("Model did not respond with text.")
414+
}
415+
print(modelResponse)
416+
// [END generate_function_call]
417+
}
418+
419+
func functionCallingModes() {
420+
let getExchangeRate = FunctionDeclaration(
421+
name: "getExchangeRate",
422+
description: "Get the exchange rate for currencies between countries",
423+
parameters: nil,
424+
requiredParameters: nil
425+
)
426+
427+
// [START function_modes]
428+
let model = VertexAI.vertexAI().generativeModel(
429+
// Setting a function calling mode is only available in Gemini 1.5 Pro
430+
modelName: "gemini-1.5-pro-preview-0409",
431+
// Pass the function declaration
432+
tools: [Tool(functionDeclarations: [getExchangeRate])],
433+
toolConfig: ToolConfig(
434+
functionCallingConfig: FunctionCallingConfig(
435+
// Only call functions (model won't generate text)
436+
mode: FunctionCallingConfig.Mode.any,
437+
// This should only be set when the Mode is .any.
438+
allowedFunctionNames: ["getExchangeRate"]
439+
)
440+
)
441+
)
442+
// [END function_modes]
443+
}
444+
329445
}

0 commit comments

Comments
 (0)