openlayer 0.1.4 → 0.1.6

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