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 +35 -0
- package/dist/index.d.ts +44 -11
- package/dist/index.js +22 -24
- package/examples/langchain.mjs +45 -0
- package/package.json +1 -1
- package/static/logo.png +0 -0
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
|
+
[](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
|
|
8
|
-
[
|
|
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
|
-
|
|
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 {
|
|
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:
|
|
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.
|
|
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 {
|
|
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
|
|
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
|
-
|
|
231
|
-
|
|
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
package/static/logo.png
ADDED
|
Binary file
|