14
14
15
15
import 'content.dart' ;
16
16
import 'error.dart' ;
17
- import 'function_calling.dart' show Tool, ToolConfig;
18
17
import 'schema.dart' ;
18
+ import 'tool.dart' show Tool, ToolConfig;
19
19
20
20
/// Response for Count Tokens
21
21
final class CountTokensResponse {
@@ -196,7 +196,8 @@ final class Candidate {
196
196
// TODO: token count?
197
197
// ignore: public_member_api_docs
198
198
Candidate (this .content, this .safetyRatings, this .citationMetadata,
199
- this .finishReason, this .finishMessage);
199
+ this .finishReason, this .finishMessage,
200
+ {this .groundingMetadata});
200
201
201
202
/// Generated content returned from the model.
202
203
final Content content;
@@ -221,6 +222,9 @@ final class Candidate {
221
222
/// Message for finish reason.
222
223
final String ? finishMessage;
223
224
225
+ /// Metadata returned to the client when grounding is enabled.
226
+ final GroundingMetadata ? groundingMetadata;
227
+
224
228
/// The concatenation of the text parts of [content] , if any.
225
229
///
226
230
/// If this candidate was finished for a reason of [FinishReason.recitation]
@@ -252,6 +256,150 @@ final class Candidate {
252
256
}
253
257
}
254
258
259
+ /// Represents a specific segment within a [Content] , often used to pinpoint
260
+ /// the exact location of text or data that grounding information refers to.
261
+ final class Segment {
262
+ // ignore: public_member_api_docs
263
+ Segment (
264
+ {required this .partIndex,
265
+ required this .startIndex,
266
+ required this .endIndex,
267
+ required this .text});
268
+
269
+ /// The zero-based index of the [Part] object within the `parts` array of its
270
+ /// parent [Content] object.
271
+ ///
272
+ /// This identifies which part of the content the segment belongs to.
273
+ final int partIndex;
274
+
275
+ /// The zero-based start index of the segment within the specified [Part] ,
276
+ /// measured in UTF-8 bytes.
277
+ ///
278
+ /// This offset is inclusive, starting from 0 at the beginning of the
279
+ /// part's content.
280
+ final int startIndex;
281
+
282
+ /// The zero-based end index of the segment within the specified [Part] ,
283
+ /// measured in UTF-8 bytes.
284
+ ///
285
+ /// This offset is exclusive, meaning the character at this index is not
286
+ /// included in the segment.
287
+ final int endIndex;
288
+
289
+ /// The text corresponding to the segment from the response.
290
+ final String text;
291
+ }
292
+
293
+ /// A grounding chunk sourced from the web.
294
+ final class WebGroundingChunk {
295
+ // ignore: public_member_api_docs
296
+ WebGroundingChunk ({this .uri, this .title, this .domain});
297
+
298
+ /// The URI of the retrieved web page.
299
+ final String ? uri;
300
+
301
+ /// The title of the retrieved web page.
302
+ final String ? title;
303
+
304
+ /// The domain of the original URI from which the content was retrieved.
305
+ ///
306
+ /// This field is only populated when using the Vertex AI Gemini API.
307
+ final String ? domain;
308
+ }
309
+
310
+ /// Represents a chunk of retrieved data that supports a claim in the model's
311
+ /// response.
312
+ ///
313
+ /// This is part of the grounding information provided when grounding is
314
+ /// enabled.
315
+ final class GroundingChunk {
316
+ // ignore: public_member_api_docs
317
+ GroundingChunk ({this .web});
318
+
319
+ /// Contains details if the grounding chunk is from a web source.
320
+ final WebGroundingChunk ? web;
321
+ }
322
+
323
+ /// Provides information about how a specific segment of the model's response
324
+ /// is supported by the retrieved grounding chunks.
325
+ final class GroundingSupport {
326
+ // ignore: public_member_api_docs
327
+ GroundingSupport (
328
+ {required this .segment, required this .groundingChunkIndices});
329
+
330
+ /// Specifies the segment of the model's response content that this
331
+ /// grounding support pertains to.
332
+ final Segment segment;
333
+
334
+ /// A list of indices that refer to specific [GroundingChunk] s within the
335
+ /// [GroundingMetadata.groundingChunks] array.
336
+ ///
337
+ /// These referenced chunks are the sources that
338
+ /// support the claim made in the associated `segment` of the response.
339
+ /// For example, an array `[1, 3, 4]`
340
+ /// means that `groundingChunks[1]` , `groundingChunks[3]` , and
341
+ /// `groundingChunks[4]` are the
342
+ /// retrieved content supporting this part of the response.
343
+ final List <int > groundingChunkIndices;
344
+ }
345
+
346
+ /// Google Search entry point for web searches.
347
+ final class SearchEntryPoint {
348
+ // ignore: public_member_api_docs
349
+ SearchEntryPoint ({required this .renderedContent});
350
+
351
+ /// An HTML/CSS snippet that **must** be embedded in an app to display a
352
+ /// Google Search entry point for follow-up web searches related to the
353
+ /// model's "Grounded Response".
354
+ ///
355
+ /// To ensure proper rendering, it's recommended to display this content
356
+ /// within a `WebView` .
357
+ final String renderedContent;
358
+ }
359
+
360
+ /// Metadata returned to the client when grounding is enabled.
361
+ ///
362
+ /// > Important: If using Grounding with Google Search, you are required to
363
+ /// comply with the "Grounding with Google Search" usage requirements for your
364
+ /// chosen API provider:
365
+ /// [Gemini Developer API] (https://ai.google.dev/gemini-api/terms#grounding-with-google-search)
366
+ /// or Vertex AI Gemini API (see [Service Terms] (https://cloud.google.com/terms/service-terms)
367
+ /// section within the Service Specific Terms).
368
+ final class GroundingMetadata {
369
+ // ignore: public_member_api_docs
370
+ GroundingMetadata (
371
+ {this .searchEntryPoint,
372
+ required this .groundingChunks,
373
+ required this .groundingSupport,
374
+ required this .webSearchQueries});
375
+
376
+ /// Google Search entry point for web searches.
377
+ ///
378
+ /// This contains an HTML/CSS snippet that **must** be embedded in an app to
379
+ // display a Google Search entry point for follow-up web searches related to
380
+ // the model's "Grounded Response".
381
+ final SearchEntryPoint ? searchEntryPoint;
382
+
383
+ /// A list of [GroundingChunk] s.
384
+ ///
385
+ /// Each chunk represents a piece of retrieved content (e.g., from a web
386
+ /// page) that the model used to ground its response.
387
+ final List <GroundingChunk > groundingChunks;
388
+
389
+ /// A list of [GroundingSupport] s.
390
+ ///
391
+ /// Each object details how specific segments of the
392
+ /// model's response are supported by the `groundingChunks` .
393
+ final List <GroundingSupport > groundingSupport;
394
+
395
+ /// A list of web search queries that the model performed to gather the
396
+ /// grounding information.
397
+ ///
398
+ /// These can be used to allow users to explore the search results
399
+ /// themselves.
400
+ final List <String > webSearchQueries;
401
+ }
402
+
255
403
/// Safety rating for a piece of content.
256
404
///
257
405
/// The safety rating contains the category of harm and the harm probability
@@ -1060,29 +1208,33 @@ Candidate _parseCandidate(Object? jsonObject) {
1060
1208
}
1061
1209
1062
1210
return Candidate (
1063
- jsonObject.containsKey ('content' )
1064
- ? parseContent (jsonObject['content' ] as Object )
1065
- : Content (null , []),
1066
- switch (jsonObject) {
1067
- {'safetyRatings' : final List <Object ?> safetyRatings} =>
1068
- safetyRatings.map (_parseSafetyRating).toList (),
1069
- _ => null
1070
- },
1071
- switch (jsonObject) {
1072
- {'citationMetadata' : final Object citationMetadata} =>
1073
- _parseCitationMetadata (citationMetadata),
1074
- _ => null
1075
- },
1076
- switch (jsonObject) {
1077
- {'finishReason' : final Object finishReason} =>
1078
- FinishReason ._parseValue (finishReason),
1079
- _ => null
1080
- },
1081
- switch (jsonObject) {
1082
- {'finishMessage' : final String finishMessage} => finishMessage,
1083
- _ => null
1084
- },
1085
- );
1211
+ jsonObject.containsKey ('content' )
1212
+ ? parseContent (jsonObject['content' ] as Object )
1213
+ : Content (null , []),
1214
+ switch (jsonObject) {
1215
+ {'safetyRatings' : final List <Object ?> safetyRatings} =>
1216
+ safetyRatings.map (_parseSafetyRating).toList (),
1217
+ _ => null
1218
+ },
1219
+ switch (jsonObject) {
1220
+ {'citationMetadata' : final Object citationMetadata} =>
1221
+ _parseCitationMetadata (citationMetadata),
1222
+ _ => null
1223
+ },
1224
+ switch (jsonObject) {
1225
+ {'finishReason' : final Object finishReason} =>
1226
+ FinishReason ._parseValue (finishReason),
1227
+ _ => null
1228
+ },
1229
+ switch (jsonObject) {
1230
+ {'finishMessage' : final String finishMessage} => finishMessage,
1231
+ _ => null
1232
+ },
1233
+ groundingMetadata: switch (jsonObject) {
1234
+ {'groundingMetadata' : final Object groundingMetadata} =>
1235
+ _parseGroundingMetadata (groundingMetadata),
1236
+ _ => null
1237
+ });
1086
1238
}
1087
1239
1088
1240
PromptFeedback _parsePromptFeedback (Object jsonObject) {
@@ -1196,3 +1348,114 @@ Citation _parseCitationSource(Object? jsonObject) {
1196
1348
jsonObject['license' ] as String ? ,
1197
1349
);
1198
1350
}
1351
+
1352
+ GroundingMetadata _parseGroundingMetadata (Object ? jsonObject) {
1353
+ if (jsonObject is ! Map ) {
1354
+ throw unhandledFormat ('GroundingMetadata' , jsonObject);
1355
+ }
1356
+
1357
+ final searchEntryPoint = switch (jsonObject) {
1358
+ {'searchEntryPoint' : final Object ? searchEntryPoint} =>
1359
+ _parseSearchEntryPoint (searchEntryPoint),
1360
+ _ => null ,
1361
+ };
1362
+ final groundingChunks = switch (jsonObject) {
1363
+ {'groundingChunks' : final List <Object ?> groundingChunks} =>
1364
+ groundingChunks.map (_parseGroundingChunk).toList (),
1365
+ _ => null ,
1366
+ } ??
1367
+ [];
1368
+ // Filters out null elements, which are returned from _parseGroundingSupport when
1369
+ // segment is null.
1370
+ final groundingSupport = switch (jsonObject) {
1371
+ {'groundingSupport' : final List <Object ?> groundingSupport} =>
1372
+ groundingSupport
1373
+ .map (_parseGroundingSupport)
1374
+ .whereType <GroundingSupport >()
1375
+ .toList (),
1376
+ _ => null ,
1377
+ } ??
1378
+ [];
1379
+ final webSearchQueries = switch (jsonObject) {
1380
+ {'webSearchQueries' : final List <String >? webSearchQueries} =>
1381
+ webSearchQueries,
1382
+ _ => null ,
1383
+ } ??
1384
+ [];
1385
+
1386
+ return GroundingMetadata (
1387
+ searchEntryPoint: searchEntryPoint,
1388
+ groundingChunks: groundingChunks,
1389
+ groundingSupport: groundingSupport,
1390
+ webSearchQueries: webSearchQueries);
1391
+ }
1392
+
1393
+ Segment _parseSegment (Object ? jsonObject) {
1394
+ if (jsonObject is ! Map ) {
1395
+ throw unhandledFormat ('Segment' , jsonObject);
1396
+ }
1397
+
1398
+ return Segment (
1399
+ partIndex: (jsonObject['partIndex' ] as int ? ) ?? 0 ,
1400
+ startIndex: (jsonObject['startIndex' ] as int ? ) ?? 0 ,
1401
+ endIndex: (jsonObject['endIndex' ] as int ? ) ?? 0 ,
1402
+ text: (jsonObject['text' ] as String ? ) ?? '' );
1403
+ }
1404
+
1405
+ WebGroundingChunk _parseWebGroundingChunk (Object ? jsonObject) {
1406
+ if (jsonObject is ! Map ) {
1407
+ throw unhandledFormat ('WebGroundingChunk' , jsonObject);
1408
+ }
1409
+
1410
+ return WebGroundingChunk (
1411
+ uri: jsonObject['uri' ] as String ? ,
1412
+ title: jsonObject['title' ] as String ? ,
1413
+ domain: jsonObject['domain' ] as String ? ,
1414
+ );
1415
+ }
1416
+
1417
+ GroundingChunk _parseGroundingChunk (Object ? jsonObject) {
1418
+ if (jsonObject is ! Map ) {
1419
+ throw unhandledFormat ('GroundingChunk' , jsonObject);
1420
+ }
1421
+
1422
+ return GroundingChunk (
1423
+ web: jsonObject['web' ] != null
1424
+ ? _parseWebGroundingChunk (jsonObject['web' ])
1425
+ : null ,
1426
+ );
1427
+ }
1428
+
1429
+ GroundingSupport ? _parseGroundingSupport (Object ? jsonObject) {
1430
+ if (jsonObject is ! Map ) {
1431
+ throw unhandledFormat ('GroundingSupport' , jsonObject);
1432
+ }
1433
+
1434
+ final segment = switch (jsonObject) {
1435
+ {'segment' : final Object ? segment} => _parseSegment (segment),
1436
+ _ => null ,
1437
+ };
1438
+ if (segment == null ) {
1439
+ return null ;
1440
+ }
1441
+
1442
+ return GroundingSupport (
1443
+ segment: segment,
1444
+ groundingChunkIndices:
1445
+ (jsonObject['groundingChunkIndices' ] as List <int >? ) ?? []);
1446
+ }
1447
+
1448
+ SearchEntryPoint _parseSearchEntryPoint (Object ? jsonObject) {
1449
+ if (jsonObject is ! Map ) {
1450
+ throw unhandledFormat ('SearchEntryPoint' , jsonObject);
1451
+ }
1452
+
1453
+ final renderedContent = jsonObject['renderedContent' ] as String ? ;
1454
+ if (renderedContent == null ) {
1455
+ throw unhandledFormat ('SearchEntryPoint' , jsonObject);
1456
+ }
1457
+
1458
+ return SearchEntryPoint (
1459
+ renderedContent: renderedContent,
1460
+ );
1461
+ }
0 commit comments