diff --git a/.gitignore b/.gitignore index d2daf1c..6c5fc87 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,3 @@ local.properties logs mobibot.properties out -/target/ diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml index 5c4010c..4dd96bf 100644 --- a/.idea/libraries/bld.xml +++ b/.idea/libraries/bld.xml @@ -2,12 +2,12 @@ - + - + diff --git a/.idea/libraries/compile.xml b/.idea/libraries/compile.xml index 99cc0c0..9bd86aa 100644 --- a/.idea/libraries/compile.xml +++ b/.idea/libraries/compile.xml @@ -7,7 +7,7 @@ - - + + \ No newline at end of file diff --git a/.idea/libraries/runtime.xml b/.idea/libraries/runtime.xml index d4069f2..2ae5c4b 100644 --- a/.idea/libraries/runtime.xml +++ b/.idea/libraries/runtime.xml @@ -8,7 +8,7 @@ - - + + \ No newline at end of file diff --git a/.idea/libraries/test.xml b/.idea/libraries/test.xml index 57ed5ef..b80486a 100644 --- a/.idea/libraries/test.xml +++ b/.idea/libraries/test.xml @@ -8,7 +8,7 @@ - - + + \ No newline at end of file diff --git a/README.md b/README.md index e438c94..a4db76e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # mobibot [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.0.20-7f52ff.svg)](https://kotlinlang.org) -[![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) +[![Kotlin](https://img.shields.io/badge/kotlin-2.0.10-7f52ff.svg)](https://kotlinlang.org) +[![bld](https://img.shields.io/badge/2.0.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) [![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index 719ca4e..b20abc9 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -71,6 +71,9 @@ ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException ReturnCount:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) + SwallowedException:GoogleSearchTest.kt$GoogleSearchTest$e: ModuleException + SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException + SwallowedException:WolframAlphaTest.kt$WolframAlphaTest$e: ModuleException ThrowsCount:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> ThrowsCount:Joke.kt$Joke.Companion$@JvmStatic @Throws(ModuleException::class) fun randomJoke(): List<Message> @@ -79,9 +82,7 @@ ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject ThrowsCount:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> ThrowsCount:WolframAlpha.kt$WolframAlpha.Companion$@JvmStatic @Throws(ModuleException::class) fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String - TooGenericExceptionCaught:ChatGpt2.kt$ChatGpt2.Companion$e: Exception TooGenericExceptionCaught:Gemini.kt$Gemini.Companion$e: Exception - TooGenericExceptionCaught:Gemini2.kt$Gemini2.Companion$e: Exception TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException TooManyFunctions:EntryLink.kt$EntryLink : Serializable @@ -93,7 +94,6 @@ WildcardImport:FeedMgrTest.kt$import assertk.assertions.* WildcardImport:FeedReaderTest.kt$import assertk.assertions.* WildcardImport:FeedsManager.kt$import com.rometools.rome.feed.synd.* - WildcardImport:Gemini2Test.kt$import assertk.assertions.* WildcardImport:GeminiTest.kt$import assertk.assertions.* WildcardImport:GoogleSearchTest.kt$import assertk.assertions.* WildcardImport:JokeTest.kt$import assertk.assertions.* diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar index 5425f1c..1d2b318 100644 Binary files a/lib/bld/bld-wrapper.jar and b/lib/bld/bld-wrapper.jar differ diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index ed0fdb7..26eaf6a 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -1,10 +1,10 @@ bld.downloadExtensionJavadoc=false bld.downloadExtensionSources=true bld.downloadLocation= -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 +bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.5 +bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.8 +bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.7 +bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.0 bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.sourceDirectories= -bld.version=2.1.0 +bld.version=2.0.1 diff --git a/pom.xml b/pom.xml index 5d1b89a..7996b05 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.thauvin.erik.mobibot mobibot - 0.8.0-rc+20240908192921 + 0.8.0-rc+20240809180718 mobibot @@ -18,7 +18,7 @@ org.apache.commons commons-lang3 - 3.17.0 + 3.16.0 compile @@ -51,28 +51,34 @@ 33.2.1-jre compile + + com.google.cloud + google-cloud-vertexai + 1.7.0 + compile + org.jetbrains.kotlin kotlin-stdlib - 2.0.20 + 2.0.10 compile org.jetbrains.kotlin kotlin-stdlib-common - 2.0.20 + 2.0.10 compile org.jetbrains.kotlin kotlin-stdlib-jdk7 - 2.0.20 + 2.0.10 compile org.jetbrains.kotlin kotlin-stdlib-jdk8 - 2.0.20 + 2.0.10 compile @@ -90,49 +96,25 @@ org.slf4j slf4j-api - 2.0.16 + 2.0.15 compile org.apache.logging.log4j log4j-api - 2.24.0 + 2.23.1 compile org.apache.logging.log4j log4j-core - 2.24.0 + 2.23.1 compile org.apache.logging.log4j log4j-slf4j2-impl - 2.24.0 - compile - - - dev.langchain4j - langchain4j-open-ai - 0.34.0 - compile - - - dev.langchain4j - langchain4j-google-ai-gemini - 0.34.0 - compile - - - dev.langchain4j - langchain4j-core - 0.34.0 - compile - - - dev.langchain4j - langchain4j - 0.34.0 + 2.23.1 compile diff --git a/properties/mobibot.properties b/properties/mobibot.properties index fd7b104..a7526cc 100644 --- a/properties/mobibot.properties +++ b/properties/mobibot.properties @@ -45,6 +45,7 @@ disabled-modules=mastodon # Automatically post links to Mastodon #mastodon-auto-post=true + # # Get Exchange Rate API key from: https://www.exchangerate-api.com/ # @@ -74,13 +75,19 @@ disabled-modules=mastodon #wolfram-units=imperial # -# Get ChatGPT/OpenAI API key from: https://platform.openai.com/api-keys +# ChatGPT/OpenAI API key from: https://beta.openai.com/account/api-keys # #chatgpt-api-key= #chatgpt-max-tokens=1024 # -# Get Google Gemini API key from https://ai.google.dev/gemini-api/docs/api-key +# 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 # -#gemini-api-key= +#gemini-project-id= +#gemini-location=us-west1 #gemini-max-tokens=1024 diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java index 980f2a6..1e6649b 100644 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ b/src/bld/java/net/thauvin/erik/MobibotBuild.java @@ -77,20 +77,20 @@ public class MobibotBuild extends Project { new Repository("https://jitpack.io"), SONATYPE_SNAPSHOTS_LEGACY); - var log4j = version(2, 24, 0); - var kotlin = version(2, 0, 20); - var langchain = version(0, 34, 0); + var log4j = version(2, 23, 1); + var kotlin = version(2, 0, 10); scope(compile) // PircBotX .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) // Commons (mostly for PircBotX) - .include(dependency("org.apache.commons", "commons-lang3", "3.17.0")) + .include(dependency("org.apache.commons", "commons-lang3", "3.16.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)) @@ -99,15 +99,10 @@ public class MobibotBuild extends Project { .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.16")) + .include(dependency("org.slf4j", "slf4j-api", "2.0.15")) .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")) @@ -123,8 +118,8 @@ public class MobibotBuild extends Project { 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, 11, 0))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 0))); + .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 3))) + .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 3))); List jars = new ArrayList<>(); runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt index 1e49a88..88bed54 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt @@ -396,11 +396,11 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro // Load the modules addons.add(Calc()) - addons.add(ChatGpt2()) + addons.add(ChatGpt()) addons.add(CryptoPrices()) addons.add(CurrencyConverter()) addons.add(Dice()) - addons.add(Gemini2()) + addons.add(Gemini()) addons.add(GoogleSearch()) addons.add(Info(tell, seen)) addons.add(Joke()) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt index 5b5e5d2..3abf162 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt @@ -14,12 +14,12 @@ import java.time.ZoneId */ object ReleaseInfo { const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20240908190240" + const val VERSION = "0.8.0-rc+20240712110931" @JvmField @Suppress("MagicNumber") val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1725847361020L), ZoneId.systemDefault() + Instant.ofEpochMilli(1720807771484L), ZoneId.systemDefault() ) const val WEBSITE = "https://mobitopia.org/mobibot/" diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt similarity index 62% rename from src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt rename to src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt index 854bb9f..c7ba4ba 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt.kt @@ -31,16 +31,23 @@ package net.thauvin.erik.mobibot.modules -import dev.langchain4j.model.openai.OpenAiChatModel -import dev.langchain4j.model.openai.OpenAiChatModelName +import net.thauvin.erik.mobibot.Constants 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 ChatGpt2 : AbstractModule() { - val logger: Logger = LoggerFactory.getLogger(ChatGpt2::class.java) +class ChatGpt : AbstractModule() { + val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java) override val name = CHATGPT_NAME @@ -86,6 +93,9 @@ class ChatGpt2 : 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" @@ -93,15 +103,48 @@ class ChatGpt2 : AbstractModule() { @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String { if (!apiKey.isNullOrEmpty()) { - try { - val model = OpenAiChatModel.builder() - .apiKey(apiKey) - .modelName(OpenAiChatModelName.GPT_4_O) - .maxTokens(maxTokens) - .build() + 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) - return model.generate(query) - } catch (e: Exception) { + 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) { throw ModuleException( "$CHATGPT_CMD($query): IO", "An IO error has occurred while conversing with $CHATGPT_NAME.", diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt index 3c8ea92..4fb7555 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt @@ -217,6 +217,6 @@ class CurrencyConverter : AbstractModule() { init { commands.add(CURRENCY_CMD) initProperties(API_KEY_PROP) - loadSymbols(properties[ChatGpt2.API_KEY_PROP]) + loadSymbols(properties[ChatGpt.API_KEY_PROP]) } } diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt similarity index 58% rename from src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt rename to src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt index 812aed3..2e4ed91 100644 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt +++ b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini.kt @@ -31,7 +31,12 @@ package net.thauvin.erik.mobibot.modules -import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel +import com.google.cloud.vertexai.VertexAI +import com.google.cloud.vertexai.api.GenerationConfig +import com.google.cloud.vertexai.api.HarmCategory +import com.google.cloud.vertexai.api.SafetySetting +import com.google.cloud.vertexai.generativeai.GenerativeModel +import com.google.cloud.vertexai.generativeai.ResponseHandler import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils.sendMessage import org.pircbotx.hooks.types.GenericMessageEvent @@ -40,8 +45,8 @@ import org.slf4j.LoggerFactory import java.util.* -class Gemini2 : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Gemini2::class.java) +class Gemini : AbstractModule() { + private val logger: Logger = LoggerFactory.getLogger(Gemini::class.java) override val name = GEMINI_NAME @@ -50,7 +55,8 @@ class Gemini2 : AbstractModule() { try { val answer = chat( args.trim(), - properties[GEMINI_API_KEY], + properties[PROJECT_ID_PROP], + properties[LOCATION_PROP], properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() ) if (!answer.isNullOrEmpty()) { @@ -76,12 +82,17 @@ class Gemini2 : AbstractModule() { const val GEMINI_NAME = "Gemini" /** - * The API key + * The Google cloud project ID property. */ - const val GEMINI_API_KEY = "gemini-api-key" + const val PROJECT_ID_PROP = "gemini-project-id" /** - * The max number of output tokens property. + * The Vertex AI location property. + */ + const val LOCATION_PROP = "gemini-location" + + /** + * The max number of tokens property. */ const val MAX_TOKENS_PROP = "gemini-max-tokens" @@ -92,18 +103,40 @@ class Gemini2 : AbstractModule() { @Throws(ModuleException::class) fun chat( query: String, - apiKey: String?, - maxTokens: Int + projectId: String?, + location: String?, + maxToken: Int ): String? { - if (!apiKey.isNullOrEmpty()) { + if (!projectId.isNullOrEmpty() && !location.isNullOrEmpty()) { try { - val gemini = GoogleAiGeminiChatModel.builder() - .apiKey(apiKey) - .modelName("gemini-1.5-flash") - .maxOutputTokens(maxTokens) - .build() + VertexAI(projectId, location).use { vertexAI -> + val generationConfig = GenerationConfig.newBuilder().setMaxOutputTokens(maxToken).build() + val safetySettings = listOf( + SafetySetting.newBuilder() + .setCategory(HarmCategory.HARM_CATEGORY_HATE_SPEECH) + .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) + .build(), + SafetySetting.newBuilder() + .setCategory(HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT) + .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) + .build(), + SafetySetting.newBuilder() + .setCategory(HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT) + .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) + .build(), + SafetySetting.newBuilder() + .setCategory(HarmCategory.HARM_CATEGORY_HARASSMENT) + .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_LOW_AND_ABOVE) + .build() + ) + val model = GenerativeModel.Builder().setModelName("gemini-1.5-flash-001") + .setGenerationConfig(generationConfig) + .setVertexAi(vertexAI).build() + .withSafetySettings(safetySettings) - return gemini.generate(query) + val response = model.generateContent(query) + return ResponseHandler.getText(response) + } } catch (e: Exception) { throw ModuleException( "$GEMINI_CMD($query): IO", @@ -126,6 +159,7 @@ class Gemini2 : AbstractModule() { add(Utils.helpFormat("%c $GEMINI_CMD explain quantum computing in simple terms")) add(Utils.helpFormat("%c $GEMINI_CMD how do I make an HTTP request in Javascript?")) } - initProperties(GEMINI_API_KEY, MAX_TOKENS_PROP) + initProperties(PROJECT_ID_PROP, LOCATION_PROP, MAX_TOKENS_PROP) } + } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt similarity index 84% rename from src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt rename to src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt index 4332a52..1809a9f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGptTest.kt @@ -39,10 +39,10 @@ import net.thauvin.erik.mobibot.DisableOnCi import net.thauvin.erik.mobibot.LocalProperties import kotlin.test.Test -class ChatGpt2Test : LocalProperties() { +class ChatGptTest : LocalProperties() { @Test fun testApiKey() { - assertFailure { ChatGpt2.chat("1 gallon to liter", "", 0) } + assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } .isInstanceOf(ModuleException::class.java) .hasNoCause() } @@ -51,7 +51,7 @@ class ChatGpt2Test : LocalProperties() { fun testChatOnCoverage() { if (System.getenv("CI") == null || System.getenv("COVERAGE_JDK") != null) { assertThat( - ChatGpt2.chat("how do I encode a URL in java?", getProperty(ChatGpt2.API_KEY_PROP), 60) + ChatGpt.chat("how do I encode a URL in java?", getProperty(ChatGpt.API_KEY_PROP), 60) ).contains("URLEncoder") } } @@ -59,12 +59,12 @@ class ChatGpt2Test : LocalProperties() { @Test @DisableOnCi fun testChat() { - val apiKey = getProperty(ChatGpt2.API_KEY_PROP) + val apiKey = getProperty(ChatGpt.API_KEY_PROP) assertThat( - ChatGpt2.chat("how do I make an HTTP request in Javascript?", apiKey, 200) + ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) ).contains("XMLHttpRequest") - assertFailure { ChatGpt2.chat("1 liter to gallon", apiKey, -1) } + assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, -1) } .isInstanceOf(ModuleException::class.java) } } diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt similarity index 79% rename from src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt rename to src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt index 226ff6a..1f0202f 100644 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt +++ b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GeminiTest.kt @@ -37,10 +37,10 @@ import net.thauvin.erik.mobibot.DisableOnCi import net.thauvin.erik.mobibot.LocalProperties import kotlin.test.Test -class Gemini2Test : LocalProperties() { +class GeminiTest : LocalProperties() { @Test fun testApiKey() { - assertFailure { Gemini2.chat("1 gallon to liter", "", 0) } + assertFailure { Gemini.chat("1 gallon to liter", "", "", 1024) } .isInstanceOf(ModuleException::class.java) .hasNoCause() } @@ -48,18 +48,19 @@ class Gemini2Test : LocalProperties() { @Test @DisableOnCi fun chatPrompt() { - val apiKey = getProperty(Gemini2.GEMINI_API_KEY) - val maxTokens = getProperty(Gemini2.MAX_TOKENS_PROP).toInt() + val projectId = getProperty(Gemini.PROJECT_ID_PROP) + val location = getProperty(Gemini.LOCATION_PROP) + val maxTokens = getProperty(Gemini.MAX_TOKENS_PROP).toInt() assertThat( - Gemini2.chat("how do I make an HTTP request in Javascript?", apiKey, maxTokens) + Gemini.chat("how do I make an HTTP request in Javascript?", projectId, location, maxTokens) ).isNotNull().contains("XMLHttpRequest") assertThat( - Gemini2.chat("how do I encode a URL in java?", apiKey, 60) + Gemini.chat("how do I encode a URL in java?", projectId, location, 60) ).isNotNull().contains("URLEncoder") - assertFailure { Gemini2.chat("1 liter to gallon", "foo", 40) } + assertFailure { Gemini.chat("1 liter to gallon", projectId, "blah", 40) } .isInstanceOf(ModuleException::class.java) } } diff --git a/website/index.html b/website/index.html index 370c3cf..fffe650 100644 --- a/website/index.html +++ b/website/index.html @@ -38,10 +38,10 @@
  • Apache Commons Net
  • CryptoPrice
  • exp4j
  • +
  • Google Vertex AI
  • JokeAPI
  • jsoup
  • kotlinx-cli
  • -
  • LangChain4J
  • OkHttp
  • OWM JAPIs
  • Pinboard Poster