Skip to content

Commit 1c5ed38

Browse files
committed
missing files
1 parent 3ed1f5c commit 1c5ed38

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import SwiftUI
16+
import GenerativeAIUIComponents
17+
#if canImport(FirebaseAILogic)
18+
import FirebaseAILogic
19+
#else
20+
import FirebaseAI
21+
#endif
22+
23+
struct ImagenFromTemplateScreen: View {
24+
let firebaseService: FirebaseAI
25+
@StateObject var viewModel: ImagenFromTemplateViewModel
26+
27+
init(firebaseService: FirebaseAI) {
28+
self.firebaseService = firebaseService
29+
_viewModel = StateObject(wrappedValue: ImagenFromTemplateViewModel(firebaseService: firebaseService))
30+
}
31+
32+
enum FocusedField: Hashable {
33+
case message
34+
}
35+
36+
@FocusState
37+
var focusedField: FocusedField?
38+
39+
var body: some View {
40+
ZStack {
41+
ScrollView {
42+
VStack {
43+
InputField("Enter a prompt to generate an image from template", text: $viewModel.userInput) {
44+
Image(
45+
systemName: viewModel.inProgress ? "stop.circle.fill" : "paperplane.circle.fill"
46+
)
47+
.font(.title)
48+
}
49+
.focused($focusedField, equals: .message)
50+
.onSubmit { sendOrStop() }
51+
52+
let spacing: CGFloat = 10
53+
LazyVGrid(columns: [
54+
GridItem(.flexible(), spacing: spacing),
55+
GridItem(.flexible(), spacing: spacing),
56+
], spacing: spacing) {
57+
ForEach(viewModel.images, id: \.self) { image in
58+
Image(uiImage: image)
59+
.resizable()
60+
.aspectRatio(1, contentMode: .fill)
61+
.cornerRadius(12)
62+
.clipped()
63+
}
64+
}
65+
.padding(.horizontal, spacing)
66+
}
67+
}
68+
if viewModel.inProgress {
69+
ProgressOverlay()
70+
}
71+
}
72+
.onTapGesture {
73+
focusedField = nil
74+
}
75+
.navigationTitle("Imagen Template")
76+
.onAppear {
77+
focusedField = .message
78+
}
79+
}
80+
81+
private func sendMessage() {
82+
Task {
83+
await viewModel.generateImageFromTemplate(prompt: viewModel.userInput)
84+
focusedField = .message
85+
}
86+
}
87+
88+
private func sendOrStop() {
89+
if viewModel.inProgress {
90+
viewModel.stop()
91+
} else {
92+
sendMessage()
93+
}
94+
}
95+
}
96+
97+
#Preview {
98+
ImagenFromTemplateScreen(firebaseService: FirebaseAI.firebaseAI())
99+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#if canImport(FirebaseAILogic)
16+
import FirebaseAILogic
17+
#else
18+
import FirebaseAI
19+
#endif
20+
import Foundation
21+
import OSLog
22+
import SwiftUI
23+
24+
@MainActor
25+
class ImagenFromTemplateViewModel: ObservableObject {
26+
private var logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "generative-ai")
27+
28+
@Published
29+
var userInput: String = ""
30+
31+
@Published
32+
var images = [UIImage]()
33+
34+
@Published
35+
var errorMessage: String?
36+
37+
@Published
38+
var inProgress = false
39+
40+
private let model: TemplateImagenModel
41+
42+
private var generateImagesTask: Task<Void, Never>?
43+
44+
init(firebaseService: FirebaseAI) {
45+
model = firebaseService.templateImagenModel()
46+
}
47+
48+
func generateImageFromTemplate(prompt: String) async {
49+
stop()
50+
51+
generateImagesTask = Task {
52+
inProgress = true
53+
defer {
54+
inProgress = false
55+
}
56+
57+
do {
58+
let response = try await model.generateImages(
59+
templateID: "image-generation-basic",
60+
inputs: [
61+
"prompt": prompt,
62+
]
63+
)
64+
65+
if !Task.isCancelled {
66+
images = response.images.compactMap { UIImage(data: $0.data) }
67+
}
68+
} catch {
69+
if !Task.isCancelled {
70+
logger.error("Error generating images from template: \(error)")
71+
}
72+
}
73+
}
74+
}
75+
76+
func stop() {
77+
generateImagesTask?.cancel()
78+
generateImagesTask = nil
79+
}
80+
}

0 commit comments

Comments
 (0)