1
1
package me.kpavlov.aimocks.openai
2
2
3
3
import io.kotest.assertions.json.containJsonKeyValue
4
+ import io.kotest.matchers.string.contain
4
5
import io.ktor.serialization.kotlinx.json.json
5
6
import kotlinx.serialization.json.Json
6
7
import me.kpavlov.aimocks.core.AbstractMockLlm
7
8
import me.kpavlov.aimocks.openai.completions.OpenaiChatCompletionRequestSpecification
8
9
import me.kpavlov.aimocks.openai.completions.OpenaiChatCompletionsBuildingStep
10
+ import me.kpavlov.aimocks.openai.embeddings.OpenaiEmbedBuildingStep
11
+ import me.kpavlov.aimocks.openai.embeddings.OpenaiEmbedRequestSpecification
12
+ import me.kpavlov.aimocks.openai.model.embeddings.CreateEmbeddingsRequest
9
13
import me.kpavlov.aimocks.openai.model.moderation.CreateModerationRequest
10
14
import me.kpavlov.aimocks.openai.model.responses.CreateResponseRequest
11
15
import me.kpavlov.aimocks.openai.moderation.OpenaiModerationBuildingStep
@@ -25,6 +29,7 @@ import java.util.function.Consumer
25
29
* @param port The port on which the mock server will run. Defaults to 0, which allows the server to select
26
30
* an available port.
27
31
* @param verbose Controls whether the mock server's operations are logged in detail. Defaults to true.
32
+ * @see <a href="https://platform.openai.com/docs/api-reference">OpenAI API Reference</a>
28
33
* @author Konstantin Pavlov
29
34
*/
30
35
public open class MockOpenai (
@@ -51,6 +56,19 @@ public open class MockOpenai(
51
56
block : Consumer <OpenaiChatCompletionRequestSpecification >,
52
57
): OpenaiChatCompletionsBuildingStep = completion(name) { block.accept(this ) }
53
58
59
+ /* *
60
+ * Configures and constructs a mock handler for the OpenAI `/v1/chat/completions` endpoint.
61
+ *
62
+ * This method allows you to define specifications and criteria for chat completion requests,
63
+ * enabling controlled responses for testing and simulations.
64
+ *
65
+ * @param name An optional identifier for the mock configuration. Defaults to `null` if not provided.
66
+ * @param block A lambda function to configure the specifications for the chat completion request,
67
+ * using the `OpenaiChatCompletionRequestSpecification` object.
68
+ * @return An instance of `OpenaiChatCompletionsBuildingStep`, representing a builder step
69
+ * for configuring mock response behavior.
70
+ * @see <a href="https://platform.openai.com/docs/api-reference/chat/create">Create Chat Completion</a>
71
+ */
54
72
public fun completion (
55
73
name : String? = null,
56
74
block : OpenaiChatCompletionRequestSpecification .() -> Unit ,
@@ -94,6 +112,17 @@ public open class MockOpenai(
94
112
)
95
113
}
96
114
115
+ /* *
116
+ * Sets up a mock handler for the OpenAI `/v1/responses` endpoint,
117
+ * allowing configuration of request matching for response generation requests.
118
+ *
119
+ * This endpoint is used to generate responses based on input files and instructions.
120
+ *
121
+ * @param name Optional identifier for the mock configuration.
122
+ * @param block Lambda to configure the request matching criteria.
123
+ * @return A builder step for specifying the mock response to response generation requests.
124
+ * @see <a href="https://platform.openai.com/docs/api-reference/responses/create">OpenAI Responses API</a>
125
+ */
97
126
public fun responses (
98
127
name : String? = null,
99
128
block : OpenaiResponsesRequestSpecification .() -> Unit ,
@@ -133,12 +162,30 @@ public open class MockOpenai(
133
162
)
134
163
}
135
164
165
+ /* *
166
+ * Java-friendly overload that accepts a Consumer for configuring the moderation request.
167
+ *
168
+ * @param name Optional identifier for the mock configuration.
169
+ * @param block Consumer to configure the request matching criteria.
170
+ * @return A builder step for specifying the mock response to moderation requests.
171
+ */
136
172
@JvmOverloads
137
173
public fun moderation (
138
174
name : String? = null,
139
175
block : Consumer <OpenaiModerationRequestSpecification >,
140
176
): OpenaiModerationBuildingStep = moderation(name) { block.accept(this ) }
141
177
178
+ /* *
179
+ * Sets up a mock handler for the OpenAI `/v1/moderations` endpoint,
180
+ * allowing configuration of request matching for moderation requests.
181
+ *
182
+ * This endpoint classifies if input text or images violate OpenAI's usage policies.
183
+ *
184
+ * @param name Optional identifier for the mock configuration.
185
+ * @param block Lambda to configure the request matching criteria.
186
+ * @return A builder step for specifying the mock response to moderation requests.
187
+ * @see <a href="https://platform.openai.com/docs/api-reference/moderations/create">OpenAI Moderations API</a>
188
+ */
142
189
public fun moderation (
143
190
name : String? = null,
144
191
block : OpenaiModerationRequestSpecification .() -> Unit ,
@@ -170,5 +217,82 @@ public open class MockOpenai(
170
217
)
171
218
}
172
219
220
+ /* *
221
+ * Java-friendly overload that accepts a Consumer for configuring the embedding request.
222
+ *
223
+ * @param name Optional identifier for the mock configuration.
224
+ * @param block Consumer to configure the request matching criteria.
225
+ * @return A builder step for specifying the mock response to embedding requests.
226
+ */
227
+ @JvmOverloads
228
+ public fun embeddings (
229
+ name : String? = null,
230
+ block : Consumer <OpenaiEmbedRequestSpecification >,
231
+ ): OpenaiEmbedBuildingStep = embeddings(name) { block.accept(this ) }
232
+
233
+ /* *
234
+ * Sets up a mock handler for the OpenAI `/v1/embeddings` endpoint,
235
+ * allowing configuration of request matching for embedding requests.
236
+ *
237
+ * Supports matching on model, input (string or list), dimensions, encoding_format,
238
+ * and user fields in the request body.
239
+ *
240
+ * @param name Optional identifier for the mock configuration.
241
+ * @param block Lambda to configure the request matching criteria.
242
+ * @return A builder step for specifying the mock response to embedding requests.
243
+ * @see <a href="https://platform.openai.com/docs/api-reference/embeddings/create">OpenAI Embeddings API</a>
244
+ */
245
+ @JvmOverloads
246
+ public fun embeddings (
247
+ name : String? = null,
248
+ block : OpenaiEmbedRequestSpecification .() -> Unit ,
249
+ ): OpenaiEmbedBuildingStep {
250
+ val requestStep =
251
+ mokksy.post(
252
+ name = name,
253
+ requestType = CreateEmbeddingsRequest ::class ,
254
+ ) {
255
+ val embedRequestSpec = OpenaiEmbedRequestSpecification ()
256
+ block(embedRequestSpec)
257
+
258
+ path(" /v1/embeddings" )
259
+
260
+ embedRequestSpec.model?.let {
261
+ bodyString + = containJsonKeyValue(" model" , it)
262
+ }
263
+
264
+ // Handle string input
265
+ embedRequestSpec.stringInput?.let {
266
+ bodyString + = containJsonKeyValue(" input" , it)
267
+ }
268
+
269
+ // Handle string list input
270
+ embedRequestSpec.stringListInput?.let {
271
+ // For list inputs, we can't use containJsonKeyValue directly.
272
+ // Instead, we'll check that the request body contains the input values
273
+ it.forEach { inputValue ->
274
+ bodyString + = contain(inputValue)
275
+ }
276
+ }
277
+
278
+ embedRequestSpec.user?.let {
279
+ bodyString + = containJsonKeyValue(" user" , it)
280
+ }
281
+
282
+ embedRequestSpec.requestBodyString.forEach {
283
+ bodyString + = contain(it)
284
+ }
285
+ }
286
+
287
+ return OpenaiEmbedBuildingStep (
288
+ buildingStep = requestStep,
289
+ mokksy = mokksy,
290
+ )
291
+ }
292
+
293
+ public fun MockOpenai.moderation (
294
+ block : Consumer <OpenaiModerationRequestSpecification >,
295
+ ): OpenaiModerationBuildingStep = moderation(block)
296
+
173
297
override fun baseUrl (): String = " http://localhost:${port()} /v1"
174
298
}
0 commit comments