1
+ package com.cjcrafter.openai
2
+
3
+ import com.cjcrafter.openai.exception.OpenAIError
4
+ import com.cjcrafter.openai.exception.WrappedIOError
5
+ import com.google.gson.JsonObject
6
+ import com.google.gson.JsonParser
7
+ import okhttp3.Call
8
+ import okhttp3.Callback
9
+ import okhttp3.Response
10
+ import java.io.IOException
11
+ import java.util.function.Consumer
12
+
13
+ internal class MyCallback (
14
+ private val isStream : Boolean ,
15
+ private val onFailure : Consumer <OpenAIError >,
16
+ private val onResponse : Consumer <JsonObject >
17
+ ) : Callback {
18
+
19
+ override fun onFailure (call : Call , e : IOException ) {
20
+ onFailure.accept(WrappedIOError (e))
21
+ }
22
+
23
+ override fun onResponse (call : Call , response : Response ) {
24
+ onResponse(response)
25
+ }
26
+
27
+ fun onResponse (response : Response ) {
28
+ if (isStream) {
29
+ handleStream(response)
30
+ return
31
+ }
32
+
33
+ val rootObject = JsonParser .parseString(response.body!! .string()).asJsonObject
34
+
35
+ // Sometimes OpenAI will respond with an error code for malformed
36
+ // requests, timeouts, rate limits, etc. We need to let the dev
37
+ // know that an error occurred.
38
+ if (rootObject.has(" error" )) {
39
+ onFailure.accept(OpenAIError .fromJson(rootObject.get(" error" ).asJsonObject))
40
+ return
41
+ }
42
+
43
+ onResponse.accept(rootObject)
44
+ }
45
+
46
+ private fun handleStream (response : Response ) {
47
+ response.body?.source()?.use { source ->
48
+ while (! source.exhausted()) {
49
+ var jsonResponse = source.readUtf8()
50
+
51
+ // OpenAI returns a json string, but they prepend the content with
52
+ // "data: " (which is not valid json). In order to parse this into
53
+ // a JsonObject, we have to strip away this extra string.
54
+ jsonResponse = jsonResponse.substring(" data: " .length)
55
+
56
+ // After OpenAI's final message (which already contains a non-null
57
+ // finish reason), they redundantly send "data: [DONE]". Ignore it.
58
+ if (jsonResponse == " [DONE]" )
59
+ continue
60
+
61
+ val rootObject = JsonParser .parseString(jsonResponse).asJsonObject
62
+
63
+ // Sometimes OpenAI will respond with an error code for malformed
64
+ // requests, timeouts, rate limits, etc. We need to let the dev
65
+ // know that an error occurred.
66
+ if (rootObject.has(" error" )) {
67
+ onFailure.accept(OpenAIError .fromJson(rootObject.get(" error" ).asJsonObject))
68
+ continue
69
+ }
70
+
71
+ // Developer defined code to run
72
+ onResponse.accept(rootObject)
73
+ }
74
+ }
75
+ }
76
+ }
0 commit comments