openlit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,658 @@
1
+ import { Span, SpanKind, SpanStatusCode, Tracer, context, trace } from '@opentelemetry/api';
2
+ import OpenlitConfig from '../../config';
3
+ import OpenLitHelper from '../../helpers';
4
+ import SemanticConvention from '../../semantic-convention';
5
+ import { SDK_NAME, TELEMETRY_SDK_NAME } from '../../constant';
6
+
7
+ export default class OpenAIWrapper {
8
+ static setBaseSpanAttributes(
9
+ span: any,
10
+ { genAIEndpoint, model, user, cost, environment, applicationName }: any
11
+ ) {
12
+ span.setAttributes({
13
+ [TELEMETRY_SDK_NAME]: SDK_NAME,
14
+ });
15
+
16
+ span.setAttribute(TELEMETRY_SDK_NAME, SDK_NAME);
17
+ span.setAttribute(SemanticConvention.GEN_AI_SYSTEM, SemanticConvention.GEN_AI_SYSTEM_OPENAI);
18
+ span.setAttribute(SemanticConvention.GEN_AI_ENDPOINT, genAIEndpoint);
19
+ span.setAttribute(SemanticConvention.GEN_AI_ENVIRONMENT, environment);
20
+ span.setAttribute(SemanticConvention.GEN_AI_APPLICATION_NAME, applicationName);
21
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_MODEL, model);
22
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_USER, user);
23
+ if (cost !== undefined) span.setAttribute(SemanticConvention.GEN_AI_USAGE_COST, cost);
24
+
25
+ span.setStatus({ code: SpanStatusCode.OK });
26
+ }
27
+
28
+ static _patchChatCompletionCreate(tracer: Tracer): any {
29
+ const genAIEndpoint = 'openai.resources.chat.completions';
30
+ return (originalMethod: (...args: any[]) => any) => {
31
+ return async function (this: any, ...args: any[]) {
32
+ const span = tracer.startSpan(genAIEndpoint, { kind: SpanKind.CLIENT });
33
+ return context
34
+ .with(trace.setSpan(context.active(), span), async () => {
35
+ return originalMethod.apply(this, args);
36
+ })
37
+ .then((response) => {
38
+ const { stream = false } = args[0];
39
+
40
+ if (!!stream) {
41
+ return OpenLitHelper.createStreamProxy(
42
+ response,
43
+ OpenAIWrapper._chatCompletionGenerator({
44
+ args,
45
+ genAIEndpoint,
46
+ response,
47
+ span,
48
+ })
49
+ );
50
+ }
51
+
52
+ return OpenAIWrapper._chatCompletion({ args, genAIEndpoint, response, span });
53
+ })
54
+ .catch((e: any) => {
55
+ OpenLitHelper.handleException(span, e);
56
+ span.end();
57
+ });
58
+ };
59
+ };
60
+ }
61
+
62
+ static async _chatCompletion({
63
+ args,
64
+ genAIEndpoint,
65
+ response,
66
+ span,
67
+ }: {
68
+ args: any[];
69
+ genAIEndpoint: string;
70
+ response: any;
71
+ span: Span;
72
+ }): Promise<any> {
73
+ try {
74
+ await OpenAIWrapper._chatCompletionCommonSetter({
75
+ args,
76
+ genAIEndpoint,
77
+ result: response,
78
+ span,
79
+ });
80
+ return response;
81
+ } catch (e: any) {
82
+ OpenLitHelper.handleException(span, e);
83
+ } finally {
84
+ span.end();
85
+ }
86
+ }
87
+
88
+ static async *_chatCompletionGenerator({
89
+ args,
90
+ genAIEndpoint,
91
+ response,
92
+ span,
93
+ }: {
94
+ args: any[];
95
+ genAIEndpoint: string;
96
+ response: any;
97
+ span: Span;
98
+ }): AsyncGenerator<unknown, any, unknown> {
99
+ try {
100
+ const { messages } = args[0];
101
+ let { tools } = args[0];
102
+ const result = {
103
+ id: '0',
104
+ created: -1,
105
+ model: '',
106
+ choices: [
107
+ {
108
+ index: 0,
109
+ logprobs: null,
110
+ finish_reason: 'stop',
111
+ message: { role: 'assistant', content: '' },
112
+ },
113
+ ],
114
+ usage: {
115
+ prompt_tokens: 0,
116
+ completion_tokens: 0,
117
+ total_tokens: 0,
118
+ },
119
+ };
120
+ for await (const chunk of response) {
121
+ result.id = chunk.id;
122
+ result.created = chunk.created;
123
+ result.model = chunk.model;
124
+
125
+ if (chunk.choices[0]?.finish_reason) {
126
+ result.choices[0].finish_reason = chunk.choices[0].finish_reason;
127
+ }
128
+ if (chunk.choices[0]?.logprobs) {
129
+ result.choices[0].logprobs = chunk.choices[0].logprobs;
130
+ }
131
+ if (chunk.choices[0]?.delta.content) {
132
+ result.choices[0].message.content += chunk.choices[0].delta.content;
133
+ }
134
+
135
+ if (chunk.choices[0]?.delta.tool_calls) {
136
+ tools = true;
137
+ }
138
+
139
+ yield chunk;
140
+ }
141
+
142
+ let promptTokens = 0;
143
+ for (const message of messages || []) {
144
+ promptTokens += OpenLitHelper.openaiTokens(message.content as string, result.model) ?? 0;
145
+ }
146
+
147
+ const completionTokens = OpenLitHelper.openaiTokens(
148
+ result.choices[0].message.content ?? '',
149
+ result.model
150
+ );
151
+ if (completionTokens) {
152
+ result.usage = {
153
+ prompt_tokens: promptTokens,
154
+ completion_tokens: completionTokens,
155
+ total_tokens: promptTokens + completionTokens,
156
+ };
157
+ }
158
+
159
+ args[0].tools = tools;
160
+
161
+ await OpenAIWrapper._chatCompletionCommonSetter({
162
+ args,
163
+ genAIEndpoint,
164
+ result,
165
+ span,
166
+ });
167
+
168
+ return result;
169
+ } catch (e: any) {
170
+ OpenLitHelper.handleException(span, e);
171
+ } finally {
172
+ span.end();
173
+ }
174
+ }
175
+
176
+ static async _chatCompletionCommonSetter({
177
+ args,
178
+ genAIEndpoint,
179
+ result,
180
+ span,
181
+ }: {
182
+ args: any[];
183
+ genAIEndpoint: string;
184
+ result: any;
185
+ span: Span;
186
+ }) {
187
+ const applicationName = OpenlitConfig.applicationName;
188
+ const environment = OpenlitConfig.environment;
189
+ const traceContent = OpenlitConfig.traceContent;
190
+ const {
191
+ messages,
192
+ frequency_penalty = 0,
193
+ max_tokens = null,
194
+ n = 1,
195
+ presence_penalty = 0,
196
+ seed = null,
197
+ temperature = 1,
198
+ top_p,
199
+ user,
200
+ stream = false,
201
+ tools,
202
+ } = args[0];
203
+
204
+ // Request Params attributes : Start
205
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_TOP_P, top_p || 1);
206
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_MAX_TOKENS, max_tokens);
207
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_TEMPERATURE, temperature);
208
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_PRESENCE_PENALTY, presence_penalty);
209
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_FREQUENCY_PENALTY, frequency_penalty);
210
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_SEED, seed);
211
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_IS_STREAM, stream);
212
+
213
+ if (traceContent) {
214
+ // Format 'messages' into a single string
215
+ const messagePrompt = messages || [];
216
+ const formattedMessages = [];
217
+
218
+ for (const message of messagePrompt) {
219
+ const role = message.role;
220
+ const content = message.content;
221
+
222
+ if (Array.isArray(content)) {
223
+ const contentStr = content
224
+ .map((item) => {
225
+ if ('type' in item) {
226
+ return `${item.type}: ${item.text ? item.text : item.image_url}`;
227
+ } else {
228
+ return `text: ${item.text}`;
229
+ }
230
+ })
231
+ .join(', ');
232
+ formattedMessages.push(`${role}: ${contentStr}`);
233
+ } else {
234
+ formattedMessages.push(`${role}: ${content}`);
235
+ }
236
+ }
237
+
238
+ const prompt = formattedMessages.join('\n');
239
+ span.setAttribute(SemanticConvention.GEN_AI_CONTENT_PROMPT, prompt);
240
+ }
241
+ // Request Params attributes : End
242
+
243
+ span.setAttribute(SemanticConvention.GEN_AI_TYPE, SemanticConvention.GEN_AI_TYPE_CHAT);
244
+
245
+ span.setAttribute(SemanticConvention.GEN_AI_RESPONSE_ID, result.id);
246
+
247
+ const model = result.model || 'gpt-3.5-turbo';
248
+
249
+ const pricingInfo = await OpenlitConfig.updatePricingJson(OpenlitConfig.pricing_json);
250
+
251
+ // Calculate cost of the operation
252
+ const cost = OpenLitHelper.getChatModelCost(
253
+ model,
254
+ pricingInfo,
255
+ result.usage.prompt_tokens,
256
+ result.usage.completion_tokens
257
+ );
258
+
259
+ OpenAIWrapper.setBaseSpanAttributes(span, {
260
+ genAIEndpoint,
261
+ model,
262
+ user,
263
+ cost,
264
+ applicationName,
265
+ environment,
266
+ });
267
+
268
+ span.setAttribute(SemanticConvention.GEN_AI_USAGE_PROMPT_TOKENS, result.usage.prompt_tokens);
269
+ span.setAttribute(
270
+ SemanticConvention.GEN_AI_USAGE_COMPLETION_TOKENS,
271
+ result.usage.completion_tokens
272
+ );
273
+ span.setAttribute(SemanticConvention.GEN_AI_USAGE_TOTAL_TOKENS, result.usage.total_tokens);
274
+
275
+ if (result.choices[0].finish_reason) {
276
+ span.setAttribute(
277
+ SemanticConvention.GEN_AI_RESPONSE_FINISH_REASON,
278
+ result.choices[0].finish_reason
279
+ );
280
+ }
281
+
282
+ if (tools) {
283
+ span.setAttribute(SemanticConvention.GEN_AI_CONTENT_COMPLETION, 'Function called with tools');
284
+ } else {
285
+ if (traceContent) {
286
+ if (n === 1) {
287
+ span.setAttribute(
288
+ SemanticConvention.GEN_AI_CONTENT_COMPLETION,
289
+ result.choices[0].message.content
290
+ );
291
+ } else {
292
+ let i = 0;
293
+ while (i < n) {
294
+ const attribute_name = `${SemanticConvention.GEN_AI_CONTENT_COMPLETION}.[i]`;
295
+ span.setAttribute(attribute_name, result.choices[i].message.content);
296
+ i += 1;
297
+ }
298
+ }
299
+ }
300
+ }
301
+ }
302
+
303
+ static _patchEmbedding(tracer: Tracer): any {
304
+ const genAIEndpoint = 'openai.resources.embeddings';
305
+ const applicationName = OpenlitConfig.applicationName;
306
+ const environment = OpenlitConfig.environment;
307
+ const traceContent = OpenlitConfig.traceContent;
308
+
309
+ return (originalMethod: (...args: any[]) => any) => {
310
+ return async function (this: any, ...args: any[]) {
311
+ const span = tracer.startSpan(genAIEndpoint, { kind: SpanKind.CLIENT });
312
+ return context.with(trace.setSpan(context.active(), span), async () => {
313
+ try {
314
+ const response = await originalMethod.apply(this, args);
315
+ span.setAttributes({
316
+ [TELEMETRY_SDK_NAME]: SDK_NAME,
317
+ });
318
+
319
+ const model = response.model || 'text-embedding-ada-002';
320
+ const pricingInfo = await OpenlitConfig.updatePricingJson(OpenlitConfig.pricing_json);
321
+ const cost = OpenLitHelper.getEmbedModelCost(
322
+ model,
323
+ pricingInfo,
324
+ response.usage.prompt_tokens
325
+ );
326
+
327
+ span.setAttribute(
328
+ SemanticConvention.GEN_AI_TYPE,
329
+ SemanticConvention.GEN_AI_TYPE_EMBEDDING
330
+ );
331
+
332
+ const { dimensions, encoding_format = 'float', input, user } = args[0];
333
+ // Set base span attribues
334
+ OpenAIWrapper.setBaseSpanAttributes(span, {
335
+ genAIEndpoint,
336
+ model,
337
+ user,
338
+ cost,
339
+ applicationName,
340
+ environment,
341
+ });
342
+
343
+ // Request Params attributes : Start
344
+
345
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_EMBEDDING_FORMAT, encoding_format);
346
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_EMBEDDING_DIMENSION, dimensions);
347
+ if (traceContent) {
348
+ span.setAttribute(SemanticConvention.GEN_AI_CONTENT_PROMPT, input);
349
+ }
350
+ // Request Params attributes : End
351
+
352
+ span.setAttribute(
353
+ SemanticConvention.GEN_AI_USAGE_PROMPT_TOKENS,
354
+ response.usage.prompt_tokens
355
+ );
356
+ span.setAttribute(
357
+ SemanticConvention.GEN_AI_USAGE_TOTAL_TOKENS,
358
+ response.usage.total_tokens
359
+ );
360
+
361
+ return response;
362
+ } catch (e: any) {
363
+ OpenLitHelper.handleException(span, e);
364
+ } finally {
365
+ span.end();
366
+ }
367
+ });
368
+ };
369
+ };
370
+ }
371
+
372
+ static _patchFineTune(tracer: Tracer): any {
373
+ const genAIEndpoint = 'openai.resources.fine_tuning.jobs';
374
+ const applicationName = OpenlitConfig.applicationName;
375
+ const environment = OpenlitConfig.environment;
376
+
377
+ return (originalMethod: (...args: any[]) => any) => {
378
+ return async function (this: any, ...args: any[]) {
379
+ const span = tracer.startSpan(genAIEndpoint, { kind: SpanKind.CLIENT });
380
+ return context.with(trace.setSpan(context.active(), span), async () => {
381
+ try {
382
+ const response = await originalMethod.apply(this, args);
383
+ span.setAttributes({
384
+ [TELEMETRY_SDK_NAME]: SDK_NAME,
385
+ });
386
+
387
+ const model = response.model || 'gpt-3.5-turbo';
388
+ const {
389
+ hyperparameters = {},
390
+ suffix = '',
391
+ training_file,
392
+ user,
393
+ validation_file,
394
+ } = args[0];
395
+
396
+ // Set base span attribues
397
+ OpenAIWrapper.setBaseSpanAttributes(span, {
398
+ genAIEndpoint,
399
+ model,
400
+ user,
401
+ applicationName,
402
+ environment,
403
+ });
404
+
405
+ span.setAttribute(
406
+ SemanticConvention.GEN_AI_TYPE,
407
+ SemanticConvention.GEN_AI_TYPE_FINETUNING
408
+ );
409
+
410
+ // Request Params attributes : Start
411
+
412
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_TRAINING_FILE, training_file);
413
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_VALIDATION_FILE, validation_file);
414
+ span.setAttribute(
415
+ SemanticConvention.GEN_AI_REQUEST_FINETUNE_BATCH_SIZE,
416
+ hyperparameters?.batch_size || 'auto'
417
+ );
418
+ span.setAttribute(
419
+ SemanticConvention.GEN_AI_REQUEST_FINETUNE_MODEL_LRM,
420
+ hyperparameters?.learning_rate_multiplier || 'auto'
421
+ );
422
+ span.setAttribute(
423
+ SemanticConvention.GEN_AI_REQUEST_FINETUNE_MODEL_EPOCHS,
424
+ hyperparameters?.n_epochs || 'auto'
425
+ );
426
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_FINETUNE_MODEL_SUFFIX, suffix);
427
+ // Request Params attributes : End
428
+
429
+ span.setAttribute(SemanticConvention.GEN_AI_RESPONSE_ID, response.id);
430
+ span.setAttribute(
431
+ SemanticConvention.GEN_AI_USAGE_PROMPT_TOKENS,
432
+ response.usage.prompt_tokens
433
+ );
434
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_FINETUNE_STATUS, response.status);
435
+
436
+ return response;
437
+ } catch (e: any) {
438
+ OpenLitHelper.handleException(span, e);
439
+ } finally {
440
+ span.end();
441
+ }
442
+ });
443
+ };
444
+ };
445
+ }
446
+
447
+ static _patchImageGenerate(tracer: Tracer): any {
448
+ const genAIEndpoint = 'openai.resources.images';
449
+ const applicationName = OpenlitConfig.applicationName;
450
+ const environment = OpenlitConfig.environment;
451
+ const traceContent = OpenlitConfig.traceContent;
452
+ return (originalMethod: (...args: any[]) => any) => {
453
+ return async function (this: any, ...args: any[]) {
454
+ const span = tracer.startSpan(genAIEndpoint, { kind: SpanKind.CLIENT });
455
+ return context.with(trace.setSpan(context.active(), span), async () => {
456
+ try {
457
+ const response = await originalMethod.apply(this, args);
458
+
459
+ const {
460
+ prompt,
461
+ quality = 'standard',
462
+ response_format = 'url',
463
+ size = '1024x1024',
464
+ style = 'vivid',
465
+ user,
466
+ } = args[0];
467
+
468
+ span.setAttribute(SemanticConvention.GEN_AI_TYPE, SemanticConvention.GEN_AI_TYPE_IMAGE);
469
+
470
+ const model = response.model || 'dall-e-2';
471
+
472
+ const pricingInfo = await OpenlitConfig.updatePricingJson(OpenlitConfig.pricing_json);
473
+
474
+ // Calculate cost of the operation
475
+ const cost =
476
+ (response.data?.length || 1) *
477
+ OpenLitHelper.getImageModelCost(model, pricingInfo, size, quality);
478
+
479
+ OpenAIWrapper.setBaseSpanAttributes(span, {
480
+ genAIEndpoint,
481
+ model,
482
+ user,
483
+ cost,
484
+ applicationName,
485
+ environment,
486
+ });
487
+
488
+ // Request Params attributes : Start
489
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_IMAGE_SIZE, size);
490
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_IMAGE_QUALITY, quality);
491
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_IMAGE_STYLE, style);
492
+
493
+ if (traceContent) {
494
+ span.setAttribute(SemanticConvention.GEN_AI_CONTENT_PROMPT, prompt);
495
+ }
496
+ // Request Params attributes : End
497
+
498
+ let imagesCount = 0;
499
+
500
+ if (response.data) {
501
+ for (const items of response.data) {
502
+ span.setAttribute(
503
+ `${SemanticConvention.GEN_AI_CONTENT_REVISED_PROMPT}.${imagesCount}`,
504
+ items.revised_prompt || ''
505
+ );
506
+
507
+ const attributeName = `${SemanticConvention.GEN_AI_RESPONSE_IMAGE}.${imagesCount}`;
508
+ span.setAttribute(attributeName, items[response_format]);
509
+
510
+ imagesCount++;
511
+ }
512
+ }
513
+
514
+ return response;
515
+ } catch (e: any) {
516
+ OpenLitHelper.handleException(span, e);
517
+ } finally {
518
+ span.end();
519
+ }
520
+ });
521
+ };
522
+ };
523
+ }
524
+
525
+ static _patchImageVariation(tracer: Tracer): any {
526
+ const genAIEndpoint = 'openai.resources.images';
527
+ const applicationName = OpenlitConfig.applicationName;
528
+ const environment = OpenlitConfig.environment;
529
+ const traceContent = OpenlitConfig.traceContent;
530
+ return (originalMethod: (...args: any[]) => any) => {
531
+ return async function (this: any, ...args: any[]) {
532
+ const span = tracer.startSpan(genAIEndpoint, { kind: SpanKind.CLIENT });
533
+ return context.with(trace.setSpan(context.active(), span), async () => {
534
+ try {
535
+ const response = await originalMethod.apply(this, args);
536
+
537
+ const {
538
+ prompt,
539
+ quality = 'standard',
540
+ response_format = 'url',
541
+ size = '1024x1024',
542
+ style = 'vivid',
543
+ user,
544
+ } = args[0];
545
+
546
+ span.setAttribute(SemanticConvention.GEN_AI_TYPE, SemanticConvention.GEN_AI_TYPE_IMAGE);
547
+ span.setAttribute(SemanticConvention.GEN_AI_RESPONSE_ID, response.created);
548
+
549
+ const model = response.model || 'dall-e-2';
550
+
551
+ const pricingInfo = await OpenlitConfig.updatePricingJson(OpenlitConfig.pricing_json);
552
+
553
+ // Calculate cost of the operation
554
+ const cost =
555
+ (response.data?.length || 1) *
556
+ OpenLitHelper.getImageModelCost(model, pricingInfo, size, quality);
557
+
558
+ OpenAIWrapper.setBaseSpanAttributes(span, {
559
+ genAIEndpoint,
560
+ model,
561
+ user,
562
+ cost,
563
+ applicationName,
564
+ environment,
565
+ });
566
+
567
+ // Request Params attributes : Start
568
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_IMAGE_SIZE, size);
569
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_IMAGE_QUALITY, quality);
570
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_IMAGE_STYLE, style);
571
+
572
+ if (traceContent) {
573
+ span.setAttribute(SemanticConvention.GEN_AI_CONTENT_PROMPT, prompt);
574
+ }
575
+ // Request Params attributes : End
576
+
577
+ let imagesCount = 0;
578
+ if (response.data) {
579
+ for (const items of response.data) {
580
+ span.setAttribute(
581
+ `${SemanticConvention.GEN_AI_CONTENT_REVISED_PROMPT}.${imagesCount}`,
582
+ items.revised_prompt || ''
583
+ );
584
+
585
+ const attributeName = `${SemanticConvention.GEN_AI_RESPONSE_IMAGE}.${imagesCount}`;
586
+ span.setAttribute(attributeName, items[response_format]);
587
+
588
+ imagesCount++;
589
+ }
590
+ }
591
+
592
+ return response;
593
+ } catch (e: any) {
594
+ OpenLitHelper.handleException(span, e);
595
+ } finally {
596
+ span.end();
597
+ }
598
+ });
599
+ };
600
+ };
601
+ }
602
+
603
+ static _patchAudioCreate(tracer: Tracer): any {
604
+ const genAIEndpoint = 'openai.resources.audio.speech';
605
+ const applicationName = OpenlitConfig.applicationName;
606
+ const environment = OpenlitConfig.environment;
607
+ const traceContent = OpenlitConfig.traceContent;
608
+ return (originalMethod: (...args: any[]) => any) => {
609
+ return async function (this: any, ...args: any[]) {
610
+ const span = tracer.startSpan(genAIEndpoint, { kind: SpanKind.CLIENT });
611
+ return context.with(trace.setSpan(context.active(), span), async () => {
612
+ try {
613
+ const response = await originalMethod.apply(this, args);
614
+
615
+ const { input, user, voice, response_format = 'mp3', speed = 1 } = args[0];
616
+
617
+ span.setAttribute(SemanticConvention.GEN_AI_TYPE, SemanticConvention.GEN_AI_TYPE_AUDIO);
618
+
619
+ const model = response.model || 'tts-1';
620
+
621
+ const pricingInfo = await OpenlitConfig.updatePricingJson(OpenlitConfig.pricing_json);
622
+
623
+ // Calculate cost of the operation
624
+ const cost = OpenLitHelper.getAudioModelCost(model, pricingInfo, input);
625
+
626
+ OpenAIWrapper.setBaseSpanAttributes(span, {
627
+ genAIEndpoint,
628
+ model,
629
+ user,
630
+ cost,
631
+ applicationName,
632
+ environment,
633
+ });
634
+
635
+ // Request Params attributes : Start
636
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_AUDIO_VOICE, voice);
637
+ span.setAttribute(
638
+ SemanticConvention.GEN_AI_REQUEST_AUDIO_RESPONSE_FORMAT,
639
+ response_format
640
+ );
641
+ span.setAttribute(SemanticConvention.GEN_AI_REQUEST_AUDIO_SPEED, speed);
642
+
643
+ if (traceContent) {
644
+ span.setAttribute(SemanticConvention.GEN_AI_CONTENT_PROMPT, input);
645
+ }
646
+ // Request Params attributes : End
647
+
648
+ return response;
649
+ } catch (e: any) {
650
+ OpenLitHelper.handleException(span, e);
651
+ } finally {
652
+ span.end();
653
+ }
654
+ });
655
+ };
656
+ };
657
+ }
658
+ }