Skip to content

Commit 40d4703

Browse files
committed
add ci build and function calling
1 parent 82072ea commit 40d4703

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+
func functionCalling() async throws {
330+
// [START create_function]
331+
func makeAPIRequest(currencyDate: String, currencyFrom: String,
332+
currencyTo: String) -> JSONObject {
333+
// This hypothetical API returns a JSON such as:
334+
// {"base":"USD","date":"2024-04-17","rates":{"SEK": 0.091}}
335+
return [
336+
"date": .string(currencyDate),
337+
"base": .string(currencyFrom),
338+
"rates": .object([currencyTo: .number(0.091)]),
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+
"currencyDate": Schema(
349+
type: .string,
350+
description: "A date that must always be in YYYY-MM-DD format or the value 'latest' if a time period is not specified"
351+
),
352+
"currencyFrom": Schema(
353+
type: .string,
354+
description: "The currency to convert from."
355+
),
356+
"currencyTo": Schema(
357+
type: .string,
358+
description: "The currency to convert to."
359+
),
360+
],
361+
requiredParameters: nil
362+
)
363+
364+
// [END create_function_metadata]
365+
366+
// [START initialize_model_function]
367+
// Specify the function declaration.
368+
let function = Tool(functionDeclarations: [getExchangeRate])
369+
370+
// Use a model that supports function calling, like Gemini 1.0 Pro.
371+
// See "Supported models" in the "Introduction to function calling" page.
372+
let generativeModel = VertexAI.vertexAI().generativeModel(modelName: "gemini-1.0-pro",
373+
tools: [function])
374+
// [END initialize_model_function]
375+
376+
// [START generate_function_call]
377+
let chat = generativeModel.startChat()
378+
379+
let prompt = "How much is 50 US dollars worth in Swedish krona?"
380+
381+
// Send the message to the generative model
382+
let response1 = try await chat.sendMessage(prompt)
383+
384+
// Check if the model responded with a function call
385+
guard let functionCall = response1.functionCalls.first else {
386+
fatalError("Model did not respond with a function call.")
387+
}
388+
// Print an error if the returned function was not declared
389+
guard functionCall.name == "getExchangeRate" else {
390+
fatalError("Unexpected function called: \(functionCall.name)")
391+
}
392+
// Verify that the names and types of the parameters match the declaration
393+
guard case let .string(currencyDate) = functionCall.args["currencyDate"] else {
394+
fatalError("Missing argument: currencyDate")
395+
}
396+
guard case let .string(currencyFrom) = functionCall.args["currencyFrom"] else {
397+
fatalError("Missing argument: currencyFrom")
398+
}
399+
guard case let .string(currencyTo) = functionCall.args["currencyTo"] else {
400+
fatalError("Missing argument: currencyTo")
401+
}
402+
403+
// Call the hypothetical API
404+
let apiResponse = makeAPIRequest(
405+
currencyDate: currencyDate,
406+
currencyFrom: currencyFrom,
407+
currencyTo: currencyTo
408+
)
409+
410+
// Send the API response back to the model so it can generate a text response that can be
411+
// displayed to the user.
412+
let response2 = try await chat.sendMessage([ModelContent(
413+
role: "function",
414+
parts: [.functionResponse(FunctionResponse(
415+
name: functionCall.name,
416+
response: apiResponse
417+
))]
418+
)])
419+
420+
// Log the text response.
421+
guard let modelResponse = response2.text else {
422+
fatalError("Model did not respond with text.")
423+
}
424+
print(modelResponse)
425+
// [END generate_function_call]
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-latest",
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)