Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
30 changes: 27 additions & 3 deletions firebaseai/FirebaseAIExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@
AEE793DF2E256D3900708F02 /* GoogleSearchSuggestionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE793DC2E256D3900708F02 /* GoogleSearchSuggestionView.swift */; };
AEE793E02E256D3900708F02 /* GroundedResponseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE793DD2E256D3900708F02 /* GroundedResponseView.swift */; };
DE26D95F2DBB3E9F007E6668 /* FirebaseAI in Frameworks */ = {isa = PBXBuildFile; productRef = DE26D95E2DBB3E9F007E6668 /* FirebaseAI */; };
DE907A812EAAE53E00AE56CE /* GenerateContentFromTemplateScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE907A802EAAE53E00AE56CE /* GenerateContentFromTemplateScreen.swift */; };
DE907A822EAAE53E00AE56CE /* GenerateContentFromTemplateScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE907A802EAAE53E00AE56CE /* GenerateContentFromTemplateScreen.swift */; };
DE907A842EAAE55600AE56CE /* GenerateContentFromTemplateViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE907A832EAAE55600AE56CE /* GenerateContentFromTemplateViewModel.swift */; };
DE907A852EAAE55600AE56CE /* GenerateContentFromTemplateViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE907A832EAAE55600AE56CE /* GenerateContentFromTemplateViewModel.swift */; };
DE907A882EAAEBCC00AE56CE /* ImagenFromTemplateViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE907A872EAAEBCC00AE56CE /* ImagenFromTemplateViewModel.swift */; };
DE907A892EAAEBCC00AE56CE /* ImagenFromTemplateScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE907A862EAAEBCC00AE56CE /* ImagenFromTemplateScreen.swift */; };
DE907A8A2EAAEBCC00AE56CE /* ImagenFromTemplateViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE907A872EAAEBCC00AE56CE /* ImagenFromTemplateViewModel.swift */; };
DE907A8B2EAAEBCC00AE56CE /* ImagenFromTemplateScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE907A862EAAEBCC00AE56CE /* ImagenFromTemplateScreen.swift */; };
DEFECAA92D7B4CCD00EF9621 /* ImagenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFECAA72D7B4CCD00EF9621 /* ImagenViewModel.swift */; };
DEFECAAA2D7B4CCD00EF9621 /* ImagenScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEFECAA62D7B4CCD00EF9621 /* ImagenScreen.swift */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -94,6 +102,10 @@
88E10F5C2B11135000C08E95 /* BouncingDots.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BouncingDots.swift; sourceTree = "<group>"; };
AEE793DC2E256D3900708F02 /* GoogleSearchSuggestionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleSearchSuggestionView.swift; sourceTree = "<group>"; };
AEE793DD2E256D3900708F02 /* GroundedResponseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroundedResponseView.swift; sourceTree = "<group>"; };
DE907A802EAAE53E00AE56CE /* GenerateContentFromTemplateScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateContentFromTemplateScreen.swift; sourceTree = "<group>"; };
DE907A832EAAE55600AE56CE /* GenerateContentFromTemplateViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateContentFromTemplateViewModel.swift; sourceTree = "<group>"; };
DE907A862EAAEBCC00AE56CE /* ImagenFromTemplateScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagenFromTemplateScreen.swift; sourceTree = "<group>"; };
DE907A872EAAEBCC00AE56CE /* ImagenFromTemplateViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagenFromTemplateViewModel.swift; sourceTree = "<group>"; };
DEFECAA62D7B4CCD00EF9621 /* ImagenScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagenScreen.swift; sourceTree = "<group>"; };
DEFECAA72D7B4CCD00EF9621 /* ImagenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagenViewModel.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -171,6 +183,7 @@
88209C1A2B0FBDC300F64795 /* Screens */ = {
isa = PBXGroup;
children = (
DE907A802EAAE53E00AE56CE /* GenerateContentFromTemplateScreen.swift */,
88209C1B2B0FBDC300F64795 /* GenerateContentScreen.swift */,
);
path = Screens;
Expand All @@ -179,6 +192,7 @@
88209C1C2B0FBDC300F64795 /* ViewModels */ = {
isa = PBXGroup;
children = (
DE907A832EAAE55600AE56CE /* GenerateContentFromTemplateViewModel.swift */,
88209C1D2B0FBDC300F64795 /* GenerateContentViewModel.swift */,
);
path = ViewModels;
Expand Down Expand Up @@ -342,6 +356,8 @@
DEFECAA82D7B4CCD00EF9621 /* ImagenScreen */ = {
isa = PBXGroup;
children = (
DE907A862EAAEBCC00AE56CE /* ImagenFromTemplateScreen.swift */,
DE907A872EAAEBCC00AE56CE /* ImagenFromTemplateViewModel.swift */,
DEFECAA62D7B4CCD00EF9621 /* ImagenScreen.swift */,
DEFECAA72D7B4CCD00EF9621 /* ImagenViewModel.swift */,
);
Expand Down Expand Up @@ -468,6 +484,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DE907A852EAAE55600AE56CE /* GenerateContentFromTemplateViewModel.swift in Sources */,
DE907A812EAAE53E00AE56CE /* GenerateContentFromTemplateScreen.swift in Sources */,
86BB55EA2E8B2D6D0054B8B5 /* FunctionCallingScreen.swift in Sources */,
86BB55EB2E8B2D6D0054B8B5 /* BouncingDots.swift in Sources */,
86BB55EC2E8B2D6D0054B8B5 /* FunctionCallingViewModel.swift in Sources */,
Expand All @@ -481,6 +499,8 @@
86BB55F42E8B2D6D0054B8B5 /* PhotoReasoningScreen.swift in Sources */,
86BB55F52E8B2D6D0054B8B5 /* ImagenViewModel.swift in Sources */,
86BB55F62E8B2D6D0054B8B5 /* ImagenScreen.swift in Sources */,
DE907A882EAAEBCC00AE56CE /* ImagenFromTemplateViewModel.swift in Sources */,
DE907A892EAAEBCC00AE56CE /* ImagenFromTemplateScreen.swift in Sources */,
86BB55F72E8B2D6D0054B8B5 /* PhotoReasoningViewModel.swift in Sources */,
86BB55F82E8B2D6D0054B8B5 /* ConversationScreen.swift in Sources */,
86BB55F92E8B2D6D0054B8B5 /* ErrorView.swift in Sources */,
Expand All @@ -494,6 +514,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DE907A842EAAE55600AE56CE /* GenerateContentFromTemplateViewModel.swift in Sources */,
DE907A822EAAE53E00AE56CE /* GenerateContentFromTemplateScreen.swift in Sources */,
86C1F4832BC726150026816F /* FunctionCallingScreen.swift in Sources */,
886F95DF2B17D5010036F07A /* BouncingDots.swift in Sources */,
86C1F4842BC726150026816F /* FunctionCallingViewModel.swift in Sources */,
Expand All @@ -507,6 +529,8 @@
886F95DC2B17BAEF0036F07A /* PhotoReasoningScreen.swift in Sources */,
DEFECAA92D7B4CCD00EF9621 /* ImagenViewModel.swift in Sources */,
DEFECAAA2D7B4CCD00EF9621 /* ImagenScreen.swift in Sources */,
DE907A8A2EAAEBCC00AE56CE /* ImagenFromTemplateViewModel.swift in Sources */,
DE907A8B2EAAEBCC00AE56CE /* ImagenFromTemplateScreen.swift in Sources */,
886F95DB2B17BAEF0036F07A /* PhotoReasoningViewModel.swift in Sources */,
886F95E12B17D5010036F07A /* ConversationScreen.swift in Sources */,
88263BF02B239C09008AB09B /* ErrorView.swift in Sources */,
Expand Down Expand Up @@ -720,7 +744,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.FirebaseAIExample;
PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.VertexAISample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -750,7 +774,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.quickstart.FirebaseAIExample;
PRODUCT_BUNDLE_IDENTIFIER = com.google.firebase.VertexAISample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -828,7 +852,7 @@
repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 12.0.0;
minimumVersion = 12.6.0;
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down
10 changes: 10 additions & 0 deletions firebaseai/FirebaseAIExample/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ struct ContentView: View {
} label: {
Label("Generate Content", systemImage: "doc.text")
}
NavigationLink {
GenerateContentFromTemplateScreen(firebaseService: firebaseService)
} label: {
Label("Generate Content from Template", systemImage: "doc.text.fill")
}
NavigationLink {
PhotoReasoningScreen(firebaseService: firebaseService)
} label: {
Expand Down Expand Up @@ -84,6 +89,11 @@ struct ContentView: View {
} label: {
Label("Imagen", systemImage: "camera.circle")
}
NavigationLink {
ImagenFromTemplateScreen(firebaseService: firebaseService)
} label: {
Label("Imagen from Template", systemImage: "camera.circle.fill")
}
}
}
.navigationTitle("Generative AI Examples")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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 MarkdownUI
import SwiftUI
#if canImport(FirebaseAILogic)
import FirebaseAILogic
#else
import FirebaseAI
#endif
import GenerativeAIUIComponents

struct GenerateContentFromTemplateScreen: View {
let firebaseService: FirebaseAI
@StateObject var viewModel: GenerateContentFromTemplateViewModel
@State var userInput = ""

init(firebaseService: FirebaseAI) {
self.firebaseService = firebaseService
_viewModel =
StateObject(
wrappedValue: GenerateContentFromTemplateViewModel(firebaseService: firebaseService)
)
}

enum FocusedField: Hashable {
case message
}

@FocusState
var focusedField: FocusedField?

var body: some View {
VStack {
VStack(alignment: .leading) {
Text("Enter your name, then tap on _Go_ to run generateContent from template on it.")
.padding(.horizontal, 6)
InputField("Enter your name", text: $userInput) {
Text("Go")
}
.focused($focusedField, equals: .message)
.onSubmit { onGenerateContentTapped() }
}
.padding(.horizontal, 16)

List {
HStack(alignment: .top) {
if viewModel.inProgress {
ProgressView()
} else {
Image(systemName: "cloud.circle.fill")
.font(.title2)
}

Markdown("\(viewModel.outputText)")
}
.listRowSeparator(.hidden)
}
.listStyle(.plain)
}
.onTapGesture {
focusedField = nil
}
.navigationTitle("Template Generate Content")
}

private func onGenerateContentTapped() {
focusedField = nil

Task {
await viewModel.generateContentFromTemplate(name: userInput)
}
}
}

#Preview {
NavigationStack {
GenerateContentFromTemplateScreen(firebaseService: FirebaseAI.firebaseAI())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// 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.

#if canImport(FirebaseAILogic)
import FirebaseAILogic
#else
import FirebaseAI
#endif
import Foundation
import OSLog

// Template Details
//
// Configuration
//
// input:
// default:
// language: english
// schema:
// name: string
// language?: string
//
// Prompt and system instructions
//
// {{role "system"}}
// The user's name is {{name}}. They prefer to communicate in {{language}}.
// {{role "user"}}
// Say hello.
//

@MainActor
class GenerateContentFromTemplateViewModel: ObservableObject {
private var logger = Logger(
subsystem: Bundle.main.bundleIdentifier ?? "com.google.firebase.VertexAISample",
category: "generative-ai"
)

@Published
var outputText = ""

@Published
var errorMessage: String?

@Published
var inProgress = false

private var model: TemplateGenerativeModel?

init(firebaseService: FirebaseAI) {
model = firebaseService.templateGenerativeModel()
}

func generateContentFromTemplate(name: String) async {
defer {
inProgress = false
}
guard let model else {
return
}

do {
inProgress = true
errorMessage = nil
outputText = ""

let response = try await model.generateContent(
templateID: "apple-qs-greeting",
inputs: [
"name": name,
"language": "Spanish",
]
)
if let text = response.text {
outputText = text
}
} catch {
logger.error("\(error.localizedDescription)")
errorMessage = error.localizedDescription
}
}
}
Loading
Loading