Skip to content

Commit

Permalink
Update usage metrics capture for gemini to include returned token cou…
Browse files Browse the repository at this point in the history
…nts, and properly count different media types (images, video and audio files) (#332)

Gemini usage metrics now include returned token counts and correctly counts different media types (images, video and audio files). This was previously counting any media type as an image.
  • Loading branch information
bryanatkinson authored and randall77 committed Jun 10, 2024
1 parent cdb1bb5 commit b5aa892
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 26 deletions.
21 changes: 19 additions & 2 deletions js/ai/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ export const GenerationUsageSchema = z.object({
outputCharacters: z.number().optional(),
inputImages: z.number().optional(),
outputImages: z.number().optional(),
inputVideos: z.number().optional(),
outputVideos: z.number().optional(),
inputAudioFiles: z.number().optional(),
outputAudioFiles: z.number().optional(),
custom: z.record(z.number()).optional(),
});
export type GenerationUsage = z.infer<typeof GenerationUsageSchema>;
Expand Down Expand Up @@ -344,6 +348,8 @@ export function modelRef<
type PartCounts = {
characters: number;
images: number;
videos: number;
audio: number;
};

/**
Expand All @@ -363,8 +369,12 @@ export function getBasicUsageStats(
return {
inputCharacters: inputCounts.characters,
inputImages: inputCounts.images,
inputVideos: inputCounts.videos,
inputAudioFiles: inputCounts.audio,
outputCharacters: outputCounts.characters,
outputImages: outputCounts.images,
outputVideos: outputCounts.videos,
outputAudioFiles: outputCounts.audio,
};
}

Expand All @@ -373,10 +383,17 @@ function getPartCounts(parts: Part[]): PartCounts {
(counts, part) => {
return {
characters: counts.characters + (part.text?.length || 0),
images: counts.images + (part.media ? 1 : 0),
images:
counts.images +
(part.media?.contentType?.startsWith('image') ? 1 : 0),
videos:
counts.videos +
(part.media?.contentType?.startsWith('video') ? 1 : 0),
audio:
counts.audio + (part.media?.contentType?.startsWith('audio') ? 1 : 0),
};
},
{ characters: 0, images: 0 }
{ characters: 0, images: 0, videos: 0, audio: 0 }
);
}

Expand Down
64 changes: 42 additions & 22 deletions js/ai/src/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { GenerateOptions } from './generate.js';
import {
GenerateRequest,
GenerateResponseData,
GenerationUsage,
MediaPart,
Part,
ToolRequestPart,
Expand Down Expand Up @@ -77,6 +78,19 @@ const generateActionInputImages = new MetricCounter(
}
);

const generateActionInputVideos = new MetricCounter(
_N('generate/input/videos'),
{
description: 'Counts input videos to a Genkit model.',
valueType: ValueType.INT,
}
);

const generateActionInputAudio = new MetricCounter(_N('generate/input/audio'), {
description: 'Counts input audio files to a Genkit model.',
valueType: ValueType.INT,
});

const generateActionOutputCharacters = new MetricCounter(
_N('generate/output/characters'),
{
Expand All @@ -101,6 +115,22 @@ const generateActionOutputImages = new MetricCounter(
}
);

const generateActionOutputVideos = new MetricCounter(
_N('generate/output/videos'),
{
description: 'Count output videos from a Genkit model.',
valueType: ValueType.INT,
}
);

const generateActionOutputAudio = new MetricCounter(
_N('generate/output/audio'),
{
description: 'Count output audio files from a Genkit model.',
valueType: ValueType.INT,
}
);

type SharedDimensions = {
modelName?: string;
path?: string;
Expand All @@ -119,19 +149,12 @@ export function recordGenerateActionMetrics(
err?: any;
}
) {
doRecordGenerateActionMetrics(modelName, {
doRecordGenerateActionMetrics(modelName, opts.response?.usage || {}, {
temperature: input.config?.temperature,
topK: input.config?.topK,
topP: input.config?.topP,
maxOutputTokens: input.config?.maxOutputTokens,
path: spanMetadataAls?.getStore()?.path,
inputTokens: opts.response?.usage?.inputTokens,
outputTokens: opts.response?.usage?.outputTokens,
totalTokens: opts.response?.usage?.totalTokens,
inputCharacters: opts.response?.usage?.inputCharacters,
outputCharacters: opts.response?.usage?.outputCharacters,
inputImages: opts.response?.usage?.inputImages,
outputImages: opts.response?.usage?.outputImages,
latencyMs: opts.response?.latencyMs,
err: opts.err,
source: 'ts',
Expand Down Expand Up @@ -290,20 +313,13 @@ function toPartLogToolResponse(part: ToolResponsePart): string {
*/
function doRecordGenerateActionMetrics(
modelName: string,
usage: GenerationUsage,
dimensions: {
path?: string;
temperature?: number;
maxOutputTokens?: number;
topK?: number;
topP?: number;
inputTokens?: number;
outputTokens?: number;
totalTokens?: number;
inputCharacters?: number;
outputCharacters?: number;
totalCharacters?: number;
inputImages?: number;
outputImages?: number;
latencyMs?: number;
err?: any;
source?: string;
Expand All @@ -329,12 +345,16 @@ function doRecordGenerateActionMetrics(
generateActionLatencies.record(dimensions.latencyMs, shared);

// inputs
generateActionInputTokens.add(dimensions.inputTokens, shared);
generateActionInputCharacters.add(dimensions.inputCharacters, shared);
generateActionInputImages.add(dimensions.inputImages, shared);
generateActionInputTokens.add(usage.inputTokens, shared);
generateActionInputCharacters.add(usage.inputCharacters, shared);
generateActionInputImages.add(usage.inputImages, shared);
generateActionInputVideos.add(usage.inputVideos, shared);
generateActionInputAudio.add(usage.inputAudioFiles, shared);

// outputs
generateActionOutputTokens.add(dimensions.outputTokens, shared);
generateActionOutputCharacters.add(dimensions.outputCharacters, shared);
generateActionOutputImages.add(dimensions.outputImages, shared);
generateActionOutputTokens.add(usage.outputTokens, shared);
generateActionOutputCharacters.add(usage.outputCharacters, shared);
generateActionOutputImages.add(usage.outputImages, shared);
generateActionOutputVideos.add(usage.outputVideos, shared);
generateActionOutputAudio.add(usage.outputAudioFiles, shared);
}
7 changes: 6 additions & 1 deletion js/plugins/googleai/src/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,12 @@ export function googleAIModel(
return {
candidates: responseCandidates,
custom: result.response,
usage: getBasicUsageStats(request.messages, responseCandidates),
usage: {
...getBasicUsageStats(request.messages, responseCandidates),
inputTokens: result.response.usageMetadata?.promptTokenCount,
outputTokens: result.response.usageMetadata?.candidatesTokenCount,
totalTokens: result.response.usageMetadata?.totalTokenCount,
},
};
}
}
Expand Down
7 changes: 6 additions & 1 deletion js/plugins/vertexai/src/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,12 @@ export function geminiModel(name: string, vertex: VertexAI): ModelAction {
return {
candidates: responseCandidates,
custom: result.response,
usage: getBasicUsageStats(request.messages, responseCandidates),
usage: {
...getBasicUsageStats(request.messages, responseCandidates),
inputTokens: result.response.usageMetadata?.promptTokenCount,
outputTokens: result.response.usageMetadata?.candidatesTokenCount,
totalTokens: result.response.usageMetadata?.totalTokenCount,
},
};
}
}
Expand Down

0 comments on commit b5aa892

Please sign in to comment.