Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 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
16 changes: 16 additions & 0 deletions FirebaseAI/Sources/GenerateContentResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ public struct GroundingMetadata: Sendable, Equatable, Hashable {
public struct GroundingChunk: Sendable, Equatable, Hashable {
/// Contains details if the grounding chunk is from a web source.
public let web: WebGroundingChunk?
/// Contains details if the grounding chunk is from Google Maps.
public let maps: MapsGroundingChunk?
}

/// A grounding chunk sourced from the web.
Expand All @@ -390,6 +392,17 @@ public struct GroundingMetadata: Sendable, Equatable, Hashable {
public let domain: String?
}

/// A grounding chunk sourced from Google Maps.
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
public struct MapsGroundingChunk: Sendable, Equatable, Hashable {
/// The URI of the retrieved map data.
public let uri: String?
/// The title of the retrieved map data.
public let title: String?
/// The place ID of the retrieved map data.
public let placeId: String?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/placeId/placeID/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed placeId to placeID and added CodingKeys to handle the JSON mapping.

}

/// Provides information about how a specific segment of the model's response is supported by the
/// retrieved grounding chunks.
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
Expand Down Expand Up @@ -705,6 +718,9 @@ extension GroundingMetadata.GroundingChunk: Decodable {}
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
extension GroundingMetadata.WebGroundingChunk: Decodable {}

@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
extension GroundingMetadata.MapsGroundingChunk: Decodable {}

@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
extension GroundingMetadata.GroundingSupport.Internal: Decodable {
enum CodingKeys: String, CodingKey {
Expand Down
24 changes: 24 additions & 0 deletions FirebaseAI/Sources/Tool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ public struct GoogleSearch: Sendable {
public init() {}
}

/// A tool that allows the generative model to use Google Maps data.
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
public struct GoogleMaps: Sendable {
public init() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a time machine I'd make the GoogleSearch initializer internal and same for this one.

Suggested change
public init() {}
init() {}

Note: This would follow the same approach as URLContext:

/// Creates a tool that allows you to provide additional context to the models in the form of
/// public web URLs.
///
/// By including URLs in your request, the Gemini model will access the content from those pages
/// to inform and enhance its response.
///
/// > Warning: URL context is a **Public Preview** feature, which means that it is not subject to
/// > any SLA or deprecation policy and could change in backwards-incompatible ways.
public static func urlContext() -> Tool {
return self.init(urlContext: URLContext())
}

}

/// A helper tool that the model may use when generating responses.
///
/// A `Tool` is a piece of code that enables the system to interact with external systems to perform
Expand All @@ -75,15 +81,20 @@ public struct Tool: Sendable {
/// Specifies the Google Search configuration.
let googleSearch: GoogleSearch?

/// Specifies the Google Maps configuration.
let googleMaps: GoogleMaps?

let codeExecution: CodeExecution?
let urlContext: URLContext?

init(functionDeclarations: [FunctionDeclaration]? = nil,
googleSearch: GoogleSearch? = nil,
googleMaps: GoogleMaps? = nil,
urlContext: URLContext? = nil,
codeExecution: CodeExecution? = nil) {
self.functionDeclarations = functionDeclarations
self.googleSearch = googleSearch
self.googleMaps = googleMaps
self.urlContext = urlContext
self.codeExecution = codeExecution
}
Expand Down Expand Up @@ -131,6 +142,16 @@ public struct Tool: Sendable {
return self.init(googleSearch: googleSearch)
}

/// Creates a tool that allows the model to use Google Maps.
///
/// - Parameters:
/// - googleMaps: An empty ``GoogleMaps`` object.
///
/// - Returns: A `Tool` configured for Google Maps.
public static func googleMaps(_ googleMaps: GoogleMaps = GoogleMaps()) -> Tool {
return self.init(googleMaps: googleMaps)
Comment on lines +146 to +152
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
///
/// - Parameters:
/// - googleMaps: An empty ``GoogleMaps`` object.
///
/// - Returns: A `Tool` configured for Google Maps.
public static func googleMaps(_ googleMaps: GoogleMaps = GoogleMaps()) -> Tool {
return self.init(googleMaps: googleMaps)
///
/// - Returns: A `Tool` configured for Google Maps.
public static func googleMaps() -> Tool {
return self.init(googleMaps: GoogleMaps())

}

/// Creates a tool that allows you to provide additional context to the models in the form of
/// public web URLs.
///
Expand Down Expand Up @@ -237,5 +258,8 @@ extension FunctionCallingConfig.Mode: Encodable {}
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
extension GoogleSearch: Encodable {}

@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
extension GoogleMaps: Encodable {}

@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
extension ToolConfig: Encodable {}
29 changes: 29 additions & 0 deletions FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,35 @@ final class GenerativeModelVertexAITests: XCTestCase {
_ = try await model.generateContent(testPrompt)
}

func testGenerateContent_withGoogleMapsTool_mapsGroundingMetadata() async throws {
let model = GenerativeModel(
modelName: testModelName,
modelResourceName: testModelResourceName,
firebaseInfo: GenerativeModelTestUtil.testFirebaseInfo(),
apiConfig: apiConfig,
tools: [.googleMaps()],
requestOptions: RequestOptions(),
urlSession: urlSession
)
MockURLProtocol.requestHandler = try GenerativeModelTestUtil.httpRequestHandler(
forResource: "unary-success-google-maps-grounding",
withExtension: "json",
subdirectory: ""
)

let response = try await model.generateContent(testPrompt)

XCTAssertEqual(response.candidates.count, 1)
let candidate = try XCTUnwrap(response.candidates.first)
let groundingMetadata = try XCTUnwrap(candidate.groundingMetadata)

XCTAssertEqual(groundingMetadata.groundingChunks.count, 1)
let firstChunk = try XCTUnwrap(groundingMetadata.groundingChunks.first?.maps)
XCTAssertEqual(firstChunk.title, "Mountain View")
XCTAssertEqual(firstChunk.uri, "https://maps.google.com/?cid=123")
XCTAssertEqual(firstChunk.placeId, "places/123456789")
}

func testGenerateContent_failure_invalidAPIKey() async throws {
let expectedStatusCode = 400
MockURLProtocol
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"text": "Mountain View is about 40 miles south of San Francisco."
}
]
},
"finishReason": "STOP",
"index": 0,
"groundingMetadata": {
"groundingChunks": [
{
"maps": {
"uri": "https://maps.google.com/?cid=123",
"title": "Mountain View",
"placeId": "places/123456789"
}
}
]
}
}
],
"usageMetadata": {
"promptTokenCount": 10,
"candidatesTokenCount": 15,
"totalTokenCount": 25
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restore this file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You didn't though. Put it back. Now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies. I have explicitly recreated the file to ensure it is restored.

This file was deleted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restore this file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You didn't though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies. I have explicitly recreated the file to ensure it is restored.

This file was deleted.

Loading