Skip to content

Commit 3df0883

Browse files
[Vertex AI] Simplify ModelContent initializers (#13832)
Co-authored-by: Ryan Wilson <[email protected]>
1 parent 14b94aa commit 3df0883

File tree

5 files changed

+21
-66
lines changed

5 files changed

+21
-66
lines changed

FirebaseVertexAI/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
generating content the types `TextPart`; additionally the types
3535
`InlineDataPart`, `FileDataPart` and `FunctionResponsePart` may be provided
3636
as input. (#13767)
37+
- [changed] **Breaking Change**: All initializers for `ModelContent` now require
38+
the label `parts: `. (#13832)
3739
- [changed] The default request timeout is now 180 seconds instead of the
3840
platform-default value of 60 seconds for a `URLRequest`; this timeout may
3941
still be customized in `RequestOptions`. (#13722)

FirebaseVertexAI/Sample/ChatSample/Views/ErrorDetailsView.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,11 @@ struct ErrorDetailsView: View {
160160
let error = GenerateContentError.responseStoppedEarly(
161161
reason: .maxTokens,
162162
response: GenerateContentResponse(candidates: [
163-
CandidateResponse(content: ModelContent(role: "model", [
163+
CandidateResponse(content: ModelContent(role: "model", parts:
164164
"""
165165
A _hypothetical_ model response.
166166
Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo.
167-
""",
168-
]),
167+
"""),
169168
safetyRatings: [
170169
SafetyRating(category: .dangerousContent, probability: .high),
171170
SafetyRating(category: .harassment, probability: .low),
@@ -183,12 +182,11 @@ struct ErrorDetailsView: View {
183182
#Preview("Prompt Blocked") {
184183
let error = GenerateContentError.promptBlocked(
185184
response: GenerateContentResponse(candidates: [
186-
CandidateResponse(content: ModelContent(role: "model", [
185+
CandidateResponse(content: ModelContent(role: "model", parts:
187186
"""
188187
A _hypothetical_ model response.
189188
Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo.
190-
""",
191-
]),
189+
"""),
192190
safetyRatings: [
193191
SafetyRating(category: .dangerousContent, probability: .high),
194192
SafetyRating(category: .harassment, probability: .low),

FirebaseVertexAI/Sample/ChatSample/Views/ErrorView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ struct ErrorView: View {
3737
NavigationView {
3838
let errorPromptBlocked = GenerateContentError.promptBlocked(
3939
response: GenerateContentResponse(candidates: [
40-
CandidateResponse(content: ModelContent(role: "model", [
40+
CandidateResponse(content: ModelContent(role: "model", parts: [
4141
"""
4242
A _hypothetical_ model response.
4343
Cillum ex aliqua amet aliquip labore amet eiusmod consectetur reprehenderit sit commodo.

FirebaseVertexAI/Sources/ModelContent.swift

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -71,32 +71,6 @@ public struct ModelContent: Equatable, Sendable {
7171
// TODO: Refactor this
7272
let internalParts: [InternalPart]
7373

74-
/// Creates a new value from any data or `Array` of data interpretable as a
75-
/// ``Part``. See ``PartsRepresentable`` for types that can be interpreted as `Part`s.
76-
public init(role: String? = "user", parts: some PartsRepresentable) {
77-
self.role = role
78-
var convertedParts = [InternalPart]()
79-
for part in parts.partsValue {
80-
switch part {
81-
case let textPart as TextPart:
82-
convertedParts.append(.text(textPart.text))
83-
case let inlineDataPart as InlineDataPart:
84-
let inlineData = inlineDataPart.inlineData
85-
convertedParts.append(.inlineData(mimetype: inlineData.mimeType, inlineData.data))
86-
case let fileDataPart as FileDataPart:
87-
let fileData = fileDataPart.fileData
88-
convertedParts.append(.fileData(mimetype: fileData.mimeType, uri: fileData.fileURI))
89-
case let functionCallPart as FunctionCallPart:
90-
convertedParts.append(.functionCall(functionCallPart.functionCall))
91-
case let functionResponsePart as FunctionResponsePart:
92-
convertedParts.append(.functionResponse(functionResponsePart.functionResponse))
93-
default:
94-
fatalError()
95-
}
96-
}
97-
internalParts = convertedParts
98-
}
99-
10074
/// Creates a new value from a list of ``Part``s.
10175
public init(role: String? = "user", parts: [any Part]) {
10276
self.role = role
@@ -124,14 +98,7 @@ public struct ModelContent: Equatable, Sendable {
12498

12599
/// Creates a new value from any data interpretable as a ``Part``.
126100
/// See ``PartsRepresentable`` for types that can be interpreted as `Part`s.
127-
public init(role: String? = "user", _ parts: any PartsRepresentable...) {
128-
let content = parts.flatMap { $0.partsValue }
129-
self.init(role: role, parts: content)
130-
}
131-
132-
/// Creates a new value from any data interpretable as a ``Part``.
133-
/// See ``PartsRepresentable``for types that can be interpreted as `Part`s.
134-
public init(role: String? = "user", _ parts: [PartsRepresentable]) {
101+
public init(role: String? = "user", parts: any PartsRepresentable...) {
135102
let content = parts.flatMap { $0.partsValue }
136103
self.init(role: role, parts: content)
137104
}

FirebaseVertexAI/Tests/Unit/VertexAIAPITests.swift

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ final class VertexAIAPITests: XCTestCase {
106106
_ = try await genAI.generateContent([str, UIImage(), TextPart(str)])
107107
_ = try await genAI.generateContent(str, UIImage(), "def", UIImage())
108108
_ = try await genAI.generateContent([str, UIImage(), "def", UIImage()])
109-
_ = try await genAI.generateContent([ModelContent("def", UIImage()),
110-
ModelContent("def", UIImage())])
109+
_ = try await genAI.generateContent([ModelContent(parts: "def", UIImage()),
110+
ModelContent(parts: "def", UIImage())])
111111
#elseif canImport(AppKit)
112112
_ = try await genAI.generateContent(NSImage())
113113
_ = try await genAI.generateContent([NSImage()])
@@ -121,37 +121,25 @@ final class VertexAIAPITests: XCTestCase {
121121
let _ = ModelContent(parts: "Constant String")
122122
let _ = ModelContent(parts: str)
123123
let _ = ModelContent(parts: [str])
124-
// Note: without `as [any PartsRepresentable]` this will fail to compile with "Cannot
125-
// convert value of type 'String' to expected element type
126-
// 'Array<Part>.ArrayLiteralElement'. Not sure if there's a way we can get it to
127-
// work.
128-
let _ = ModelContent(
129-
parts: [str, InlineDataPart(data: Data(), mimeType: "foo")] as [any PartsRepresentable]
130-
)
124+
let _ = ModelContent(parts: [str, InlineDataPart(data: Data(), mimeType: "foo")])
131125
#if canImport(UIKit)
132126
_ = ModelContent(role: "user", parts: UIImage())
133127
_ = ModelContent(role: "user", parts: [UIImage()])
134-
// Note: without `as [any PartsRepresentable]` this will fail to compile with "Cannot convert
135-
// value of type `[Any]` to expected type `[any PartsRepresentable]`. Not sure if there's a
136-
// way we can get it to work.
137-
_ = ModelContent(parts: [str, UIImage()] as [any PartsRepresentable])
138-
// Alternatively, you can explicitly declare the type in a variable and pass it in.
128+
_ = ModelContent(parts: [str, UIImage()])
129+
// Note: without explicitly specifying`: [any PartsRepresentable]` this will fail to compile
130+
// below with "Cannot convert value of type `[Any]` to expected type `[any Part]`.
139131
let representable2: [any PartsRepresentable] = [str, UIImage()]
140132
_ = ModelContent(parts: representable2)
141-
_ =
142-
ModelContent(parts: [str, UIImage(), TextPart(str)] as [any PartsRepresentable])
133+
_ = ModelContent(parts: [str, UIImage(), TextPart(str)])
143134
#elseif canImport(AppKit)
144135
_ = ModelContent(role: "user", parts: NSImage())
145136
_ = ModelContent(role: "user", parts: [NSImage()])
146-
// Note: without `as [any PartsRepresentable]` this will fail to compile with "Cannot convert
147-
// value of type `[Any]` to expected type `[any PartsRepresentable]`. Not sure if there's a
148-
// way we can get it to work.
149-
_ = ModelContent(parts: [str, NSImage()] as [any PartsRepresentable])
150-
// Alternatively, you can explicitly declare the type in a variable and pass it in.
137+
_ = ModelContent(parts: [str, NSImage()])
138+
// Note: without explicitly specifying`: [any PartsRepresentable]` this will fail to compile
139+
// below with "Cannot convert value of type `[Any]` to expected type `[any Part]`.
151140
let representable2: [any PartsRepresentable] = [str, NSImage()]
152141
_ = ModelContent(parts: representable2)
153-
_ =
154-
ModelContent(parts: [str, NSImage(), TextPart(str)] as [any PartsRepresentable])
142+
_ = ModelContent(parts: [str, NSImage(), TextPart(str)])
155143
#endif
156144

157145
// countTokens API
@@ -160,8 +148,8 @@ final class VertexAIAPITests: XCTestCase {
160148
let _: CountTokensResponse = try await genAI.countTokens("What color is the Sky?",
161149
UIImage())
162150
let _: CountTokensResponse = try await genAI.countTokens([
163-
ModelContent("What color is the Sky?", UIImage()),
164-
ModelContent(UIImage(), "What color is the Sky?", UIImage()),
151+
ModelContent(parts: "What color is the Sky?", UIImage()),
152+
ModelContent(parts: UIImage(), "What color is the Sky?", UIImage()),
165153
])
166154
#endif
167155

0 commit comments

Comments
 (0)