@arizeai/openinference-instrumentation-openai 0.0.2 → 0.0.4
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.
- package/README.md +2 -2
- package/dist/esm/instrumentation.d.ts.map +1 -1
- package/dist/esm/instrumentation.js +107 -10
- package/dist/esm/instrumentation.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esnext/instrumentation.d.ts.map +1 -1
- package/dist/esnext/instrumentation.js +102 -10
- package/dist/esnext/instrumentation.js.map +1 -1
- package/dist/esnext/tsconfig.esnext.tsbuildinfo +1 -1
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/src/instrumentation.d.ts.map +1 -1
- package/dist/src/instrumentation.js +102 -10
- package/dist/src/instrumentation.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/test/openai.test.js +46 -15
- package/dist/test/openai.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -2
- package/src/instrumentation.ts +297 -166
- package/src/version.ts +1 -1
package/package.json
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arizeai/openinference-instrumentation-openai",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "OpenInference instrumentation for OpenAI",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "dist/src/index.js",
|
|
7
7
|
"module": "dist/esm/index.js",
|
|
8
8
|
"esnext": "dist/esnext/index.js",
|
|
9
9
|
"types": "dist/src/index.d.ts",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/Arize-ai/openinference.git"
|
|
13
|
+
},
|
|
10
14
|
"dependencies": {
|
|
11
15
|
"@opentelemetry/api": "^1.7.0",
|
|
12
16
|
"@opentelemetry/instrumentation": "^0.46.0",
|
|
13
|
-
"@arizeai/openinference-semantic-conventions": "0.0.
|
|
17
|
+
"@arizeai/openinference-semantic-conventions": "0.0.13"
|
|
14
18
|
},
|
|
15
19
|
"keywords": [],
|
|
16
20
|
"files": [
|
|
@@ -30,6 +34,7 @@
|
|
|
30
34
|
"prebuild": "rimraf dist & pnpm run version:update",
|
|
31
35
|
"build": "tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json",
|
|
32
36
|
"version:update": "../../scripts/version-update.js",
|
|
37
|
+
"type:check": "tsc --noEmit",
|
|
33
38
|
"test": "jest ."
|
|
34
39
|
}
|
|
35
40
|
}
|
package/src/instrumentation.ts
CHANGED
|
@@ -1,209 +1,340 @@
|
|
|
1
1
|
import * as openai from "openai";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
InstrumentationBase,
|
|
4
|
+
InstrumentationConfig,
|
|
5
|
+
InstrumentationModuleDefinition,
|
|
6
|
+
InstrumentationNodeModuleDefinition,
|
|
7
|
+
safeExecuteInTheMiddle,
|
|
8
8
|
} from "@opentelemetry/instrumentation";
|
|
9
9
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
diag,
|
|
11
|
+
context,
|
|
12
|
+
trace,
|
|
13
|
+
SpanKind,
|
|
14
|
+
Attributes,
|
|
15
|
+
SpanStatusCode,
|
|
16
16
|
} from "@opentelemetry/api";
|
|
17
17
|
import { VERSION } from "./version";
|
|
18
18
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
SemanticConventions,
|
|
20
|
+
OpenInferenceSpanKind,
|
|
21
|
+
MimeType,
|
|
22
22
|
} from "@arizeai/openinference-semantic-conventions";
|
|
23
23
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
ChatCompletion,
|
|
25
|
+
ChatCompletionChunk,
|
|
26
|
+
ChatCompletionCreateParamsBase,
|
|
27
27
|
} from "openai/resources/chat/completions";
|
|
28
28
|
import { Stream } from "openai/streaming";
|
|
29
|
+
import {
|
|
30
|
+
CreateEmbeddingResponse,
|
|
31
|
+
EmbeddingCreateParams,
|
|
32
|
+
} from "openai/resources";
|
|
29
33
|
|
|
30
34
|
const MODULE_NAME = "openai";
|
|
31
35
|
|
|
32
36
|
export class OpenAIInstrumentation extends InstrumentationBase<typeof openai> {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
constructor(config?: InstrumentationConfig) {
|
|
38
|
+
super(
|
|
39
|
+
"@arizeai/openinference-instrumentation-openai",
|
|
40
|
+
VERSION,
|
|
41
|
+
Object.assign({}, config),
|
|
42
|
+
);
|
|
43
|
+
}
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
protected init(): InstrumentationModuleDefinition<typeof openai> {
|
|
46
|
+
const module = new InstrumentationNodeModuleDefinition<typeof openai>(
|
|
47
|
+
"openai",
|
|
48
|
+
["^4.0.0"],
|
|
49
|
+
this.patch.bind(this),
|
|
50
|
+
this.unpatch.bind(this),
|
|
51
|
+
);
|
|
52
|
+
return module;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Patches the OpenAI module
|
|
56
|
+
*/
|
|
57
|
+
private patch(
|
|
58
|
+
module: typeof openai & { openInferencePatched?: boolean },
|
|
59
|
+
moduleVersion?: string,
|
|
60
|
+
) {
|
|
61
|
+
diag.debug(`Applying patch for ${MODULE_NAME}@${moduleVersion}`);
|
|
62
|
+
if (module?.openInferencePatched) {
|
|
63
|
+
return module;
|
|
49
64
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
module: typeof openai & { openInferencePatched?: boolean },
|
|
55
|
-
moduleVersion?: string
|
|
56
|
-
) {
|
|
57
|
-
diag.debug(`Applying patch for ${MODULE_NAME}@${moduleVersion}`);
|
|
58
|
-
if (module?.openInferencePatched) {
|
|
59
|
-
return module;
|
|
60
|
-
}
|
|
61
|
-
const instrumentation: OpenAIInstrumentation = this;
|
|
62
|
-
type CompletionCreateType =
|
|
63
|
-
typeof module.OpenAI.Chat.Completions.prototype.create;
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
66
|
+
const instrumentation: OpenAIInstrumentation = this;
|
|
67
|
+
type CompletionCreateType =
|
|
68
|
+
typeof module.OpenAI.Chat.Completions.prototype.create;
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
70
|
+
// Patch create chat completions
|
|
71
|
+
this._wrap(
|
|
72
|
+
module.OpenAI.Chat.Completions.prototype,
|
|
73
|
+
"create",
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
|
+
(original: CompletionCreateType): any => {
|
|
76
|
+
return function patchedCreate(
|
|
77
|
+
this: unknown,
|
|
78
|
+
...args: Parameters<
|
|
79
|
+
typeof module.OpenAI.Chat.Completions.prototype.create
|
|
80
|
+
>
|
|
81
|
+
) {
|
|
82
|
+
const body = args[0];
|
|
83
|
+
const { messages: _messages, ...invocationParameters } = body;
|
|
84
|
+
const span = instrumentation.tracer.startSpan(
|
|
85
|
+
`OpenAI Chat Completions`,
|
|
86
|
+
{
|
|
87
|
+
kind: SpanKind.INTERNAL,
|
|
88
|
+
attributes: {
|
|
89
|
+
[SemanticConventions.OPENINFERENCE_SPAN_KIND]:
|
|
90
|
+
OpenInferenceSpanKind.LLM,
|
|
91
|
+
[SemanticConventions.LLM_MODEL_NAME]: body.model,
|
|
92
|
+
[SemanticConventions.INPUT_VALUE]: JSON.stringify(body),
|
|
93
|
+
[SemanticConventions.INPUT_MIME_TYPE]: MimeType.JSON,
|
|
94
|
+
[SemanticConventions.LLM_INVOCATION_PARAMETERS]:
|
|
95
|
+
JSON.stringify(invocationParameters),
|
|
96
|
+
...getLLMInputMessagesAttributes(body),
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
const execContext = trace.setSpan(context.active(), span);
|
|
101
|
+
const execPromise = safeExecuteInTheMiddle<
|
|
102
|
+
ReturnType<CompletionCreateType>
|
|
103
|
+
>(
|
|
104
|
+
() => {
|
|
105
|
+
return context.with(execContext, () => {
|
|
106
|
+
return original.apply(this, args);
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
(error) => {
|
|
110
|
+
// Push the error to the span
|
|
111
|
+
if (error) {
|
|
112
|
+
span.recordException(error);
|
|
113
|
+
span.setStatus({
|
|
114
|
+
code: SpanStatusCode.ERROR,
|
|
115
|
+
message: error.message,
|
|
116
|
+
});
|
|
117
|
+
span.end();
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
);
|
|
121
|
+
const wrappedPromise = execPromise.then((result) => {
|
|
122
|
+
if (result) {
|
|
123
|
+
// Record the results
|
|
124
|
+
span.setAttributes({
|
|
125
|
+
[SemanticConventions.OUTPUT_VALUE]: JSON.stringify(result),
|
|
126
|
+
[SemanticConventions.OUTPUT_MIME_TYPE]: MimeType.JSON,
|
|
127
|
+
// Override the model from the value sent by the server
|
|
128
|
+
[SemanticConventions.LLM_MODEL_NAME]: isChatCompletionResponse(
|
|
129
|
+
result,
|
|
130
|
+
)
|
|
131
|
+
? result.model
|
|
132
|
+
: body.model,
|
|
133
|
+
...getLLMOutputMessagesAttributes(result),
|
|
134
|
+
...getUsageAttributes(result),
|
|
135
|
+
});
|
|
131
136
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
138
|
+
span.end();
|
|
139
|
+
return result;
|
|
140
|
+
});
|
|
141
|
+
return context.bind(execContext, wrappedPromise);
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// Patch embeddings
|
|
147
|
+
type EmbeddingsCreateType =
|
|
148
|
+
typeof module.OpenAI.Embeddings.prototype.create;
|
|
149
|
+
this._wrap(
|
|
150
|
+
module.OpenAI.Embeddings.prototype,
|
|
151
|
+
"create",
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
153
|
+
(original: EmbeddingsCreateType): any => {
|
|
154
|
+
return function patchedEmbeddingCreate(
|
|
155
|
+
this: unknown,
|
|
156
|
+
...args: Parameters<typeof module.OpenAI.Embeddings.prototype.create>
|
|
157
|
+
) {
|
|
158
|
+
const body = args[0];
|
|
159
|
+
const { input } = body;
|
|
160
|
+
const isStringInput = typeof input == "string";
|
|
161
|
+
const span = instrumentation.tracer.startSpan(`OpenAI Embeddings`, {
|
|
162
|
+
kind: SpanKind.INTERNAL,
|
|
163
|
+
attributes: {
|
|
164
|
+
[SemanticConventions.OPENINFERENCE_SPAN_KIND]:
|
|
165
|
+
OpenInferenceSpanKind.EMBEDDING,
|
|
166
|
+
[SemanticConventions.EMBEDDING_MODEL_NAME]: body.model,
|
|
167
|
+
[SemanticConventions.INPUT_VALUE]: isStringInput
|
|
168
|
+
? input
|
|
169
|
+
: JSON.stringify(input),
|
|
170
|
+
[SemanticConventions.INPUT_MIME_TYPE]: isStringInput
|
|
171
|
+
? MimeType.TEXT
|
|
172
|
+
: MimeType.JSON,
|
|
173
|
+
...getEmbeddingTextAttributes(body),
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
const execContext = trace.setSpan(context.active(), span);
|
|
177
|
+
const execPromise = safeExecuteInTheMiddle<
|
|
178
|
+
ReturnType<EmbeddingsCreateType>
|
|
179
|
+
>(
|
|
180
|
+
() => {
|
|
181
|
+
return context.with(execContext, () => {
|
|
182
|
+
return original.apply(this, args);
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
(error) => {
|
|
186
|
+
// Push the error to the span
|
|
187
|
+
if (error) {
|
|
188
|
+
span.recordException(error);
|
|
189
|
+
span.setStatus({
|
|
190
|
+
code: SpanStatusCode.ERROR,
|
|
191
|
+
message: error.message,
|
|
192
|
+
});
|
|
193
|
+
span.end();
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
);
|
|
197
|
+
const wrappedPromise = execPromise.then((result) => {
|
|
198
|
+
if (result) {
|
|
199
|
+
// Record the results
|
|
200
|
+
span.setAttributes({
|
|
201
|
+
// Do not record the output data as it can be large
|
|
202
|
+
...getEmbeddingEmbeddingsAttributes(result),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
206
|
+
span.end();
|
|
207
|
+
return result;
|
|
208
|
+
});
|
|
209
|
+
return context.bind(execContext, wrappedPromise);
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
module.openInferencePatched = true;
|
|
215
|
+
return module;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Un-patches the OpenAI module's chat completions API
|
|
219
|
+
*/
|
|
220
|
+
private unpatch(moduleExports: typeof openai, moduleVersion?: string) {
|
|
221
|
+
diag.debug(`Removing patch for ${MODULE_NAME}@${moduleVersion}`);
|
|
222
|
+
this._unwrap(moduleExports.OpenAI.Chat.Completions.prototype, "create");
|
|
223
|
+
this._unwrap(moduleExports.OpenAI.Embeddings.prototype, "create");
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* type-guard that checks if the response is a chat completion response
|
|
229
|
+
*/
|
|
230
|
+
function isChatCompletionResponse(
|
|
231
|
+
response: Stream<ChatCompletionChunk> | ChatCompletion,
|
|
232
|
+
): response is ChatCompletion {
|
|
233
|
+
return "choices" in response;
|
|
143
234
|
}
|
|
144
235
|
|
|
145
236
|
/**
|
|
146
237
|
* Converts the body of the request to LLM input messages
|
|
147
238
|
*/
|
|
148
239
|
function getLLMInputMessagesAttributes(
|
|
149
|
-
|
|
240
|
+
body: ChatCompletionCreateParamsBase,
|
|
150
241
|
): Attributes {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
242
|
+
return body.messages.reduce((acc, message, index) => {
|
|
243
|
+
const index_prefix = `${SemanticConventions.LLM_INPUT_MESSAGES}.${index}`;
|
|
244
|
+
acc[`${index_prefix}.${SemanticConventions.MESSAGE_CONTENT}`] = String(
|
|
245
|
+
message.content,
|
|
246
|
+
);
|
|
247
|
+
acc[`${index_prefix}.${SemanticConventions.MESSAGE_ROLE}`] = String(
|
|
248
|
+
message.role,
|
|
249
|
+
);
|
|
250
|
+
return acc;
|
|
251
|
+
}, {} as Attributes);
|
|
161
252
|
}
|
|
162
253
|
|
|
163
254
|
/**
|
|
164
255
|
* Get Usage attributes
|
|
165
256
|
*/
|
|
166
257
|
function getUsageAttributes(
|
|
167
|
-
|
|
258
|
+
response: Stream<ChatCompletionChunk> | ChatCompletion,
|
|
168
259
|
) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
260
|
+
if (Object.prototype.hasOwnProperty.call(response, "usage")) {
|
|
261
|
+
const completion = response as ChatCompletion;
|
|
262
|
+
if (completion.usage) {
|
|
263
|
+
return {
|
|
264
|
+
[SemanticConventions.LLM_TOKEN_COUNT_COMPLETION]:
|
|
265
|
+
completion.usage.completion_tokens,
|
|
266
|
+
[SemanticConventions.LLM_TOKEN_COUNT_PROMPT]:
|
|
267
|
+
completion.usage.prompt_tokens,
|
|
268
|
+
[SemanticConventions.LLM_TOKEN_COUNT_TOTAL]:
|
|
269
|
+
completion.usage.total_tokens,
|
|
270
|
+
};
|
|
181
271
|
}
|
|
182
|
-
|
|
272
|
+
}
|
|
273
|
+
return {};
|
|
183
274
|
}
|
|
184
275
|
|
|
185
276
|
/**
|
|
186
277
|
* Converts the result to LLM output attributes
|
|
187
278
|
*/
|
|
188
279
|
function getLLMOutputMessagesAttributes(
|
|
189
|
-
|
|
280
|
+
response: Stream<ChatCompletionChunk> | ChatCompletion,
|
|
190
281
|
): Attributes {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
return [choice.message].reduce((acc, message, index) => {
|
|
200
|
-
const index_prefix = `${SemanticConventions.LLM_OUTPUT_MESSAGES}.${index}`;
|
|
201
|
-
acc[`${index_prefix}.${SemanticConventions.MESSAGE_CONTENT}`] =
|
|
202
|
-
String(message.content);
|
|
203
|
-
acc[`${index_prefix}.${SemanticConventions.MESSAGE_ROLE}`] =
|
|
204
|
-
message.role;
|
|
205
|
-
return acc;
|
|
206
|
-
}, {} as Attributes);
|
|
282
|
+
// Handle chat completion
|
|
283
|
+
if (Object.prototype.hasOwnProperty.call(response, "choices")) {
|
|
284
|
+
const completion = response as ChatCompletion;
|
|
285
|
+
// Right now support just the first choice
|
|
286
|
+
const choice = completion.choices[0];
|
|
287
|
+
if (!choice) {
|
|
288
|
+
return {};
|
|
207
289
|
}
|
|
208
|
-
return {
|
|
290
|
+
return [choice.message].reduce((acc, message, index) => {
|
|
291
|
+
const index_prefix = `${SemanticConventions.LLM_OUTPUT_MESSAGES}.${index}`;
|
|
292
|
+
acc[`${index_prefix}.${SemanticConventions.MESSAGE_CONTENT}`] = String(
|
|
293
|
+
message.content,
|
|
294
|
+
);
|
|
295
|
+
acc[`${index_prefix}.${SemanticConventions.MESSAGE_ROLE}`] = message.role;
|
|
296
|
+
return acc;
|
|
297
|
+
}, {} as Attributes);
|
|
298
|
+
}
|
|
299
|
+
return {};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Converts the embedding result payload to embedding attributes
|
|
304
|
+
*/
|
|
305
|
+
function getEmbeddingTextAttributes(
|
|
306
|
+
request: EmbeddingCreateParams,
|
|
307
|
+
): Attributes {
|
|
308
|
+
if (typeof request.input == "string") {
|
|
309
|
+
return {
|
|
310
|
+
[`${SemanticConventions.EMBEDDING_EMBEDDINGS}.0.${SemanticConventions.EMBEDDING_TEXT}`]:
|
|
311
|
+
request.input,
|
|
312
|
+
};
|
|
313
|
+
} else if (
|
|
314
|
+
Array.isArray(request.input) &&
|
|
315
|
+
request.input.length > 0 &&
|
|
316
|
+
typeof request.input[0] == "string"
|
|
317
|
+
) {
|
|
318
|
+
return request.input.reduce((acc, input, index) => {
|
|
319
|
+
const index_prefix = `${SemanticConventions.EMBEDDING_EMBEDDINGS}.${index}`;
|
|
320
|
+
acc[`${index_prefix}.${SemanticConventions.EMBEDDING_TEXT}`] = input;
|
|
321
|
+
return acc;
|
|
322
|
+
}, {} as Attributes);
|
|
323
|
+
}
|
|
324
|
+
// Ignore other cases where input is a number or an array of numbers
|
|
325
|
+
return {};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Converts the embedding result payload to embedding attributes
|
|
330
|
+
*/
|
|
331
|
+
function getEmbeddingEmbeddingsAttributes(
|
|
332
|
+
response: CreateEmbeddingResponse,
|
|
333
|
+
): Attributes {
|
|
334
|
+
return response.data.reduce((acc, embedding, index) => {
|
|
335
|
+
const index_prefix = `${SemanticConventions.EMBEDDING_EMBEDDINGS}.${index}`;
|
|
336
|
+
acc[`${index_prefix}.${SemanticConventions.EMBEDDING_VECTOR}`] =
|
|
337
|
+
embedding.embedding;
|
|
338
|
+
return acc;
|
|
339
|
+
}, {} as Attributes);
|
|
209
340
|
}
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// this is an auto-generated file. see js/scripts/version-update.js
|
|
2
|
-
export const VERSION = "0.0.
|
|
2
|
+
export const VERSION = "0.0.4";
|