Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jbo/remove chatgpt library #460

Merged
merged 4 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions src/main/kotlin/javabot/Javabot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ constructor(

val activeOperations = sortedSetOf(OperationComparator())

@Volatile private var running = true
@Volatile
private var running = true

init {
val hook = Thread { this.shutdown() }
Expand Down Expand Up @@ -262,8 +263,8 @@ constructor(

if (
!ignores.contains(sender.nick) &&
!shunDao.isShunned(sender.nick) &&
(message.channel != null || isOnCommonChannel(message.user))
!shunDao.isShunned(sender.nick) &&
(message.channel != null || isOnCommonChannel(message.user))
) {
try {
if (message.triggered) {
Expand Down Expand Up @@ -292,16 +293,16 @@ constructor(
}

private fun postMessage(event: Message) {
if (event is Action) {
postAction(event.channel!!, event.value)
} else {
val value = event.massageTell()
if (event.channel != null) {
logMessage(event.channel, event.user, value)
adapter.send(event.channel, value)
} else {
LOG.debug("channel is null. sending directly to user: " + event)
privateMessageUser(event.user, value)
when {
event is NoOperationMessage -> {}
event is Action -> postAction(event.channel!!, event.value)
event.channel != null -> {
logMessage(event.channel, event.user, event.massageTell())
adapter.send(event.channel, event.massageTell())
}
else -> {
LOG.debug("channel is null. sending directly to user: $event")
privateMessageUser(event.user, event.massageTell())
}
}
}
Expand Down Expand Up @@ -338,9 +339,9 @@ constructor(

if (
responses.isEmpty() &&
(!message.value
.lowercase(Locale.getDefault())
.startsWith("${nick}'s".lowercase(Locale.getDefault())))
(!message.value
.lowercase(Locale.getDefault())
.startsWith("${nick}'s".lowercase(Locale.getDefault())))
) {
responses.add(
Message(message.channel, message.user, Sofia.unhandledMessage(message.user.nick))
Expand Down
24 changes: 24 additions & 0 deletions src/main/kotlin/javabot/Message.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,27 @@ open class Message(
return "Message{channel=${channel?.name ?: ""}, user=${user.nick}, message='$value', tell=${tell}}"
}
}

/**
* This is a standard message type whose content is NOT output to a user.
*/
class NoOperationMessage(
channel: Channel? = null,
user: JavabotUser,
value: String,
target: JavabotUser? = null,
triggered: Boolean = true,
addressed: Boolean = false
) : Message(
channel,
user,
value,
target,
triggered,
addressed
) {
constructor(
message: Message,
value: String
) : this(message.channel, message.user, value, message.target)
}
40 changes: 28 additions & 12 deletions src/main/kotlin/javabot/dao/ChatGPTDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package javabot.dao
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.google.common.cache.CacheBuilder
import com.google.inject.Inject
import com.google.inject.Singleton
import io.dropwizard.util.Duration
import javabot.Javabot
import javabot.JavabotConfig
import javabot.operations.throttle.BotRateLimiter
import javabot.service.HttpService
import java.util.concurrent.TimeUnit

data class GPTMessageContainer(
val messages: List<GPTMessage>,
Expand Down Expand Up @@ -52,22 +53,37 @@ constructor(
private val javabotConfig: JavabotConfig,
private val httpService: HttpService,
) {
private var limiter: BotRateLimiter =
private val mapper: ObjectMapper

private val limiter: BotRateLimiter =
BotRateLimiter(javabotConfig.chatGptLimit(), Duration.days(1).toMilliseconds())
private val queryCache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(1, TimeUnit.DAYS)
.build<String, GPTResponse>();

init {
mapper = ObjectMapper()
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
}

private fun getGPTResponse(prompt: String): GPTResponse {
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
}

fun sendPromptToChatGPT(prompt: String): String? {
fun sendPromptToChatGPT(key: String, prompt: String): String? {
val mapper = ObjectMapper()
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
return if (javabotConfig.chatGptKey().isNotEmpty() && limiter.tryAcquire()) {
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)
val response = queryCache.get(key) { getGPTResponse(prompt) }
return response.choices.first().message.content
} else {
// no chatGPT key? No chatGPT attempt.
Expand Down
18 changes: 11 additions & 7 deletions src/main/kotlin/javabot/operations/ChatGPTOperation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package javabot.operations
import java.util.*
import javabot.Javabot
import javabot.Message
import javabot.NoOperationMessage
import javabot.dao.AdminDao
import javabot.dao.ChatGPTDao
import javabot.dao.FactoidDao
Expand All @@ -17,7 +18,7 @@ constructor(
private var chatGPTDao: ChatGPTDao,
private var getFactoidOperation: GetFactoidOperation

) : BotOperation(bot, adminDao) {
) : BotOperation(bot, adminDao) {
override fun handleMessage(event: Message): List<Message> {
val message = event.value
val responses = mutableListOf<Message>()
Expand All @@ -39,28 +40,31 @@ constructor(
)

else -> {
val factoid=getFactoidOperation.handleMessage(Message(event.user,query)).firstOrNull()?.value
val seed=when {
factoid!=null ->
val factoid = getFactoidOperation.handleMessage(Message(event.user, query)).firstOrNull()?.value
val seed = when {
factoid != null ->
"Please frame the response in the context of the query having a potential answer of '${factoid}'."

else -> ""
}
val uuid = UUID.randomUUID()
val prompt =
"""
Someone is asking '$query'.
Restrict your answer to being applicable to the Java Virtual Machine,
and limit the response's length to under 510 characters,
and limit the response's length to under 500 characters,
formatted as simple text, no markdown or other markup, but urls are acceptable.
$seed
If the answer does not contain constructive information for Java programmers,
respond **ONLY** with "$uuid-not applicable" and no other text.
""".trimIndent().trim()
try {
val result = chatGPTDao.sendPromptToChatGPT(prompt)
val result = chatGPTDao.sendPromptToChatGPT(query, prompt)
if (!result.isNullOrEmpty() && !result.lowercase().contains(uuid.toString())) {
val response=result.cleanForIRC()
val response = result.cleanForIRC()
responses.add(Message(event, response))
} else {
responses.add(NoOperationMessage(event, "no appropriate response from ChatGPT"))
}
} catch (e: Throwable) {
Javabot.LOG.info("exception", e)
Expand Down
4 changes: 3 additions & 1 deletion src/test/kotlin/javabot/operations/ChatGPTOperationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ class ChatGPTOperationTest : BaseTest() {
arrayOf("speed of an african laden swallow", true, ""),
arrayOf("what is the maven directory structure", false, "Maven directory structure"),
arrayOf("suffering-oriented programming", false, "Suffering-oriented programming"),
arrayOf("list of DI frameworks", false, "Spring")
arrayOf("list of DI frameworks", false, "Spring"),
arrayOf("list of DI frameworks", false, "Spring"),
arrayOf("how do I declare a new variable in Javascript", true, "")
)

@Test(dataProvider = "queries")
Expand Down
Loading