Skip to content

Commit 9d0a8d8

Browse files
authored
[Vertex AI] Make ImageGenerationResponse generic and add image types (#14224)
1 parent e773941 commit 9d0a8d8

File tree

9 files changed

+329
-225
lines changed

9 files changed

+329
-225
lines changed

FirebaseVertexAI/Sources/Types/Internal/Imagen/DecodableImagenImage.swift

Lines changed: 0 additions & 62 deletions
This file was deleted.

FirebaseVertexAI/Sources/Types/Internal/Imagen/ImageGenerationResponse.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@
1515
import Foundation
1616

1717
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
18-
struct ImageGenerationResponse {
19-
let images: [InternalImagenImage]
20-
let raiFilteredReason: String?
18+
public struct ImageGenerationResponse<ImageType: ImagenImageRepresentable> {
19+
public let images: [ImageType]
20+
public let raiFilteredReason: String?
2121
}
2222

2323
// MARK: - Codable Conformances
2424

2525
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
26-
extension ImageGenerationResponse: Decodable {
26+
extension ImageGenerationResponse: Decodable where ImageType: Decodable {
2727
enum CodingKeys: CodingKey {
2828
case predictions
2929
}
@@ -38,15 +38,15 @@ extension ImageGenerationResponse: Decodable {
3838
}
3939
var predictionsContainer = try container.nestedUnkeyedContainer(forKey: .predictions)
4040

41-
var images = [InternalImagenImage]()
41+
var images = [ImageType]()
4242
var raiFilteredReasons = [String]()
4343
while !predictionsContainer.isAtEnd {
44-
if let image = try? predictionsContainer.decode(InternalImagenImage.self) {
44+
if let image = try? predictionsContainer.decode(ImageType.self) {
4545
images.append(image)
4646
} else if let filterReason = try? predictionsContainer.decode(RAIFilteredReason.self) {
4747
raiFilteredReasons.append(filterReason.raiFilteredReason)
4848
} else if let _ = try? predictionsContainer.decode(JSONObject.self) {
49-
// TODO: Log or throw unsupported prediction type
49+
// TODO(#14221): Log or throw unsupported prediction type
5050
} else {
5151
// This should never be thrown since JSONObject accepts any valid JSON.
5252
throw DecodingError.dataCorruptedError(
@@ -58,6 +58,6 @@ extension ImageGenerationResponse: Decodable {
5858

5959
self.images = images
6060
raiFilteredReason = raiFilteredReasons.first
61-
// TODO: Log if more than one RAI Filtered Reason; unexpected behaviour.
61+
// TODO(#14221): Log if more than one RAI Filtered Reason; unexpected behaviour.
6262
}
6363
}

FirebaseVertexAI/Sources/Types/Internal/Imagen/InternalImagenImage.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,4 @@ struct InternalImagenImage {
2626
}
2727

2828
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
29-
extension InternalImagenImage: DecodableImagenImage {}
30-
31-
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
32-
extension InternalImagenImage: Equatable {}
29+
extension InternalImagenImage: ImagenImage {}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2024 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 Foundation
16+
17+
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
18+
public struct ImagenFileDataImage {
19+
public let mimeType: String
20+
public let gcsURI: String
21+
22+
init(mimeType: String, gcsURI: String) {
23+
self.mimeType = mimeType
24+
self.gcsURI = gcsURI
25+
}
26+
}
27+
28+
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
29+
extension ImagenFileDataImage: ImagenImageRepresentable {
30+
public var imagenImage: any ImagenImage {
31+
InternalImagenImage(mimeType: mimeType, bytesBase64Encoded: nil, gcsURI: gcsURI)
32+
}
33+
}
34+
35+
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
36+
extension ImagenFileDataImage: Equatable {}
37+
38+
// MARK: - Codable Conformances
39+
40+
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
41+
extension ImagenFileDataImage: Decodable {
42+
enum CodingKeys: String, CodingKey {
43+
case mimeType
44+
case gcsURI = "gcsUri"
45+
}
46+
47+
public init(from decoder: any Decoder) throws {
48+
let container = try decoder.container(keyedBy: CodingKeys.self)
49+
let mimeType = try container.decode(String.self, forKey: .mimeType)
50+
let gcsURI = try container.decode(String.self, forKey: .gcsURI)
51+
self.init(mimeType: mimeType, gcsURI: gcsURI)
52+
}
53+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2024 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 Foundation
16+
17+
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
18+
public struct ImagenInlineDataImage {
19+
public let mimeType: String
20+
public let data: Data
21+
22+
init(mimeType: String, bytesBase64Encoded: String) {
23+
self.mimeType = mimeType
24+
guard let data = Data(base64Encoded: bytesBase64Encoded) else {
25+
// TODO(#14221): Add error handling for invalid base64 bytes.
26+
fatalError("Creating a `Data` from `bytesBase64Encoded` failed.")
27+
}
28+
self.data = data
29+
}
30+
}
31+
32+
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
33+
extension ImagenInlineDataImage: ImagenImageRepresentable {
34+
public var imagenImage: any ImagenImage {
35+
InternalImagenImage(
36+
mimeType: mimeType,
37+
bytesBase64Encoded: data.base64EncodedString(),
38+
gcsURI: nil
39+
)
40+
}
41+
}
42+
43+
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
44+
extension ImagenInlineDataImage: Equatable {}
45+
46+
// MARK: - Codable Conformances
47+
48+
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
49+
extension ImagenInlineDataImage: Decodable {
50+
enum CodingKeys: CodingKey {
51+
case mimeType
52+
case bytesBase64Encoded
53+
}
54+
55+
public init(from decoder: any Decoder) throws {
56+
let container = try decoder.container(keyedBy: CodingKeys.self)
57+
let mimeType = try container.decode(String.self, forKey: .mimeType)
58+
let bytesBase64Encoded = try container.decode(String.self, forKey: .bytesBase64Encoded)
59+
self.init(mimeType: mimeType, bytesBase64Encoded: bytesBase64Encoded)
60+
}
61+
}

0 commit comments

Comments
 (0)