openlayer 0.1.4 → 0.1.5
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/dist/index.d.ts +173 -7
- package/dist/index.js +220 -117
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,66 @@
|
|
|
1
1
|
import { RequestOptions } from 'openai/core';
|
|
2
2
|
import { ChatCompletion, ChatCompletionChunk, ChatCompletionCreateParams, Completion, CompletionCreateParams } from 'openai/resources';
|
|
3
3
|
import { Stream } from 'openai/streaming';
|
|
4
|
+
/**
|
|
5
|
+
* Represents the data structure for a chat completion.
|
|
6
|
+
*/
|
|
4
7
|
export interface ChatCompletionData {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
/**
|
|
10
|
+
* The input data for the chat completion. It can be a string, an array of strings,
|
|
11
|
+
* or a nested array of numbers.
|
|
12
|
+
*/
|
|
13
|
+
input: string | string[] | number[] | number[][];
|
|
14
|
+
/**
|
|
15
|
+
* The latency of the chat completion in milliseconds. Optional.
|
|
16
|
+
*/
|
|
17
|
+
latency?: number;
|
|
18
|
+
/**
|
|
19
|
+
* The output string generated by the chat completion.
|
|
20
|
+
*/
|
|
21
|
+
output: string;
|
|
22
|
+
/**
|
|
23
|
+
* A timestamp representing when the chat completion occurred. Optional.
|
|
24
|
+
*/
|
|
25
|
+
timestamp?: number;
|
|
26
|
+
/**
|
|
27
|
+
* The number of tokens used in the chat completion. Optional.
|
|
28
|
+
*/
|
|
9
29
|
tokens?: number;
|
|
10
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Configuration settings for uploading chat completion data to Openlayer.
|
|
33
|
+
*/
|
|
34
|
+
export interface ChatCompletionConfig {
|
|
35
|
+
/**
|
|
36
|
+
* The name of the column that stores the ground truth data. Can be null.
|
|
37
|
+
*/
|
|
38
|
+
groundTruthColumnName: string | null;
|
|
39
|
+
/**
|
|
40
|
+
* The name of the column that stores inference IDs. Can be null.
|
|
41
|
+
*/
|
|
42
|
+
inferenceIdColumnName: string | null;
|
|
43
|
+
/**
|
|
44
|
+
* An array of names for input variable columns. Can be null.
|
|
45
|
+
*/
|
|
46
|
+
inputVariableNames: string[] | null;
|
|
47
|
+
/**
|
|
48
|
+
* The name of the column that stores latency data. Can be null.
|
|
49
|
+
*/
|
|
50
|
+
latencyColumnName: string | null;
|
|
51
|
+
/**
|
|
52
|
+
* The name of the column that stores the number of tokens. Can be null.
|
|
53
|
+
*/
|
|
54
|
+
numOfTokenColumnName: string | null;
|
|
55
|
+
/**
|
|
56
|
+
* The name of the column that stores output data. Can be null.
|
|
57
|
+
*/
|
|
58
|
+
outputColumnName: string | null;
|
|
59
|
+
/**
|
|
60
|
+
* The name of the column that stores timestamp data. Can be null.
|
|
61
|
+
*/
|
|
62
|
+
timestampColumnName: string | null;
|
|
63
|
+
}
|
|
11
64
|
type ConstructorProps = {
|
|
12
65
|
openAiApiKey: string;
|
|
13
66
|
openlayerApiKey?: string;
|
|
@@ -15,10 +68,66 @@ type ConstructorProps = {
|
|
|
15
68
|
openlayerProjectName?: string;
|
|
16
69
|
openlayerServerUrl?: string;
|
|
17
70
|
};
|
|
71
|
+
type OpenlayerInferencePipeline = {
|
|
72
|
+
dataVolumeGraphs?: OpenlayerSampleVolumeGraph;
|
|
73
|
+
dateCreated: string;
|
|
74
|
+
dateLastEvaluated?: string;
|
|
75
|
+
dateLastSampleReceived?: string;
|
|
76
|
+
dateOfNextEvaluation?: string;
|
|
77
|
+
dateUpdated: string;
|
|
78
|
+
description?: string;
|
|
79
|
+
failingGoalCount: number;
|
|
80
|
+
id: string;
|
|
81
|
+
name: string;
|
|
82
|
+
passingGoalCount: number;
|
|
83
|
+
projectId: string;
|
|
84
|
+
status: OpenlayerInferencePipelineStatus;
|
|
85
|
+
statusMessage?: string;
|
|
86
|
+
totalGoalCount: number;
|
|
87
|
+
};
|
|
88
|
+
type OpenlayerInferencePipelineStatus = 'completed' | 'failed' | 'paused' | 'queued' | 'running' | 'unknown';
|
|
89
|
+
type OpenlayerProject = {
|
|
90
|
+
dateCreated: string;
|
|
91
|
+
dateUpdated: string;
|
|
92
|
+
description?: string;
|
|
93
|
+
developmentGoalCount: number;
|
|
94
|
+
goalCount: number;
|
|
95
|
+
id: string;
|
|
96
|
+
inferencePipelineCount: number;
|
|
97
|
+
memberIds: string[];
|
|
98
|
+
monitoringGoalCount: number;
|
|
99
|
+
name: string;
|
|
100
|
+
sample?: boolean;
|
|
101
|
+
slackChannelId?: string;
|
|
102
|
+
slackChannelName?: string;
|
|
103
|
+
slackChannelNotificationsEnabled: boolean;
|
|
104
|
+
taskType: OpenlayerTaskType;
|
|
105
|
+
unreadNotificationCount: number;
|
|
106
|
+
versionCount: number;
|
|
107
|
+
};
|
|
108
|
+
type OpenlayerSampleVolumeGraphBucket = {
|
|
109
|
+
title: string;
|
|
110
|
+
xAxis: {
|
|
111
|
+
data: string[];
|
|
112
|
+
title: string;
|
|
113
|
+
};
|
|
114
|
+
yAxis: {
|
|
115
|
+
data: number[];
|
|
116
|
+
title: string;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
type OpenlayerSampleVolumeGraph = {
|
|
120
|
+
daily: OpenlayerSampleVolumeGraphBucket;
|
|
121
|
+
hourly: OpenlayerSampleVolumeGraphBucket;
|
|
122
|
+
monthly: OpenlayerSampleVolumeGraphBucket;
|
|
123
|
+
weekly: OpenlayerSampleVolumeGraphBucket;
|
|
124
|
+
};
|
|
125
|
+
type OpenlayerTaskType = 'llm-base' | 'tabular-classification' | 'tabular-regression' | 'text-classification';
|
|
18
126
|
declare class OpenAIMonitor {
|
|
19
127
|
private OpenAIClient;
|
|
20
128
|
private monitoringOn;
|
|
21
129
|
private openlayerApiKey?;
|
|
130
|
+
private openlayerDefaultDataConfig;
|
|
22
131
|
private openlayerProjectName?;
|
|
23
132
|
private openlayerInferencePipelineName?;
|
|
24
133
|
private openlayerServerUrl;
|
|
@@ -26,10 +135,67 @@ declare class OpenAIMonitor {
|
|
|
26
135
|
constructor({ openAiApiKey, openlayerApiKey, openlayerInferencePipelineName, openlayerProjectName, openlayerServerUrl, }: ConstructorProps);
|
|
27
136
|
private formatChatCompletionInput;
|
|
28
137
|
private resolvedQuery;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
138
|
+
private uploadToInferencePipeline;
|
|
139
|
+
/**
|
|
140
|
+
* Uploads data to Openlayer. This function takes ChatCompletionData and an optional
|
|
141
|
+
* ChatCompletionConfig, then uploads the data to the specified Openlayer Inference Pipeline.
|
|
142
|
+
* @param data The ChatCompletionData to be uploaded.
|
|
143
|
+
* @param config Configuration for the data upload.
|
|
144
|
+
* @throws Throws an error if Openlayer API key or project name are not set.
|
|
145
|
+
* @returns A promise that resolves when the data has been successfully uploaded.
|
|
146
|
+
*/
|
|
147
|
+
uploadDataToOpenlayer: (data: ChatCompletionData, config: ChatCompletionConfig) => Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Creates a new ChatCompletion instance. If monitoring is not active, an error is thrown.
|
|
150
|
+
* This function also measures latency and uploads data to Openlayer.
|
|
151
|
+
* @param body The parameters for creating a chat completion.
|
|
152
|
+
* @param options Optional request options.
|
|
153
|
+
* @throws Throws an error if monitoring is not active or if there is no output received from OpenAI.
|
|
154
|
+
* @returns A promise that resolves to a ChatCompletion or a Stream of ChatCompletionChunks.
|
|
155
|
+
*/
|
|
32
156
|
createChatCompletion: (body: ChatCompletionCreateParams, options?: RequestOptions) => Promise<ChatCompletion | Stream<ChatCompletionChunk>>;
|
|
157
|
+
/**
|
|
158
|
+
* Creates a new Completion instance. If monitoring is not active, an error is thrown.
|
|
159
|
+
* This function also measures latency and uploads data to Openlayer.
|
|
160
|
+
* @param body The parameters for creating a completion.
|
|
161
|
+
* @param options Optional request options.
|
|
162
|
+
* @throws Throws an error if monitoring is not active or if no prompt is provided.
|
|
163
|
+
* @returns A promise that resolves to a Completion or a Stream of Completions.
|
|
164
|
+
*/
|
|
33
165
|
createCompletion: (body: CompletionCreateParams, options?: RequestOptions) => Promise<Completion | Stream<Completion>>;
|
|
166
|
+
/**
|
|
167
|
+
* Creates a new inference pipeline in Openlayer, or loads an existing one if it already exists.
|
|
168
|
+
* @param name The name of the inference pipeline.
|
|
169
|
+
* @param projectId The project ID containing the inference pipeline.
|
|
170
|
+
* @throws Throws an error if the inference pipeline cannot be created or found.
|
|
171
|
+
* @returns A promise that resolves to an OpenlayerInferencePipeline object.
|
|
172
|
+
*/
|
|
173
|
+
createInferencePipeline: (name: string, projectId: string) => Promise<OpenlayerInferencePipeline>;
|
|
174
|
+
/**
|
|
175
|
+
* Creates a new project in Openlayer, or loads an existing one if it already exists.
|
|
176
|
+
* @param name The name of the project.
|
|
177
|
+
* @param taskType The type of task associated with the project.
|
|
178
|
+
* @param description Optional description of the project.
|
|
179
|
+
* @throws Throws an error if the project cannot be created or found.
|
|
180
|
+
* @returns A promise that resolves to an OpenlayerProject object.
|
|
181
|
+
*/
|
|
182
|
+
createProject: (name: string, taskType: OpenlayerTaskType, description?: string) => Promise<OpenlayerProject>;
|
|
183
|
+
/**
|
|
184
|
+
* Loads an existing inference pipeline from Openlayer based on its name and project ID.
|
|
185
|
+
* @param name The name of the inference pipeline.
|
|
186
|
+
* @param projectId The project ID containing the inference pipeline.
|
|
187
|
+
* @throws Throws an error if the inference pipeline is not found.
|
|
188
|
+
* @returns A promise that resolves to an OpenlayerInferencePipeline object.
|
|
189
|
+
*/
|
|
190
|
+
loadInferencePipeline: (name: string, projectId: string) => Promise<OpenlayerInferencePipeline>;
|
|
191
|
+
loadProject: (name: string) => Promise<OpenlayerProject>;
|
|
192
|
+
/**
|
|
193
|
+
* Starts monitoring for the OpenAI Monitor instance. If monitoring is already active, a warning is logged.
|
|
194
|
+
*/
|
|
195
|
+
startMonitoring(): void;
|
|
196
|
+
/**
|
|
197
|
+
* Stops monitoring for the OpenAI Monitor instance. If monitoring is not active, a warning is logged.
|
|
198
|
+
*/
|
|
199
|
+
stopMonitoring(): void;
|
|
34
200
|
}
|
|
35
201
|
export default OpenAIMonitor;
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,15 @@ const request_1 = require("./utils/request");
|
|
|
22
22
|
class OpenAIMonitor {
|
|
23
23
|
constructor({ openAiApiKey, openlayerApiKey, openlayerInferencePipelineName, openlayerProjectName, openlayerServerUrl, }) {
|
|
24
24
|
this.monitoringOn = false;
|
|
25
|
+
this.openlayerDefaultDataConfig = {
|
|
26
|
+
groundTruthColumnName: null,
|
|
27
|
+
inferenceIdColumnName: 'id',
|
|
28
|
+
inputVariableNames: ['input'],
|
|
29
|
+
latencyColumnName: 'latency',
|
|
30
|
+
numOfTokenColumnName: 'tokens',
|
|
31
|
+
outputColumnName: 'output',
|
|
32
|
+
timestampColumnName: 'timestamp',
|
|
33
|
+
};
|
|
25
34
|
this.openlayerServerUrl = 'https://api.openlayer.com/v1';
|
|
26
35
|
this.version = '0.1.0a16';
|
|
27
36
|
this.formatChatCompletionInput = (messages) => messages
|
|
@@ -30,115 +39,62 @@ class OpenAIMonitor {
|
|
|
30
39
|
.join('\n')
|
|
31
40
|
.trim();
|
|
32
41
|
this.resolvedQuery = (endpoint, args = {}) => (0, request_1.resolvedQuery)(this.openlayerServerUrl, endpoint, args);
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Object.assign(Object.assign({}, data), { id: (0, uuid_1.v4)(), timestamp: Math.round(data.timestamp / 1000) }),
|
|
50
|
-
],
|
|
51
|
-
}),
|
|
52
|
-
headers: {
|
|
53
|
-
Authorization: `Bearer ${this.openlayerApiKey}`,
|
|
54
|
-
'Content-Type': 'application/json',
|
|
55
|
-
},
|
|
56
|
-
method: 'POST',
|
|
57
|
-
});
|
|
58
|
-
if (!response.ok) {
|
|
59
|
-
console.error('Error making POST request:', response.status);
|
|
60
|
-
throw new Error(`Error: ${response.status}`);
|
|
61
|
-
}
|
|
62
|
-
return yield response.json();
|
|
42
|
+
this.uploadToInferencePipeline = (inferencePipelineId, data, config) => __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
var _a;
|
|
44
|
+
const dataStreamEndpoint = `/inference-pipelines/${inferencePipelineId}/data-stream`;
|
|
45
|
+
const dataStreamQuery = this.resolvedQuery(dataStreamEndpoint);
|
|
46
|
+
const response = yield fetch(dataStreamQuery, {
|
|
47
|
+
body: JSON.stringify({
|
|
48
|
+
config,
|
|
49
|
+
rows: [
|
|
50
|
+
Object.assign(Object.assign({}, data), { id: (0, uuid_1.v4)(), timestamp: Math.round(((_a = data.timestamp) !== null && _a !== void 0 ? _a : Date.now()) / 1000) }),
|
|
51
|
+
],
|
|
52
|
+
}),
|
|
53
|
+
headers: {
|
|
54
|
+
Authorization: `Bearer ${this.openlayerApiKey}`,
|
|
55
|
+
'Content-Type': 'application/json',
|
|
56
|
+
},
|
|
57
|
+
method: 'POST',
|
|
63
58
|
});
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
console.error('Error making POST request:', response.status);
|
|
61
|
+
throw new Error(`Error: ${response.status}`);
|
|
62
|
+
}
|
|
63
|
+
return yield response.json();
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* Uploads data to Openlayer. This function takes ChatCompletionData and an optional
|
|
67
|
+
* ChatCompletionConfig, then uploads the data to the specified Openlayer Inference Pipeline.
|
|
68
|
+
* @param data The ChatCompletionData to be uploaded.
|
|
69
|
+
* @param config Configuration for the data upload.
|
|
70
|
+
* @throws Throws an error if Openlayer API key or project name are not set.
|
|
71
|
+
* @returns A promise that resolves when the data has been successfully uploaded.
|
|
72
|
+
*/
|
|
73
|
+
this.uploadDataToOpenlayer = (data, config) => __awaiter(this, void 0, void 0, function* () {
|
|
64
74
|
if (!this.openlayerApiKey || !this.openlayerProjectName) {
|
|
65
75
|
throw new Error('Openlayer API key and project name are required for publishing.');
|
|
66
76
|
}
|
|
67
77
|
try {
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
version: this.version,
|
|
72
|
-
};
|
|
73
|
-
const projectsQuery = this.resolvedQuery(projectsEndpoint, projectsQueryParameters);
|
|
74
|
-
const projectsResponse = yield fetch(projectsQuery, {
|
|
75
|
-
headers: {
|
|
76
|
-
Authorization: `Bearer ${this.openlayerApiKey}`,
|
|
77
|
-
'Content-Type': 'application/json',
|
|
78
|
-
},
|
|
79
|
-
method: 'GET',
|
|
80
|
-
});
|
|
81
|
-
const { items: projects } = yield projectsResponse.json();
|
|
82
|
-
if (!Array.isArray(projects)) {
|
|
83
|
-
throw new Error('Invalid response from Openlayer');
|
|
84
|
-
}
|
|
85
|
-
const project = projects.find(({ name }) => name === this.openlayerProjectName);
|
|
86
|
-
if (!(project === null || project === void 0 ? void 0 : project.id)) {
|
|
87
|
-
throw new Error('Project not found');
|
|
88
|
-
}
|
|
89
|
-
const inferencePipelineEndpoint = `/projects/${project.id}/inference-pipelines`;
|
|
90
|
-
const inferencePipelineQueryParameters = {
|
|
91
|
-
name: this.openlayerInferencePipelineName,
|
|
92
|
-
version: this.version,
|
|
93
|
-
};
|
|
94
|
-
const inferencePipelineQuery = this.resolvedQuery(inferencePipelineEndpoint, inferencePipelineQueryParameters);
|
|
95
|
-
const inferencePipelineResponse = yield fetch(inferencePipelineQuery, {
|
|
96
|
-
headers: {
|
|
97
|
-
Authorization: `Bearer ${this.openlayerApiKey}`,
|
|
98
|
-
'Content-Type': 'application/json',
|
|
99
|
-
},
|
|
100
|
-
method: 'GET',
|
|
101
|
-
});
|
|
102
|
-
const { items: inferencePipelines } = yield inferencePipelineResponse.json();
|
|
103
|
-
const inferencePipeline = Array.isArray(inferencePipelines)
|
|
104
|
-
? inferencePipelines.find(({ name }) => typeof this.openlayerInferencePipelineName === 'undefined' ||
|
|
105
|
-
name === this.openlayerInferencePipelineName)
|
|
106
|
-
: undefined;
|
|
107
|
-
if (inferencePipeline === null || inferencePipeline === void 0 ? void 0 : inferencePipeline.id) {
|
|
108
|
-
const { id: inferencePipelineId } = inferencePipeline;
|
|
109
|
-
yield uploadToInferencePipeline(inferencePipelineId);
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
const createInferencePipelineEndpoint = `/projects/${project.id}/inference-pipelines`;
|
|
113
|
-
const createInferencePipelineQuery = this.resolvedQuery(createInferencePipelineEndpoint, { version: this.version });
|
|
114
|
-
const createInferencePipelineResponse = yield fetch(createInferencePipelineQuery, {
|
|
115
|
-
body: JSON.stringify({
|
|
116
|
-
description: '',
|
|
117
|
-
name: typeof this.openlayerInferencePipelineName === 'undefined'
|
|
118
|
-
? 'production'
|
|
119
|
-
: this.openlayerInferencePipelineName,
|
|
120
|
-
}),
|
|
121
|
-
headers: {
|
|
122
|
-
Authorization: `Bearer ${this.openlayerApiKey}`,
|
|
123
|
-
'Content-Type': 'application/json',
|
|
124
|
-
},
|
|
125
|
-
method: 'POST',
|
|
126
|
-
});
|
|
127
|
-
const { id: inferencePipelineId } = yield createInferencePipelineResponse.json();
|
|
128
|
-
if (!inferencePipelineId) {
|
|
129
|
-
throw new Error('Error creating inference pipeline');
|
|
130
|
-
}
|
|
131
|
-
yield uploadToInferencePipeline(inferencePipelineId);
|
|
132
|
-
}
|
|
78
|
+
const project = yield this.createProject(this.openlayerProjectName, 'llm-base');
|
|
79
|
+
const inferencePipeline = yield this.createInferencePipeline(this.openlayerProjectName, project.id);
|
|
80
|
+
yield this.uploadToInferencePipeline(inferencePipeline.id, data, config);
|
|
133
81
|
}
|
|
134
82
|
catch (error) {
|
|
135
83
|
console.error('Error publishing data to Openlayer:', error);
|
|
136
84
|
throw error;
|
|
137
85
|
}
|
|
138
86
|
});
|
|
87
|
+
/**
|
|
88
|
+
* Creates a new ChatCompletion instance. If monitoring is not active, an error is thrown.
|
|
89
|
+
* This function also measures latency and uploads data to Openlayer.
|
|
90
|
+
* @param body The parameters for creating a chat completion.
|
|
91
|
+
* @param options Optional request options.
|
|
92
|
+
* @throws Throws an error if monitoring is not active or if there is no output received from OpenAI.
|
|
93
|
+
* @returns A promise that resolves to a ChatCompletion or a Stream of ChatCompletionChunks.
|
|
94
|
+
*/
|
|
139
95
|
this.createChatCompletion = (body, options) => __awaiter(this, void 0, void 0, function* () {
|
|
140
|
-
var
|
|
141
|
-
var
|
|
96
|
+
var _b, e_1, _c, _d;
|
|
97
|
+
var _e, _f;
|
|
142
98
|
if (!this.monitoringOn) {
|
|
143
99
|
throw new Error('Monitoring is not active.');
|
|
144
100
|
}
|
|
@@ -150,10 +106,10 @@ class OpenAIMonitor {
|
|
|
150
106
|
if (body.stream) {
|
|
151
107
|
const streamedResponse = response;
|
|
152
108
|
try {
|
|
153
|
-
for (var
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const chunk =
|
|
109
|
+
for (var _g = true, streamedResponse_1 = __asyncValues(streamedResponse), streamedResponse_1_1; streamedResponse_1_1 = yield streamedResponse_1.next(), _b = streamedResponse_1_1.done, !_b; _g = true) {
|
|
110
|
+
_d = streamedResponse_1_1.value;
|
|
111
|
+
_g = false;
|
|
112
|
+
const chunk = _d;
|
|
157
113
|
// Process each chunk - for example, accumulate input data
|
|
158
114
|
outputData += chunk.choices[0].delta.content;
|
|
159
115
|
}
|
|
@@ -161,7 +117,7 @@ class OpenAIMonitor {
|
|
|
161
117
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
162
118
|
finally {
|
|
163
119
|
try {
|
|
164
|
-
if (!
|
|
120
|
+
if (!_g && !_b && (_c = streamedResponse_1.return)) yield _c.call(streamedResponse_1);
|
|
165
121
|
}
|
|
166
122
|
finally { if (e_1) throw e_1.error; }
|
|
167
123
|
}
|
|
@@ -172,29 +128,44 @@ class OpenAIMonitor {
|
|
|
172
128
|
latency,
|
|
173
129
|
output: outputData,
|
|
174
130
|
timestamp: startTime,
|
|
175
|
-
});
|
|
131
|
+
}, this.openlayerDefaultDataConfig);
|
|
176
132
|
}
|
|
177
133
|
else {
|
|
178
134
|
const nonStreamedResponse = response;
|
|
179
135
|
// Handle regular (non-streamed) response
|
|
180
136
|
const endTime = Date.now();
|
|
181
137
|
const latency = endTime - startTime;
|
|
138
|
+
const output = nonStreamedResponse.choices[0].message.content;
|
|
139
|
+
if (typeof output !== 'string') {
|
|
140
|
+
throw new Error('No output received from OpenAI.');
|
|
141
|
+
}
|
|
182
142
|
this.uploadDataToOpenlayer({
|
|
183
143
|
input: this.formatChatCompletionInput(body.messages),
|
|
184
144
|
latency,
|
|
185
|
-
output
|
|
145
|
+
output,
|
|
186
146
|
timestamp: startTime,
|
|
187
|
-
tokens: (
|
|
188
|
-
});
|
|
147
|
+
tokens: (_f = (_e = nonStreamedResponse.usage) === null || _e === void 0 ? void 0 : _e.total_tokens) !== null && _f !== void 0 ? _f : 0,
|
|
148
|
+
}, this.openlayerDefaultDataConfig);
|
|
189
149
|
}
|
|
190
150
|
return response;
|
|
191
151
|
});
|
|
152
|
+
/**
|
|
153
|
+
* Creates a new Completion instance. If monitoring is not active, an error is thrown.
|
|
154
|
+
* This function also measures latency and uploads data to Openlayer.
|
|
155
|
+
* @param body The parameters for creating a completion.
|
|
156
|
+
* @param options Optional request options.
|
|
157
|
+
* @throws Throws an error if monitoring is not active or if no prompt is provided.
|
|
158
|
+
* @returns A promise that resolves to a Completion or a Stream of Completions.
|
|
159
|
+
*/
|
|
192
160
|
this.createCompletion = (body, options) => __awaiter(this, void 0, void 0, function* () {
|
|
193
|
-
var
|
|
194
|
-
var
|
|
161
|
+
var _h, e_2, _j, _k;
|
|
162
|
+
var _l, _m, _o, _p;
|
|
195
163
|
if (!this.monitoringOn) {
|
|
196
164
|
throw new Error('Monitoring is not active.');
|
|
197
165
|
}
|
|
166
|
+
if (!body.prompt) {
|
|
167
|
+
throw new Error('No prompt provided.');
|
|
168
|
+
}
|
|
198
169
|
// Start a timer to measure latency
|
|
199
170
|
const startTime = Date.now();
|
|
200
171
|
// Accumulate output and tokens data for streamed responses
|
|
@@ -204,19 +175,19 @@ class OpenAIMonitor {
|
|
|
204
175
|
if (body.stream) {
|
|
205
176
|
const streamedResponse = response;
|
|
206
177
|
try {
|
|
207
|
-
for (var
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const chunk =
|
|
178
|
+
for (var _q = true, streamedResponse_2 = __asyncValues(streamedResponse), streamedResponse_2_1; streamedResponse_2_1 = yield streamedResponse_2.next(), _h = streamedResponse_2_1.done, !_h; _q = true) {
|
|
179
|
+
_k = streamedResponse_2_1.value;
|
|
180
|
+
_q = false;
|
|
181
|
+
const chunk = _k;
|
|
211
182
|
// Process each chunk - for example, accumulate input data
|
|
212
183
|
outputData += chunk.choices[0].text.trim();
|
|
213
|
-
tokensData += (
|
|
184
|
+
tokensData += (_m = (_l = chunk.usage) === null || _l === void 0 ? void 0 : _l.total_tokens) !== null && _m !== void 0 ? _m : 0;
|
|
214
185
|
}
|
|
215
186
|
}
|
|
216
187
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
217
188
|
finally {
|
|
218
189
|
try {
|
|
219
|
-
if (!
|
|
190
|
+
if (!_q && !_h && (_j = streamedResponse_2.return)) yield _j.call(streamedResponse_2);
|
|
220
191
|
}
|
|
221
192
|
finally { if (e_2) throw e_2.error; }
|
|
222
193
|
}
|
|
@@ -228,7 +199,7 @@ class OpenAIMonitor {
|
|
|
228
199
|
output: outputData,
|
|
229
200
|
timestamp: startTime,
|
|
230
201
|
tokens: tokensData,
|
|
231
|
-
});
|
|
202
|
+
}, this.openlayerDefaultDataConfig);
|
|
232
203
|
}
|
|
233
204
|
else {
|
|
234
205
|
const nonStreamedResponse = response;
|
|
@@ -240,11 +211,137 @@ class OpenAIMonitor {
|
|
|
240
211
|
latency,
|
|
241
212
|
output: nonStreamedResponse.choices[0].text,
|
|
242
213
|
timestamp: startTime,
|
|
243
|
-
tokens: (
|
|
244
|
-
});
|
|
214
|
+
tokens: (_p = (_o = nonStreamedResponse.usage) === null || _o === void 0 ? void 0 : _o.total_tokens) !== null && _p !== void 0 ? _p : 0,
|
|
215
|
+
}, this.openlayerDefaultDataConfig);
|
|
245
216
|
}
|
|
246
217
|
return response;
|
|
247
218
|
});
|
|
219
|
+
/**
|
|
220
|
+
* Creates a new inference pipeline in Openlayer, or loads an existing one if it already exists.
|
|
221
|
+
* @param name The name of the inference pipeline.
|
|
222
|
+
* @param projectId The project ID containing the inference pipeline.
|
|
223
|
+
* @throws Throws an error if the inference pipeline cannot be created or found.
|
|
224
|
+
* @returns A promise that resolves to an OpenlayerInferencePipeline object.
|
|
225
|
+
*/
|
|
226
|
+
this.createInferencePipeline = (name, projectId) => __awaiter(this, void 0, void 0, function* () {
|
|
227
|
+
try {
|
|
228
|
+
return yield this.loadInferencePipeline(name, projectId);
|
|
229
|
+
}
|
|
230
|
+
catch (_r) {
|
|
231
|
+
const createInferencePipelineEndpoint = `/projects/${projectId}/inference-pipelines`;
|
|
232
|
+
const createInferencePipelineQuery = this.resolvedQuery(createInferencePipelineEndpoint, { version: this.version });
|
|
233
|
+
const createInferencePipelineResponse = yield fetch(createInferencePipelineQuery, {
|
|
234
|
+
body: JSON.stringify({
|
|
235
|
+
description: '',
|
|
236
|
+
name: typeof this.openlayerInferencePipelineName === 'undefined'
|
|
237
|
+
? 'production'
|
|
238
|
+
: this.openlayerInferencePipelineName,
|
|
239
|
+
}),
|
|
240
|
+
headers: {
|
|
241
|
+
Authorization: `Bearer ${this.openlayerApiKey}`,
|
|
242
|
+
'Content-Type': 'application/json',
|
|
243
|
+
},
|
|
244
|
+
method: 'POST',
|
|
245
|
+
});
|
|
246
|
+
const inferencePipeline = yield createInferencePipelineResponse.json();
|
|
247
|
+
if (!(inferencePipeline === null || inferencePipeline === void 0 ? void 0 : inferencePipeline.id)) {
|
|
248
|
+
throw new Error('Error creating inference pipeline');
|
|
249
|
+
}
|
|
250
|
+
return inferencePipeline;
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
/**
|
|
254
|
+
* Creates a new project in Openlayer, or loads an existing one if it already exists.
|
|
255
|
+
* @param name The name of the project.
|
|
256
|
+
* @param taskType The type of task associated with the project.
|
|
257
|
+
* @param description Optional description of the project.
|
|
258
|
+
* @throws Throws an error if the project cannot be created or found.
|
|
259
|
+
* @returns A promise that resolves to an OpenlayerProject object.
|
|
260
|
+
*/
|
|
261
|
+
this.createProject = (name, taskType, description) => __awaiter(this, void 0, void 0, function* () {
|
|
262
|
+
try {
|
|
263
|
+
return yield this.loadProject(name);
|
|
264
|
+
}
|
|
265
|
+
catch (_s) {
|
|
266
|
+
const projectsEndpoint = '/projects';
|
|
267
|
+
const projectsQuery = this.resolvedQuery(projectsEndpoint);
|
|
268
|
+
const projectsResponse = yield fetch(projectsQuery, {
|
|
269
|
+
body: JSON.stringify({
|
|
270
|
+
description,
|
|
271
|
+
name,
|
|
272
|
+
taskType,
|
|
273
|
+
}),
|
|
274
|
+
headers: {
|
|
275
|
+
Authorization: `Bearer ${this.openlayerApiKey}`,
|
|
276
|
+
'Content-Type': 'application/json',
|
|
277
|
+
},
|
|
278
|
+
method: 'POST',
|
|
279
|
+
});
|
|
280
|
+
const { items: projects } = yield projectsResponse.json();
|
|
281
|
+
if (!Array.isArray(projects)) {
|
|
282
|
+
throw new Error('Invalid response from Openlayer');
|
|
283
|
+
}
|
|
284
|
+
const project = projects.find((p) => p.name === name);
|
|
285
|
+
if (!(project === null || project === void 0 ? void 0 : project.id)) {
|
|
286
|
+
throw new Error('Project not found');
|
|
287
|
+
}
|
|
288
|
+
return project;
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
/**
|
|
292
|
+
* Loads an existing inference pipeline from Openlayer based on its name and project ID.
|
|
293
|
+
* @param name The name of the inference pipeline.
|
|
294
|
+
* @param projectId The project ID containing the inference pipeline.
|
|
295
|
+
* @throws Throws an error if the inference pipeline is not found.
|
|
296
|
+
* @returns A promise that resolves to an OpenlayerInferencePipeline object.
|
|
297
|
+
*/
|
|
298
|
+
this.loadInferencePipeline = (name, projectId) => __awaiter(this, void 0, void 0, function* () {
|
|
299
|
+
const inferencePipelineEndpoint = `/projects/${projectId}/inference-pipelines`;
|
|
300
|
+
const inferencePipelineQueryParameters = {
|
|
301
|
+
name: this.openlayerInferencePipelineName,
|
|
302
|
+
version: this.version,
|
|
303
|
+
};
|
|
304
|
+
const inferencePipelineQuery = this.resolvedQuery(inferencePipelineEndpoint, inferencePipelineQueryParameters);
|
|
305
|
+
const inferencePipelineResponse = yield fetch(inferencePipelineQuery, {
|
|
306
|
+
headers: {
|
|
307
|
+
Authorization: `Bearer ${this.openlayerApiKey}`,
|
|
308
|
+
'Content-Type': 'application/json',
|
|
309
|
+
},
|
|
310
|
+
method: 'GET',
|
|
311
|
+
});
|
|
312
|
+
const { items: inferencePipelines } = yield inferencePipelineResponse.json();
|
|
313
|
+
const inferencePipeline = Array.isArray(inferencePipelines)
|
|
314
|
+
? inferencePipelines.find((p) => p.name === name)
|
|
315
|
+
: undefined;
|
|
316
|
+
if (!(inferencePipeline === null || inferencePipeline === void 0 ? void 0 : inferencePipeline.id)) {
|
|
317
|
+
throw new Error('Inference pipeline not found');
|
|
318
|
+
}
|
|
319
|
+
return inferencePipeline;
|
|
320
|
+
});
|
|
321
|
+
this.loadProject = (name) => __awaiter(this, void 0, void 0, function* () {
|
|
322
|
+
const projectsEndpoint = '/projects';
|
|
323
|
+
const projectsQueryParameters = {
|
|
324
|
+
name,
|
|
325
|
+
version: this.version,
|
|
326
|
+
};
|
|
327
|
+
const projectsQuery = this.resolvedQuery(projectsEndpoint, projectsQueryParameters);
|
|
328
|
+
const projectsResponse = yield fetch(projectsQuery, {
|
|
329
|
+
headers: {
|
|
330
|
+
Authorization: `Bearer ${this.openlayerApiKey}`,
|
|
331
|
+
'Content-Type': 'application/json',
|
|
332
|
+
},
|
|
333
|
+
method: 'GET',
|
|
334
|
+
});
|
|
335
|
+
const { items: projects } = yield projectsResponse.json();
|
|
336
|
+
if (!Array.isArray(projects)) {
|
|
337
|
+
throw new Error('Invalid response from Openlayer');
|
|
338
|
+
}
|
|
339
|
+
const project = projects.find((p) => p.name === name);
|
|
340
|
+
if (!(project === null || project === void 0 ? void 0 : project.id)) {
|
|
341
|
+
throw new Error('Project not found');
|
|
342
|
+
}
|
|
343
|
+
return project;
|
|
344
|
+
});
|
|
248
345
|
this.OpenAIClient = new openai_1.default({
|
|
249
346
|
apiKey: openAiApiKey,
|
|
250
347
|
dangerouslyAllowBrowser: true,
|
|
@@ -259,6 +356,9 @@ class OpenAIMonitor {
|
|
|
259
356
|
throw new Error('Openlayer API key and project name are required for publishing.');
|
|
260
357
|
}
|
|
261
358
|
}
|
|
359
|
+
/**
|
|
360
|
+
* Starts monitoring for the OpenAI Monitor instance. If monitoring is already active, a warning is logged.
|
|
361
|
+
*/
|
|
262
362
|
startMonitoring() {
|
|
263
363
|
if (this.monitoringOn) {
|
|
264
364
|
console.warn('Monitoring is already on!');
|
|
@@ -267,6 +367,9 @@ class OpenAIMonitor {
|
|
|
267
367
|
this.monitoringOn = true;
|
|
268
368
|
console.info('Monitoring started.');
|
|
269
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* Stops monitoring for the OpenAI Monitor instance. If monitoring is not active, a warning is logged.
|
|
372
|
+
*/
|
|
270
373
|
stopMonitoring() {
|
|
271
374
|
if (!this.monitoringOn) {
|
|
272
375
|
console.warn('Monitoring is not active.');
|