Skip to content

Commit

Permalink
Moved to LangChain4J for ChatGPT and Gemini modules
Browse files Browse the repository at this point in the history
  • Loading branch information
ethauvin committed Sep 9, 2024
1 parent ebc3da7 commit c60531f
Show file tree
Hide file tree
Showing 14 changed files with 102 additions and 163 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ local.properties
logs
mobibot.properties
out
/target/
6 changes: 3 additions & 3 deletions config/detekt/baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@
<ID>ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean</ID>
<ID>ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException</ID>
<ID>ReturnCount:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
<ID>SwallowedException:GoogleSearchTest.kt$GoogleSearchTest$e: ModuleException</ID>
<ID>SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException</ID>
<ID>SwallowedException:WolframAlphaTest.kt$WolframAlphaTest$e: ModuleException</ID>
<ID>ThrowsCount:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String</ID>
<ID>ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List&lt;Message&gt;</ID>
<ID>ThrowsCount:Joke.kt$Joke.Companion$@JvmStatic @Throws(ModuleException::class) fun randomJoke(): List&lt;Message&gt;</ID>
Expand All @@ -82,7 +79,9 @@
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject</ID>
<ID>ThrowsCount:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>ThrowsCount:WolframAlpha.kt$WolframAlpha.Companion$@JvmStatic @Throws(ModuleException::class) fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String</ID>
<ID>TooGenericExceptionCaught:ChatGpt2.kt$ChatGpt2.Companion$e: Exception</ID>
<ID>TooGenericExceptionCaught:Gemini.kt$Gemini.Companion$e: Exception</ID>
<ID>TooGenericExceptionCaught:Gemini2.kt$Gemini2.Companion$e: Exception</ID>
<ID>TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException</ID>
<ID>TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException</ID>
<ID>TooManyFunctions:EntryLink.kt$EntryLink : Serializable</ID>
Expand All @@ -94,6 +93,7 @@
<ID>WildcardImport:FeedMgrTest.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:FeedReaderTest.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:FeedsManager.kt$import com.rometools.rome.feed.synd.*</ID>
<ID>WildcardImport:Gemini2Test.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:GeminiTest.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:GoogleSearchTest.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:JokeTest.kt$import assertk.assertions.*</ID>
Expand Down
2 changes: 1 addition & 1 deletion lib/bld/bld-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true
bld.downloadLocation=
bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.6
bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.7
bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.9
bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.8
bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.1
Expand Down
50 changes: 34 additions & 16 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.thauvin.erik.mobibot</groupId>
<artifactId>mobibot</artifactId>
<version>0.8.0-rc+20240809180718</version>
<version>0.8.0-rc+20240908192921</version>
<name>mobibot</name>
<description></description>
<url></url>
Expand All @@ -18,7 +18,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.16.0</version>
<version>3.17.0</version>
<scope>compile</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -51,34 +51,28 @@
<version>33.2.1-jre</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-vertexai</artifactId>
<version>1.7.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>2.0.10</version>
<version>2.0.20</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-common</artifactId>
<version>2.0.10</version>
<version>2.0.20</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk7</artifactId>
<version>2.0.10</version>
<version>2.0.20</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>2.0.10</version>
<version>2.0.20</version>
<scope>compile</scope>
</dependency>
<dependency>
Expand All @@ -96,25 +90,49 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.15</version>
<version>2.0.16</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.1</version>
<version>2.24.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
<version>2.24.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.23.1</version>
<version>2.24.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>0.34.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-google-ai-gemini</artifactId>
<version>0.34.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-core</artifactId>
<version>0.34.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>0.34.0</version>
<scope>compile</scope>
</dependency>
<dependency>
Expand Down
13 changes: 3 additions & 10 deletions properties/mobibot.properties
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ disabled-modules=mastodon
# Automatically post links to Mastodon
#mastodon-auto-post=true


#
# Get Exchange Rate API key from: https://www.exchangerate-api.com/
#
Expand Down Expand Up @@ -75,19 +74,13 @@ disabled-modules=mastodon
#wolfram-units=imperial

#
# ChatGPT/OpenAI API key from: https://beta.openai.com/account/api-keys
# Get ChatGPT/OpenAI API key from: https://platform.openai.com/api-keys
#
#chatgpt-api-key=
#chatgpt-max-tokens=1024

#
# Set a Vertex AI Gemini API project in Google Cloud:
# https://cloud.google.com/vertex-ai/docs/generative-ai/start/quickstarts/quickstart-multimodal
# Don't forget to:
# gcloud config set project PROJECT_ID
# gcloud auth login LOGIN
# gcloud auth application-default login
# Get Google Gemini API key from https://ai.google.dev/gemini-api/docs/api-key
#
#gemini-project-id=
#gemini-location=us-west1
#gemini-api-key=
#gemini-max-tokens=1024
19 changes: 12 additions & 7 deletions src/bld/java/net/thauvin/erik/MobibotBuild.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,20 @@ public MobibotBuild() {
new Repository("https://jitpack.io"),
SONATYPE_SNAPSHOTS_LEGACY);

var log4j = version(2, 23, 1);
var kotlin = version(2, 0, 10);
var log4j = version(2, 24, 0);
var kotlin = version(2, 0, 20);
var langchain = version(0, 34, 0);
scope(compile)
// PircBotX
.include(dependency("com.github.pircbotx", "pircbotx", "2.3.1"))
// Commons (mostly for PircBotX)
.include(dependency("org.apache.commons", "commons-lang3", "3.16.0"))
.include(dependency("org.apache.commons", "commons-lang3", "3.17.0"))
.include(dependency("org.apache.commons", "commons-text", "1.12.0"))
.include(dependency("commons-codec", "commons-codec", "1.17.1"))
.include(dependency("commons-net", "commons-net", "3.11.1"))
// Google
.include(dependency("com.google.code.gson", "gson", "2.11.0"))
.include(dependency("com.google.guava", "guava", "33.2.1-jre"))
.include(dependency("com.google.cloud", "google-cloud-vertexai", "1.7.0"))
// Kotlin
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin))
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin))
Expand All @@ -99,10 +99,15 @@ public MobibotBuild() {
.include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.8.1"))
.include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6"))
// Logging
.include(dependency("org.slf4j", "slf4j-api", "2.0.15"))
.include(dependency("org.slf4j", "slf4j-api", "2.0.16"))
.include(dependency("org.apache.logging.log4j", "log4j-api", log4j))
.include(dependency("org.apache.logging.log4j", "log4j-core", log4j))
.include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", log4j))
// LangChain4J
.include(dependency("dev.langchain4j", "langchain4j-open-ai", langchain))
.include(dependency("dev.langchain4j", "langchain4j-google-ai-gemini", langchain))
.include(dependency("dev.langchain4j", "langchain4j-core", langchain))
.include(dependency("dev.langchain4j", "langchain4j", langchain))
// Misc.
.include(dependency("com.rometools", "rome", "2.1.0"))
.include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0"))
Expand All @@ -118,8 +123,8 @@ public MobibotBuild() {
scope(test)
.include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1)))
.include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 3)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 3)));
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 0)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 0)));

List<String> jars = new ArrayList<>();
runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName()));
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -396,11 +396,11 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro

// Load the modules
addons.add(Calc())
addons.add(ChatGpt())
addons.add(ChatGpt2())
addons.add(CryptoPrices())
addons.add(CurrencyConverter())
addons.add(Dice())
addons.add(Gemini())
addons.add(Gemini2())
addons.add(GoogleSearch())
addons.add(Info(tell, seen))
addons.add(Joke())
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import java.time.ZoneId
*/
object ReleaseInfo {
const val PROJECT = "mobibot"
const val VERSION = "0.8.0-rc+20240712110931"
const val VERSION = "0.8.0-rc+20240908190240"

@JvmField
@Suppress("MagicNumber")
val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant(
Instant.ofEpochMilli(1720807771484L), ZoneId.systemDefault()
Instant.ofEpochMilli(1725847361020L), ZoneId.systemDefault()
)

const val WEBSITE = "https://mobitopia.org/mobibot/"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,16 @@

package net.thauvin.erik.mobibot.modules

import net.thauvin.erik.mobibot.Constants
import dev.langchain4j.model.openai.OpenAiChatModel
import dev.langchain4j.model.openai.OpenAiChatModelName
import net.thauvin.erik.mobibot.Utils
import net.thauvin.erik.mobibot.Utils.sendMessage
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import org.pircbotx.hooks.types.GenericMessageEvent
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse

class ChatGpt : AbstractModule() {
val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java)
class ChatGpt2 : AbstractModule() {
val logger: Logger = LoggerFactory.getLogger(ChatGpt2::class.java)

override val name = CHATGPT_NAME

Expand Down Expand Up @@ -93,58 +86,22 @@ class ChatGpt : AbstractModule() {
*/
const val MAX_TOKENS_PROP = "chatgpt-max-tokens"

// ChatGPT API URL
private const val API_URL = "https://api.openai.com/v1/chat/completions"

// ChatGPT command
private const val CHATGPT_CMD = "chatgpt"

@JvmStatic
@Throws(ModuleException::class)
fun chat(query: String, apiKey: String?, maxTokens: Int): String {
if (!apiKey.isNullOrEmpty()) {
val jsonObject = JSONObject()
jsonObject.put("model", "gpt-3.5-turbo-1106")
jsonObject.put("max_tokens", maxTokens)
val message = JSONObject()
message.put("role", "user")
message.put("content", query)
val messages = JSONArray()
messages.put(message)
jsonObject.put("messages", messages)

val request = HttpRequest.newBuilder()
.uri(URI.create(API_URL))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer $apiKey")
.header("User-Agent", Constants.USER_AGENT)
.POST(HttpRequest.BodyPublishers.ofString(jsonObject.toString()))
.build()
try {
val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
if (response.statusCode() == 200) {
try {
val jsonResponse = JSONObject(response.body())
val choices = jsonResponse.getJSONArray("choices")
return choices.getJSONObject(0).getJSONObject("message").getString("content").trim()
} catch (e: JSONException) {
throw ModuleException(
"$CHATGPT_CMD($query): JSON",
"A JSON error has occurred while conversing with $CHATGPT_NAME.",
e
)
}
} else {
if (response.statusCode() == 429) {
throw ModuleException(
"$CHATGPT_CMD($query): Rate limit reached",
"Rate limit reached. Please try again later."
)
} else {
throw IOException("HTTP Status Code: " + response.statusCode())
}
}
} catch (e: IOException) {
val model = OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName(OpenAiChatModelName.GPT_4_O)
.maxTokens(maxTokens)
.build()

return model.generate(query)
} catch (e: Exception) {
throw ModuleException(
"$CHATGPT_CMD($query): IO",
"An IO error has occurred while conversing with $CHATGPT_NAME.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,6 @@ class CurrencyConverter : AbstractModule() {
init {
commands.add(CURRENCY_CMD)
initProperties(API_KEY_PROP)
loadSymbols(properties[ChatGpt.API_KEY_PROP])
loadSymbols(properties[ChatGpt2.API_KEY_PROP])
}
}
Loading

0 comments on commit c60531f

Please sign in to comment.