Skip to content

Commit e52f760

Browse files
I have added parsing for promptTokensDetails and candidatesTokensDetails in the _parseUsageMetadata function.
1 parent 5199edb commit e52f760

File tree

2 files changed

+73
-2
lines changed

2 files changed

+73
-2
lines changed

packages/firebase_ai/firebase_ai/lib/src/developer/api.dart

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ import '../api.dart'
2020
Candidate,
2121
Citation,
2222
CitationMetadata,
23+
ContentModality,
2324
CountTokensResponse,
2425
FinishReason,
2526
GenerateContentResponse,
2627
GenerationConfig,
2728
HarmBlockThreshold,
2829
HarmCategory,
2930
HarmProbability,
31+
ModalityTokenCount,
3032
PromptFeedback,
3133
SafetyRating,
3234
SafetySetting,
@@ -38,6 +40,31 @@ import '../content.dart'
3840
import '../error.dart';
3941
import '../tool.dart' show Tool, ToolConfig;
4042

43+
ContentModality _parseContentModality(Object jsonObject) {
44+
return switch (jsonObject) {
45+
'MODALITY_UNSPECIFIED' => ContentModality.unspecified,
46+
'TEXT' => ContentModality.text,
47+
'IMAGE' => ContentModality.image,
48+
'VIDEO' => ContentModality.video,
49+
'AUDIO' => ContentModality.audio,
50+
'DOCUMENT' => ContentModality.document,
51+
_ => throw unhandledFormat('ContentModality', jsonObject),
52+
};
53+
}
54+
55+
ModalityTokenCount _parseModalityTokenCount(Object? jsonObject) {
56+
if (jsonObject is! Map) {
57+
throw unhandledFormat('ModalityTokenCount', jsonObject);
58+
}
59+
final modality = _parseContentModality(jsonObject['modality']);
60+
61+
if (jsonObject.containsKey('tokenCount')) {
62+
return ModalityTokenCount(modality, jsonObject['tokenCount'] as int);
63+
} else {
64+
return ModalityTokenCount(modality, 0);
65+
}
66+
}
67+
4168
HarmProbability _parseHarmProbability(Object jsonObject) =>
4269
switch (jsonObject) {
4370
'UNSPECIFIED' => HarmProbability.unknown,
@@ -251,13 +278,23 @@ UsageMetadata _parseUsageMetadata(Object jsonObject) {
251278
{'thoughtsTokenCount': final int thoughtsTokenCount} => thoughtsTokenCount,
252279
_ => null,
253280
};
281+
final promptTokensDetails = switch (jsonObject) {
282+
{'promptTokensDetails': final List<Object?> promptTokensDetails} =>
283+
promptTokensDetails.map(_parseModalityTokenCount).toList(),
284+
_ => null,
285+
};
286+
final candidatesTokensDetails = switch (jsonObject) {
287+
{'candidatesTokensDetails': final List<Object?> candidatesTokensDetails} =>
288+
candidatesTokensDetails.map(_parseModalityTokenCount).toList(),
289+
_ => null,
290+
};
254291
return createUsageMetadata(
255292
promptTokenCount: promptTokenCount,
256293
candidatesTokenCount: candidatesTokenCount,
257294
totalTokenCount: totalTokenCount,
258295
thoughtsTokenCount: thoughtsTokenCount,
259-
promptTokensDetails: null,
260-
candidatesTokensDetails: null,
296+
promptTokensDetails: promptTokensDetails,
297+
candidatesTokensDetails: candidatesTokensDetails,
261298
);
262299
}
263300

packages/firebase_ai/firebase_ai/test/developer_api_test.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,40 @@ void main() {
153153
expect((part as InlineDataPart).mimeType, 'application/octet-stream');
154154
expect(part.bytes, inlineData);
155155
});
156+
157+
test(
158+
'parses usageMetadata with prompt and candidate token details correctly',
159+
() {
160+
final jsonResponse = {
161+
'usageMetadata': {
162+
'promptTokenCount': 10,
163+
'candidatesTokenCount': 25,
164+
'totalTokenCount': 35,
165+
'promptTokensDetails': [
166+
{'modality': 'TEXT', 'tokenCount': 10}
167+
],
168+
'candidatesTokensDetails': [
169+
{'modality': 'TEXT', 'tokenCount': 25}
170+
],
171+
}
172+
};
173+
174+
final response =
175+
DeveloperSerialization().parseGenerateContentResponse(jsonResponse);
176+
177+
expect(response.usageMetadata, isNotNull);
178+
expect(response.usageMetadata!.promptTokenCount, 10);
179+
expect(response.usageMetadata!.candidatesTokenCount, 25);
180+
expect(response.usageMetadata!.totalTokenCount, 35);
181+
expect(response.usageMetadata!.promptTokensDetails, isNotNull);
182+
expect(response.usageMetadata!.promptTokensDetails, hasLength(1));
183+
expect(response.usageMetadata!.promptTokensDetails!.first.tokenCount,
184+
10);
185+
expect(response.usageMetadata!.candidatesTokensDetails, isNotNull);
186+
expect(response.usageMetadata!.candidatesTokensDetails, hasLength(1));
187+
expect(response.usageMetadata!.candidatesTokensDetails!.first.tokenCount,
188+
25);
189+
});
156190
});
157191
});
158192
}

0 commit comments

Comments
 (0)