@@ -17,58 +17,24 @@ import Foundation
17
17
/// The model's response to a generate content request.
18
18
@available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
19
19
public struct GenerateContentResponse {
20
- /// Token usage metadata for processing the generate content request.
21
- public struct UsageMetadata {
22
- /// The number of tokens in the request prompt.
23
- public let promptTokenCount : Int
24
-
25
- /// The total number of tokens across the generated response candidates.
26
- public let candidatesTokenCount : Int
27
-
28
- /// The total number of tokens in both the request and response.
29
- public let totalTokenCount : Int
30
- }
31
-
32
20
/// A list of candidate response content, ordered from best to worst.
33
21
public let candidates : [ CandidateResponse ]
34
22
35
23
/// A value containing the safety ratings for the response, or, if the request was blocked, a
36
24
/// reason for blocking the request.
37
25
public let promptFeedback : PromptFeedback ?
38
26
39
- /// Token usage metadata for processing the generate content request.
40
- public let usageMetadata : UsageMetadata ?
41
-
42
27
/// The response's content as text, if it exists.
43
28
public var text : String ? {
44
29
guard let candidate = candidates. first else {
45
30
Logging . default. error ( " Could not get text from a response that had no candidates. " )
46
31
return nil
47
32
}
48
- let textValues : [ String ] = candidate. content. parts. compactMap { part in
49
- guard case let . text( text) = part else {
50
- return nil
51
- }
52
- return text
53
- }
54
- guard textValues. count > 0 else {
33
+ guard let text = candidate. content. parts. first? . text else {
55
34
Logging . default. error ( " Could not get a text part from the first candidate. " )
56
35
return nil
57
36
}
58
- return textValues. joined ( separator: " " )
59
- }
60
-
61
- /// Returns function calls found in any `Part`s of the first candidate of the response, if any.
62
- public var functionCalls : [ FunctionCall ] {
63
- guard let candidate = candidates. first else {
64
- return [ ]
65
- }
66
- return candidate. content. parts. compactMap { part in
67
- guard case let . functionCall( functionCall) = part else {
68
- return nil
69
- }
70
- return functionCall
71
- }
37
+ return text
72
38
}
73
39
74
40
/// Returns function calls found in any `Part`s of the first candidate of the response, if any.
@@ -85,128 +51,17 @@ public struct GenerateContentResponse {
85
51
}
86
52
87
53
/// Initializer for SwiftUI previews or tests.
88
- public init ( candidates: [ CandidateResponse ] , promptFeedback: PromptFeedback ? = nil ,
89
- usageMetadata: UsageMetadata ? = nil ) {
54
+ public init ( candidates: [ CandidateResponse ] , promptFeedback: PromptFeedback ? = nil ) {
90
55
self . candidates = candidates
91
56
self . promptFeedback = promptFeedback
92
- self . usageMetadata = usageMetadata
93
57
}
94
58
}
95
59
96
- /// A struct representing a possible reply to a content generation prompt. Each content generation
97
- /// prompt may produce multiple candidate responses.
98
- @available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
99
- public struct CandidateResponse {
100
- /// The response's content.
101
- public let content : ModelContent
102
-
103
- /// The safety rating of the response content.
104
- public let safetyRatings : [ SafetyRating ]
105
-
106
- /// The reason the model stopped generating content, if it exists; for example, if the model
107
- /// generated a predefined stop sequence.
108
- public let finishReason : FinishReason ?
109
-
110
- /// Cited works in the model's response content, if it exists.
111
- public let citationMetadata : CitationMetadata ?
112
-
113
- /// Initializer for SwiftUI previews or tests.
114
- public init ( content: ModelContent , safetyRatings: [ SafetyRating ] , finishReason: FinishReason ? ,
115
- citationMetadata: CitationMetadata ? ) {
116
- self . content = content
117
- self . safetyRatings = safetyRatings
118
- self . finishReason = finishReason
119
- self . citationMetadata = citationMetadata
120
- }
121
- }
122
-
123
- /// A collection of source attributions for a piece of content.
124
- @available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
125
- public struct CitationMetadata {
126
- /// A list of individual cited sources and the parts of the content to which they apply.
127
- public let citationSources : [ Citation ]
128
- }
129
-
130
- /// A struct describing a source attribution.
131
- @available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
132
- public struct Citation {
133
- /// The inclusive beginning of a sequence in a model response that derives from a cited source.
134
- public let startIndex : Int
135
-
136
- /// The exclusive end of a sequence in a model response that derives from a cited source.
137
- public let endIndex : Int
138
-
139
- /// A link to the cited source.
140
- public let uri : String
141
-
142
- /// The license the cited source work is distributed under, if specified.
143
- public let license : String ?
144
- }
145
-
146
- /// A value enumerating possible reasons for a model to terminate a content generation request.
147
- @available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
148
- public enum FinishReason : String {
149
- case unknown = " FINISH_REASON_UNKNOWN "
150
-
151
- case unspecified = " FINISH_REASON_UNSPECIFIED "
152
-
153
- /// Natural stop point of the model or provided stop sequence.
154
- case stop = " STOP "
155
-
156
- /// The maximum number of tokens as specified in the request was reached.
157
- case maxTokens = " MAX_TOKENS "
158
-
159
- /// The token generation was stopped because the response was flagged for safety reasons.
160
- /// NOTE: When streaming, the Candidate.content will be empty if content filters blocked the
161
- /// output.
162
- case safety = " SAFETY "
163
-
164
- /// The token generation was stopped because the response was flagged for unauthorized citations.
165
- case recitation = " RECITATION "
166
-
167
- /// All other reasons that stopped token generation.
168
- case other = " OTHER "
169
- }
170
-
171
- /// A metadata struct containing any feedback the model had on the prompt it was provided.
172
- @available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
173
- public struct PromptFeedback {
174
- /// A type describing possible reasons to block a prompt.
175
- public enum BlockReason : String {
176
- /// The block reason is unknown.
177
- case unknown = " UNKNOWN "
178
-
179
- /// The block reason was not specified in the server response.
180
- case unspecified = " BLOCK_REASON_UNSPECIFIED "
181
-
182
- /// The prompt was blocked because it was deemed unsafe.
183
- case safety = " SAFETY "
184
-
185
- /// All other block reasons.
186
- case other = " OTHER "
187
- }
188
-
189
- /// The reason a prompt was blocked, if it was blocked.
190
- public let blockReason : BlockReason ?
191
-
192
- /// The safety ratings of the prompt.
193
- public let safetyRatings : [ SafetyRating ]
194
-
195
- /// Initializer for SwiftUI previews or tests.
196
- public init ( blockReason: BlockReason ? , safetyRatings: [ SafetyRating ] ) {
197
- self . blockReason = blockReason
198
- self . safetyRatings = safetyRatings
199
- }
200
- }
201
-
202
- // MARK: - Codable Conformances
203
-
204
60
@available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
205
61
extension GenerateContentResponse : Decodable {
206
62
enum CodingKeys : CodingKey {
207
63
case candidates
208
64
case promptFeedback
209
- case usageMetadata
210
65
}
211
66
212
67
public init ( from decoder: Decoder ) throws {
@@ -231,24 +86,33 @@ extension GenerateContentResponse: Decodable {
231
86
candidates = [ ]
232
87
}
233
88
promptFeedback = try container. decodeIfPresent ( PromptFeedback . self, forKey: . promptFeedback)
234
- usageMetadata = try container. decodeIfPresent ( UsageMetadata . self, forKey: . usageMetadata)
235
89
}
236
90
}
237
91
92
+ /// A struct representing a possible reply to a content generation prompt. Each content generation
93
+ /// prompt may produce multiple candidate responses.
238
94
@available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
239
- extension GenerateContentResponse . UsageMetadata : Decodable {
240
- enum CodingKeys : CodingKey {
241
- case promptTokenCount
242
- case candidatesTokenCount
243
- case totalTokenCount
244
- }
95
+ public struct CandidateResponse {
96
+ /// The response's content.
97
+ public let content : ModelContent
245
98
246
- public init ( from decoder: any Decoder ) throws {
247
- let container = try decoder. container ( keyedBy: CodingKeys . self)
248
- promptTokenCount = try container. decodeIfPresent ( Int . self, forKey: . promptTokenCount) ?? 0
249
- candidatesTokenCount = try container
250
- . decodeIfPresent ( Int . self, forKey: . candidatesTokenCount) ?? 0
251
- totalTokenCount = try container. decodeIfPresent ( Int . self, forKey: . totalTokenCount) ?? 0
99
+ /// The safety rating of the response content.
100
+ public let safetyRatings : [ SafetyRating ]
101
+
102
+ /// The reason the model stopped generating content, if it exists; for example, if the model
103
+ /// generated a predefined stop sequence.
104
+ public let finishReason : FinishReason ?
105
+
106
+ /// Cited works in the model's response content, if it exists.
107
+ public let citationMetadata : CitationMetadata ?
108
+
109
+ /// Initializer for SwiftUI previews or tests.
110
+ public init ( content: ModelContent , safetyRatings: [ SafetyRating ] , finishReason: FinishReason ? ,
111
+ citationMetadata: CitationMetadata ? ) {
112
+ self . content = content
113
+ self . safetyRatings = safetyRatings
114
+ self . finishReason = finishReason
115
+ self . citationMetadata = citationMetadata
252
116
}
253
117
}
254
118
@@ -262,6 +126,8 @@ extension CandidateResponse: Decodable {
262
126
case citationMetadata
263
127
}
264
128
129
+ /// Initializes a response from a decoder. Used for decoding server responses; not for public
130
+ /// use.
265
131
public init ( from decoder: Decoder ) throws {
266
132
let container = try decoder. container ( keyedBy: CodingKeys . self)
267
133
@@ -299,34 +165,57 @@ extension CandidateResponse: Decodable {
299
165
}
300
166
}
301
167
168
+ /// A collection of source attributions for a piece of content.
302
169
@available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
303
- extension CitationMetadata : Decodable { }
170
+ public struct CitationMetadata : Decodable {
171
+ /// A list of individual cited sources and the parts of the content to which they apply.
172
+ public let citationSources : [ Citation ]
173
+ }
304
174
175
+ /// A struct describing a source attribution.
305
176
@available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
306
- extension Citation : Decodable {
307
- enum CodingKeys : CodingKey {
308
- case startIndex
309
- case endIndex
310
- case uri
311
- case license
312
- }
177
+ public struct Citation : Decodable {
178
+ /// The inclusive beginning of a sequence in a model response that derives from a cited source.
179
+ public let startIndex : Int
313
180
314
- public init ( from decoder: any Decoder ) throws {
315
- let container = try decoder. container ( keyedBy: CodingKeys . self)
316
- startIndex = try container. decodeIfPresent ( Int . self, forKey: . startIndex) ?? 0
317
- endIndex = try container. decode ( Int . self, forKey: . endIndex)
318
- uri = try container. decode ( String . self, forKey: . uri)
319
- if let license = try container. decodeIfPresent ( String . self, forKey: . license) ,
320
- !license. isEmpty {
321
- self . license = license
322
- } else {
323
- license = nil
324
- }
325
- }
181
+ /// The exclusive end of a sequence in a model response that derives from a cited source.
182
+ public let endIndex : Int
183
+
184
+ /// A link to the cited source.
185
+ public let uri : String
186
+
187
+ /// The license the cited source work is distributed under.
188
+ public let license : String
189
+ }
190
+
191
+ /// A value enumerating possible reasons for a model to terminate a content generation request.
192
+ @available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
193
+ public enum FinishReason : String {
194
+ case unknown = " FINISH_REASON_UNKNOWN "
195
+
196
+ case unspecified = " FINISH_REASON_UNSPECIFIED "
197
+
198
+ /// Natural stop point of the model or provided stop sequence.
199
+ case stop = " STOP "
200
+
201
+ /// The maximum number of tokens as specified in the request was reached.
202
+ case maxTokens = " MAX_TOKENS "
203
+
204
+ /// The token generation was stopped because the response was flagged for safety reasons.
205
+ /// NOTE: When streaming, the Candidate.content will be empty if content filters blocked the
206
+ /// output.
207
+ case safety = " SAFETY "
208
+
209
+ /// The token generation was stopped because the response was flagged for unauthorized citations.
210
+ case recitation = " RECITATION "
211
+
212
+ /// All other reasons that stopped token generation.
213
+ case other = " OTHER "
326
214
}
327
215
328
216
@available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
329
217
extension FinishReason : Decodable {
218
+ /// Do not explicitly use. Initializer required for Decodable conformance.
330
219
public init ( from decoder: Decoder ) throws {
331
220
let value = try decoder. singleValueContainer ( ) . decode ( String . self)
332
221
guard let decodedFinishReason = FinishReason ( rawValue: value) else {
@@ -340,18 +229,47 @@ extension FinishReason: Decodable {
340
229
}
341
230
}
342
231
232
+ /// A metadata struct containing any feedback the model had on the prompt it was provided.
343
233
@available ( iOS 15 . 0 , macOS 11 . 0 , macCatalyst 15 . 0 , * )
344
- extension PromptFeedback . BlockReason : Decodable {
345
- public init ( from decoder: Decoder ) throws {
346
- let value = try decoder. singleValueContainer ( ) . decode ( String . self)
347
- guard let decodedBlockReason = PromptFeedback . BlockReason ( rawValue: value) else {
348
- Logging . default
349
- . error ( " [GoogleGenerativeAI] Unrecognized BlockReason with value \" \( value) \" . " )
350
- self = . unknown
351
- return
234
+ public struct PromptFeedback {
235
+ /// A type describing possible reasons to block a prompt.
236
+ public enum BlockReason : String , Decodable {
237
+ /// The block reason is unknown.
238
+ case unknown = " UNKNOWN "
239
+
240
+ /// The block reason was not specified in the server response.
241
+ case unspecified = " BLOCK_REASON_UNSPECIFIED "
242
+
243
+ /// The prompt was blocked because it was deemed unsafe.
244
+ case safety = " SAFETY "
245
+
246
+ /// All other block reasons.
247
+ case other = " OTHER "
248
+
249
+ /// Do not explicitly use. Initializer required for Decodable conformance.
250
+ public init ( from decoder: Decoder ) throws {
251
+ let value = try decoder. singleValueContainer ( ) . decode ( String . self)
252
+ guard let decodedBlockReason = BlockReason ( rawValue: value) else {
253
+ Logging . default
254
+ . error ( " [GoogleGenerativeAI] Unrecognized BlockReason with value \" \( value) \" . " )
255
+ self = . unknown
256
+ return
257
+ }
258
+
259
+ self = decodedBlockReason
352
260
}
261
+ }
262
+
263
+ /// The reason a prompt was blocked, if it was blocked.
264
+ public let blockReason : BlockReason ?
353
265
354
- self = decodedBlockReason
266
+ /// The safety ratings of the prompt.
267
+ public let safetyRatings : [ SafetyRating ]
268
+
269
+ /// Initializer for SwiftUI previews or tests.
270
+ public init ( blockReason: BlockReason ? , safetyRatings: [ SafetyRating ] ) {
271
+ self . blockReason = blockReason
272
+ self . safetyRatings = safetyRatings
355
273
}
356
274
}
357
275
@@ -362,6 +280,7 @@ extension PromptFeedback: Decodable {
362
280
case safetyRatings
363
281
}
364
282
283
+ /// Do not explicitly use. Initializer required for Decodable conformance.
365
284
public init ( from decoder: Decoder ) throws {
366
285
let container = try decoder. container ( keyedBy: CodingKeys . self)
367
286
blockReason = try container. decodeIfPresent (
0 commit comments