diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml index 0135c09e..2a0b49ca 100644 --- a/.github/workflows/samples.yml +++ b/.github/workflows/samples.yml @@ -16,10 +16,10 @@ jobs: matrix: # Test build with debug and release configs (whether or not DEBUG is set and optimization level) build: [build, archive] - os: [macos-13] + os: [macos-14] include: - - os: macos-13 - xcode: Xcode_15.0.1 + - os: macos-14 + xcode: Xcode_16.2 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 diff --git a/Examples/GenerativeAISample/APIKey/APIKey.swift b/Examples/GenerativeAISample/APIKey/APIKey.swift deleted file mode 100644 index 3f458ca6..00000000 --- a/Examples/GenerativeAISample/APIKey/APIKey.swift +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2023 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 Foundation - -enum APIKey { - /// Fetch the API key from `GenerativeAI-Info.plist` - /// This is just *one* way how you can retrieve the API key for your app. - static var `default`: String { - guard let filePath = Bundle.main.path(forResource: "GenerativeAI-Info", ofType: "plist") - else { - fatalError("Couldn't find file 'GenerativeAI-Info.plist'.") - } - let plist = NSDictionary(contentsOfFile: filePath) - guard let value = plist?.object(forKey: "API_KEY") as? String else { - fatalError("Couldn't find key 'API_KEY' in 'GenerativeAI-Info.plist'.") - } - if value.starts(with: "_") || value.isEmpty { - fatalError( - "Follow the instructions at https://ai.google.dev/tutorials/setup to get an API key." - ) - } - return value - } -} diff --git a/Examples/GenerativeAISample/ChatSample/Screens/ConversationScreen.swift b/Examples/GenerativeAISample/ChatSample/Screens/ConversationScreen.swift index d0bcde3f..5ddc2b84 100644 --- a/Examples/GenerativeAISample/ChatSample/Screens/ConversationScreen.swift +++ b/Examples/GenerativeAISample/ChatSample/Screens/ConversationScreen.swift @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// REMOVED: `import GoogleGenerativeAI` -- was not used in this file import GenerativeAIUIComponents -import GoogleGenerativeAI import SwiftUI struct ConversationScreen: View { diff --git a/Examples/GenerativeAISample/ChatSample/ViewModels/ConversationViewModel.swift b/Examples/GenerativeAISample/ChatSample/ViewModels/ConversationViewModel.swift index 9508c3f6..96d072f0 100644 --- a/Examples/GenerativeAISample/ChatSample/ViewModels/ConversationViewModel.swift +++ b/Examples/GenerativeAISample/ChatSample/ViewModels/ConversationViewModel.swift @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import FirebaseAI // REPLACED: `GoogleGenerativeAI` with `FirebaseAI` import Foundation -import GoogleGenerativeAI import UIKit @MainActor @@ -36,7 +36,12 @@ class ConversationViewModel: ObservableObject { private var chatTask: Task? init() { - model = GenerativeModel(name: "gemini-1.5-flash-latest", apiKey: APIKey.default) + // BEFORE + // model = GenerativeModel(name: "gemini-1.5-flash-latest", apiKey: APIKey.default) + + // AFTER + model = FirebaseAI.firebaseAI().generativeModel(modelName: "gemini-2.0-flash") + chat = model.startChat() } @@ -79,7 +84,7 @@ class ConversationViewModel: ObservableObject { messages.append(systemMessage) do { - let responseStream = chat.sendMessageStream(text) + let responseStream = try chat.sendMessageStream(text) // ADDED: `try` for try await chunk in responseStream { messages[messages.count - 1].pending = false if let text = chunk.text { diff --git a/Examples/GenerativeAISample/ChatSample/Views/ErrorDetailsView.swift b/Examples/GenerativeAISample/ChatSample/Views/ErrorDetailsView.swift index 5ec5ddc8..0e612edd 100644 --- a/Examples/GenerativeAISample/ChatSample/Views/ErrorDetailsView.swift +++ b/Examples/GenerativeAISample/ChatSample/Views/ErrorDetailsView.swift @@ -12,19 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -import GoogleGenerativeAI +import FirebaseAI // REPLACED: `GoogleGenerativeAI` with `FirebaseAI` import MarkdownUI import SwiftUI -extension SafetySetting.HarmCategory: CustomStringConvertible { +extension HarmCategory: CustomStringConvertible { // REMOVED: `SafetySetting.` public var description: String { switch self { case .dangerousContent: "Dangerous content" case .harassment: "Harassment" case .hateSpeech: "Hate speech" case .sexuallyExplicit: "Sexually explicit" - case .unknown: "Unknown" - case .unspecified: "Unspecified" + case .civicIntegrity: "Civic integrity" // ADDED + // REMOVED: case .unspecified: "Unspecified" + default: "Unknown" // REPLACED `case .unknown` } } } @@ -36,8 +37,7 @@ extension SafetyRating.HarmProbability: CustomStringConvertible { case .low: "Low" case .medium: "Medium" case .negligible: "Negligible" - case .unknown: "Unknown" - case .unspecified: "Unspecified" + default: "Unknown" // REPLACED: `case .unknown` } } } @@ -102,6 +102,17 @@ struct ErrorDetailsView: View { value: underlyingError.localizedDescription) } + // ADDED + case let GenerateContentError.promptImageContentError(underlying: underlyingError): + Section("Error Type") { + Text("Creating prompt image content failed") + } + + Section("Details") { + SubtitleFormRow(title: "Error description", + value: underlyingError.localizedDescription) + } + case let GenerateContentError.promptBlocked(response: generateContentResponse): Section("Error Type") { Text("Your prompt was blocked") @@ -142,36 +153,9 @@ struct ErrorDetailsView: View { SafetyRatingsSection(ratings: ratings) } - case GenerateContentError.invalidAPIKey: - Section("Error Type") { - Text("Invalid API Key") - } - - Section("Details") { - SubtitleFormRow(title: "Error description", value: error.localizedDescription) - SubtitleMarkdownFormRow( - title: "Help", - value: """ - Please provide a valid value for `API_KEY` in the `GenerativeAI-Info.plist` file. - """ - ) - } - - case GenerateContentError.unsupportedUserLocation: - Section("Error Type") { - Text("Unsupported User Location") - } + // REMOVED: `GenerateContentError.invalidAPIKey` - Section("Details") { - SubtitleFormRow(title: "Error description", value: error.localizedDescription) - SubtitleMarkdownFormRow( - title: "Help", - value: """ - The API is unsupported in your location (country / territory); please see the list of - [available regions](https://ai.google.dev/available_regions#available_regions). - """ - ) - } + // REMOVED: `GenerateContentError.unsupportedUserLocation` default: Section("Error Type") { @@ -192,23 +176,32 @@ struct ErrorDetailsView: View { #Preview("Response Stopped Early") { let error = GenerateContentError.responseStoppedEarly( reason: .maxTokens, - response: GenerateContentResponse(candidates: [ - CandidateResponse(content: ModelContent(role: "model", [ - """ - A _hypothetical_ model response. - Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo. - """, - ]), - safetyRatings: [ - SafetyRating(category: .dangerousContent, probability: .high), - SafetyRating(category: .harassment, probability: .low), - SafetyRating(category: .hateSpeech, probability: .low), - SafetyRating(category: .sexuallyExplicit, probability: .low), + response: GenerateContentResponse( + candidates: [ + Candidate( // REPLACED: `CandidateResponse` with `Candidate` + content: ModelContent(role: "model", parts: [ // ADDED: `parts: ` + """ + A _hypothetical_ model response. + Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo. + """, + ]), + safetyRatings: [ + // ADDED: `probabilityScore`, `severity`, `severityScore`, and `blocked` + SafetyRating(category: .dangerousContent, probability: .high, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + SafetyRating(category: .harassment, probability: .low, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + SafetyRating(category: .hateSpeech, probability: .low, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + SafetyRating(category: .sexuallyExplicit, probability: .low, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + ], + finishReason: FinishReason.maxTokens, + citationMetadata: nil + ), ], - finishReason: FinishReason.maxTokens, - citationMetadata: nil), - ], - promptFeedback: nil) + promptFeedback: nil + ) ) return ErrorDetailsView(error: error) @@ -217,17 +210,24 @@ struct ErrorDetailsView: View { #Preview("Prompt Blocked") { let error = GenerateContentError.promptBlocked( response: GenerateContentResponse(candidates: [ - CandidateResponse(content: ModelContent(role: "model", [ + // REPLACED: `CandidateResponse` with `Candidate` + Candidate(content: ModelContent(role: "model", parts: [ // ADDED: `parts: ` """ A _hypothetical_ model response. Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo. """, ]), safetyRatings: [ - SafetyRating(category: .dangerousContent, probability: .high), - SafetyRating(category: .harassment, probability: .low), - SafetyRating(category: .hateSpeech, probability: .low), - SafetyRating(category: .sexuallyExplicit, probability: .low), + // ADDED: `probabilityScore`, `severity`, `severityScore`, and `blocked` + SafetyRating(category: .dangerousContent, probability: .high, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + SafetyRating(category: .harassment, probability: .low, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + SafetyRating(category: .hateSpeech, probability: .low, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + SafetyRating(category: .sexuallyExplicit, probability: .low, + probabilityScore: 0.0, severity: .negligible, severityScore: 0.0, + blocked: false), ], finishReason: FinishReason.other, citationMetadata: nil), @@ -238,10 +238,6 @@ struct ErrorDetailsView: View { return ErrorDetailsView(error: error) } -#Preview("Invalid API Key") { - ErrorDetailsView(error: GenerateContentError.invalidAPIKey(message: "Fix API key placeholder")) -} +// REMOVED: Preview for `GenerateContentError.invalidAPIKey` -#Preview("Unsupported User Location") { - ErrorDetailsView(error: GenerateContentError.unsupportedUserLocation) -} +// REMOVED: Preview for `GenerateContentError.unsupportedUserLocation` diff --git a/Examples/GenerativeAISample/ChatSample/Views/ErrorView.swift b/Examples/GenerativeAISample/ChatSample/Views/ErrorView.swift index aafdcd26..d89415cd 100644 --- a/Examples/GenerativeAISample/ChatSample/Views/ErrorView.swift +++ b/Examples/GenerativeAISample/ChatSample/Views/ErrorView.swift @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import GoogleGenerativeAI +import FirebaseAI // REPLACED: `GoogleGenerativeAI` with `FirebaseAI` import SwiftUI struct ErrorView: View { @@ -36,23 +36,32 @@ struct ErrorView: View { #Preview { NavigationView { let errorPromptBlocked = GenerateContentError.promptBlocked( - response: GenerateContentResponse(candidates: [ - CandidateResponse(content: ModelContent(role: "model", [ - """ - A _hypothetical_ model response. - Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo. - """, - ]), - safetyRatings: [ - SafetyRating(category: .dangerousContent, probability: .high), - SafetyRating(category: .harassment, probability: .low), - SafetyRating(category: .hateSpeech, probability: .low), - SafetyRating(category: .sexuallyExplicit, probability: .low), + response: GenerateContentResponse( + candidates: [ + Candidate( // REPLACED: `CandidateResponse` with `Candidate` + content: ModelContent(role: "model", parts: [ // ADDED: `parts: ` + """ + A _hypothetical_ model response. + Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo. + """, + ]), + safetyRatings: [ + // ADDED: `probabilityScore`, `severity`, `severityScore`, `blocked` + SafetyRating(category: .dangerousContent, probability: .high, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + SafetyRating(category: .harassment, probability: .low, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + SafetyRating(category: .hateSpeech, probability: .low, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + SafetyRating(category: .sexuallyExplicit, probability: .low, probabilityScore: 0.0, + severity: .negligible, severityScore: 0.0, blocked: false), + ], + finishReason: FinishReason.other, + citationMetadata: nil + ), ], - finishReason: FinishReason.other, - citationMetadata: nil), - ], - promptFeedback: nil) + promptFeedback: nil + ) ) List { MessageView(message: ChatMessage.samples[0]) diff --git a/Examples/GenerativeAISample/FunctionCallingSample/Screens/FunctionCallingScreen.swift b/Examples/GenerativeAISample/FunctionCallingSample/Screens/FunctionCallingScreen.swift index c7f4dd5a..d0508639 100644 --- a/Examples/GenerativeAISample/FunctionCallingSample/Screens/FunctionCallingScreen.swift +++ b/Examples/GenerativeAISample/FunctionCallingSample/Screens/FunctionCallingScreen.swift @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +// REMOVED: `import GoogleGenerativeAI` -- was not used in this file + import GenerativeAIUIComponents -import GoogleGenerativeAI import SwiftUI struct FunctionCallingScreen: View { diff --git a/Examples/GenerativeAISample/FunctionCallingSample/ViewModels/FunctionCallingViewModel.swift b/Examples/GenerativeAISample/FunctionCallingSample/ViewModels/FunctionCallingViewModel.swift index 8d65c5fd..7ed1e699 100644 --- a/Examples/GenerativeAISample/FunctionCallingSample/ViewModels/FunctionCallingViewModel.swift +++ b/Examples/GenerativeAISample/FunctionCallingSample/ViewModels/FunctionCallingViewModel.swift @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import FirebaseAI // REPLACED: `import GoogleGenerativeAI` import Foundation -import GoogleGenerativeAI import UIKit @MainActor @@ -30,7 +30,7 @@ class FunctionCallingViewModel: ObservableObject { } /// Function calls pending processing - private var functionCalls = [FunctionCall]() + private var functionCalls = [FunctionCallPart]() // RENAMED: `FunctionCall` to `FunctionCallPart` private var model: GenerativeModel private var chat: Chat @@ -38,28 +38,24 @@ class FunctionCallingViewModel: ObservableObject { private var chatTask: Task? init() { - model = GenerativeModel( - name: "gemini-1.5-flash-latest", - apiKey: APIKey.default, - tools: [Tool(functionDeclarations: [ + model = FirebaseAI.firebaseAI().generativeModel( // REPLACED: `model = GenerativeModel(` + modelName: "gemini-2.0-flash", // REPLACED: `model:` with `modelName:` + // REMOVED: `apiKey: APIKey.default,` + tools: [.functionDeclarations([ // REPLACED: `Tool(functionDeclarations:` FunctionDeclaration( name: "get_exchange_rate", description: "Get the exchange rate for currencies between countries", parameters: [ - "currency_from": Schema( - type: .string, - format: "enum", - description: "The currency to convert from in ISO 4217 format", - enumValues: ["USD", "EUR", "JPY", "GBP", "AUD", "CAD"] + "currency_from": .enumeration( // REPLACED: `Schema(type: .string, format: "enum", ...` + values: ["USD", "EUR", "JPY", "GBP", "AUD", "CAD"], // REPLACED: `enumValues` + description: "The currency to convert from in ISO 4217 format" ), - "currency_to": Schema( - type: .string, - format: "enum", - description: "The currency to convert to in ISO 4217 format", - enumValues: ["USD", "EUR", "JPY", "GBP", "AUD", "CAD"] + "currency_to": .enumeration( // REPLACED: `Schema(type: .string, format: "enum", ...` + values: ["USD", "EUR", "JPY", "GBP", "AUD", "CAD"], // REPLACED: `enumValues` + description: "The currency to convert to in ISO 4217 format" ), - ], - requiredParameters: ["currency_from", "currency_to"] + ] + // REMOVED: `requiredParameters: ["currency_from", "currency_to"]` ), ])] ) @@ -117,12 +113,12 @@ class FunctionCallingViewModel: ObservableObject { let functionResponses = try await processFunctionCalls() let responseStream: AsyncThrowingStream if functionResponses.isEmpty { - responseStream = chat.sendMessageStream(text) + responseStream = try chat.sendMessageStream(text) // ADDED: `try` } else { for functionResponse in functionResponses { messages.insert(functionResponse.chatMessage(), at: messages.count - 1) } - responseStream = chat.sendMessageStream(functionResponses.modelContent()) + responseStream = try chat.sendMessageStream(functionResponses.modelContent()) // ADDED: `try` } for try await chunk in responseStream { processResponseContent(content: chunk) @@ -150,26 +146,29 @@ class FunctionCallingViewModel: ObservableObject { for part in candidate.content.parts { switch part { - case let .text(text): + case let textPart as TextPart: // REPLACED: `case let .text(text)` // replace pending message with backend response - messages[messages.count - 1].message += text + messages[messages.count - 1].message += textPart.text messages[messages.count - 1].pending = false - case let .functionCall(functionCall): + case let functionCall as FunctionCallPart: // REPLACED: `.functionCall(functionCall)` messages.insert(functionCall.chatMessage(), at: messages.count - 1) functionCalls.append(functionCall) - case .data, .fileData, .functionResponse, .executableCode, .codeExecutionResult: - fatalError("Unsupported response content.") + case is InlineDataPart, is FileDataPart: + fatalError("Unsupported response content: \(part)") + // REMOVED: `.executableCode, .codeExecutionResult` + default: + fatalError("Unknown response content: \(part)") } } } - func processFunctionCalls() async throws -> [FunctionResponse] { - var functionResponses = [FunctionResponse]() + func processFunctionCalls() async throws -> [FunctionResponsePart] { + var functionResponses = [FunctionResponsePart]() for functionCall in functionCalls { switch functionCall.name { case "get_exchange_rate": let exchangeRates = getExchangeRate(args: functionCall.args) - functionResponses.append(FunctionResponse( + functionResponses.append(FunctionResponsePart( name: "get_exchange_rate", response: exchangeRates )) @@ -214,7 +213,7 @@ class FunctionCallingViewModel: ObservableObject { } } -private extension FunctionCall { +private extension FunctionCallPart { // RENAMED: `FunctionCall` to `FunctionCallPart` func chatMessage() -> ChatMessage { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted @@ -234,7 +233,7 @@ private extension FunctionCall { } } -private extension FunctionResponse { +private extension FunctionResponsePart { // RENAMED: `FunctionResponse` to `FunctionResponsePart` func chatMessage() -> ChatMessage { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted @@ -254,11 +253,11 @@ private extension FunctionResponse { } } -private extension [FunctionResponse] { +private extension [FunctionResponsePart] { // RENAMED: `FunctionResponse` to `FunctionResponsePart` func modelContent() -> [ModelContent] { return self.map { ModelContent( role: "function", - parts: [ModelContent.Part.functionResponse($0)] + parts: [$0] // REPLACED: `[ModelContent.Part.functionResponse($0)]` ) } } diff --git a/Examples/GenerativeAISample/GenerativeAIMultimodalSample/ViewModels/PhotoReasoningViewModel.swift b/Examples/GenerativeAISample/GenerativeAIMultimodalSample/ViewModels/PhotoReasoningViewModel.swift index 3e3fd19d..a66776e3 100644 --- a/Examples/GenerativeAISample/GenerativeAIMultimodalSample/ViewModels/PhotoReasoningViewModel.swift +++ b/Examples/GenerativeAISample/GenerativeAIMultimodalSample/ViewModels/PhotoReasoningViewModel.swift @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import FirebaseAI // REPLACED: `GoogleGenerativeAI` with `FirebaseAI` import Foundation -import GoogleGenerativeAI import OSLog import PhotosUI import SwiftUI @@ -44,7 +44,11 @@ class PhotoReasoningViewModel: ObservableObject { private var model: GenerativeModel? init() { - model = GenerativeModel(name: "gemini-1.5-flash-latest", apiKey: APIKey.default) + // BEFORE + // model = GenerativeModel(name: "gemini-1.5-flash-latest", apiKey: APIKey.default) + + // AFTER + model = FirebaseAI.firebaseAI().generativeModel(modelName: "gemini-2.0-flash") } func reason() async { @@ -62,7 +66,7 @@ class PhotoReasoningViewModel: ObservableObject { let prompt = "Look at the image(s), and then answer the following question: \(userInput)" - var images = [any ThrowingPartsRepresentable]() + var images = [any PartsRepresentable]() // REPLACED: `ThrowingPartsRepresentable` for item in selectedItems { if let data = try? await item.loadTransferable(type: Data.self) { guard let image = UIImage(data: data) else { @@ -84,7 +88,7 @@ class PhotoReasoningViewModel: ObservableObject { } } - let outputContentStream = model.generateContentStream(prompt, images) + let outputContentStream = try model.generateContentStream(prompt, images) // ADDED: `try` // stream response for try await outputContent in outputContentStream { diff --git a/Examples/GenerativeAISample/GenerativeAISample.xcodeproj/project.pbxproj b/Examples/GenerativeAISample/GenerativeAISample.xcodeproj/project.pbxproj index 4c4f872e..eabe9a7f 100644 --- a/Examples/GenerativeAISample/GenerativeAISample.xcodeproj/project.pbxproj +++ b/Examples/GenerativeAISample/GenerativeAISample.xcodeproj/project.pbxproj @@ -3,25 +3,25 @@ archiveVersion = 1; classes = { }; - objectVersion = 60; + objectVersion = 56; objects = { /* Begin PBXBuildFile section */ + 86E8E2002DD24637003DBFE4 /* FirebaseAI in Frameworks */ = {isa = PBXBuildFile; productRef = 86E8E1FF2DD24637003DBFE4 /* FirebaseAI */; }; + 86E8E2022DD25F5A003DBFE4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 86E8E2012DD25F5A003DBFE4 /* GoogleService-Info.plist */; }; + 86E8E2032DD25F5A003DBFE4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 86E8E2012DD25F5A003DBFE4 /* GoogleService-Info.plist */; }; + 86E8E2042DD25F5A003DBFE4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 86E8E2012DD25F5A003DBFE4 /* GoogleService-Info.plist */; }; + 86E8E2052DD25F5A003DBFE4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 86E8E2012DD25F5A003DBFE4 /* GoogleService-Info.plist */; }; + 86E8E2072DD26065003DBFE4 /* FirebaseAI in Frameworks */ = {isa = PBXBuildFile; productRef = 86E8E2062DD26065003DBFE4 /* FirebaseAI */; }; + 86E8E2092DD2608E003DBFE4 /* FirebaseAI in Frameworks */ = {isa = PBXBuildFile; productRef = 86E8E2082DD2608E003DBFE4 /* FirebaseAI */; }; + 86E8E20B2DD260BE003DBFE4 /* FirebaseAI in Frameworks */ = {isa = PBXBuildFile; productRef = 86E8E20A2DD260BE003DBFE4 /* FirebaseAI */; }; 86FBBA072BBE0D49006031A1 /* FunctionCallingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86FBBA052BBE0D49006031A1 /* FunctionCallingScreen.swift */; }; 86FBBA272BBF0594006031A1 /* FunctionCallingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86FBBA252BBF0594006031A1 /* FunctionCallingViewModel.swift */; }; 880266762B0FC39000CF7CB6 /* PhotoReasoningViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8802666F2B0FC39000CF7CB6 /* PhotoReasoningViewModel.swift */; }; 880266792B0FC39000CF7CB6 /* PhotoReasoningScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880266752B0FC39000CF7CB6 /* PhotoReasoningScreen.swift */; }; - 881B753A2B0FDCE600528058 /* APIKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88209C192B0FBDC300F64795 /* APIKey.swift */; }; - 881B753B2B0FDCE600528058 /* APIKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88209C192B0FBDC300F64795 /* APIKey.swift */; }; - 88209C152B0F928F00F64795 /* GenerativeAI-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 88209C142B0F928F00F64795 /* GenerativeAI-Info.plist */; }; - 88209C162B0F92AF00F64795 /* GenerativeAI-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 88209C142B0F928F00F64795 /* GenerativeAI-Info.plist */; }; - 88209C172B0F92AF00F64795 /* GenerativeAI-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 88209C142B0F928F00F64795 /* GenerativeAI-Info.plist */; }; - 88209C1E2B0FBDC300F64795 /* APIKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88209C192B0FBDC300F64795 /* APIKey.swift */; }; 88209C1F2B0FBDC300F64795 /* SummarizeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88209C1B2B0FBDC300F64795 /* SummarizeScreen.swift */; }; 88209C202B0FBDC300F64795 /* SummarizeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88209C1D2B0FBDC300F64795 /* SummarizeViewModel.swift */; }; 88209C242B0FBE1700F64795 /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 88209C232B0FBE1700F64795 /* MarkdownUI */; }; - 88209C262B0FBF7100F64795 /* GoogleGenerativeAI in Frameworks */ = {isa = PBXBuildFile; productRef = 88209C252B0FBF7100F64795 /* GoogleGenerativeAI */; }; - 88209C292B0FBFA200F64795 /* GoogleGenerativeAI in Frameworks */ = {isa = PBXBuildFile; productRef = 88209C282B0FBFA200F64795 /* GoogleGenerativeAI */; }; 88263BEF2B239BFE008AB09B /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88263BEE2B239BFE008AB09B /* ErrorView.swift */; }; 88263BF02B239C09008AB09B /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88263BEE2B239BFE008AB09B /* ErrorView.swift */; }; 88263BF12B239C11008AB09B /* ErrorDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 889873842B208563005B4896 /* ErrorDetailsView.swift */; }; @@ -38,7 +38,6 @@ 886F95D52B17BA010036F07A /* SummarizeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88209C1B2B0FBDC300F64795 /* SummarizeScreen.swift */; }; 886F95D62B17BA010036F07A /* SummarizeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88209C1D2B0FBDC300F64795 /* SummarizeViewModel.swift */; }; 886F95D82B17BA420036F07A /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 886F95D72B17BA420036F07A /* MarkdownUI */; }; - 886F95DA2B17BA8D0036F07A /* GoogleGenerativeAI in Frameworks */ = {isa = PBXBuildFile; productRef = 886F95D92B17BA8D0036F07A /* GoogleGenerativeAI */; }; 886F95DB2B17BAEF0036F07A /* PhotoReasoningViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8802666F2B0FC39000CF7CB6 /* PhotoReasoningViewModel.swift */; }; 886F95DC2B17BAEF0036F07A /* PhotoReasoningScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 880266752B0FC39000CF7CB6 /* PhotoReasoningScreen.swift */; }; 886F95DD2B17D5010036F07A /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E10F5A2B11133E00C08E95 /* MessageView.swift */; }; @@ -59,19 +58,15 @@ 88E10F592B11131900C08E95 /* ChatMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E10F582B11131900C08E95 /* ChatMessage.swift */; }; 88E10F5B2B11133E00C08E95 /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E10F5A2B11133E00C08E95 /* MessageView.swift */; }; 88E10F5D2B11135000C08E95 /* BouncingDots.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88E10F5C2B11135000C08E95 /* BouncingDots.swift */; }; - 88E10F5E2B11140200C08E95 /* GenerativeAI-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 88209C142B0F928F00F64795 /* GenerativeAI-Info.plist */; }; - 88E10F5F2B11140500C08E95 /* APIKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88209C192B0FBDC300F64795 /* APIKey.swift */; }; - 88E10F612B11162B00C08E95 /* GoogleGenerativeAI in Frameworks */ = {isa = PBXBuildFile; productRef = 88E10F602B11162B00C08E95 /* GoogleGenerativeAI */; }; CB0DFFD52B2B4F08006E109D /* GenerativeAIUIComponents in Frameworks */ = {isa = PBXBuildFile; productRef = CB0DFFD42B2B4F08006E109D /* GenerativeAIUIComponents */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 86E8E2012DD25F5A003DBFE4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 86FBBA052BBE0D49006031A1 /* FunctionCallingScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FunctionCallingScreen.swift; sourceTree = ""; }; 86FBBA252BBF0594006031A1 /* FunctionCallingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FunctionCallingViewModel.swift; sourceTree = ""; }; 8802666F2B0FC39000CF7CB6 /* PhotoReasoningViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoReasoningViewModel.swift; sourceTree = ""; }; 880266752B0FC39000CF7CB6 /* PhotoReasoningScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoReasoningScreen.swift; sourceTree = ""; }; - 88209C142B0F928F00F64795 /* GenerativeAI-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GenerativeAI-Info.plist"; sourceTree = ""; }; - 88209C192B0FBDC300F64795 /* APIKey.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIKey.swift; sourceTree = ""; }; 88209C1B2B0FBDC300F64795 /* SummarizeScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SummarizeScreen.swift; sourceTree = ""; }; 88209C1D2B0FBDC300F64795 /* SummarizeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SummarizeViewModel.swift; sourceTree = ""; }; 88263BEE2B239BFE008AB09B /* ErrorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; @@ -107,7 +102,7 @@ buildActionMask = 2147483647; files = ( 886F95D82B17BA420036F07A /* MarkdownUI in Frameworks */, - 886F95DA2B17BA8D0036F07A /* GoogleGenerativeAI in Frameworks */, + 86E8E2002DD24637003DBFE4 /* FirebaseAI in Frameworks */, 886F95E32B17D6630036F07A /* GenerativeAIUIComponents in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -117,7 +112,7 @@ buildActionMask = 2147483647; files = ( 88209C242B0FBE1700F64795 /* MarkdownUI in Frameworks */, - 88209C262B0FBF7100F64795 /* GoogleGenerativeAI in Frameworks */, + 86E8E20B2DD260BE003DBFE4 /* FirebaseAI in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -125,7 +120,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 88209C292B0FBFA200F64795 /* GoogleGenerativeAI in Frameworks */, + 86E8E2092DD2608E003DBFE4 /* FirebaseAI in Frameworks */, 88B8A91E2B0FC55100424728 /* MarkdownUI in Frameworks */, 88B8A9372B0FCBE700424728 /* GenerativeAIUIComponents in Frameworks */, ); @@ -135,7 +130,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 88E10F612B11162B00C08E95 /* GoogleGenerativeAI in Frameworks */, + 86E8E2072DD26065003DBFE4 /* FirebaseAI in Frameworks */, 88D9474D2B14F27E008B5580 /* MarkdownUI in Frameworks */, CB0DFFD52B2B4F08006E109D /* GenerativeAIUIComponents in Frameworks */, ); @@ -212,7 +207,7 @@ isa = PBXGroup; children = ( 88B8A9352B0FCBA700424728 /* GenerativeAIUIComponents */, - 88B8A91F2B0FC73700424728 /* APIKey */, + 86E8E2012DD25F5A003DBFE4 /* GoogleService-Info.plist */, 8848C8312B0D04BC007B434F /* GenerativeAISample */, 8848C8452B0D051E007B434F /* GenerativeAITextSample */, 8848C8572B0D056C007B434F /* GenerativeAIMultimodalSample */, @@ -293,15 +288,6 @@ path = "Preview Content"; sourceTree = ""; }; - 88B8A91F2B0FC73700424728 /* APIKey */ = { - isa = PBXGroup; - children = ( - 88209C192B0FBDC300F64795 /* APIKey.swift */, - 88209C142B0F928F00F64795 /* GenerativeAI-Info.plist */, - ); - path = APIKey; - sourceTree = ""; - }; 88E10F432B110D5300C08E95 /* ChatSample */ = { isa = PBXGroup; children = ( @@ -366,7 +352,6 @@ isa = PBXNativeTarget; buildConfigurationList = 8848C83D2B0D04BD007B434F /* Build configuration list for PBXNativeTarget "GenerativeAISample" */; buildPhases = ( - 880BB1102B16519D0014C3DF /* ShellScript */, 8848C82B2B0D04BC007B434F /* Sources */, 8848C82C2B0D04BC007B434F /* Frameworks */, 8848C82D2B0D04BC007B434F /* Resources */, @@ -378,8 +363,8 @@ name = GenerativeAISample; packageProductDependencies = ( 886F95D72B17BA420036F07A /* MarkdownUI */, - 886F95D92B17BA8D0036F07A /* GoogleGenerativeAI */, 886F95E22B17D6630036F07A /* GenerativeAIUIComponents */, + 86E8E1FF2DD24637003DBFE4 /* FirebaseAI */, ); productName = GenerativeAISample; productReference = 8848C82F2B0D04BC007B434F /* GenerativeAISample.app */; @@ -389,7 +374,6 @@ isa = PBXNativeTarget; buildConfigurationList = 8848C84F2B0D051F007B434F /* Build configuration list for PBXNativeTarget "GenerativeAITextSample" */; buildPhases = ( - 880BB10F2B1651650014C3DF /* ShellScript */, 8848C8402B0D051E007B434F /* Sources */, 8848C8412B0D051E007B434F /* Frameworks */, 8848C8422B0D051E007B434F /* Resources */, @@ -401,7 +385,7 @@ name = GenerativeAITextSample; packageProductDependencies = ( 88209C232B0FBE1700F64795 /* MarkdownUI */, - 88209C252B0FBF7100F64795 /* GoogleGenerativeAI */, + 86E8E20A2DD260BE003DBFE4 /* FirebaseAI */, ); productName = GenerativeAITextSample; productReference = 8848C8442B0D051E007B434F /* GenerativeAITextSample.app */; @@ -411,7 +395,6 @@ isa = PBXNativeTarget; buildConfigurationList = 8848C8612B0D056D007B434F /* Build configuration list for PBXNativeTarget "GenerativeAIMultimodalSample" */; buildPhases = ( - 880BB10E2B1651210014C3DF /* ShellScript */, 8848C8522B0D056C007B434F /* Sources */, 8848C8532B0D056C007B434F /* Frameworks */, 8848C8542B0D056C007B434F /* Resources */, @@ -422,9 +405,9 @@ ); name = GenerativeAIMultimodalSample; packageProductDependencies = ( - 88209C282B0FBFA200F64795 /* GoogleGenerativeAI */, 88B8A91D2B0FC55100424728 /* MarkdownUI */, 88B8A9362B0FCBE700424728 /* GenerativeAIUIComponents */, + 86E8E2082DD2608E003DBFE4 /* FirebaseAI */, ); productName = GenerativeAIMultimodalSample; productReference = 8848C8562B0D056C007B434F /* GenerativeAIMultimodalSample.app */; @@ -434,7 +417,6 @@ isa = PBXNativeTarget; buildConfigurationList = 88E10F4F2B110D5400C08E95 /* Build configuration list for PBXNativeTarget "ChatSample" */; buildPhases = ( - 880BB10C2B164F790014C3DF /* ShellScript */, 88E10F3E2B110D5300C08E95 /* Sources */, 88E10F3F2B110D5300C08E95 /* Frameworks */, 88E10F402B110D5300C08E95 /* Resources */, @@ -445,9 +427,9 @@ ); name = ChatSample; packageProductDependencies = ( - 88E10F602B11162B00C08E95 /* GoogleGenerativeAI */, 88D9474C2B14F27E008B5580 /* MarkdownUI */, CB0DFFD42B2B4F08006E109D /* GenerativeAIUIComponents */, + 86E8E2062DD26065003DBFE4 /* FirebaseAI */, ); productName = ChatSample; productReference = 88E10F422B110D5300C08E95 /* ChatSample.app */; @@ -488,8 +470,8 @@ mainGroup = 8848C8262B0D04BC007B434F; packageReferences = ( 88209C212B0FBDF700F64795 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */, - 88209C272B0FBFA200F64795 /* XCLocalSwiftPackageReference "../.." */, DEA09AC32B1FCE22001962D9 /* XCRemoteSwiftPackageReference "NetworkImage" */, + 86E8E1FE2DD2454A003DBFE4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, ); productRefGroup = 8848C8302B0D04BC007B434F /* Products */; projectDirPath = ""; @@ -509,8 +491,8 @@ buildActionMask = 2147483647; files = ( 8848C83A2B0D04BD007B434F /* Preview Assets.xcassets in Resources */, + 86E8E2032DD25F5A003DBFE4 /* GoogleService-Info.plist in Resources */, 8848C8372B0D04BD007B434F /* Assets.xcassets in Resources */, - 88209C152B0F928F00F64795 /* GenerativeAI-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -519,8 +501,8 @@ buildActionMask = 2147483647; files = ( 8848C84E2B0D051F007B434F /* Preview Assets.xcassets in Resources */, + 86E8E2052DD25F5A003DBFE4 /* GoogleService-Info.plist in Resources */, 8848C84B2B0D051F007B434F /* Assets.xcassets in Resources */, - 88209C162B0F92AF00F64795 /* GenerativeAI-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -529,8 +511,8 @@ buildActionMask = 2147483647; files = ( 8848C8602B0D056D007B434F /* Preview Assets.xcassets in Resources */, + 86E8E2022DD25F5A003DBFE4 /* GoogleService-Info.plist in Resources */, 8848C85D2B0D056D007B434F /* Assets.xcassets in Resources */, - 88209C172B0F92AF00F64795 /* GenerativeAI-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -539,88 +521,13 @@ buildActionMask = 2147483647; files = ( 88E10F4C2B110D5400C08E95 /* Preview Assets.xcassets in Resources */, + 86E8E2042DD25F5A003DBFE4 /* GoogleService-Info.plist in Resources */, 88E10F492B110D5400C08E95 /* Assets.xcassets in Resources */, - 88E10F5E2B11140200C08E95 /* GenerativeAI-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 880BB10C2B164F790014C3DF /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - "$(SRCROOT)/APIKey/GenerativeAI-Info.plist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "CONFIG_FILE_BASE_NAME=\"GenerativeAI-Info\"\n\nCONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}.plist\nSAMPLE_CONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}-Sample.plist\n\nCONFIG_FILE_PATH=$SRCROOT/APIKey/$CONFIG_FILE_NAME\nSAMPLE_CONFIG_FILE_PATH=$SRCROOT/APIKey/$SAMPLE_CONFIG_FILE_NAME\n\nif [ -f \"$CONFIG_FILE_PATH\" ]; then\n echo \"$CONFIG_FILE_PATH exists.\"\nelse\n echo \"$CONFIG_FILE_PATH does not exist, copying sample\"\n cp -v \"${SAMPLE_CONFIG_FILE_PATH}\" \"${CONFIG_FILE_PATH}\"\nfi\n"; - }; - 880BB10E2B1651210014C3DF /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - "$(SRCROOT)/APIKey/GenerativeAI-Info.plist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "CONFIG_FILE_BASE_NAME=\"GenerativeAI-Info\"\n\nCONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}.plist\nSAMPLE_CONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}-Sample.plist\n\nCONFIG_FILE_PATH=$SRCROOT/APIKey/$CONFIG_FILE_NAME\nSAMPLE_CONFIG_FILE_PATH=$SRCROOT/APIKey/$SAMPLE_CONFIG_FILE_NAME\n\nif [ -f \"$CONFIG_FILE_PATH\" ]; then\n echo \"$CONFIG_FILE_PATH exists.\"\nelse\n echo \"$CONFIG_FILE_PATH does not exist, copying sample\"\n cp -v \"${SAMPLE_CONFIG_FILE_PATH}\" \"${CONFIG_FILE_PATH}\"\nfi\n"; - }; - 880BB10F2B1651650014C3DF /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - "$(SRCROOT)/APIKey/GenerativeAI-Info.plist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "CONFIG_FILE_BASE_NAME=\"GenerativeAI-Info\"\n\nCONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}.plist\nSAMPLE_CONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}-Sample.plist\n\nCONFIG_FILE_PATH=$SRCROOT/APIKey/$CONFIG_FILE_NAME\nSAMPLE_CONFIG_FILE_PATH=$SRCROOT/APIKey/$SAMPLE_CONFIG_FILE_NAME\n\nif [ -f \"$CONFIG_FILE_PATH\" ]; then\n echo \"$CONFIG_FILE_PATH exists.\"\nelse\n echo \"$CONFIG_FILE_PATH does not exist, copying sample\"\n cp -v \"${SAMPLE_CONFIG_FILE_PATH}\" \"${CONFIG_FILE_PATH}\"\nfi\n"; - }; - 880BB1102B16519D0014C3DF /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - "$(SRCROOT)/APIKey/GenerativeAI-Info.plist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "CONFIG_FILE_BASE_NAME=\"GenerativeAI-Info\"\n\nCONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}.plist\nSAMPLE_CONFIG_FILE_NAME=${CONFIG_FILE_BASE_NAME}-Sample.plist\n\nCONFIG_FILE_PATH=$SRCROOT/APIKey/$CONFIG_FILE_NAME\nSAMPLE_CONFIG_FILE_PATH=$SRCROOT/APIKey/$SAMPLE_CONFIG_FILE_NAME\n\nif [ -f \"$CONFIG_FILE_PATH\" ]; then\n echo \"$CONFIG_FILE_PATH exists.\"\nelse\n echo \"$CONFIG_FILE_PATH does not exist, copying sample\"\n cp -v \"${SAMPLE_CONFIG_FILE_PATH}\" \"${CONFIG_FILE_PATH}\"\nfi\n"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 8848C82B2B0D04BC007B434F /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -632,7 +539,6 @@ 8848C8352B0D04BC007B434F /* ContentView.swift in Sources */, 886F95D52B17BA010036F07A /* SummarizeScreen.swift in Sources */, 86FBBA072BBE0D49006031A1 /* FunctionCallingScreen.swift in Sources */, - 881B753B2B0FDCE600528058 /* APIKey.swift in Sources */, 8848C8332B0D04BC007B434F /* GenerativeAISampleApp.swift in Sources */, 886F95E02B17D5010036F07A /* ConversationViewModel.swift in Sources */, 886F95DD2B17D5010036F07A /* MessageView.swift in Sources */, @@ -650,7 +556,6 @@ buildActionMask = 2147483647; files = ( 88209C1F2B0FBDC300F64795 /* SummarizeScreen.swift in Sources */, - 88209C1E2B0FBDC300F64795 /* APIKey.swift in Sources */, 8848C8472B0D051E007B434F /* GenerativeAITextSampleApp.swift in Sources */, 88209C202B0FBDC300F64795 /* SummarizeViewModel.swift in Sources */, ); @@ -663,7 +568,6 @@ 880266762B0FC39000CF7CB6 /* PhotoReasoningViewModel.swift in Sources */, 880266792B0FC39000CF7CB6 /* PhotoReasoningScreen.swift in Sources */, 8848C8592B0D056C007B434F /* GenerativeAIMultimodalSampleApp.swift in Sources */, - 881B753A2B0FDCE600528058 /* APIKey.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -672,7 +576,6 @@ buildActionMask = 2147483647; files = ( 88E10F5B2B11133E00C08E95 /* MessageView.swift in Sources */, - 88E10F5F2B11140500C08E95 /* APIKey.swift in Sources */, 88E10F572B1112F600C08E95 /* ConversationViewModel.swift in Sources */, 88E10F552B1112CA00C08E95 /* ConversationScreen.swift in Sources */, 88E10F592B11131900C08E95 /* ChatMessage.swift in Sources */, @@ -1101,20 +1004,21 @@ }; /* End XCConfigurationList section */ -/* Begin XCLocalSwiftPackageReference section */ - 88209C272B0FBFA200F64795 /* XCLocalSwiftPackageReference "../.." */ = { - isa = XCLocalSwiftPackageReference; - relativePath = ../..; - }; -/* End XCLocalSwiftPackageReference section */ - /* Begin XCRemoteSwiftPackageReference section */ + 86E8E1FE2DD2454A003DBFE4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git"; + requirement = { + kind = revision; + revision = 0be8ceca17f4b5c738070f35b049c1c8278d75bb; + }; + }; 88209C212B0FBDF700F64795 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/gonzalezreal/swift-markdown-ui"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.0; + kind = revision; + revision = 5f613358148239d0292c0cef674a3c2314737f9e; }; }; DEA09AC32B1FCE22001962D9 /* XCRemoteSwiftPackageReference "NetworkImage" */ = { @@ -1122,34 +1026,41 @@ repositoryURL = "https://github.com/gonzalezreal/NetworkImage"; requirement = { kind = revision; - revision = 7aff8d1b31148d32c5933d75557d42f6323ee3d1; + revision = 2849f5323265386e200484b0d0f896e73c3411b9; }; }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 88209C232B0FBE1700F64795 /* MarkdownUI */ = { + 86E8E1FF2DD24637003DBFE4 /* FirebaseAI */ = { isa = XCSwiftPackageProductDependency; - package = 88209C212B0FBDF700F64795 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */; - productName = MarkdownUI; + package = 86E8E1FE2DD2454A003DBFE4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAI; }; - 88209C252B0FBF7100F64795 /* GoogleGenerativeAI */ = { + 86E8E2062DD26065003DBFE4 /* FirebaseAI */ = { isa = XCSwiftPackageProductDependency; - package = 88209C212B0FBDF700F64795 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */; - productName = GoogleGenerativeAI; + package = 86E8E1FE2DD2454A003DBFE4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAI; }; - 88209C282B0FBFA200F64795 /* GoogleGenerativeAI */ = { + 86E8E2082DD2608E003DBFE4 /* FirebaseAI */ = { isa = XCSwiftPackageProductDependency; - productName = GoogleGenerativeAI; + package = 86E8E1FE2DD2454A003DBFE4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAI; }; - 886F95D72B17BA420036F07A /* MarkdownUI */ = { + 86E8E20A2DD260BE003DBFE4 /* FirebaseAI */ = { + isa = XCSwiftPackageProductDependency; + package = 86E8E1FE2DD2454A003DBFE4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAI; + }; + 88209C232B0FBE1700F64795 /* MarkdownUI */ = { isa = XCSwiftPackageProductDependency; package = 88209C212B0FBDF700F64795 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */; productName = MarkdownUI; }; - 886F95D92B17BA8D0036F07A /* GoogleGenerativeAI */ = { + 886F95D72B17BA420036F07A /* MarkdownUI */ = { isa = XCSwiftPackageProductDependency; - productName = GoogleGenerativeAI; + package = 88209C212B0FBDF700F64795 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */; + productName = MarkdownUI; }; 886F95E22B17D6630036F07A /* GenerativeAIUIComponents */ = { isa = XCSwiftPackageProductDependency; @@ -1169,11 +1080,6 @@ package = 88209C212B0FBDF700F64795 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */; productName = MarkdownUI; }; - 88E10F602B11162B00C08E95 /* GoogleGenerativeAI */ = { - isa = XCSwiftPackageProductDependency; - package = 88209C212B0FBDF700F64795 /* XCRemoteSwiftPackageReference "swift-markdown-ui" */; - productName = GoogleGenerativeAI; - }; CB0DFFD42B2B4F08006E109D /* GenerativeAIUIComponents */ = { isa = XCSwiftPackageProductDependency; productName = GenerativeAIUIComponents; diff --git a/Examples/GenerativeAISample/GenerativeAISample/GenerativeAISampleApp.swift b/Examples/GenerativeAISample/GenerativeAISample/GenerativeAISampleApp.swift index b29edbb0..2de33473 100644 --- a/Examples/GenerativeAISample/GenerativeAISample/GenerativeAISampleApp.swift +++ b/Examples/GenerativeAISample/GenerativeAISample/GenerativeAISampleApp.swift @@ -12,10 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +import FirebaseCore // ADDED import SwiftUI @main struct GenerativeAISampleApp: App { + init() { + FirebaseApp.configure() // ADDED + } + var body: some Scene { WindowGroup { ContentView() diff --git a/Examples/GenerativeAISample/GenerativeAITextSample/ViewModels/SummarizeViewModel.swift b/Examples/GenerativeAISample/GenerativeAITextSample/ViewModels/SummarizeViewModel.swift index 08aab40b..8b4b0402 100644 --- a/Examples/GenerativeAISample/GenerativeAITextSample/ViewModels/SummarizeViewModel.swift +++ b/Examples/GenerativeAISample/GenerativeAITextSample/ViewModels/SummarizeViewModel.swift @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import FirebaseAI // REPLACED: `import GoogleGenerativeAI` import Foundation -import GoogleGenerativeAI import OSLog @MainActor @@ -32,7 +32,11 @@ class SummarizeViewModel: ObservableObject { private var model: GenerativeModel? init() { - model = GenerativeModel(name: "gemini-1.5-flash-latest", apiKey: APIKey.default) + // BEFORE + // model = GenerativeModel(name: "gemini-1.5-flash-latest", apiKey: APIKey.default) + + // AFTER + model = FirebaseAI.firebaseAI().generativeModel(modelName: "gemini-2.0-flash") } func summarize(inputText: String) async { @@ -50,7 +54,7 @@ class SummarizeViewModel: ObservableObject { let prompt = "Summarize the following text for me: \(inputText)" - let outputContentStream = model.generateContentStream(prompt) + let outputContentStream = try model.generateContentStream(prompt) // ADDED: `try` // stream response for try await outputContent in outputContentStream { diff --git a/Examples/GenerativeAISample/GoogleService-Info.plist b/Examples/GenerativeAISample/GoogleService-Info.plist new file mode 100644 index 00000000..5ba0a7af --- /dev/null +++ b/Examples/GenerativeAISample/GoogleService-Info.plist @@ -0,0 +1,40 @@ + + + + + AD_UNIT_ID_FOR_BANNER_TEST + ca-app-pub-3940256099942544/2934735716 + AD_UNIT_ID_FOR_INTERSTITIAL_TEST + ca-app-pub-3940256099942544/4411468910 + API_KEY + AIzaSyAzlj4APqi5S58nFtE52Da0fYBOHA2MhaY + BUNDLE_ID + com.example.google.generativeai.GenerativeAISample + CLIENT_ID + 123456789000-hjugbg6ud799v4c49dim8ce2usclthar.apps.googleusercontent.com + DATABASE_URL + https://mockproject-1234.firebaseio.com + GCM_SENDER_ID + 123456789000 + GOOGLE_APP_ID + 1:123456789000:ios:f1bf012572b04063 + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + PLIST_VERSION + 1 + PROJECT_ID + mockproject-1234 + REVERSED_CLIENT_ID + com.googleusercontent.apps.123456789000-hjugbg6ud799v4c49dim8ce2usclthar + STORAGE_BUCKET + mockproject-1234.appspot.com + + diff --git a/scripts/build.sh b/scripts/build.sh index 4bb9ba80..2c9bf444 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -199,10 +199,8 @@ xcb_flags+=( COMPILER_INDEX_STORE_ENABLE=NO ) -fail_on_warnings=SWIFT_TREAT_WARNINGS_AS_ERRORS=YES - if [[ $workspace = *.xcodeproj ]] ; then - RunXcodebuild -project $workspace -scheme $product "${xcb_flags[@]}" $fail_on_warnings $method + RunXcodebuild -project "$workspace" -scheme "$product" "${xcb_flags[@]}" "$method" else - RunXcodebuild -workspace $workspace -scheme $product -destination "$destination" "${xcb_flags[@]}" $fail_on_warnings $method + RunXcodebuild -workspace "$workspace" -scheme "$product" -destination "$destination" "${xcb_flags[@]}" "$method" fi