openai-api-mock 0.1.12 → 0.1.14
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/main.js +11 -0
- package/main.test.js +52 -33
- package/package.json +1 -1
- package/readme.md +19 -0
- package/src/chat.js +7 -5
- package/src/chat.stream.js +60 -0
package/main.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const nock = require('nock');
|
|
2
|
+
|
|
3
|
+
|
|
2
4
|
const { getChatResponce } = require('./src/chat.js');
|
|
5
|
+
const { createChatStream } = require('./src/chat.stream.js');
|
|
6
|
+
|
|
3
7
|
const { getImageResponce } = require('./src/image.js');
|
|
4
8
|
|
|
5
9
|
const OPEN_AI_BASE_URL = 'https://api.openai.com';
|
|
@@ -13,6 +17,13 @@ function mockOpenAIResponse(force = false) {
|
|
|
13
17
|
nock(OPEN_AI_BASE_URL)
|
|
14
18
|
.post(CHAT_COMPLETIONS_ENDPOINT)
|
|
15
19
|
.reply(function (uri, requestBody) {
|
|
20
|
+
let isSteaming = (requestBody.stream && requestBody.stream == true) ? true : false
|
|
21
|
+
|
|
22
|
+
if (isSteaming) {
|
|
23
|
+
const stream = createChatStream();
|
|
24
|
+
return [200, stream];
|
|
25
|
+
}
|
|
26
|
+
|
|
16
27
|
return [200, getChatResponce(requestBody)];
|
|
17
28
|
});
|
|
18
29
|
|
package/main.test.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { mockOpenAIResponse, stopMocking } = require('./main');
|
|
2
|
+
const { Stream } = require('stream');
|
|
2
3
|
|
|
3
4
|
const OpenAI = require('openai');
|
|
4
5
|
const openai = new OpenAI({ apiKey: "OPENAI_API_KEY" });
|
|
@@ -26,6 +27,24 @@ describe('Mock OpenAI Chat & Image generation API', () => {
|
|
|
26
27
|
}
|
|
27
28
|
});
|
|
28
29
|
|
|
30
|
+
it('should mock the streaming chat completion', async () => {
|
|
31
|
+
try {
|
|
32
|
+
const response = await openai.chat.completions.create({
|
|
33
|
+
model: "gpt-3.5",
|
|
34
|
+
stream: true,
|
|
35
|
+
messages: [
|
|
36
|
+
{ role: 'user', content: "What's the biggest country in the world" },
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
for await (const part of response) {
|
|
41
|
+
console.log(part.choices[0]?.delta?.content || '')
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
throw new Error(error);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
29
48
|
it('should mock the chat completion with function call', async () => {
|
|
30
49
|
try {
|
|
31
50
|
const response = await openai.chat.completions.create({
|
|
@@ -90,7 +109,7 @@ describe('Mock OpenAI Chat & Image generation API', () => {
|
|
|
90
109
|
|
|
91
110
|
|
|
92
111
|
it('should mock the chat completion with email function call (tools)', async () => {
|
|
93
|
-
try{
|
|
112
|
+
try {
|
|
94
113
|
const response = await openai.chat.completions.create({
|
|
95
114
|
model: "gpt-3.5",
|
|
96
115
|
messages: [
|
|
@@ -99,23 +118,23 @@ describe('Mock OpenAI Chat & Image generation API', () => {
|
|
|
99
118
|
],
|
|
100
119
|
tools: [
|
|
101
120
|
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
type: "function",
|
|
122
|
+
function: {
|
|
123
|
+
name: 'send_email',
|
|
124
|
+
description: 'Send an email to the user with the recipes',
|
|
125
|
+
parameters: {
|
|
126
|
+
type: "object",
|
|
127
|
+
properties: {
|
|
128
|
+
email: {
|
|
129
|
+
type: "string",
|
|
130
|
+
description: "The email address of the user",
|
|
131
|
+
}
|
|
112
132
|
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
133
|
+
},
|
|
134
|
+
required: ["email"],
|
|
135
|
+
}
|
|
117
136
|
|
|
118
|
-
|
|
137
|
+
}],
|
|
119
138
|
|
|
120
139
|
tool_choice: { name: 'send_email' },
|
|
121
140
|
});
|
|
@@ -124,8 +143,8 @@ describe('Mock OpenAI Chat & Image generation API', () => {
|
|
|
124
143
|
expect(response.choices[0].message.tool_calls[0].function).toHaveProperty('name', 'send_email');
|
|
125
144
|
expect(response.choices[0].message.tool_calls[0].function).toHaveProperty('arguments');
|
|
126
145
|
expect(JSON.parse(response.choices[0].message.tool_calls[0].function.arguments)).toHaveProperty('email');
|
|
127
|
-
|
|
128
|
-
}catch(error){
|
|
146
|
+
|
|
147
|
+
} catch (error) {
|
|
129
148
|
throw new Error(error);
|
|
130
149
|
}
|
|
131
150
|
|
|
@@ -133,14 +152,14 @@ describe('Mock OpenAI Chat & Image generation API', () => {
|
|
|
133
152
|
|
|
134
153
|
|
|
135
154
|
it('should mock the chat completion with function call (tools)', async () => {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
const response = await openai.chat.completions.create({
|
|
156
|
+
model: "gpt-3.5",
|
|
157
|
+
messages: [
|
|
158
|
+
{ role: 'system', content: "You'r an expert chef" },
|
|
159
|
+
{ role: 'user', content: "Suggest at least 5 recipes" },
|
|
160
|
+
],
|
|
161
|
+
tools: [
|
|
162
|
+
{
|
|
144
163
|
type: "function",
|
|
145
164
|
function: {
|
|
146
165
|
name: 'get_recipes',
|
|
@@ -183,13 +202,13 @@ describe('Mock OpenAI Chat & Image generation API', () => {
|
|
|
183
202
|
}
|
|
184
203
|
|
|
185
204
|
}],
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
205
|
+
tool_choice: { name: 'get_recipes' },
|
|
206
|
+
});
|
|
207
|
+
expect(response.model).toEqual('gpt-3.5-mock');
|
|
208
|
+
expect(response.choices[0]).toHaveProperty('finish_reason', 'tool_calls');
|
|
209
|
+
expect(response.choices[0].message.tool_calls[0].function).toHaveProperty('name', 'get_recipes');
|
|
210
|
+
expect(response.choices[0].message.tool_calls[0].function).toHaveProperty('arguments');
|
|
211
|
+
expect(JSON.parse(response.choices[0].message.tool_calls[0].function.arguments)).toHaveProperty('recipes');
|
|
193
212
|
});
|
|
194
213
|
|
|
195
214
|
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -66,7 +66,26 @@ In this example, the `response` constant will contain mock data, simulating a re
|
|
|
66
66
|
usage: { completion_tokens: 17, prompt_tokens: 57, total_tokens: 74 }
|
|
67
67
|
}
|
|
68
68
|
```
|
|
69
|
+
The library also supports mocking `stream` responses
|
|
69
70
|
|
|
71
|
+
```js
|
|
72
|
+
// Call the mockOpenAIResponse function once to set up the mock
|
|
73
|
+
mockOpenAIResponse()
|
|
74
|
+
// Now, when you call the OpenAI API, it will return a mock response
|
|
75
|
+
const response = await openai.chat.completions.create({
|
|
76
|
+
model: "gpt-3.5",
|
|
77
|
+
stream : true,
|
|
78
|
+
messages: [
|
|
79
|
+
{ role: 'system', content: "You'r an expert chef" },
|
|
80
|
+
{ role: 'user', content: "Suggest at least 5 recipes" },
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// then read it
|
|
85
|
+
for await (const part of response) {
|
|
86
|
+
console.log(part.choices[0]?.delta?.content || '')
|
|
87
|
+
}
|
|
88
|
+
```
|
|
70
89
|
|
|
71
90
|
## Intercepted URLs
|
|
72
91
|
|
package/src/chat.js
CHANGED
|
@@ -35,6 +35,8 @@ function createDefaultResponse(created) {
|
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
|
|
39
|
+
|
|
38
40
|
function createFunctionCallingResponse(requestBody, created) {
|
|
39
41
|
const isTool = Boolean(requestBody.tools);
|
|
40
42
|
const functionOrToolCallObject = isTool
|
|
@@ -159,15 +161,15 @@ function generateFakeStringData(name) {
|
|
|
159
161
|
} else if (name === "price") {
|
|
160
162
|
return faker.commerce.price();
|
|
161
163
|
} else if (name === "company") {
|
|
162
|
-
return faker.company.
|
|
164
|
+
return faker.company.name();
|
|
163
165
|
} else if (name === "phone") {
|
|
164
|
-
return faker.phone.
|
|
166
|
+
return faker.phone.number();
|
|
165
167
|
} else if (name === "address") {
|
|
166
|
-
return faker.
|
|
168
|
+
return faker.location.streetAddress();
|
|
167
169
|
} else if (name === "date") {
|
|
168
170
|
return faker.date.past();
|
|
169
171
|
} else if (name === "jobTitle") {
|
|
170
|
-
return faker.
|
|
172
|
+
return faker.person.jobTitle();
|
|
171
173
|
} else if (name === "creditCardNumber") {
|
|
172
174
|
return faker.finance.creditCardNumber();
|
|
173
175
|
} else if (name === "currencyCode") {
|
|
@@ -175,7 +177,7 @@ function generateFakeStringData(name) {
|
|
|
175
177
|
} else if (name === "productName") {
|
|
176
178
|
return faker.commerce.productName();
|
|
177
179
|
} else if (name === "uuid") {
|
|
178
|
-
return faker.
|
|
180
|
+
return faker.string.uuid();
|
|
179
181
|
} else {
|
|
180
182
|
return faker.lorem.words(5);
|
|
181
183
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const { faker } = require("@faker-js/faker");
|
|
2
|
+
const { Readable } = require('stream');
|
|
3
|
+
|
|
4
|
+
function createChatStream() {
|
|
5
|
+
const stream = new Readable({
|
|
6
|
+
read() { }
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
let count = 0;
|
|
10
|
+
const maxCount = 5;
|
|
11
|
+
|
|
12
|
+
function sendData() {
|
|
13
|
+
setTimeout(() => {
|
|
14
|
+
if (count < maxCount - 1) {
|
|
15
|
+
stream.push(`data: ${getSteamChatObject()}\n\n`);
|
|
16
|
+
count++;
|
|
17
|
+
sendData(); // Call the function recursively until the last iteration
|
|
18
|
+
} else if (count === maxCount - 1) {
|
|
19
|
+
stream.push(`data: [DONE]\n\n`);
|
|
20
|
+
stream.push(null); // End the stream after sending the data
|
|
21
|
+
}
|
|
22
|
+
}, 200);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
sendData(); // Start sending data
|
|
26
|
+
|
|
27
|
+
return stream;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getSteamChatObject() {
|
|
31
|
+
const created = Math.floor(Date.now() / 1000);
|
|
32
|
+
|
|
33
|
+
let lorem = faker.lorem.paragraph()
|
|
34
|
+
const loremArray = lorem.split(" ");
|
|
35
|
+
|
|
36
|
+
let ob = {
|
|
37
|
+
id: `chatcmpl-${faker.string.alphanumeric(30)}`,
|
|
38
|
+
object: 'chat.completion.chunk',
|
|
39
|
+
created: created,
|
|
40
|
+
model: "gpt-3.5-mock",
|
|
41
|
+
system_fingerprint: null,
|
|
42
|
+
choices: [
|
|
43
|
+
{
|
|
44
|
+
index: 0,
|
|
45
|
+
delta: {
|
|
46
|
+
content: loremArray[0]
|
|
47
|
+
},
|
|
48
|
+
logprobs: null,
|
|
49
|
+
finish_reason: null
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return JSON.stringify(ob);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = {
|
|
58
|
+
createChatStream,
|
|
59
|
+
getSteamChatObject,
|
|
60
|
+
};
|