@@ -5,17 +5,21 @@ import arrow.resilience.retry
5
5
import com.xebia.functional.xef.configure
6
6
import com.xebia.functional.xef.env.OpenAIConfig
7
7
import com.xebia.functional.xef.httpClient
8
+ import com.xebia.functional.xef.llm.AIClientError
8
9
import io.github.oshai.KLogger
9
10
import io.github.oshai.KotlinLogging
10
11
import io.ktor.client.HttpClient
11
12
import io.ktor.client.call.body
12
13
import io.ktor.client.engine.HttpClientEngine
13
14
import io.ktor.client.plugins.timeout
14
15
import io.ktor.client.request.post
15
- import io.ktor.client.statement.HttpResponse
16
+ import io.ktor.client.statement.*
16
17
import io.ktor.http.path
17
18
import kotlinx.serialization.SerialName
18
19
import kotlinx.serialization.Serializable
20
+ import kotlinx.serialization.decodeFromString
21
+ import kotlinx.serialization.json.Json
22
+ import kotlinx.serialization.json.JsonElement
19
23
20
24
private val logger: KLogger = KotlinLogging .logger {}
21
25
@@ -60,7 +64,7 @@ private class KtorOpenAIClient(
60
64
}
61
65
}
62
66
63
- val body: CompletionResult = response.body ()
67
+ val body: CompletionResult = response.bodyOrError ()
64
68
with (body.usage) {
65
69
logger.debug {
66
70
" Completion Tokens :: prompt: $promptTokens , completion: $completionTokens , total: $totalTokens "
@@ -85,7 +89,7 @@ private class KtorOpenAIClient(
85
89
timeout { requestTimeoutMillis = config.requestTimeout.inWholeMilliseconds }
86
90
}
87
91
}
88
- val body: ChatCompletionResponse = response.body ()
92
+ val body: ChatCompletionResponse = response.bodyOrError ()
89
93
with (body.usage) {
90
94
logger.debug {
91
95
" Chat Completion Tokens :: prompt: $promptTokens , completion: $completionTokens , total: $totalTokens "
@@ -103,7 +107,7 @@ private class KtorOpenAIClient(
103
107
timeout { requestTimeoutMillis = config.requestTimeout.inWholeMilliseconds }
104
108
}
105
109
}
106
- val body: EmbeddingResult = response.body ()
110
+ val body: EmbeddingResult = response.bodyOrError ()
107
111
with (body.usage) { logger.debug { " Embeddings Tokens :: total: $totalTokens " } }
108
112
return body
109
113
}
@@ -117,6 +121,20 @@ private class KtorOpenAIClient(
117
121
timeout { requestTimeoutMillis = config.requestTimeout.inWholeMilliseconds }
118
122
}
119
123
}
120
- return response.body()
124
+ return response.bodyOrError()
125
+ }
126
+ }
127
+
128
+ val JsonLenient = Json {
129
+ isLenient = true
130
+ ignoreUnknownKeys = true
131
+ }
132
+
133
+ private suspend inline fun <reified T > HttpResponse.bodyOrError (): T {
134
+ val contents = bodyAsText()
135
+ try {
136
+ return JsonLenient .decodeFromString<T >(contents)
137
+ } catch (_: IllegalArgumentException ) {
138
+ throw AIClientError (JsonLenient .decodeFromString<JsonElement >(contents))
121
139
}
122
140
}
0 commit comments