diff --git a/FirebaseAI/Sources/GenerateContentResponse.swift b/FirebaseAI/Sources/GenerateContentResponse.swift index a7d7da85d67..f23def563d5 100644 --- a/FirebaseAI/Sources/GenerateContentResponse.swift +++ b/FirebaseAI/Sources/GenerateContentResponse.swift @@ -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. @@ -390,6 +392,23 @@ 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? + + enum CodingKeys: String, CodingKey { + case uri + case title + case placeID = "placeId" + } + } + /// 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, *) @@ -705,6 +724,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 { diff --git a/FirebaseAI/Sources/Tool.swift b/FirebaseAI/Sources/Tool.swift index e051b3b5ea4..9e402540cf9 100644 --- a/FirebaseAI/Sources/Tool.swift +++ b/FirebaseAI/Sources/Tool.swift @@ -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() {} +} + /// 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 @@ -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 } @@ -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) + } + /// Creates a tool that allows you to provide additional context to the models in the form of /// public web URLs. /// @@ -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 {} diff --git a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift index b302af838c4..c0cb358188d 100644 --- a/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift +++ b/FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift @@ -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 diff --git a/FirebaseAI/Tests/Unit/Resources/unary-success-google-maps-grounding.json b/FirebaseAI/Tests/Unit/Resources/unary-success-google-maps-grounding.json new file mode 100644 index 00000000000..ebd5398205b --- /dev/null +++ b/FirebaseAI/Tests/Unit/Resources/unary-success-google-maps-grounding.json @@ -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 + } +}