Compare commits

..

No commits in common. "c60531f6170ed701ac742986cb8c5e13a6b823ea" and "3cbe44c1c08c6f317d1ddabc07adee8eedb5cfc6" have entirely different histories.

20 changed files with 177 additions and 116 deletions

1
.gitignore vendored
View file

@ -60,4 +60,3 @@ local.properties
logs logs
mobibot.properties mobibot.properties
out out
/target/

View file

@ -2,12 +2,12 @@
<library name="bld"> <library name="bld">
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$/lib/bld" /> <root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.1.0.jar!/" /> <root url="jar://$USER_HOME$/.bld/dist/bld-2.0.1.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/bld" /> <root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.1.0-sources.jar!/" /> <root url="jar://$USER_HOME$/.bld/dist/bld-2.0.1-sources.jar!/" />
</SOURCES> </SOURCES>
<excluded> <excluded>
<root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" />

View file

@ -7,7 +7,7 @@
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/compile" /> <root url="file://$PROJECT_DIR$/lib/compile" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" /> <jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" type="SOURCES" />
</library> </library>
</component> </component>

View file

@ -8,7 +8,7 @@
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/runtime" /> <root url="file://$PROJECT_DIR$/lib/runtime" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" /> <jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" type="SOURCES" />
</library> </library>
</component> </component>

View file

@ -8,7 +8,7 @@
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/test" /> <root url="file://$PROJECT_DIR$/lib/test" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" /> <jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" type="SOURCES" />
</library> </library>
</component> </component>

View file

@ -1,8 +1,8 @@
# mobibot # mobibot
[![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![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) [![Kotlin](https://img.shields.io/badge/kotlin-2.0.10-7f52ff.svg)](https://kotlinlang.org)
[![bld](https://img.shields.io/badge/2.1.0-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![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) [![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) [![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) [![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master)

View file

@ -71,6 +71,9 @@
<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>
<ID>ReturnCount:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent)</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: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: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> <ID>ThrowsCount:Joke.kt$Joke.Companion$@JvmStatic @Throws(ModuleException::class) fun randomJoke(): List&lt;Message&gt;</ID>
@ -79,9 +82,7 @@
<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&gt;</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:ChatGpt2.kt$ChatGpt2.Companion$e: Exception</ID>
<ID>TooGenericExceptionCaught:Gemini.kt$Gemini.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: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>
@ -93,7 +94,6 @@
<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:Gemini2Test.kt$import assertk.assertions.*</ID>
<ID>WildcardImport:GeminiTest.kt$import assertk.assertions.*</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>

Binary file not shown.

View file

@ -1,10 +1,10 @@
bld.downloadExtensionJavadoc=false bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true bld.downloadExtensionSources=true
bld.downloadLocation= bld.downloadLocation=
bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.7 bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.5
bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.9 bld.extension-gv=com.uwyn.rife2:bld-generated-version:0.9.8
bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report: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.1 bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.0.0
bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES
bld.sourceDirectories= bld.sourceDirectories=
bld.version=2.1.0 bld.version=2.0.1

50
pom.xml
View file

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>net.thauvin.erik.mobibot</groupId> <groupId>net.thauvin.erik.mobibot</groupId>
<artifactId>mobibot</artifactId> <artifactId>mobibot</artifactId>
<version>0.8.0-rc+20240908192921</version> <version>0.8.0-rc+20240809180718</version>
<name>mobibot</name> <name>mobibot</name>
<description></description> <description></description>
<url></url> <url></url>
@ -18,7 +18,7 @@
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.17.0</version> <version>3.16.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -51,28 +51,34 @@
<version>33.2.1-jre</version> <version>33.2.1-jre</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-vertexai</artifactId>
<version>1.7.0</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>org.jetbrains.kotlin</groupId> <groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId> <artifactId>kotlin-stdlib</artifactId>
<version>2.0.20</version> <version>2.0.10</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jetbrains.kotlin</groupId> <groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-common</artifactId> <artifactId>kotlin-stdlib-common</artifactId>
<version>2.0.20</version> <version>2.0.10</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jetbrains.kotlin</groupId> <groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk7</artifactId> <artifactId>kotlin-stdlib-jdk7</artifactId>
<version>2.0.20</version> <version>2.0.10</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jetbrains.kotlin</groupId> <groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId> <artifactId>kotlin-stdlib-jdk8</artifactId>
<version>2.0.20</version> <version>2.0.10</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -90,49 +96,25 @@
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
<version>2.0.16</version> <version>2.0.15</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId> <artifactId>log4j-api</artifactId>
<version>2.24.0</version> <version>2.23.1</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId> <artifactId>log4j-core</artifactId>
<version>2.24.0</version> <version>2.23.1</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId> <artifactId>log4j-slf4j2-impl</artifactId>
<version>2.24.0</version> <version>2.23.1</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> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>

View file

@ -45,6 +45,7 @@ disabled-modules=mastodon
# Automatically post links to Mastodon # Automatically post links to Mastodon
#mastodon-auto-post=true #mastodon-auto-post=true
# #
# Get Exchange Rate API key from: https://www.exchangerate-api.com/ # Get Exchange Rate API key from: https://www.exchangerate-api.com/
# #
@ -74,13 +75,19 @@ disabled-modules=mastodon
#wolfram-units=imperial #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-api-key=
#chatgpt-max-tokens=1024 #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 #gemini-max-tokens=1024

View file

@ -77,20 +77,20 @@ public class MobibotBuild extends Project {
new Repository("https://jitpack.io"), new Repository("https://jitpack.io"),
SONATYPE_SNAPSHOTS_LEGACY); SONATYPE_SNAPSHOTS_LEGACY);
var log4j = version(2, 24, 0); var log4j = version(2, 23, 1);
var kotlin = version(2, 0, 20); var kotlin = version(2, 0, 10);
var langchain = version(0, 34, 0);
scope(compile) scope(compile)
// PircBotX // PircBotX
.include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1"))
// Commons (mostly for PircBotX) // 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("org.apache.commons", "commons-text", "1.12.0"))
.include(dependency("commons-codec", "commons-codec", "1.17.1")) .include(dependency("commons-codec", "commons-codec", "1.17.1"))
.include(dependency("commons-net", "commons-net", "3.11.1")) .include(dependency("commons-net", "commons-net", "3.11.1"))
// Google // Google
.include(dependency("com.google.code.gson", "gson", "2.11.0")) .include(dependency("com.google.code.gson", "gson", "2.11.0"))
.include(dependency("com.google.guava", "guava", "33.2.1-jre")) .include(dependency("com.google.guava", "guava", "33.2.1-jre"))
.include(dependency("com.google.cloud", "google-cloud-vertexai", "1.7.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-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-coroutines-core", "1.8.1"))
.include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6"))
// Logging // 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-api", log4j))
.include(dependency("org.apache.logging.log4j", "log4j-core", log4j)) .include(dependency("org.apache.logging.log4j", "log4j-core", log4j))
.include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", 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. // Misc.
.include(dependency("com.rometools", "rome", "2.1.0")) .include(dependency("com.rometools", "rome", "2.1.0"))
.include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0")) .include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0"))
@ -123,8 +118,8 @@ public class MobibotBuild extends Project {
scope(test) scope(test)
.include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))) .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1)))
.include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 11, 0))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 3)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 11, 0))); .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 3)));
List<String> jars = new ArrayList<>(); List<String> jars = new ArrayList<>();
runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName()));

View file

@ -396,11 +396,11 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
// Load the modules // Load the modules
addons.add(Calc()) addons.add(Calc())
addons.add(ChatGpt2()) addons.add(ChatGpt())
addons.add(CryptoPrices()) addons.add(CryptoPrices())
addons.add(CurrencyConverter()) addons.add(CurrencyConverter())
addons.add(Dice()) addons.add(Dice())
addons.add(Gemini2()) 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+20240908190240" const val VERSION = "0.8.0-rc+20240712110931"
@JvmField @JvmField
@Suppress("MagicNumber") @Suppress("MagicNumber")
val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant(
Instant.ofEpochMilli(1725847361020L), ZoneId.systemDefault() Instant.ofEpochMilli(1720807771484L), ZoneId.systemDefault()
) )
const val WEBSITE = "https://mobitopia.org/mobibot/" const val WEBSITE = "https://mobitopia.org/mobibot/"

View file

@ -31,16 +31,23 @@
package net.thauvin.erik.mobibot.modules package net.thauvin.erik.mobibot.modules
import dev.langchain4j.model.openai.OpenAiChatModel import net.thauvin.erik.mobibot.Constants
import dev.langchain4j.model.openai.OpenAiChatModelName
import net.thauvin.erik.mobibot.Utils import net.thauvin.erik.mobibot.Utils
import net.thauvin.erik.mobibot.Utils.sendMessage 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.pircbotx.hooks.types.GenericMessageEvent
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory 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() { class ChatGpt : AbstractModule() {
val logger: Logger = LoggerFactory.getLogger(ChatGpt2::class.java) val logger: Logger = LoggerFactory.getLogger(ChatGpt::class.java)
override val name = CHATGPT_NAME override val name = CHATGPT_NAME
@ -86,6 +93,9 @@ class ChatGpt2 : AbstractModule() {
*/ */
const val MAX_TOKENS_PROP = "chatgpt-max-tokens" 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 // ChatGPT command
private const val CHATGPT_CMD = "chatgpt" private const val CHATGPT_CMD = "chatgpt"
@ -93,15 +103,48 @@ class ChatGpt2 : AbstractModule() {
@Throws(ModuleException::class) @Throws(ModuleException::class)
fun chat(query: String, apiKey: String?, maxTokens: Int): String { fun chat(query: String, apiKey: String?, maxTokens: Int): String {
if (!apiKey.isNullOrEmpty()) { if (!apiKey.isNullOrEmpty()) {
try { val jsonObject = JSONObject()
val model = OpenAiChatModel.builder() jsonObject.put("model", "gpt-3.5-turbo-1106")
.apiKey(apiKey) jsonObject.put("max_tokens", maxTokens)
.modelName(OpenAiChatModelName.GPT_4_O) val message = JSONObject()
.maxTokens(maxTokens) message.put("role", "user")
.build() message.put("content", query)
val messages = JSONArray()
messages.put(message)
jsonObject.put("messages", messages)
return model.generate(query) val request = HttpRequest.newBuilder()
} catch (e: Exception) { .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( throw ModuleException(
"$CHATGPT_CMD($query): IO", "$CHATGPT_CMD($query): IO",
"An IO error has occurred while conversing with $CHATGPT_NAME.", "An IO error has occurred while conversing with $CHATGPT_NAME.",

View file

@ -217,6 +217,6 @@ class CurrencyConverter : AbstractModule() {
init { init {
commands.add(CURRENCY_CMD) commands.add(CURRENCY_CMD)
initProperties(API_KEY_PROP) initProperties(API_KEY_PROP)
loadSymbols(properties[ChatGpt2.API_KEY_PROP]) loadSymbols(properties[ChatGpt.API_KEY_PROP])
} }
} }

View file

@ -31,7 +31,12 @@
package net.thauvin.erik.mobibot.modules 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
import net.thauvin.erik.mobibot.Utils.sendMessage import net.thauvin.erik.mobibot.Utils.sendMessage
import org.pircbotx.hooks.types.GenericMessageEvent import org.pircbotx.hooks.types.GenericMessageEvent
@ -40,8 +45,8 @@ import org.slf4j.LoggerFactory
import java.util.* import java.util.*
class Gemini2 : AbstractModule() { class Gemini : AbstractModule() {
private val logger: Logger = LoggerFactory.getLogger(Gemini2::class.java) private val logger: Logger = LoggerFactory.getLogger(Gemini::class.java)
override val name = GEMINI_NAME override val name = GEMINI_NAME
@ -50,7 +55,8 @@ class Gemini2 : AbstractModule() {
try { try {
val answer = chat( val answer = chat(
args.trim(), args.trim(),
properties[GEMINI_API_KEY], properties[PROJECT_ID_PROP],
properties[LOCATION_PROP],
properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt()
) )
if (!answer.isNullOrEmpty()) { if (!answer.isNullOrEmpty()) {
@ -76,12 +82,17 @@ class Gemini2 : AbstractModule() {
const val GEMINI_NAME = "Gemini" 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" const val MAX_TOKENS_PROP = "gemini-max-tokens"
@ -92,18 +103,40 @@ class Gemini2 : AbstractModule() {
@Throws(ModuleException::class) @Throws(ModuleException::class)
fun chat( fun chat(
query: String, query: String,
apiKey: String?, projectId: String?,
maxTokens: Int location: String?,
maxToken: Int
): String? { ): String? {
if (!apiKey.isNullOrEmpty()) { if (!projectId.isNullOrEmpty() && !location.isNullOrEmpty()) {
try { try {
val gemini = GoogleAiGeminiChatModel.builder() VertexAI(projectId, location).use { vertexAI ->
.apiKey(apiKey) val generationConfig = GenerationConfig.newBuilder().setMaxOutputTokens(maxToken).build()
.modelName("gemini-1.5-flash") val safetySettings = listOf(
.maxOutputTokens(maxTokens) SafetySetting.newBuilder()
.build() .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) { } catch (e: Exception) {
throw ModuleException( throw ModuleException(
"$GEMINI_CMD($query): IO", "$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 explain quantum computing in simple terms"))
add(Utils.helpFormat("%c $GEMINI_CMD how do I make an HTTP request in Javascript?")) 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)
} }
} }

View file

@ -39,10 +39,10 @@ import net.thauvin.erik.mobibot.DisableOnCi
import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.LocalProperties
import kotlin.test.Test import kotlin.test.Test
class ChatGpt2Test : LocalProperties() { class ChatGptTest : LocalProperties() {
@Test @Test
fun testApiKey() { fun testApiKey() {
assertFailure { ChatGpt2.chat("1 gallon to liter", "", 0) } assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) }
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
.hasNoCause() .hasNoCause()
} }
@ -51,7 +51,7 @@ class ChatGpt2Test : LocalProperties() {
fun testChatOnCoverage() { fun testChatOnCoverage() {
if (System.getenv("CI") == null || System.getenv("COVERAGE_JDK") != null) { if (System.getenv("CI") == null || System.getenv("COVERAGE_JDK") != null) {
assertThat( 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") ).contains("URLEncoder")
} }
} }
@ -59,12 +59,12 @@ class ChatGpt2Test : LocalProperties() {
@Test @Test
@DisableOnCi @DisableOnCi
fun testChat() { fun testChat() {
val apiKey = getProperty(ChatGpt2.API_KEY_PROP) val apiKey = getProperty(ChatGpt.API_KEY_PROP)
assertThat( 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") ).contains("XMLHttpRequest")
assertFailure { ChatGpt2.chat("1 liter to gallon", apiKey, -1) } assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, -1) }
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
} }
} }

View file

@ -37,10 +37,10 @@ import net.thauvin.erik.mobibot.DisableOnCi
import net.thauvin.erik.mobibot.LocalProperties import net.thauvin.erik.mobibot.LocalProperties
import kotlin.test.Test import kotlin.test.Test
class Gemini2Test : LocalProperties() { class GeminiTest : LocalProperties() {
@Test @Test
fun testApiKey() { fun testApiKey() {
assertFailure { Gemini2.chat("1 gallon to liter", "", 0) } assertFailure { Gemini.chat("1 gallon to liter", "", "", 1024) }
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
.hasNoCause() .hasNoCause()
} }
@ -48,18 +48,19 @@ class Gemini2Test : LocalProperties() {
@Test @Test
@DisableOnCi @DisableOnCi
fun chatPrompt() { fun chatPrompt() {
val apiKey = getProperty(Gemini2.GEMINI_API_KEY) val projectId = getProperty(Gemini.PROJECT_ID_PROP)
val maxTokens = getProperty(Gemini2.MAX_TOKENS_PROP).toInt() val location = getProperty(Gemini.LOCATION_PROP)
val maxTokens = getProperty(Gemini.MAX_TOKENS_PROP).toInt()
assertThat( 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") ).isNotNull().contains("XMLHttpRequest")
assertThat( 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") ).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) .isInstanceOf(ModuleException::class.java)
} }
} }

View file

@ -38,10 +38,10 @@
<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>
<li><a href="https://docs.langchain4j.dev/">LangChain4J</a></li>
<li><a href="https://square.github.io/okhttp/">OkHttp</a></li> <li><a href="https://square.github.io/okhttp/">OkHttp</a></li>
<li><a href="https://bitbucket.org/aksinghnet/owm-japis">OWM JAPIs</a></li> <li><a href="https://bitbucket.org/aksinghnet/owm-japis">OWM JAPIs</a></li>
<li><a href="https://github.com/ethauvin/pinboard-poster">Pinboard Poster</a></li> <li><a href="https://github.com/ethauvin/pinboard-poster">Pinboard Poster</a></li>