diff --git a/pom.xml b/pom.xml
index 68108bd9..f6ee4347 100644
--- a/pom.xml
+++ b/pom.xml
@@ -540,11 +540,7 @@
xz
1.9
-
- io.github.umutayb
- gpt-utilities
- 0.1.4
-
+
diff --git a/src/main/kotlin/javabot/dao/ChatGPTDao.kt b/src/main/kotlin/javabot/dao/ChatGPTDao.kt
index d1825047..f65f2806 100644
--- a/src/main/kotlin/javabot/dao/ChatGPTDao.kt
+++ b/src/main/kotlin/javabot/dao/ChatGPTDao.kt
@@ -1,27 +1,73 @@
package javabot.dao
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.fasterxml.jackson.databind.DeserializationFeature
+import com.fasterxml.jackson.databind.ObjectMapper
import com.google.inject.Inject
import com.google.inject.Singleton
-import gpt.api.GPT
-import gpt.models.Message
-import gpt.models.MessageModel
import io.dropwizard.util.Duration
import javabot.JavabotConfig
import javabot.operations.throttle.BotRateLimiter
+import javabot.service.HttpService
-@Singleton
-class ChatGPTDao @Inject constructor(val javabotConfig: JavabotConfig) {
+data class GPTMessageContainer(
+ val messages: List,
+ val model: String = "gpt-4",
+ val temperature: Double = 0.7
+)
+
+data class GPTMessage(val content: String, val role: String = "user")
+
+class GPTResponse(
+ @JsonProperty("id") val id: String,
+ @JsonProperty("object") val completion: String,
+ @JsonProperty("created") val created: Long,
+ @JsonProperty("model") val model: String,
+ @JsonProperty("choices") val choices: List,
+ @JsonProperty("usage") val usage: GPTUsage
+)
+
+class GPTUsage(
+ @JsonProperty("prompt_tokens") val promptTokens: Int,
+ @JsonProperty("completion_tokens") val completionTokens: Int,
+ @JsonProperty("total_tokens") val totalTokens: Int
+)
+class GPTChoice(
+ @JsonProperty("message") val message: GPTChoiceMessage,
+ @JsonProperty("index") val index: Int,
+ @JsonProperty("finish_reason") val finishReason: String
+)
+
+data class GPTChoiceMessage(
+ @JsonProperty("content") val content: String,
+ @JsonProperty("role") val role: String
+)
+
+@Singleton
+class ChatGPTDao
+@Inject
+constructor(
+ private val javabotConfig: JavabotConfig,
+ private val httpService: HttpService,
+) {
private var limiter: BotRateLimiter =
BotRateLimiter(javabotConfig.chatGptLimit(), Duration.days(1).toMilliseconds())
fun sendPromptToChatGPT(prompt: String): String? {
+ val mapper = ObjectMapper()
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
return if (javabotConfig.chatGptKey().isNotEmpty() && limiter.tryAcquire()) {
- val model = "gpt-4"
- val gpt = GPT(javabotConfig.chatGptKey())
- val messageModel = MessageModel(model, listOf(Message("user", prompt)))
- val messageResponse = gpt.sendMessage(messageModel)
- return messageResponse.choices[0].message.content
+ val data =
+ httpService.post(
+ "https://api.openai.com/v1/chat/completions",
+ emptyMap(),
+ mapOf("Authorization" to "Bearer ${javabotConfig.chatGptKey()}"),
+ emptyMap(),
+ GPTMessageContainer(listOf(GPTMessage(prompt)))
+ )
+ val response = mapper.readValue(data, GPTResponse::class.java)
+ return response.choices.first().message.content
} else {
// no chatGPT key? No chatGPT attempt.
null
diff --git a/src/main/kotlin/javabot/operations/ChatGPTOperation.kt b/src/main/kotlin/javabot/operations/ChatGPTOperation.kt
index 82e4e679..a64b23ec 100644
--- a/src/main/kotlin/javabot/operations/ChatGPTOperation.kt
+++ b/src/main/kotlin/javabot/operations/ChatGPTOperation.kt
@@ -19,16 +19,20 @@ constructor(bot: Javabot, adminDao: AdminDao, var chatGPTDao: ChatGPTDao) :
val uuid = UUID.randomUUID()
val query = message.substringAfter("gpt ")
val prompt =
- """Someone is asking "$query".
+ """Someone is asking '$query'.
Restrict your answer to being applicable to the Java Virtual Machine,
and limit the response's length as if it were to be posted on Twitter,
but without hashtags or other such twitter-like features;
if the answer does not contain constructive information for Java programming,
- respond ONLY with \"$uuid-not applicable\" and no other text"""
+ respond ONLY with "$uuid-not applicable" and no other text"""
.trimIndent()
- val result = chatGPTDao.sendPromptToChatGPT(prompt)
- if (!result.isNullOrEmpty() && !result.lowercase().contains(uuid.toString())) {
- responses.add(Message(event, result.toString()))
+ try {
+ val result = chatGPTDao.sendPromptToChatGPT(prompt)
+ if (!result.isNullOrEmpty() && !result.lowercase().contains(uuid.toString())) {
+ responses.add(Message(event, result.toString()))
+ }
+ } catch (e: Throwable) {
+ Javabot.LOG.info("exception", e)
}
}
return responses
diff --git a/src/main/kotlin/javabot/service/HttpService.kt b/src/main/kotlin/javabot/service/HttpService.kt
index 39730134..57c82bff 100644
--- a/src/main/kotlin/javabot/service/HttpService.kt
+++ b/src/main/kotlin/javabot/service/HttpService.kt
@@ -1,12 +1,15 @@
package javabot.service
+import com.fasterxml.jackson.databind.ObjectMapper
import com.google.inject.Singleton
import java.time.Duration
import java.util.concurrent.TimeUnit
import okhttp3.Headers.Companion.toHeaders
import okhttp3.HttpUrl.Companion.toHttpUrl
+import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
class HttpServiceException(message: String = "No message") : Exception(message)
@@ -63,26 +66,57 @@ class HttpService {
params: Map = emptyMap(),
headers: Map = emptyMap(),
options: Map = emptyMap()
+ ): String = request(url, params, headers, options, "get", null)
+
+ fun post(
+ url: String,
+ params: Map = emptyMap(),
+ headers: Map = emptyMap(),
+ options: Map = emptyMap(),
+ body: Any? = null
+ ): String = request(url, params, headers, options, "post", body)
+
+ fun request(
+ url: String,
+ params: Map = emptyMap(),
+ headers: Map = emptyMap(),
+ options: Map = emptyMap(),
+ method: String = "get",
+ body: Any? = null
): String {
val httpUrl = url.toHttpUrl()
val builder = httpUrl.newBuilder()
params.forEach { builder.addQueryParameter(it.key, it.value) }
- val request = Request.Builder().url(builder.build()).headers(headers.toHeaders()).build()
+ val requestBuilder = Request.Builder().url(builder.build()).headers(headers.toHeaders())
+ when (method) {
+ "get" -> requestBuilder.get()
+ "post" -> {
+ val mapper = ObjectMapper()
+ val bodyContent = mapper.writeValueAsString(body)
+ requestBuilder.post(
+ bodyContent.toRequestBody("application/json; chartset=utf-8".toMediaType())
+ )
+ }
+ else ->
+ throw IllegalArgumentException("method type $method not supported by HttpService")
+ }
+ val request = requestBuilder.build()
// if options aren't empty, build a local copy of the request.
// otherwise, use the global client options as is.
- if (!options.isEmpty()) {
- val localRequest = client.newBuilder()
+ if (options.isNotEmpty()) {
+ val localRequest = client.newBuilder()
- options.forEach { action -> action.key.apply(localRequest, action.value) }
+ options.forEach { action -> action.key.apply(localRequest, action.value) }
- localRequest.build()
- } else {
- client
- }
+ localRequest.build()
+ } else {
+ client
+ }
.newCall(request)
.execute()
.use { response ->
+ println(response)
if (response.isSuccessful) {
return (response.body?.string() ?: throw HttpServiceException())
} else {