openai-api-mock 0.1.13 → 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 +2 -0
- 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
|
@@ -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
|
+
};
|