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 #459

Merged
merged 1 commit 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
1 change: 1 addition & 0 deletions src/main/kotlin/javabot/dao/ChatGPTDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
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
Expand Down
79 changes: 60 additions & 19 deletions src/main/kotlin/javabot/operations/ChatGPTOperation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,77 @@ import javabot.Javabot
import javabot.Message
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. */
class ChatGPTOperation
@Inject
constructor(bot: Javabot, adminDao: AdminDao, var chatGPTDao: ChatGPTDao) :
BotOperation(bot, adminDao) {
constructor(
bot: Javabot,
adminDao: AdminDao,
private var chatGPTDao: ChatGPTDao,
private var getFactoidOperation: GetFactoidOperation

) : BotOperation(bot, adminDao) {
override fun handleMessage(event: Message): List<Message> {
val responses = mutableListOf<Message>()
val message = event.value
val responses = mutableListOf<Message>()
if (message.lowercase(Locale.getDefault()).startsWith("gpt ")) {
val uuid = UUID.randomUUID()
val query = message.substringAfter("gpt ")
val prompt =
"""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"""
.trimIndent()
try {
val result = chatGPTDao.sendPromptToChatGPT(prompt)
if (!result.isNullOrEmpty() && !result.lowercase().contains(uuid.toString())) {
responses.add(Message(event, result.toString()))
val query = message.substringAfter("gpt ").trim()
when {
query.equals("help", true) ->
responses.add(
Message(
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
question was "what would people say about my query, if they
weren't really sure of what a correct answer might be?"
"""
.cleanForIRC()
)
)

else -> {
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,
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)
if (!result.isNullOrEmpty() && !result.lowercase().contains(uuid.toString())) {
val response=result.cleanForIRC()
responses.add(Message(event, response))
}
} catch (e: Throwable) {
Javabot.LOG.info("exception", e)
}
}
} catch (e: Throwable) {
Javabot.LOG.info("exception", e)
}
}
return responses
}
}

fun String.cleanForIRC(): String {
return this.trimIndent()
.trim()
.replace("\n ", " ")
.replace(" \n", " ")
.replace("\n", " ")
}
5 changes: 2 additions & 3 deletions src/main/kotlin/javabot/service/HttpService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class HttpService {
private val client =
OkHttpClient()
.newBuilder()
.callTimeout(10, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.callTimeout(15, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS)
.addInterceptor { chain ->
val request = chain.request()
Expand Down Expand Up @@ -116,7 +116,6 @@ class HttpService {
.newCall(request)
.execute()
.use { response ->
println(response)
if (response.isSuccessful) {
return (response.body?.string() ?: throw HttpServiceException())
} else {
Expand Down
60 changes: 56 additions & 4 deletions src/test/kotlin/javabot/operations/ChatGPTOperationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,55 @@ import javabot.BaseTest
import javabot.Javabot.Companion.LOG
import javabot.JavabotConfig
import org.testng.Assert.assertTrue
import org.testng.annotations.BeforeClass
import org.testng.annotations.DataProvider
import org.testng.annotations.Test

class ChatGPTOperationTest : BaseTest() {
@Inject protected lateinit var operation: ChatGPTOperation
@Inject
protected lateinit var operation: ChatGPTOperation
@Inject
protected lateinit var addFactoidOperation: AddFactoidOperation

@Inject
protected lateinit var config: JavabotConfig

@BeforeClass
fun prepFactoids() {
addFactoidOperation.handleMessage(message("""
~suffering-oriented programming is
<reply>Suffering-oriented programming:
make it work, make it pretty, make it fast
- in that order.
http://nathanmarz.com/blog/suffering-oriented-programming.html"""
.cleanForIRC()))
}
@DataProvider
fun queries() = arrayOf(
arrayOf("help", false, "query. Note that GPT"),
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")
)

@Test(dataProvider = "queries")
fun runTestQuery(prompt: String, empty: Boolean, match: String) {
if (config.chatGptKey().isNotEmpty()) {
val response =
operation.handleMessage(message("~gpt $prompt"))
if (empty) {
assertTrue(response.isEmpty())
} else {
assertTrue(response.isNotEmpty())
assertTrue(response[0].value.lowercase().contains(match.lowercase()))
}
} else {
LOG.info("ChatGPT testing skipped, no key configured")
}
}

@Inject protected lateinit var config: JavabotConfig

@Test
fun testNonJavaQuestion() {
if (config.chatGptKey().isNotEmpty()) {
val response =
Expand All @@ -24,7 +65,6 @@ class ChatGPTOperationTest : BaseTest() {
}
}

@Test
fun testMavenDirectories() {
if (config.chatGptKey().isNotEmpty()) {
val response =
Expand All @@ -36,4 +76,16 @@ class ChatGPTOperationTest : BaseTest() {
LOG.info("ChatGPT testing skipped, no key configured")
}
}

fun testSuffering() {
val prompt = "~gpt what is suffering-oriented programming?"
if (config.chatGptKey().isNotEmpty()) {
val response =
operation.handleMessage(message("~gpt speed of an african laden swallow"))
assertTrue(response.isEmpty())
LOG.info("ChatGPT inappropriate (non-java) content test passed")
} else {
LOG.info("ChatGPT testing skipped, no key configured")
}
}
}
Loading