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

Add counter to factoid usage; also includes IDEA formatting #473

Merged
merged 6 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -553,14 +553,14 @@
<critter.version>4.4.4</critter.version>
<dropwizard.version>2.1.5</dropwizard.version>
<guice.version>5.1.0</guice.version>
<jackson.version>2.14.2</jackson.version>
<jackson.version>2.17.0</jackson.version>
<jacoco.version>0.8.5</jacoco.version>
<jaxb.version>2.3.1</jaxb.version>
<jsoup.version>1.15.4</jsoup.version>
<kotlin.version>1.9.22</kotlin.version>
<kotlin.version>1.9.23</kotlin.version>
<logback.version>1.5.3</logback.version>
<morphia.version>2.3.9</morphia.version>
<okhttp.version>4.10.0</okhttp.version>
<okhttp.version>4.12.0</okhttp.version>
<slf4j.version>2.0.12</slf4j.version>
<sofia.version>0.25</sofia.version>
<kgpt.version>1.0.1</kgpt.version>
Expand Down
13 changes: 6 additions & 7 deletions src/main/kotlin/javabot/Javabot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ 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 @@ -263,8 +262,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 @@ -339,9 +338,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
13 changes: 2 additions & 11 deletions src/main/kotlin/javabot/Message.kt
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,15 @@ open class Message(
}
}

/**
* This is a standard message type whose content is NOT output to a user.
*/
/** 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
) {
) : Message(channel, user, value, target, triggered, addressed) {
constructor(
message: Message,
value: String
Expand Down
22 changes: 9 additions & 13 deletions src/main/kotlin/javabot/dao/ChatGPTDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,33 @@ package javabot.dao
import com.enigmastation.kgpt.GPT
import com.enigmastation.kgpt.model.BaseGPTResponse
import com.enigmastation.kgpt.model.GPTMessage
import com.enigmastation.kgpt.model.GPTResponse
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 java.util.concurrent.TimeUnit
import javabot.JavabotConfig
import javabot.operations.throttle.BotRateLimiter
import javabot.service.HttpService
import java.util.concurrent.TimeUnit

@Singleton
class ChatGPTDao
@Inject
constructor(
private val javabotConfig: JavabotConfig,
) {
private val gpt= GPT(javabotConfig.chatGptKey())
private val gpt = GPT(javabotConfig.chatGptKey())

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

private fun getGPTResponse(prompts:List<GPTMessage>): BaseGPTResponse = gpt.query(prompts)
private fun getGPTResponse(prompts: List<GPTMessage>): BaseGPTResponse = gpt.query(prompts)

fun sendPromptToChatGPT(key: String, prompts:List<GPTMessage>): String? {
fun sendPromptToChatGPT(key: String, prompts: List<GPTMessage>): String? {
return if (limiter.tryAcquire()) {
val response = queryCache.get(key) { getGPTResponse(prompts) }
return response.first()
Expand Down
8 changes: 5 additions & 3 deletions src/main/kotlin/javabot/model/Factoid.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class Factoid() : Serializable, Persistent {
var lastUsed: LocalDateTime? = null

var locked = false
var usage = 0

@Indexed lateinit var upperName: String

Expand Down Expand Up @@ -94,7 +95,7 @@ class Factoid() : Serializable, Persistent {

private fun camelcase(`in`: String): String {
val sb = StringBuilder(`in`.replace("\\s".toRegex(), " "))
if (!`in`.isEmpty()) {
if (`in`.isNotEmpty()) {
var idx = sb.indexOf(" ")
sb.setCharAt(0, Character.toUpperCase(sb[0]))
while (idx > -1) {
Expand Down Expand Up @@ -141,14 +142,15 @@ class Factoid() : Serializable, Persistent {

override fun toString(): String {
return format(
"Factoid{id=%s, name='%s', value='%s', userName='%s', updated=%s, lastUsed=%s, locked=%s}",
"Factoid{id=%s, name='%s', value='%s', userName='%s', updated=%s, lastUsed=%s, locked=%s, usage=%d}",
id,
name,
value,
userName,
updated,
lastUsed,
locked
locked,
usage
)
}

Expand Down
57 changes: 32 additions & 25 deletions src/main/kotlin/javabot/operations/ChatGPTOperation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import javabot.Message
import javabot.NoOperationMessage
import javabot.dao.AdminDao
import javabot.dao.ChatGPTDao
import javabot.dao.FactoidDao
import javax.inject.Inject

/** Gets current weather conditions for a place given as a parameter. */
Expand All @@ -19,7 +18,6 @@ constructor(
adminDao: AdminDao,
private var chatGPTDao: ChatGPTDao,
private var getFactoidOperation: GetFactoidOperation

) : BotOperation(bot, adminDao) {
override fun handleMessage(event: Message): List<Message> {
val message = event.value
Expand All @@ -30,7 +28,8 @@ constructor(
query.equals("help", true) ->
responses.add(
Message(
event, """
event,
"""
Simply use '~gpt query' to generate a Java-focused query.
Note that GPT is not exceptionally reliable: the data is based
on content from April 2023, and should be considered as if the
Expand All @@ -40,36 +39,48 @@ constructor(
.cleanForIRC()
)
)

else -> {
val factoid = getFactoidOperation.handleMessage(Message(event.user, query)).firstOrNull()?.value
val seed = when {
factoid != null ->
"Frame the response in the context of the query having a potential answer of '${factoid}'."
else -> null
}
val factoid =
getFactoidOperation
.handleMessage(Message(event.user, query))
.firstOrNull()
?.value
val seed =
when {
factoid != null ->
"Frame the response in the context of the query having a potential answer of '${factoid}'."
else -> null
}
val uuid = UUID.randomUUID()
try {
val result = chatGPTDao.sendPromptToChatGPT(
query,
listOfNotNull(
"Someone is asking '$query', in the context of the Java Virtual Machine.".asUser(),
"""
val result =
chatGPTDao.sendPromptToChatGPT(
query,
listOfNotNull(
"Someone is asking '$query', in the context of the Java Virtual Machine."
.asUser(),
"""
If the answer does not contain constructive information for Java programmers,
respond **ONLY** with \"$uuid-not applicable\" and no other text.

Restrict your answer to being applicable to the Java Virtual Machine, and
limit the response's length to under 500 characters, formatted as simple text,
no markdown or other markup, but urls are acceptable.
""".trimIndent().asSystem(),
seed?.asSystem()
"""
.trimIndent()
.asSystem(),
seed?.asSystem()
)
)
)
if (!result.isNullOrEmpty() && !result.lowercase().contains(uuid.toString())) {
if (
!result.isNullOrEmpty() && !result.lowercase().contains(uuid.toString())
) {
val response = result.cleanForIRC()
responses.add(Message(event, response))
} else {
responses.add(NoOperationMessage(event, "no appropriate response from ChatGPT"))
responses.add(
NoOperationMessage(event, "no appropriate response from ChatGPT")
)
}
} catch (e: Throwable) {
Javabot.LOG.info("exception", e)
Expand All @@ -82,9 +93,5 @@ constructor(
}

fun String.cleanForIRC(): String {
return this.trimIndent()
.trim()
.replace("\n ", " ")
.replace(" \n", " ")
.replace("\n", " ")
return this.trimIndent().trim().replace("\n ", " ").replace(" \n", " ").replace("\n", " ")
}
1 change: 1 addition & 0 deletions src/main/kotlin/javabot/operations/GetFactoidOperation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ constructor(bot: Javabot, adminDao: AdminDao, var factoidDao: FactoidDao) :
if (factoid != null) {
getResponse(responses, event, backtrack, params, factoid)
factoid.lastUsed = LocalDateTime.now()
factoid.usage += 1
factoidDao.save(factoid)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package javabot.operations.urlcontent

import java.net.URI
import java.net.URL
import java.util.ArrayList
import java.util.stream.Collectors
import org.apache.commons.lang.StringUtils.isBlank
import org.apache.commons.lang3.ArrayUtils
import org.apache.commons.lang3.StringUtils

class URLFromMessageParser {

Expand All @@ -21,7 +21,7 @@ class URLFromMessageParser {
val url =
if (idxSpace == -1) message.substring(idxHttp)
else message.substring(idxHttp, idxSpace)
potentialUrlsFound.add(stripPunctuation(message, url, idxHttp))
potentialUrlsFound.add(stripPunctuation(url))
idxHttp = if (idxSpace == -1) -1 else message.indexOf("http", idxSpace)
}

Expand All @@ -30,49 +30,37 @@ class URLFromMessageParser {
return list
}

private fun stripPunctuation(message: String, url: String, idxUrlStart: Int): String {
private fun stripPunctuation(url: String): String {
val last = url[url.length - 1]

val idxPunc = ArrayUtils.indexOf(CLOSE_PUNCTUATION, last)
if (idxPunc == -1) {
return url
} else {
return url.substring(0, url.indexOf(CLOSE_PUNCTUATION[idxPunc]))
}

// Walk backwards in message from urlStart, and strip the punctuation if an open
// brace/bracket is seen
// before another close. Otherwise, return the url as is.
for (c in StringUtils.reverse(message.substring(0, idxUrlStart)).toCharArray()) {
if (c == OPEN_PUNCTUATION[idxPunc]) {
return url.substring(0, url.length - 1)
}
if (c == CLOSE_PUNCTUATION[idxPunc]) {
return url
}
}
return url
}

private fun urlFromToken(token: String): URL? {
return try {
val url = URL(token)
val url = URI(token).toURL()
if (blacklistHosts.contains(url.host)) null else url
} catch (e: Exception) {
null
}
}

companion object {
private val OPEN_PUNCTUATION = charArrayOf('{', '(', '[')
private val CLOSE_PUNCTUATION = charArrayOf('}', ')', ']')
val blacklistHosts =
val blacklistHosts: List<String> =
try {
this::class
.java
.getResourceAsStream("/urlBlacklist.csv")
.bufferedReader(Charsets.UTF_8)
.use { it.lines().collect(Collectors.toList()) }
?.bufferedReader(Charsets.UTF_8)
.use { it!!.lines().collect(Collectors.toList()) }
} catch (ignored: Exception) {
emptyList<String>()
emptyList()
}
}
}
13 changes: 6 additions & 7 deletions src/main/kotlin/javabot/service/HttpService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,22 +97,21 @@ class HttpService {
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.isNotEmpty()) {
val localRequest = client.newBuilder()
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 ->
Expand Down
Loading
Loading