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 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
- type: "function",
103
- function: {
104
- name: 'send_email',
105
- description: 'Send an email to the user with the recipes',
106
- parameters: {
107
- type: "object",
108
- properties: {
109
- email: {
110
- type: "string",
111
- description: "The email address of the user",
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
- required: ["email"],
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
- const response = await openai.chat.completions.create({
137
- model: "gpt-3.5",
138
- messages: [
139
- { role: 'system', content: "You'r an expert chef" },
140
- { role: 'user', content: "Suggest at least 5 recipes" },
141
- ],
142
- tools: [
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
- tool_choice: { name: 'get_recipes' },
187
- });
188
- expect(response.model).toEqual('gpt-3.5-mock');
189
- expect(response.choices[0]).toHaveProperty('finish_reason', 'tool_calls');
190
- expect(response.choices[0].message.tool_calls[0].function).toHaveProperty('name', 'get_recipes');
191
- expect(response.choices[0].message.tool_calls[0].function).toHaveProperty('arguments');
192
- expect(JSON.parse(response.choices[0].message.tool_calls[0].function.arguments)).toHaveProperty('recipes');
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openai-api-mock",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "A Node.js module for mocking OpenAI API responses in a development environment",
5
5
  "repository": {
6
6
  "type": "git",
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.companyName();
164
+ return faker.company.name();
163
165
  } else if (name === "phone") {
164
- return faker.phone.phoneNumber();
166
+ return faker.phone.number();
165
167
  } else if (name === "address") {
166
- return faker.address.streetAddress();
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.name.jobTitle();
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.datatype.uuid();
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
+ };