diff --git a/src/main/java/me/ailama/commands/AiCommand.java b/src/main/java/me/ailama/commands/AiCommand.java index 7034d41..04d3fc0 100644 --- a/src/main/java/me/ailama/commands/AiCommand.java +++ b/src/main/java/me/ailama/commands/AiCommand.java @@ -5,7 +5,7 @@ import me.ailama.handler.commandhandler.SearXNGManager; import me.ailama.handler.interfaces.AiLamaSlashCommand; import me.ailama.handler.interfaces.Assistant; -import me.ailama.handler.other.Tool; +import me.ailama.handler.models.Tool; import me.ailama.main.AiLama; import me.ailama.main.Main; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; diff --git a/src/main/java/me/ailama/handler/commandhandler/OllamaManager.java b/src/main/java/me/ailama/handler/commandhandler/OllamaManager.java index 744d33d..c480c74 100644 --- a/src/main/java/me/ailama/handler/commandhandler/OllamaManager.java +++ b/src/main/java/me/ailama/handler/commandhandler/OllamaManager.java @@ -20,6 +20,10 @@ import me.ailama.handler.interfaces.Assistant; import me.ailama.main.AiLama; import me.ailama.main.Main; +import me.ailama.tools.ApiTools; +import me.ailama.tools.MathTools; +import me.ailama.tools.TimeTools; +import me.ailama.tools.UtilityTools; import org.apache.commons.lang3.StringEscapeUtils; import org.jetbrains.annotations.NotNull; import org.jsoup.Jsoup; @@ -40,6 +44,8 @@ public class OllamaManager { private final HashMap tools; + private final HashMap, ArrayList> classInstanceMap; + public OllamaManager() { url = AiLama.getInstance().fixUrl(Config.get("OLLAMA_URL") + ":" + Config.get("OLLAMA_PORT")); @@ -47,11 +53,19 @@ public OllamaManager() { embeddingModel = Config.get("OLLAMA_EMBEDDING_MODEL"); tools = new HashMap<>(); + classInstanceMap = new HashMap<>(); addTool(AiLama.getInstance()); + addTool(new MathTools()); + addTool(new ApiTools()); + addTool(new TimeTools()); + addTool(new UtilityTools()); } public void addTool(Object toolClass) { + + ArrayList toolsList = new ArrayList<>(); + getMethodsAnnotated(toolClass.getClass()).forEach(method -> { if(method.getReturnType() == void.class) { @@ -68,11 +82,16 @@ public void addTool(Object toolClass) { } tools.put(name,method); + toolsList.add(name); } } catch (Exception e) { Main.LOGGER.error("Error while adding tool: " + e.getMessage()); } }); + + if(!toolsList.isEmpty()) { + classInstanceMap.put(toolClass.getClass(), toolsList); + } } // Get the final JSON of all the tools @@ -146,6 +165,15 @@ public Method getTool(String toolName) { return tools.get(toolName); } + public Class getToolClass(String toolName) { + for(Class clazz : classInstanceMap.keySet()) { + if(classInstanceMap.get(clazz).contains(toolName)) { + return clazz; + } + } + return null; + } + // Execute the Tool public Object executeTool(String toolName, Object... args) { @@ -157,7 +185,7 @@ public Object executeTool(String toolName, Object... args) { return null; } - return tool.invoke(AiLama.getInstance(),args); + return tool.invoke(getToolClass(toolName).getConstructor().newInstance(), args); } catch (Exception e) { Main.LOGGER.error("Error while executing tool: " + e.getMessage()); diff --git a/src/main/java/me/ailama/handler/commandhandler/SearXNGManager.java b/src/main/java/me/ailama/handler/commandhandler/SearXNGManager.java index 8438565..0ddd669 100644 --- a/src/main/java/me/ailama/handler/commandhandler/SearXNGManager.java +++ b/src/main/java/me/ailama/handler/commandhandler/SearXNGManager.java @@ -3,8 +3,8 @@ import com.drew.lang.annotations.Nullable; import com.fasterxml.jackson.databind.ObjectMapper; import me.ailama.config.Config; -import me.ailama.handler.other.SearXNG; -import me.ailama.handler.other.SearXNGResult; +import me.ailama.handler.models.SearXNG; +import me.ailama.handler.models.SearXNGResult; import me.ailama.main.AiLama; import me.ailama.main.Main; import okhttp3.OkHttpClient; @@ -13,7 +13,6 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import java.util.stream.Stream; public class SearXNGManager { diff --git a/src/main/java/me/ailama/handler/other/SearXNG.java b/src/main/java/me/ailama/handler/models/SearXNG.java similarity index 82% rename from src/main/java/me/ailama/handler/other/SearXNG.java rename to src/main/java/me/ailama/handler/models/SearXNG.java index abd3ed0..2417beb 100644 --- a/src/main/java/me/ailama/handler/other/SearXNG.java +++ b/src/main/java/me/ailama/handler/models/SearXNG.java @@ -1,9 +1,8 @@ -package me.ailama.handler.other; +package me.ailama.handler.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import java.util.ArrayList; -import java.util.List; @JsonIgnoreProperties(ignoreUnknown = true) public class SearXNG { diff --git a/src/main/java/me/ailama/handler/other/SearXNGResult.java b/src/main/java/me/ailama/handler/models/SearXNGResult.java similarity index 92% rename from src/main/java/me/ailama/handler/other/SearXNGResult.java rename to src/main/java/me/ailama/handler/models/SearXNGResult.java index 2b42474..16623cf 100644 --- a/src/main/java/me/ailama/handler/other/SearXNGResult.java +++ b/src/main/java/me/ailama/handler/models/SearXNGResult.java @@ -1,4 +1,4 @@ -package me.ailama.handler.other; +package me.ailama.handler.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/src/main/java/me/ailama/handler/other/Tool.java b/src/main/java/me/ailama/handler/models/Tool.java similarity index 89% rename from src/main/java/me/ailama/handler/other/Tool.java rename to src/main/java/me/ailama/handler/models/Tool.java index e902ee5..8e2dcc6 100644 --- a/src/main/java/me/ailama/handler/other/Tool.java +++ b/src/main/java/me/ailama/handler/models/Tool.java @@ -1,4 +1,4 @@ -package me.ailama.handler.other; +package me.ailama.handler.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/src/main/java/me/ailama/main/AiLama.java b/src/main/java/me/ailama/main/AiLama.java index 34fe5d9..cd8f4d9 100644 --- a/src/main/java/me/ailama/main/AiLama.java +++ b/src/main/java/me/ailama/main/AiLama.java @@ -4,10 +4,7 @@ import me.ailama.handler.annotations.Args; import net.dv8tion.jda.api.utils.data.DataObject; import okhttp3.*; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import java.net.URI; import java.util.ArrayList; import java.util.List; @@ -19,84 +16,6 @@ public AiLama() { } - @Tool(name = "add", description = "Addition ('+') of two numbers like N1+N2", arguments = { - @Args(name = "a", Type = "number"), - @Args(name = "b", Type = "number") - }) - public String add(Number a, Number b) { - return String.valueOf(a.doubleValue() + b.doubleValue()); - } - - @Tool(name = "subtract", description = "Subtraction ('-') of two numbers like N1-N2", arguments = { - @Args(name = "a", Type = "number"), - @Args(name = "b", Type = "number") - }) - public String subtract(Number a, Number b) { - return String.valueOf(a.doubleValue() - b.doubleValue()); - } - - @Tool(name = "multiply", description = "Multiplication ('*') of two numbers like N1*N2", arguments = { - @Args(name = "a", Type = "number"), - @Args(name = "b", Type = "number") - }) - public String multiply(Number a, Number b) { - return String.valueOf(a.doubleValue() * b.doubleValue()); - } - - @Tool(name = "divide", description = "Division ('/') of two numbers like N1/N2", arguments = { - @Args(name = "a", Type = "number"), - @Args(name = "b", Type = "number") - }) - public String divide(Number a, Number b) { - return String.valueOf(a.doubleValue() / b.doubleValue()); - } - - @Tool(name = "modulus", description = "Modulus ('%') of two numbers like N1%N2", arguments = { - @Args(name = "a", Type = "number"), - @Args(name = "b", Type = "number") - }) - public String modulus(Number a, Number b) { - return String.valueOf(a.doubleValue() % b.doubleValue()); - } - - @Tool(name = "power", description = "Power ('^') of two numbers like N1^N2", arguments = { - @Args(name = "a", Type = "number"), - @Args(name = "b", Type = "number") - }) - public String power(Number a, Number b) { - return String.valueOf(Math.pow(a.doubleValue(), b.doubleValue())); - } - - @Tool(name = "sqrt", description = "Square root of a number like sqrt(N1)", arguments = { - @Args(name = "a", Type = "number") - }) - public String sqrt(Number a) { - return String.valueOf(Math.sqrt(a.doubleValue())); - } - - @Tool(name = "cubeRoot", description = "Cube root of a number", arguments = { - @Args(name = "a", Type = "number") - }) - public String cubeRoot(Number a) { - return String.valueOf(Math.cbrt(a.doubleValue())); - } - - @Tool(name = "formatTime", description = "Format time from milliseconds to a readable format like formatTime(N1)", arguments = { - @Args(name = "timeInMillis", Type = "number") - }) - public String formatTime(final long timeInMillis) { - - int seconds = (int) (timeInMillis / 1000) % 60; - int minutes = (int) ((timeInMillis / (1000*60)) % 60); - int hours = (int) ((timeInMillis / (1000*60*60)) % 24); - int days = (int) (timeInMillis / (1000*60*60*24)); - - if (days > 0) { - return String.format("%02d:%02d:%02d:%02d", days, hours, minutes, seconds); - } - return String.format("%02d:%02d:%02d", hours, minutes, seconds); - } - @Tool(name = "fixUrl", description = "Fix a URL if it doesn't start with 'http://' or 'https://'", arguments = { @Args(name = "url", Type = "string") }) @@ -107,29 +26,6 @@ public String fixUrl(String url) { return url; } - @Tool(name = "time", description = "Get the current time in a specific timezone like time(is24Hour, timeZone)", arguments = { - @Args(name = "is24Hour", Type = "boolean", description = "true for 24-hour format, false for 12-hour format"), - @Args(name = "timeZone", Type = "string", description = "Timezone in which you want to get the time like 'Asia/Kolkata'") - }) - public String time(boolean is24Hour, String timeZone) { - DateTime dateTime = new DateTime(); - if (timeZone != null) { - dateTime = dateTime.withZone(DateTimeZone.forID(timeZone)); - } - return dateTime.toString(is24Hour ? "HH:mm:ss" : "hh:mm:ss a"); - } - - @Tool(name = "currencyRate", description = "Converts a currency rate to another", arguments = { - @Args(name = "amount", Type = "double", description = "Amount to convert", noNull = true), - @Args(name = "currency1", Type = "string", description = "Currency to convert from, Like INR"), - @Args(name = "currency2", Type = "string", description = "Currency to convert to, Like USD") - }) - public String currencyRate(Double amount, String currency1, String currency2) { - final double finalRate = Double.parseDouble(getRates(currency1.toLowerCase(),currency2.toLowerCase())); - final double conv = finalRate * amount; - return String.format("%.4f", conv); - } - public String getRates(String currency,String currency2) { final OkHttpClient okHttpClient = new OkHttpClient(); String rate = ""; @@ -156,6 +52,7 @@ public String getRates(String currency,String currency2) { return "0"; } } + public List getParts(final String string, final int partitionSize) { final List parts = new ArrayList<>(); for (int len = string.length(), i = 0; i < len; i += partitionSize) { @@ -164,19 +61,6 @@ public List getParts(final String string, final int partitionSize) { return parts; } - @Tool(name = "isValidURL", description = "Check if a URL is valid like isValidURL(url)", arguments = { - @Args(name = "url", Type = "string") - }) - public boolean isValidURL(String url) { - try { - //noinspection ResultOfMethodCallIgnored - new URI(url).toURL(); - return true; - } catch (Exception e) { - return false; - } - } - public static AiLama getInstance() { if (AiLama.INSTANCE == null) { AiLama.INSTANCE = new AiLama(); diff --git a/src/main/java/me/ailama/tools/ApiTools.java b/src/main/java/me/ailama/tools/ApiTools.java new file mode 100644 index 0000000..84a7c74 --- /dev/null +++ b/src/main/java/me/ailama/tools/ApiTools.java @@ -0,0 +1,18 @@ +package me.ailama.tools; + +import me.ailama.handler.annotations.Args; +import me.ailama.handler.annotations.Tool; +import me.ailama.main.AiLama; + +public class ApiTools { + @Tool(name = "currencyRate", description = "Converts a currency rate to another", arguments = { + @Args(name = "amount", Type = "double", description = "Amount to convert", noNull = true), + @Args(name = "currency1", Type = "string", description = "Currency to convert from, Like INR"), + @Args(name = "currency2", Type = "string", description = "Currency to convert to, Like USD") + }) + public String currencyRate(Double amount, String currency1, String currency2) { + final double finalRate = Double.parseDouble(AiLama.getInstance().getRates(currency1.toLowerCase(),currency2.toLowerCase())); + final double conv = finalRate * amount; + return String.format("%.4f", conv); + } +} diff --git a/src/main/java/me/ailama/tools/MathTools.java b/src/main/java/me/ailama/tools/MathTools.java new file mode 100644 index 0000000..a3fdee2 --- /dev/null +++ b/src/main/java/me/ailama/tools/MathTools.java @@ -0,0 +1,70 @@ +package me.ailama.tools; + +import me.ailama.handler.annotations.Args; +import me.ailama.handler.annotations.Tool; + +public class MathTools { + + @Tool(name = "add", description = "Addition ('+') of two numbers like N1+N2", arguments = { + @Args(name = "a", Type = "number"), + @Args(name = "b", Type = "number") + }) + public String add(Number a, Number b) { + return String.valueOf(a.doubleValue() + b.doubleValue()); + } + + @Tool(name = "subtract", description = "Subtraction ('-') of two numbers like N1-N2", arguments = { + @Args(name = "a", Type = "number"), + @Args(name = "b", Type = "number") + }) + public String subtract(Number a, Number b) { + return String.valueOf(a.doubleValue() - b.doubleValue()); + } + + @Tool(name = "multiply", description = "Multiplication ('*') of two numbers like N1*N2", arguments = { + @Args(name = "a", Type = "number"), + @Args(name = "b", Type = "number") + }) + public String multiply(Number a, Number b) { + return String.valueOf(a.doubleValue() * b.doubleValue()); + } + + @Tool(name = "divide", description = "Division ('/') of two numbers like N1/N2", arguments = { + @Args(name = "a", Type = "number"), + @Args(name = "b", Type = "number") + }) + public String divide(Number a, Number b) { + return String.valueOf(a.doubleValue() / b.doubleValue()); + } + + @Tool(name = "modulus", description = "Modulus ('%') of two numbers like N1%N2", arguments = { + @Args(name = "a", Type = "number"), + @Args(name = "b", Type = "number") + }) + public String modulus(Number a, Number b) { + return String.valueOf(a.doubleValue() % b.doubleValue()); + } + + @Tool(name = "power", description = "Power ('^') of two numbers like N1^N2", arguments = { + @Args(name = "a", Type = "number"), + @Args(name = "b", Type = "number") + }) + public String power(Number a, Number b) { + return String.valueOf(Math.pow(a.doubleValue(), b.doubleValue())); + } + + @Tool(name = "sqrt", description = "Square root of a number like sqrt(N1)", arguments = { + @Args(name = "a", Type = "number") + }) + public String sqrt(Number a) { + return String.valueOf(Math.sqrt(a.doubleValue())); + } + + @Tool(name = "cubeRoot", description = "Cube root of a number", arguments = { + @Args(name = "a", Type = "number") + }) + public String cubeRoot(Number a) { + return String.valueOf(Math.cbrt(a.doubleValue())); + } + +} diff --git a/src/main/java/me/ailama/tools/TimeTools.java b/src/main/java/me/ailama/tools/TimeTools.java new file mode 100644 index 0000000..97b3ff4 --- /dev/null +++ b/src/main/java/me/ailama/tools/TimeTools.java @@ -0,0 +1,38 @@ +package me.ailama.tools; + +import me.ailama.handler.annotations.Args; +import me.ailama.handler.annotations.Tool; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; + +public class TimeTools { + + @Tool(name = "formatTime", description = "Format time from milliseconds to a readable format like formatTime(N1)", arguments = { + @Args(name = "timeInMillis", Type = "number") + }) + public String formatTime(final long timeInMillis) { + + int seconds = (int) (timeInMillis / 1000) % 60; + int minutes = (int) ((timeInMillis / (1000*60)) % 60); + int hours = (int) ((timeInMillis / (1000*60*60)) % 24); + int days = (int) (timeInMillis / (1000*60*60*24)); + + if (days > 0) { + return String.format("%02d:%02d:%02d:%02d", days, hours, minutes, seconds); + } + return String.format("%02d:%02d:%02d", hours, minutes, seconds); + } + + @Tool(name = "time", description = "Get the current time in a specific timezone like time(is24Hour, timeZone)", arguments = { + @Args(name = "is24Hour", Type = "boolean", description = "true for 24-hour format, false for 12-hour format"), + @Args(name = "timeZone", Type = "string", description = "Timezone in which you want to get the time like 'Asia/Kolkata'") + }) + public String time(boolean is24Hour, String timeZone) { + DateTime dateTime = new DateTime(); + if (timeZone != null) { + dateTime = dateTime.withZone(DateTimeZone.forID(timeZone)); + } + return dateTime.toString(is24Hour ? "HH:mm:ss" : "hh:mm:ss a"); + } + +} diff --git a/src/main/java/me/ailama/tools/UtilityTools.java b/src/main/java/me/ailama/tools/UtilityTools.java new file mode 100644 index 0000000..e1355fd --- /dev/null +++ b/src/main/java/me/ailama/tools/UtilityTools.java @@ -0,0 +1,21 @@ +package me.ailama.tools; + +import me.ailama.handler.annotations.Args; +import me.ailama.handler.annotations.Tool; + +import java.net.URI; + +public class UtilityTools { + @Tool(name = "isValidURL", description = "Check if a URL is valid like isValidURL(url)", arguments = { + @Args(name = "url", Type = "string") + }) + public boolean isValidURL(String url) { + try { + //noinspection ResultOfMethodCallIgnored + new URI(url).toURL(); + return true; + } catch (Exception e) { + return false; + } + } +}