@@ -19,7 +19,8 @@ import 'schema.dart';
|
19 | 19 | /// Response for Count Tokens
|
20 | 20 | final class CountTokensResponse {
|
21 | 21 | /// Constructor
|
22 |
| - CountTokensResponse(this.totalTokens, {this.totalBillableCharacters}); |
| 22 | + CountTokensResponse(this.totalTokens, |
| 23 | +{this.totalBillableCharacters, this.promptTokensDetails}); |
23 | 24 |
|
24 | 25 | /// The number of tokens that the `model` tokenizes the `prompt` into.
|
25 | 26 | ///
|
@@ -30,6 +31,9 @@ final class CountTokensResponse {
|
30 | 31 | ///
|
31 | 32 | /// Always non-negative.
|
32 | 33 | final int? totalBillableCharacters;
|
| 34 | + |
| 35 | +/// List of modalities that were processed in the request input. |
| 36 | + final List<ModalityTokenCount>? promptTokensDetails; |
33 | 37 | }
|
34 | 38 |
|
35 | 39 | /// Response from the model; supports multiple candidates.
|
@@ -128,11 +132,12 @@ final class PromptFeedback {
|
128 | 132 | /// Metadata on the generation request's token usage.
|
129 | 133 | final class UsageMetadata {
|
130 | 134 | /// Constructor
|
131 |
| - UsageMetadata._({ |
132 |
| -this.promptTokenCount, |
133 |
| -this.candidatesTokenCount, |
134 |
| -this.totalTokenCount, |
135 |
| -}); |
| 135 | + UsageMetadata._( |
| 136 | +{this.promptTokenCount, |
| 137 | +this.candidatesTokenCount, |
| 138 | +this.totalTokenCount, |
| 139 | +this.promptTokensDetails, |
| 140 | +this.candidatesTokensDetails}); |
136 | 141 |
|
137 | 142 | /// Number of tokens in the prompt.
|
138 | 143 | final int? promptTokenCount;
|
@@ -142,6 +147,12 @@ final class UsageMetadata {
|
142 | 147 |
|
143 | 148 | /// Total token count for the generation request (prompt + candidates).
|
144 | 149 | final int? totalTokenCount;
|
| 150 | + |
| 151 | +/// List of modalities that were processed in the request input. |
| 152 | + final List<ModalityTokenCount>? promptTokensDetails; |
| 153 | + |
| 154 | +/// List of modalities that were returned in the response. |
| 155 | + final List<ModalityTokenCount>? candidatesTokensDetails; |
145 | 156 | }
|
146 | 157 |
|
147 | 158 | /// Response candidate generated from a [GenerativeModel].
|
@@ -481,6 +492,62 @@ enum FinishReason {
|
481 | 492 | String toString() => name;
|
482 | 493 | }
|
483 | 494 |
|
| 495 | +/// Represents token counting info for a single modality. |
| 496 | +final class ModalityTokenCount { |
| 497 | +/// Constructor |
| 498 | + ModalityTokenCount(this.modality, this.tokenCount); |
| 499 | + |
| 500 | +/// The modality associated with this token count. |
| 501 | + final ContentModality modality; |
| 502 | + |
| 503 | +/// The number of tokens counted. |
| 504 | + final int tokenCount; |
| 505 | +} |
| 506 | + |
| 507 | +/// Content part modality. |
| 508 | +enum ContentModality { |
| 509 | +/// Unspecified modality. |
| 510 | + unspecified('MODALITY_UNSPECIFIED'), |
| 511 | + |
| 512 | +/// Plain text. |
| 513 | + text('TEXT'), |
| 514 | + |
| 515 | +/// Image. |
| 516 | + image('IMAGE'), |
| 517 | + |
| 518 | +/// Video. |
| 519 | + video('VIDEO'), |
| 520 | + |
| 521 | +/// Audio. |
| 522 | + audio('AUDIO'), |
| 523 | + |
| 524 | +/// Document, e.g. PDF. |
| 525 | + document('DOCUMENT'); |
| 526 | + |
| 527 | +const ContentModality(this._jsonString); |
| 528 | + |
| 529 | +static ContentModality _parseValue(Object jsonObject) { |
| 530 | +return switch (jsonObject) { |
| 531 | +'MODALITY_UNSPECIFIED' => ContentModality.unspecified, |
| 532 | +'TEXT' => ContentModality.text, |
| 533 | +'IMAGE' => ContentModality.image, |
| 534 | +'video' => ContentModality.video, |
| 535 | +'audio' => ContentModality.audio, |
| 536 | +'document' => ContentModality.document, |
| 537 | +_ => |
| 538 | +throw FormatException('Unhandled ContentModality format', jsonObject), |
| 539 | +}; |
| 540 | +} |
| 541 | + |
| 542 | +final String _jsonString; |
| 543 | + |
| 544 | +@override |
| 545 | +String toString() => name; |
| 546 | + |
| 547 | +/// Convert to json format. |
| 548 | + Object toJson() => _jsonString; |
| 549 | +} |
| 550 | + |
484 | 551 | /// Safety setting, affecting the safety-blocking behavior.
|
485 | 552 | ///
|
486 | 553 | /// Passing a safety setting for a category changes the allowed probability that
|
@@ -696,16 +763,28 @@ GenerateContentResponse parseGenerateContentResponse(Object jsonObject) {
|
696 | 763 | /// Parse the json to [CountTokensResponse]
|
697 | 764 | CountTokensResponse parseCountTokensResponse(Object jsonObject) {
|
698 | 765 | if (jsonObject case {'error': final Object error}) throw parseError(error);
|
699 |
| -if (jsonObject case {'totalTokens': final int totalTokens}) { |
700 |
| -if (jsonObject |
701 |
| -case {'totalBillableCharacters': final int totalBillableCharacters}) { |
702 |
| -return CountTokensResponse(totalTokens, |
703 |
| -totalBillableCharacters: totalBillableCharacters); |
704 |
| -} else { |
705 |
| -return CountTokensResponse(totalTokens); |
706 |
| -} |
| 766 | + |
| 767 | +if (jsonObject is! Map) { |
| 768 | +throw unhandledFormat('CountTokensResponse', jsonObject); |
707 | 769 | }
|
708 |
| -throw unhandledFormat('CountTokensResponse', jsonObject); |
| 770 | + |
| 771 | +final totalTokens = jsonObject['totalTokens'] as int; |
| 772 | +final totalBillableCharacters = switch (jsonObject) { |
| 773 | +{'totalBillableCharacters': final int totalBillableCharacters} => |
| 774 | +totalBillableCharacters, |
| 775 | +_ => null, |
| 776 | +}; |
| 777 | +final promptTokensDetails = switch (jsonObject) { |
| 778 | +{'promptTokensDetails': final List<Object?> promptTokensDetails} => |
| 779 | +promptTokensDetails.map(_parseModalityTokenCount).toList(), |
| 780 | +_ => null, |
| 781 | +}; |
| 782 | + |
| 783 | +return CountTokensResponse( |
| 784 | +totalTokens, |
| 785 | +totalBillableCharacters: totalBillableCharacters, |
| 786 | +promptTokensDetails: promptTokensDetails, |
| 787 | +); |
709 | 788 | }
|
710 | 789 |
|
711 | 790 | Candidate _parseCandidate(Object? jsonObject) {
|
@@ -777,10 +856,30 @@ UsageMetadata _parseUsageMetadata(Object jsonObject) {
|
777 | 856 | {'totalTokenCount': final int totalTokenCount} => totalTokenCount,
|
778 | 857 | _ => null,
|
779 | 858 | };
|
| 859 | +final promptTokensDetails = switch (jsonObject) { |
| 860 | +{'promptTokensDetails': final List<Object?> promptTokensDetails} => |
| 861 | +promptTokensDetails.map(_parseModalityTokenCount).toList(), |
| 862 | +_ => null, |
| 863 | +}; |
| 864 | +final candidatesTokensDetails = switch (jsonObject) { |
| 865 | +{'candidatesTokensDetails': final List<Object?> candidatesTokensDetails} => |
| 866 | +candidatesTokensDetails.map(_parseModalityTokenCount).toList(), |
| 867 | +_ => null, |
| 868 | +}; |
780 | 869 | return UsageMetadata._(
|
781 | 870 | promptTokenCount: promptTokenCount,
|
782 | 871 | candidatesTokenCount: candidatesTokenCount,
|
783 |
| -totalTokenCount: totalTokenCount); |
| 872 | +totalTokenCount: totalTokenCount, |
| 873 | +promptTokensDetails: promptTokensDetails, |
| 874 | +candidatesTokensDetails: candidatesTokensDetails); |
| 875 | +} |
| 876 | + |
| 877 | +ModalityTokenCount _parseModalityTokenCount(Object? jsonObject) { |
| 878 | +if (jsonObject is! Map) { |
| 879 | +throw unhandledFormat('ModalityTokenCount', jsonObject); |
| 880 | +} |
| 881 | +return ModalityTokenCount(ContentModality._parseValue(jsonObject['modality']), |
| 882 | +jsonObject['tokenCount'] as int); |
784 | 883 | }
|
785 | 884 |
|
786 | 885 | SafetyRating _parseSafetyRating(Object? jsonObject) {
|
|
0 commit comments