Added Google Gemini module

This commit is contained in:
Erik C. Thauvin 2023-12-17 21:33:02 -08:00
parent 8412a8c26d
commit 4a4e702d9f
10 changed files with 230 additions and 26 deletions

View file

@ -1,15 +1,15 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version="1.0" ?>
<SmellBaseline> <SmellBaseline>
<ManuallySuppressedIssues/> <ManuallySuppressedIssues></ManuallySuppressedIssues>
<CurrentIssues> <CurrentIssues>
<ID>CyclomaticComplexMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML)</ID> <ID>CyclomaticComplexMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML)</ID>
<ID>CyclomaticComplexMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message></ID> <ID>CyclomaticComplexMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>LongMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML)</ID> <ID>LongMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML)</ID>
<ID>LongMethod:Mobibot.kt$Mobibot.Companion$@JvmStatic @Throws(Exception::class) fun main(args: Array&lt;String>)</ID> <ID>LongMethod:Mobibot.kt$Mobibot.Companion$@JvmStatic @Throws(Exception::class) fun main(args: Array&lt;String&gt;)</ID>
<ID>LongMethod:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List&lt;Message></ID> <ID>LongMethod:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message></ID> <ID>LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent )</ID> <ID>LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent )</ID>
<ID>LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList&lt;EntryComment> = mutableListOf(), // Tags/categories val tags: MutableList&lt;SyndCategory> = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String )</ID> <ID>LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList&lt;EntryComment&gt; = mutableListOf(), // Tags/categories val tags: MutableList&lt;SyndCategory&gt; = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String )</ID>
<ID>MagicNumber:ChatGpt.kt$ChatGpt$400</ID> <ID>MagicNumber:ChatGpt.kt$ChatGpt$400</ID>
<ID>MagicNumber:ChatGpt.kt$ChatGpt.Companion$200</ID> <ID>MagicNumber:ChatGpt.kt$ChatGpt.Companion$200</ID>
<ID>MagicNumber:ChatGpt.kt$ChatGpt.Companion$429</ID> <ID>MagicNumber:ChatGpt.kt$ChatGpt.Companion$429</ID>
@ -20,6 +20,7 @@
<ID>MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$4</ID> <ID>MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$4</ID>
<ID>MagicNumber:Cycle.kt$Cycle$10</ID> <ID>MagicNumber:Cycle.kt$Cycle$10</ID>
<ID>MagicNumber:Cycle.kt$Cycle$1000L</ID> <ID>MagicNumber:Cycle.kt$Cycle$1000L</ID>
<ID>MagicNumber:Gemini.kt$Gemini$400</ID>
<ID>MagicNumber:Ignore.kt$Ignore$8</ID> <ID>MagicNumber:Ignore.kt$Ignore$8</ID>
<ID>MagicNumber:Info.kt$Info.Companion$30</ID> <ID>MagicNumber:Info.kt$Info.Companion$30</ID>
<ID>MagicNumber:Info.kt$Info.Companion$365</ID> <ID>MagicNumber:Info.kt$Info.Companion$365</ID>
@ -52,22 +53,22 @@
<ID>NestedBlockDepth:Comment.kt$Comment$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:Comment.kt$Comment$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
<ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic @Throws(ModuleException::class) fun loadSymbols(apiKey: String?)</ID> <ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic @Throws(ModuleException::class) fun loadSymbols(apiKey: String?)</ID>
<ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic fun convertCurrency(apiKey: String?, query: String): Message</ID> <ID>NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic fun convertCurrency(apiKey: String?, query: String): Message</ID>
<ID>NestedBlockDepth:EntryLink.kt$EntryLink$private fun setTags(tags: List&lt;String?>)</ID> <ID>NestedBlockDepth:EntryLink.kt$EntryLink$private fun setTags(tags: List&lt;String?&gt;)</ID>
<ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic @Throws(IOException::class, FeedException::class) fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String</ID> <ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic @Throws(IOException::class, FeedException::class) fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String</ID>
<ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML)</ID> <ID>NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML)</ID>
<ID>NestedBlockDepth:GoogleSearch.kt$GoogleSearch$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:GoogleSearch.kt$GoogleSearch$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID>
<ID>NestedBlockDepth:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List&lt;Message></ID> <ID>NestedBlockDepth: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>NestedBlockDepth:LinksManager.kt$LinksManager$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:LinksManager.kt$LinksManager$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
<ID>NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID>
<ID>NestedBlockDepth:Mastodon.kt$Mastodon.Companion$@JvmStatic @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String</ID> <ID>NestedBlockDepth:Mastodon.kt$Mastodon.Companion$@JvmStatic @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String</ID>
<ID>NestedBlockDepth:Posting.kt$Posting$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:Posting.kt$Posting$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
<ID>NestedBlockDepth:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</ID>
<ID>NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List&lt;Message></ID> <ID>NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent)</ID> <ID>NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent)</ID>
<ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any</ID> <ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any</ID>
<ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveSerialData(file: String, data: Any, logger: Logger, description: String)</ID> <ID>NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveSerialData(file: String, data: Any, logger: Logger, description: String)</ID>
<ID>NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID> <ID>NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent)</ID>
<ID>NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message></ID> <ID>NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean</ID> <ID>ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean</ID>
<ID>ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean</ID> <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:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException</ID>
@ -76,13 +77,14 @@
<ID>SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException</ID> <ID>SwallowedException:StockQuoteTest.kt$StockQuoteTest$e: ModuleException</ID>
<ID>SwallowedException:WolframAlphaTest.kt$WolframAlphaTest$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: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></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></ID> <ID>ThrowsCount:Joke.kt$Joke.Companion$@JvmStatic @Throws(ModuleException::class) fun randomJoke(): List&lt;Message&gt;</ID>
<ID>ThrowsCount:Mastodon.kt$Mastodon.Companion$@JvmStatic @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String</ID> <ID>ThrowsCount:Mastodon.kt$Mastodon.Companion$@JvmStatic @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String</ID>
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List&lt;Message></ID> <ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List&lt;Message&gt;</ID>
<ID>ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject</ID> <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></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>ThrowsCount:WolframAlpha.kt$WolframAlpha.Companion$@JvmStatic @Throws(ModuleException::class) fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String</ID>
<ID>TooGenericExceptionCaught:Gemini.kt$Gemini.Companion$e: Exception</ID>
<ID>TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException</ID> <ID>TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException</ID>
<ID>TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException</ID> <ID>TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException</ID>
<ID>TooManyFunctions:EntryLink.kt$EntryLink : Serializable</ID> <ID>TooManyFunctions:EntryLink.kt$EntryLink : Serializable</ID>
@ -94,6 +96,7 @@
<ID>WildcardImport:FeedMgrTest.kt$import assertk.assertions.*</ID> <ID>WildcardImport:FeedMgrTest.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:FeedReaderTest.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:FeedsManager.kt$import com.rometools.rome.feed.synd.*</ID>
<ID>WildcardImport:GeminiTest.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:GoogleSearchTest.kt$import assertk.assertions.*</ID> <ID>WildcardImport:GoogleSearchTest.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:JokeTest.kt$import assertk.assertions.*</ID> <ID>WildcardImport:JokeTest.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:Mobibot.kt$import java.io.*</ID> <ID>WildcardImport:Mobibot.kt$import java.io.*</ID>

View file

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
./bld jar deploy ./bld clean jar deploy
[ $? -eq 0 ] && sftp nix3.thauvin.us <<EOF [ $? -eq 0 ] && sftp nix4.thauvin.us <<EOF
cd mobitopia/mobibot cd /home/mobibot/mobitopia/mobibot
lcd deploy lcd deploy
put *.jar put *.jar
cd lib cd lib

View file

@ -79,3 +79,14 @@ disabled-modules=mastodon
# #
#chatgpt-api-key= #chatgpt-api-key=
#chatgpt-max-tokens=1024 #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
#gemini-project-id=
#gemini-location=us-west1
#gemini-max-tokens=1024

View file

@ -50,7 +50,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.jar.Attributes; import java.util.jar.Attributes;
import static rife.bld.dependencies.Repository.*; import static rife.bld.dependencies.Repository.MAVEN_CENTRAL;
import static rife.bld.dependencies.Repository.MAVEN_LOCAL;
import static rife.bld.dependencies.Scope.compile; import static rife.bld.dependencies.Scope.compile;
import static rife.bld.dependencies.Scope.test; import static rife.bld.dependencies.Scope.test;
@ -82,9 +83,9 @@ public class MobibotBuild extends Project {
// Google // Google
.include(dependency("com.google.code.gson", "gson", "2.10.1")) .include(dependency("com.google.code.gson", "gson", "2.10.1"))
.include(dependency("com.google.guava", "guava", "32.1.3-jre")) .include(dependency("com.google.guava", "guava", "32.1.3-jre"))
.include(dependency("com.google.cloud", "google-cloud-vertexai", version(0, 1, 0)))
// Kotlin // Kotlin
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin))
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin))
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin))
.include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin))
.include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.7.3"))
@ -100,19 +101,20 @@ public class MobibotBuild extends Project {
.include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) .include(dependency("net.aksingh", "owm-japis", "2.5.3.0"))
.include(dependency("net.objecthunter", "exp4j", "0.4.8")) .include(dependency("net.objecthunter", "exp4j", "0.4.8"))
.include(dependency("org.json", "json", "20231013")) .include(dependency("org.json", "json", "20231013"))
.include(dependency("org.jsoup", "jsoup", "1.16.2")) .include(dependency("org.jsoup", "jsoup", "1.17.1"))
// Thauvin // Thauvin
.include(dependency("net.thauvin.erik", "cryptoprice", "1.0.2")) .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.2"))
.include(dependency("net.thauvin.erik", "jokeapi", "0.9.1")) .include(dependency("net.thauvin.erik", "jokeapi", "0.9.1"))
.include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.1")) .include(dependency("net.thauvin.erik", "pinboard-poster", "1.1.1"))
.include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.4.0")); .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.4.0"));
scope(test) scope(test)
.include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 27, 0))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 0)))
.include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 21))) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", version(1, 9, 21)))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 1)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1))); .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 1)));
List<String> jars = new ArrayList<>(); List<String> jars = new ArrayList<>();
runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName()));
compileClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); compileClasspathJars().forEach(f -> jars.add("./lib/" + f.getName()));
jarOperation() jarOperation()
.manifestAttribute(Attributes.Name.MAIN_CLASS, mainClass()) .manifestAttribute(Attributes.Name.MAIN_CLASS, mainClass())
@ -149,6 +151,9 @@ public class MobibotBuild extends Project {
for (var jar : compileClasspathJars()) { for (var jar : compileClasspathJars()) {
FileUtils.copy(jar, new File(lib, jar.getName())); FileUtils.copy(jar, new File(lib, jar.getName()));
} }
for (var jar : runtimeClasspathJars()) {
FileUtils.copy(jar, new File(lib, jar.getName()));
}
FileUtils.copy(new File(buildDistDirectory(), jarFileName()), new File(deploy, "mobibot.jar")); FileUtils.copy(new File(buildDistDirectory(), jarFileName()), new File(deploy, "mobibot.jar"));
} }

View file

@ -400,6 +400,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
addons.add(CryptoPrices()) addons.add(CryptoPrices())
addons.add(CurrencyConverter()) addons.add(CurrencyConverter())
addons.add(Dice()) addons.add(Dice())
addons.add(Gemini())
addons.add(GoogleSearch()) addons.add(GoogleSearch())
addons.add(Info(tell, seen)) addons.add(Info(tell, seen))
addons.add(Joke()) addons.add(Joke())

View file

@ -14,12 +14,12 @@ import java.time.ZoneId
*/ */
object ReleaseInfo { object ReleaseInfo {
const val PROJECT = "mobibot" const val PROJECT = "mobibot"
const val VERSION = "0.8.0-rc+20231125224843" const val VERSION = "0.8.0-rc+20231217213124"
@JvmField @JvmField
@Suppress("MagicNumber") @Suppress("MagicNumber")
val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant(
Instant.ofEpochMilli(1700981323173L), ZoneId.systemDefault() Instant.ofEpochMilli(1702877484912L), ZoneId.systemDefault()
) )
const val WEBSITE = "https://www.mobitopia.org/mobibot/" const val WEBSITE = "https://www.mobitopia.org/mobibot/"

View file

@ -42,7 +42,7 @@ class Versions : AbstractCommand() {
private val allVersions = listOf( private val allVersions = listOf(
"Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILD_DATE.toIsoLocalDate()})", "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILD_DATE.toIsoLocalDate()})",
"${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" +
", JVM ${System.getProperty("java.runtime.version")}", ", JVM ${System.getProperty("java.version")}",
"Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}"
) )
override val name = "versions" override val name = "versions"

View file

@ -0,0 +1,116 @@
package net.thauvin.erik.mobibot.modules
import com.google.auth.Credentials
import com.google.cloud.vertexai.VertexAI
import com.google.cloud.vertexai.api.GenerateContentResponse
import com.google.cloud.vertexai.api.GenerationConfig
import com.google.cloud.vertexai.generativeai.preview.ChatSession
import com.google.cloud.vertexai.generativeai.preview.GenerativeModel
import com.google.cloud.vertexai.generativeai.preview.ResponseHandler
import net.thauvin.erik.mobibot.Utils
import net.thauvin.erik.mobibot.Utils.sendMessage
import okio.IOException
import org.apache.commons.text.WordUtils
import org.pircbotx.hooks.types.GenericMessageEvent
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class Gemini : AbstractModule() {
private val logger: Logger = LoggerFactory.getLogger(Gemini::class.java)
override val name = GEMINI_NAME
override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) {
if (args.isNotBlank()) {
try {
val answer = chat(
args.trim(),
properties[PROJECT_ID_PROP],
properties[LOCATION_PROPR],
properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt()
)
if (!answer.isNullOrEmpty()) {
event.sendMessage(answer)
} else {
event.respond("$name is stumped.")
}
} catch (e: ModuleException) {
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
e.message?.let {
event.respond(it)
}
}
} else {
helpResponse(event)
}
}
companion object {
/**
* The service name.
*/
const val GEMINI_NAME = "Gemini"
/**
* The Google cloud project ID.
*/
const val PROJECT_ID_PROP = "gemini-project-id"
/**
* The Vertex AI location.
*/
const val LOCATION_PROPR = "gemini-location"
/**
* The max tokens property.
*/
const val MAX_TOKENS_PROP = "gemini-max-tokens"
// ChatGPT command
private const val GEMINI_CMD = "gemini"
@JvmStatic
@Throws(ModuleException::class)
fun chat(
query: String,
projectId: String?,
location: String?,
maxToken: Int
): String? {
if (!projectId.isNullOrEmpty() && !location.isNullOrEmpty()) {
try {
VertexAI(projectId, location).use { vertexAI ->
val generationConfig = GenerationConfig.newBuilder().setMaxOutputTokens(maxToken).build()
val model = GenerativeModel("gemini-pro-vision", generationConfig, vertexAI)
val session = ChatSession(model)
val response = session.sendMessage(query)
return ResponseHandler.getText(response);
}
} catch (e: Exception) {
throw ModuleException(
"$GEMINI_CMD($query): IO",
"An IO error has occurred while conversing with ${GEMINI_NAME}.",
e
)
}
} else {
throw ModuleException("${GEMINI_CMD}($query)", "No ${GEMINI_NAME} Project ID or Location specified.")
}
}
}
init {
commands.add(GEMINI_CMD)
with(help) {
add("To get answers from $name:")
add(Utils.helpFormat("%c ${GEMINI_CMD} <query>"))
add("For example:")
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(PROJECT_ID_PROP, LOCATION_PROPR, MAX_TOKENS_PROP)
}
}

View file

@ -0,0 +1,66 @@
/*
* ChatGptTest.kt
*
* Copyright 2004-2023 Erik C. Thauvin (erik@thauvin.net)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of this project nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.thauvin.erik.mobibot.modules
import assertk.assertFailure
import assertk.assertThat
import assertk.assertions.*
import net.thauvin.erik.mobibot.DisableOnCi
import net.thauvin.erik.mobibot.LocalProperties
import kotlin.test.Test
class GeminiTest : LocalProperties() {
@Test
fun testApiKey() {
assertFailure { Gemini.chat("1 gallon to liter", "", "", 1024) }
.isInstanceOf(ModuleException::class.java)
.hasNoCause()
}
@Test
@DisableOnCi
fun chatPrompt() {
val projectId = getProperty(Gemini.PROJECT_ID_PROP)
val location = getProperty(Gemini.LOCATION_PROPR)
val maxTokens = getProperty(Gemini.MAX_TOKENS_PROP).toInt()
assertThat(
Gemini.chat("how do I make an HTTP request in Javascript?", projectId, location, maxTokens)
).isNotNull().contains("XMLHttpRequest")
assertThat(
Gemini.chat("how do I encode a URL in java?", projectId, location, 60)
).isNotNull().contains("URLEncoder")
assertFailure { Gemini.chat("1 liter to gallon", projectId, "blah", 40) }
.isInstanceOf(ModuleException::class.java)
}
}

View file

@ -38,6 +38,7 @@
<li><a href="https://commons.apache.org/proper/commons-net/">Apache Commons Net</a></li> <li><a href="https://commons.apache.org/proper/commons-net/">Apache Commons Net</a></li>
<li><a href="https://github.com/ethauvin/cryptoprice">CryptoPrice</a></li> <li><a href="https://github.com/ethauvin/cryptoprice">CryptoPrice</a></li>
<li><a href="https://www.objecthunter.net/exp4j/">exp4j</a></li> <li><a href="https://www.objecthunter.net/exp4j/">exp4j</a></li>
<li><a href="https://github.com/googleapis/google-cloud-java/tree/main/java-vertexai">Google Vertex AI</a></li>
<li><a href="https://github.com/ethauvin/jokeapi">JokeAPI</a></li> <li><a href="https://github.com/ethauvin/jokeapi">JokeAPI</a></li>
<li><a href="https://jsoup.org/">jsoup</a></li> <li><a href="https://jsoup.org/">jsoup</a></li>
<li><a href="https://github.com/Kotlin/kotlinx-cli">kotlinx-cli</a></li> <li><a href="https://github.com/Kotlin/kotlinx-cli">kotlinx-cli</a></li>
@ -80,9 +81,10 @@
<li>Performing Google searches <li>Performing Google searches
<div><code>mobibot: google mobitopia on irc</code></div> <div><code>mobibot: google mobitopia on irc</code></div>
</li> </li>
<li>Getting answers from <a href="https://wolframalpha.com/">Wolfram Alpha</a> and <a href="https://chat.openai.com/chat">ChatGPT</a> <li>Getting answers from <a href="https://wolframalpha.com/">Wolfram Alpha</a>, <a href="https://chat.openai.com/chat">ChatGPT</a> and <a href="https://deepmind.google/technologies/gemini/">Google Gemini</a>
<div><code>mobibot: wolfram days until christmas</code></div> <div><code>mobibot: wolfram days until christmas</code></div>
<div><code>mobibot: chatgpt explain quantum computing in simple terms</code></div> <div><code>mobibot: chatgpt explain quantum computing in simple terms</code></div>
<div><code>mobibot: gemini what are all the colors in a rainbow?</code></div>
</li> </li>
<li>Displaying weather information <li>Displaying weather information
<div><code>mobibot: weather san francisco</code></div> <div><code>mobibot: weather san francisco</code></div>