|
| 1 | +import { LDClient, LDContext } from '@launchdarkly/node-server-sdk'; |
| 2 | + |
| 3 | +import { LDAIConfigTracker } from './api/config'; |
| 4 | +import { createBedrockTokenUsage, FeedbackKind, TokenUsage } from './api/metrics'; |
| 5 | +import { createOpenAiUsage } from './api/metrics/OpenAiUsage'; |
| 6 | + |
| 7 | +export class LDAIConfigTrackerImpl implements LDAIConfigTracker { |
| 8 | + private _ldClient: LDClient; |
| 9 | + private _variationId: string; |
| 10 | + private _configKey: string; |
| 11 | + private _context: LDContext; |
| 12 | + |
| 13 | + constructor(ldClient: LDClient, configKey: string, versionId: string, context: LDContext) { |
| 14 | + this._ldClient = ldClient; |
| 15 | + this._variationId = versionId; |
| 16 | + this._configKey = configKey; |
| 17 | + this._context = context; |
| 18 | + } |
| 19 | + |
| 20 | + private _getTrackData(): { variationId: string; configKey: string } { |
| 21 | + return { |
| 22 | + variationId: this._variationId, |
| 23 | + configKey: this._configKey, |
| 24 | + }; |
| 25 | + } |
| 26 | + |
| 27 | + trackDuration(duration: number): void { |
| 28 | + this._ldClient.track('$ld:ai:duration:total', this._context, this._getTrackData(), duration); |
| 29 | + } |
| 30 | + |
| 31 | + async trackDurationOf(func: (...args: any[]) => Promise<any>, ...args: any[]): Promise<any> { |
| 32 | + const startTime = Date.now(); |
| 33 | + const result = await func(...args); |
| 34 | + const endTime = Date.now(); |
| 35 | + const duration = endTime - startTime; // duration in milliseconds |
| 36 | + this.trackDuration(duration); |
| 37 | + return result; |
| 38 | + } |
| 39 | + |
| 40 | + trackError(error: number): void { |
| 41 | + this._ldClient.track('$ld:ai:error', this._context, this._getTrackData(), error); |
| 42 | + } |
| 43 | + |
| 44 | + trackFeedback(feedback: { kind: FeedbackKind }): void { |
| 45 | + if (feedback.kind === FeedbackKind.Positive) { |
| 46 | + this._ldClient.track('$ld:ai:feedback:user:positive', this._context, this._getTrackData(), 1); |
| 47 | + } else if (feedback.kind === FeedbackKind.Negative) { |
| 48 | + this._ldClient.track('$ld:ai:feedback:user:negative', this._context, this._getTrackData(), 1); |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + trackGeneration(generation: number): void { |
| 53 | + this._ldClient.track('$ld:ai:generation', this._context, this._getTrackData(), generation); |
| 54 | + } |
| 55 | + |
| 56 | + async trackOpenAI(func: (...args: any[]) => Promise<any>, ...args: any[]): Promise<any> { |
| 57 | + const result = await this.trackDurationOf(func, ...args); |
| 58 | + this.trackGeneration(1); |
| 59 | + if (result.usage) { |
| 60 | + this.trackTokens(createOpenAiUsage(result.usage)); |
| 61 | + } |
| 62 | + return result; |
| 63 | + } |
| 64 | + |
| 65 | + async trackBedrockConverse(res: { |
| 66 | + $metadata?: { httpStatusCode: number }; |
| 67 | + metrics?: { latencyMs: number }; |
| 68 | + usage?: { |
| 69 | + inputTokens: number; |
| 70 | + outputTokens: number; |
| 71 | + totalTokens: number; |
| 72 | + }; |
| 73 | + }): Promise<any> { |
| 74 | + if (res.$metadata?.httpStatusCode === 200) { |
| 75 | + this.trackGeneration(1); |
| 76 | + } else if (res.$metadata?.httpStatusCode && res.$metadata.httpStatusCode >= 400) { |
| 77 | + this.trackError(res.$metadata.httpStatusCode); |
| 78 | + } |
| 79 | + if (res.metrics) { |
| 80 | + this.trackDuration(res.metrics.latencyMs); |
| 81 | + } |
| 82 | + if (res.usage) { |
| 83 | + this.trackTokens(createBedrockTokenUsage(res.usage)); |
| 84 | + } |
| 85 | + return res; |
| 86 | + } |
| 87 | + |
| 88 | + trackTokens(tokens: TokenUsage): void { |
| 89 | + const trackData = this._getTrackData(); |
| 90 | + if (tokens.total > 0) { |
| 91 | + this._ldClient.track('$ld:ai:tokens:total', this._context, trackData, tokens.total); |
| 92 | + } |
| 93 | + if (tokens.input > 0) { |
| 94 | + this._ldClient.track('$ld:ai:tokens:input', this._context, trackData, tokens.input); |
| 95 | + } |
| 96 | + if (tokens.output > 0) { |
| 97 | + this._ldClient.track('$ld:ai:tokens:output', this._context, trackData, tokens.output); |
| 98 | + } |
| 99 | + } |
| 100 | +} |
0 commit comments