Skip to content

Commit 5880681

Browse files
authored
fix(go): add automatic telemetry metrics for background models (#3841)
1 parent bbdd99e commit 5880681

File tree

3 files changed

+71
-30
lines changed

3 files changed

+71
-30
lines changed

‎go/ai/background_model.go‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ func NewBackgroundModel(name string, opts *BackgroundModelOptions, startFn Start
131131
simulateSystemPrompt(&opts.ModelOptions, nil),
132132
augmentWithContext(&opts.ModelOptions, nil),
133133
validateSupport(name, &opts.ModelOptions),
134-
addAutomaticTelemetry(),
135134
}
136135
fn := core.ChainMiddleware(mws...)(backgroundModelToModelFn(startFn))
137136

‎go/ai/model_middleware.go‎

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,36 @@ type DownloadMediaOptions struct {
4848
Filter func(part *Part) bool // Filter to apply to parts that are media URLs.
4949
}
5050

51+
func CalculateInputOutputUsage(req *ModelRequest, resp *ModelResponse) {
52+
if resp.Usage == nil {
53+
resp.Usage = &GenerationUsage{}
54+
}
55+
if resp.Usage.InputCharacters == 0 {
56+
resp.Usage.InputCharacters = countInputCharacters(req)
57+
}
58+
if resp.Usage.OutputCharacters == 0 {
59+
resp.Usage.OutputCharacters = countOutputCharacters(resp)
60+
}
61+
if resp.Usage.InputImages == 0 {
62+
resp.Usage.InputImages = countInputParts(req, func(part *Part) bool { return part.IsImage() })
63+
}
64+
if resp.Usage.OutputImages == 0 {
65+
resp.Usage.OutputImages = countOutputParts(resp, func(part *Part) bool { return part.IsImage() })
66+
}
67+
if resp.Usage.InputVideos == 0 {
68+
resp.Usage.InputVideos = countInputParts(req, func(part *Part) bool { return part.IsVideo() })
69+
}
70+
if resp.Usage.OutputVideos == 0 {
71+
resp.Usage.OutputVideos = countOutputParts(resp, func(part *Part) bool { return part.IsVideo() })
72+
}
73+
if resp.Usage.InputAudioFiles == 0 {
74+
resp.Usage.InputAudioFiles = countInputParts(req, func(part *Part) bool { return part.IsAudio() })
75+
}
76+
if resp.Usage.OutputAudioFiles == 0 {
77+
resp.Usage.OutputAudioFiles = countOutputParts(resp, func(part *Part) bool { return part.IsAudio() })
78+
}
79+
}
80+
5181
// addAutomaticTelemetry creates middleware that automatically measures latency and calculates character and media counts.
5282
func addAutomaticTelemetry() ModelMiddleware {
5383
return func(fn ModelFunc) ModelFunc {
@@ -66,33 +96,7 @@ func addAutomaticTelemetry() ModelMiddleware {
6696
resp.LatencyMs = latencyMs
6797
}
6898

69-
if resp.Usage == nil {
70-
resp.Usage = &GenerationUsage{}
71-
}
72-
if resp.Usage.InputCharacters == 0 {
73-
resp.Usage.InputCharacters = countInputCharacters(req)
74-
}
75-
if resp.Usage.OutputCharacters == 0 {
76-
resp.Usage.OutputCharacters = countOutputCharacters(resp)
77-
}
78-
if resp.Usage.InputImages == 0 {
79-
resp.Usage.InputImages = countInputParts(req, func(part *Part) bool { return part.IsImage() })
80-
}
81-
if resp.Usage.OutputImages == 0 {
82-
resp.Usage.OutputImages = countOutputParts(resp, func(part *Part) bool { return part.IsImage() })
83-
}
84-
if resp.Usage.InputVideos == 0 {
85-
resp.Usage.InputVideos = countInputParts(req, func(part *Part) bool { return part.IsVideo() })
86-
}
87-
if resp.Usage.OutputVideos == 0 {
88-
resp.Usage.OutputVideos = countOutputParts(resp, func(part *Part) bool { return part.IsVideo() })
89-
}
90-
if resp.Usage.InputAudioFiles == 0 {
91-
resp.Usage.InputAudioFiles = countInputParts(req, func(part *Part) bool { return part.IsAudio() })
92-
}
93-
if resp.Usage.OutputAudioFiles == 0 {
94-
resp.Usage.OutputAudioFiles = countOutputParts(resp, func(part *Part) bool { return part.IsAudio() })
95-
}
99+
CalculateInputOutputUsage(req, resp)
96100

97101
return resp, nil
98102
}

‎go/plugins/googlegenai/veo.go‎

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package googlegenai
1919
import (
2020
"context"
2121
"fmt"
22+
"time"
2223

2324
"github.com/firebase/genkit/go/ai"
2425
"github.com/firebase/genkit/go/core"
@@ -55,7 +56,15 @@ func newVeoModel(
5556
return nil, fmt.Errorf("veo video generation failed: %w", err)
5657
}
5758

58-
return fromVeoOperation(operation), nil
59+
op := fromVeoOperation(operation)
60+
61+
if op.Metadata == nil {
62+
op.Metadata = make(map[string]any)
63+
}
64+
op.Metadata["inputRequest"] = req
65+
op.Metadata["startTime"] = time.Now()
66+
67+
return op, nil
5968
}
6069

6170
checkFunc := func(ctx context.Context, op *ai.ModelOperation) (*ai.ModelOperation, error) {
@@ -64,7 +73,36 @@ func newVeoModel(
6473
return nil, fmt.Errorf("veo operation status check failed: %w", err)
6574
}
6675

67-
return fromVeoOperation(veoOp), nil
76+
updatedOp := fromVeoOperation(veoOp)
77+
78+
// Restore metadata from the original operation
79+
if op.Metadata != nil {
80+
if updatedOp.Metadata == nil {
81+
updatedOp.Metadata = make(map[string]any)
82+
}
83+
for k, v := range op.Metadata {
84+
updatedOp.Metadata[k] = v
85+
}
86+
}
87+
88+
// Add telemetry metrics when operation completes
89+
if updatedOp.Done && updatedOp.Output != nil {
90+
if req, ok := updatedOp.Metadata["inputRequest"].(*ai.ModelRequest); ok {
91+
ai.CalculateInputOutputUsage(req, updatedOp.Output)
92+
} else {
93+
ai.CalculateInputOutputUsage(nil, updatedOp.Output)
94+
}
95+
96+
// Calculate latency if startTime is available
97+
if startTime, ok := updatedOp.Metadata["startTime"].(time.Time); ok {
98+
latencyMs := float64(time.Since(startTime).Nanoseconds()) / 1e6
99+
if updatedOp.Output.LatencyMs == 0 {
100+
updatedOp.Output.LatencyMs = latencyMs
101+
}
102+
}
103+
}
104+
105+
return updatedOp, nil
68106
}
69107

70108
return ai.NewBackgroundModel(name, &ai.BackgroundModelOptions{ModelOptions: info}, startFunc, checkFunc)

0 commit comments

Comments
 (0)