openlayer 0.1.12 → 0.1.13

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 ADDED
@@ -0,0 +1,35 @@
1
+ <div align="left">
2
+ <img src="static/logo.png"><br>
3
+ </div>
4
+
5
+ # Openlayer | JavaScript/TypeScript Library
6
+
7
+ [![npm version](https://badge.fury.io/js/openlayer.svg)](https://badge.fury.io/js/openlayer)
8
+
9
+ ## What is it?
10
+
11
+ Openlayer is a debugging workspace for ML & Data Science. Openlayer combines and builds upon SOTA techniques in explainability, model and dataset versioning, synthetic data generation, data-centric testing and much more to form a powerful, **unified platform for model development**.
12
+
13
+ 👉 [Join our Discord community!](https://discord.gg/t6wS2g6MMB) We'd love to meet you and help you get started with Openlayer!
14
+
15
+ This is the official JavaScript/TypeScript library for interacting with the Openlayer platform. Navigate [here](https://docs.openlayer.com) for a quickstart guide and for in-depth tutorials.
16
+
17
+ ## Main Features
18
+
19
+ This library's primary function is to enable you to easily package your models and datasets and add them to your Openlayer account.
20
+
21
+ ## Installation
22
+
23
+ Install with npm
24
+
25
+ ```console
26
+ npm i openlayer
27
+ ```
28
+
29
+ ## Documentation
30
+
31
+ The official documentation for this library can be found [here](https://docs.openlayer.com).
32
+
33
+ ## Contributing
34
+
35
+ All contributions, bug reports, bug fixes, documentation improvements, enhancements, and ideas are welcome! Just send us a message on [Discord](https://discord.gg/t6wS2g6MMB).
package/dist/index.d.ts CHANGED
@@ -1,16 +1,12 @@
1
1
  import { RequestOptions } from 'openai/core';
2
- import { ChatCompletion, ChatCompletionChunk, ChatCompletionCreateParams, Completion, CompletionCreateParams } from 'openai/resources';
2
+ import { ChatCompletion, ChatCompletionChunk, ChatCompletionCreateParams, ChatCompletionMessageParam, Completion, CompletionCreateParams } from 'openai/resources';
3
3
  import { Stream } from 'openai/streaming';
4
4
  /**
5
5
  * Represents the data structure for a chat completion.
6
+ * Object keys represent a column name and the values represent the column value.
6
7
  */
7
- export interface ChatCompletionData {
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[][];
8
+ export interface StreamingData {
9
+ [columnName: string]: any;
14
10
  /**
15
11
  * The latency of the chat completion in milliseconds. Optional.
16
12
  */
@@ -28,6 +24,43 @@ export interface ChatCompletionData {
28
24
  */
29
25
  tokens?: number;
30
26
  }
27
+ /**
28
+ * Configuration settings for uploading chat completion data to Openlayer.
29
+ */
30
+ interface StreamingDataConfig {
31
+ /**
32
+ * The name of the column that stores the ground truth data. Can be null.
33
+ */
34
+ groundTruthColumnName: string | null;
35
+ /**
36
+ * The name of the column that stores inference IDs. Can be null.
37
+ */
38
+ inferenceIdColumnName: string | null;
39
+ /**
40
+ * An array of names for input variable columns. Can be null.
41
+ */
42
+ inputVariableNames?: string[] | null;
43
+ /**
44
+ * The name of the column that stores latency data. Can be null.
45
+ */
46
+ latencyColumnName: string | null;
47
+ /**
48
+ * The name of the column that stores the number of tokens. Can be null.
49
+ */
50
+ numOfTokenColumnName: string | null;
51
+ /**
52
+ * The name of the column that stores output data. Can be null.
53
+ */
54
+ outputColumnName: string | null;
55
+ /**
56
+ * The full prompt history for the chat completion.
57
+ */
58
+ prompt?: ChatCompletionMessageParam[];
59
+ /**
60
+ * The name of the column that stores timestamp data. Can be null.
61
+ */
62
+ timestampColumnName: string | null;
63
+ }
31
64
  type OpenlayerClientConstructorProps = {
32
65
  openlayerApiKey?: string;
33
66
  openlayerInferencePipelineName?: string;
@@ -96,7 +129,7 @@ type OpenlayerSampleVolumeGraph = {
96
129
  type OpenlayerTaskType = 'llm-base' | 'tabular-classification' | 'tabular-regression' | 'text-classification';
97
130
  export declare class OpenlayerClient {
98
131
  private openlayerApiKey?;
99
- private openlayerDefaultDataConfig;
132
+ defaultConfig: StreamingDataConfig;
100
133
  private openlayerServerUrl;
101
134
  private version;
102
135
  /**
@@ -108,12 +141,12 @@ export declare class OpenlayerClient {
108
141
  private resolvedQuery;
109
142
  /**
110
143
  * Streams data to the Openlayer inference pipeline.
111
- * @param {ChatCompletionData} data - The chat completion data to be streamed.
144
+ * @param {StreamingData} data - The chat completion data to be streamed.
112
145
  * @param {string} inferencePipelineId - The ID of the Openlayer inference pipeline to which data is streamed.
113
146
  * @returns {Promise<void>} A promise that resolves when the data has been successfully streamed.
114
147
  * @throws {Error} Throws an error if the Openlayer API key is not set or an error occurs in the streaming process.
115
148
  */
116
- streamData: (data: ChatCompletionData, inferencePipelineId: string) => Promise<void>;
149
+ streamData: (data: StreamingData, config: StreamingDataConfig, inferencePipelineId: string) => Promise<void>;
117
150
  /**
118
151
  * Creates a new inference pipeline in Openlayer or loads an existing one.
119
152
  * @param {string} projectId - The ID of the project containing the inference pipeline.
package/dist/index.js CHANGED
@@ -27,10 +27,9 @@ class OpenlayerClient {
27
27
  * @throws {Error} Throws an error if the Openlayer API key is not provided.
28
28
  */
29
29
  constructor({ openlayerApiKey, openlayerServerUrl, }) {
30
- this.openlayerDefaultDataConfig = {
30
+ this.defaultConfig = {
31
31
  groundTruthColumnName: null,
32
32
  inferenceIdColumnName: 'id',
33
- inputVariableNames: ['input'],
34
33
  latencyColumnName: 'latency',
35
34
  numOfTokenColumnName: 'tokens',
36
35
  outputColumnName: 'output',
@@ -41,12 +40,12 @@ class OpenlayerClient {
41
40
  this.resolvedQuery = (endpoint, args = {}) => (0, request_1.resolvedQuery)(this.openlayerServerUrl, endpoint, args);
42
41
  /**
43
42
  * Streams data to the Openlayer inference pipeline.
44
- * @param {ChatCompletionData} data - The chat completion data to be streamed.
43
+ * @param {StreamingData} data - The chat completion data to be streamed.
45
44
  * @param {string} inferencePipelineId - The ID of the Openlayer inference pipeline to which data is streamed.
46
45
  * @returns {Promise<void>} A promise that resolves when the data has been successfully streamed.
47
46
  * @throws {Error} Throws an error if the Openlayer API key is not set or an error occurs in the streaming process.
48
47
  */
49
- this.streamData = (data, inferencePipelineId) => __awaiter(this, void 0, void 0, function* () {
48
+ this.streamData = (data, config, inferencePipelineId) => __awaiter(this, void 0, void 0, function* () {
50
49
  var _a;
51
50
  if (!this.openlayerApiKey) {
52
51
  throw new Error('Openlayer API key are required for streaming data.');
@@ -56,7 +55,7 @@ class OpenlayerClient {
56
55
  const dataStreamQuery = this.resolvedQuery(dataStreamEndpoint);
57
56
  const response = yield fetch(dataStreamQuery, {
58
57
  body: JSON.stringify({
59
- config: this.openlayerDefaultDataConfig,
58
+ config,
60
59
  rows: [
61
60
  Object.assign(Object.assign({}, data), { id: (0, uuid_1.v4)(), timestamp: Math.round(((_a = data.timestamp) !== null && _a !== void 0 ? _a : Date.now()) / 1000) }),
62
61
  ],
@@ -226,11 +225,9 @@ class OpenAIMonitor {
226
225
  constructor({ openAiApiKey, openlayerApiKey, openlayerProjectName, openlayerInferencePipelineName, openlayerServerUrl, }) {
227
226
  this.openlayerInferencePipelineName = 'production';
228
227
  this.monitoringOn = false;
229
- this.formatChatCompletionInput = (messages) => messages
230
- .filter(({ role }) => role === 'user')
231
- .map(({ content }) => content)
232
- .join('\n')
233
- .trim();
228
+ this.formatChatCompletionInput = (messages) => messages.map(({ content, role }, i) => (role === 'user'
229
+ ? `{{ message_${i} }}`
230
+ : content));
234
231
  /**
235
232
  * Creates a chat completion using the OpenAI client and streams the result to Openlayer.
236
233
  * @param {ChatCompletionCreateParams} body - The parameters for creating a chat completion.
@@ -251,6 +248,15 @@ class OpenAIMonitor {
251
248
  // Accumulate output for streamed responses
252
249
  let outputData = '';
253
250
  const response = yield this.openAIClient.chat.completions.create(body, options);
251
+ const prompt = this.formatChatCompletionInput(body.messages);
252
+ const inputVariableNames = prompt
253
+ .filter(({ role }) => role === 'user')
254
+ .map(({ content }) => content);
255
+ const inputVariables = body.messages
256
+ .filter(({ role }) => role === 'user')
257
+ .map(({ content }) => content);
258
+ const inputVariablesMap = inputVariableNames.reduce((acc, name, i) => (Object.assign(Object.assign({}, acc), { [name]: inputVariables[i] })), {});
259
+ const config = Object.assign(Object.assign({}, this.openlayerClient.defaultConfig), { inputVariableNames });
254
260
  if (body.stream) {
255
261
  const streamedResponse = response;
256
262
  try {
@@ -271,12 +277,7 @@ class OpenAIMonitor {
271
277
  }
272
278
  const endTime = Date.now();
273
279
  const latency = endTime - startTime;
274
- this.openlayerClient.streamData({
275
- input: this.formatChatCompletionInput(body.messages),
276
- latency,
277
- output: outputData,
278
- timestamp: startTime,
279
- }, inferencePipeline.id);
280
+ this.openlayerClient.streamData(Object.assign({ latency, output: outputData, prompt, timestamp: startTime }, inputVariablesMap), config, inferencePipeline.id);
280
281
  }
281
282
  else {
282
283
  const nonStreamedResponse = response;
@@ -287,13 +288,9 @@ class OpenAIMonitor {
287
288
  if (typeof output !== 'string') {
288
289
  throw new Error('No output received from OpenAI.');
289
290
  }
290
- this.openlayerClient.streamData({
291
- input: this.formatChatCompletionInput(body.messages),
292
- latency,
291
+ this.openlayerClient.streamData(Object.assign({ latency,
293
292
  output,
294
- timestamp: startTime,
295
- tokens: (_e = (_d = nonStreamedResponse.usage) === null || _d === void 0 ? void 0 : _d.total_tokens) !== null && _e !== void 0 ? _e : 0,
296
- }, inferencePipeline.id);
293
+ prompt, timestamp: startTime, tokens: (_e = (_d = nonStreamedResponse.usage) === null || _d === void 0 ? void 0 : _d.total_tokens) !== null && _e !== void 0 ? _e : 0 }, inputVariablesMap), config, inferencePipeline.id);
297
294
  }
298
295
  return response;
299
296
  });
@@ -321,6 +318,7 @@ class OpenAIMonitor {
321
318
  let outputData = '';
322
319
  let tokensData = 0;
323
320
  const response = yield this.openAIClient.completions.create(body, options);
321
+ const config = Object.assign(Object.assign({}, this.openlayerClient.defaultConfig), { inputVariableNames: ['input'] });
324
322
  if (body.stream) {
325
323
  const streamedResponse = response;
326
324
  try {
@@ -348,7 +346,7 @@ class OpenAIMonitor {
348
346
  output: outputData,
349
347
  timestamp: startTime,
350
348
  tokens: tokensData,
351
- }, inferencePipeline.id);
349
+ }, config, inferencePipeline.id);
352
350
  }
353
351
  else {
354
352
  const nonStreamedResponse = response;
@@ -361,7 +359,7 @@ class OpenAIMonitor {
361
359
  output: nonStreamedResponse.choices[0].text,
362
360
  timestamp: startTime,
363
361
  tokens: (_o = (_m = nonStreamedResponse.usage) === null || _m === void 0 ? void 0 : _m.total_tokens) !== null && _o !== void 0 ? _o : 0,
364
- }, inferencePipeline.id);
362
+ }, config, inferencePipeline.id);
365
363
  }
366
364
  return response;
367
365
  });
@@ -0,0 +1,45 @@
1
+ /*
2
+ * This example shows how to use Openlayer to monitor your LangChain workflows.
3
+ */
4
+
5
+ import { ChatOpenAI } from 'langchain/chat_models/openai';
6
+ import { OpenlayerClient } from 'openlayer';
7
+
8
+ // Instantiate the Openlayer client with your API key
9
+ const openlayer = new OpenlayerClient({
10
+ openlayerApiKey: 'YOUR_OPENLAYER_API_KEY',
11
+ });
12
+
13
+ // Create or load your project
14
+ const project = await openlayer.createProject('YOUR_PROJECT_NAME', 'llm-base');
15
+
16
+ /*
17
+ * Create or load an inference pipeline from your project.
18
+ * If no name is specified, it will default to 'production'
19
+ */
20
+ const inferencePipeline = await openlayer.createInferencePipeline(project.id);
21
+ const chatModel = new ChatOpenAI();
22
+ const inputs = [
23
+ 'What is the meaning of life?',
24
+ 'What would be a good name for a company that makes colorful socks?',
25
+ ];
26
+
27
+ await Promise.all(
28
+ inputs.map(async (input) => {
29
+ // Call the LLM
30
+ const output = await chatModel.predict(input);
31
+
32
+ // Stream the results to Openlayer
33
+ await openlayer.streamData(
34
+ {
35
+ input,
36
+ output,
37
+ },
38
+ {
39
+ ...openlayer.defaultConfig,
40
+ inputVariableNames: ['input'],
41
+ },
42
+ inferencePipeline.id
43
+ );
44
+ })
45
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openlayer",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "The Openlayer TypeScript client",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
Binary file