diff --git a/.gitignore b/.gitignore
index 4fd0163..92acb10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,5 +44,5 @@ bin/
/pythonFiles/
/messages/
/logs/
-/data/
+data
/cache/
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index f449e21..88d702b 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -12,6 +12,7 @@
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7..35eb1dd 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/Core/src/main/java/me/zacharias/chat/core/Core.java b/Core/src/main/java/me/zacharias/chat/core/Core.java
index a08a205..8109e82 100644
--- a/Core/src/main/java/me/zacharias/chat/core/Core.java
+++ b/Core/src/main/java/me/zacharias/chat/core/Core.java
@@ -160,7 +160,7 @@ public class Core {
logWriter.close();
LocalDateTime now = LocalDateTime.now();
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH-mm-ss");
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd_HH-mm-ss");
File messagesFile = new File("./messages/"+now.format(formatter)+".json");
@@ -175,7 +175,7 @@ public class Core {
messagesWriter.write(messages.toString());
messagesWriter.close();
- File f = new File("./cache/messages.json");
+ File f = new File("./data/messages.json");
if(f.exists())
{
f.delete();
@@ -236,14 +236,28 @@ public class Core {
/**
* Adds a new tool to the System
- * @param funtionTool The tool to add
+ * @param functionTool The tool to add
* @param source The source of the tool
*/
- public void addTool(OllamaFunctionTool funtionTool, @MagicConstant(valuesFromClass = Core.Source.class) String source) {
- funtionTools.add(new Pair<>(funtionTool, source));
- ollamaObject.addTool(funtionTool);
+ public void addTool(OllamaFunctionTool functionTool, @MagicConstant(valuesFromClass = Source.class) String source) {
+ funtionTools.add(new Pair<>(functionTool, source));
+ ollamaObject.addTool(functionTool);
}
-
+
+ /**
+ * Adds a list of tools to the System
+ * @param tools The tools to add
+ */
+ @SuppressWarnings("MagicConstant")
+ public void addTools(OllamaFunctionTools tools)
+ {
+ for(Pair tool : tools)
+ {
+
+ addTool(tool.getKey(), tool.getValue());
+ }
+ }
+
/**
* Gets the list of tools added to the System
* @return The list of tools added to the System compressed as Pairs of the tool and the source
@@ -324,6 +338,7 @@ public class Core {
throw new RuntimeException("HTTP Response code - " + responseCode);
}
} catch (IOException e) {
+// System.err.println("Error: JSON: "+);
throw new RuntimeException(e);
}
}
diff --git a/Core/src/main/java/me/zacharias/chat/ollama/OllamaFunctionTools.java b/Core/src/main/java/me/zacharias/chat/ollama/OllamaFunctionTools.java
new file mode 100644
index 0000000..b281a2e
--- /dev/null
+++ b/Core/src/main/java/me/zacharias/chat/ollama/OllamaFunctionTools.java
@@ -0,0 +1,111 @@
+package me.zacharias.chat.ollama;
+
+import me.zacharias.chat.core.Core;
+import me.zacharias.chat.core.Pair;
+import org.intellij.lang.annotations.MagicConstant;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+
+public class OllamaFunctionTools implements Iterable> {
+ /**
+ * A list of tools for the OllamaObject.
+ * OPS! Shuld only be ussed to add a set of tools to the OllamaObject, not to be used for storage of tools internaly or externaly
+ */
+ private ArrayList tools;
+ /**
+ * A list of source for the tools.
+ * OPS! Shuld only be ussed to add a set of tools to the OllamaObject, not to be used for storage of tools internaly or externaly
+ * OPS! most be the same size as the tools list! since each tool matches to a source!
+ */
+ private ArrayList source;
+
+ /**
+ * Gets the tools of the {@link OllamaFunctionTools}
+ * @param tools A list of {@link OllamaFunctionTool}
+ * @param source The source of the tools
+ */
+ private OllamaFunctionTools(ArrayList tools, ArrayList source) {
+ if(source == null || tools == null || source.size() != tools.size() || source.isEmpty())
+ throw new IllegalArgumentException("The source and tools must be the same size! and not empty!");
+ this.tools = tools;
+ this.source = source;
+ }
+
+ /**
+ * Gets the tools of the {@link OllamaFunctionTools}
+ * @param tools A list of {@link OllamaFunctionTool}
+ * @param source The source of the tools
+ */
+ private OllamaFunctionTools(OllamaFunctionTool[] tools, @MagicConstant(valuesFromClass = Core.Source.class) String[] source) {
+ if(source == null || tools == null || source.length != tools.length || source.length == 0)
+ throw new IllegalArgumentException("The source and tools must be the same size! and not empty!");
+ this.tools = new ArrayList<>();
+ this.source = new ArrayList<>();
+
+ for (OllamaFunctionTool tool : tools) {
+ this.tools.add(tool);
+ this.source.add(tool.name());
+ }
+
+ for (String s : source) {
+ if (s.equals(Core.Source.INTERNAL)) {
+ this.source.add(s);
+ }
+ }
+ }
+
+ public static OllamaFunctionToolsBuilder builder() {
+ return new OllamaFunctionToolsBuilder();
+ }
+
+ @Override
+ public @NotNull Iterator> iterator() {
+ ArrayList> pairs = new ArrayList<>();
+ for (int i = 0; i < tools.size(); i++) {
+ pairs.add(new Pair<>(tools.get(i), source.get(i)));
+ }
+ return pairs.iterator();
+ }
+
+ @Override
+ public void forEach(Consumer super Pair> action) {
+ for (Pair pair : this) {
+ action.accept(pair);
+ }
+ }
+
+ @Override
+ public Spliterator> spliterator() {
+ // TODO: Implement this method
+ throw new UnsupportedOperationException("Not implemented yet");
+ //return Iterable.super.spliterator();
+ }
+
+ public static class OllamaFunctionToolsBuilder {
+ private ArrayList tools = new ArrayList<>();
+ private ArrayList source = new ArrayList<>();
+
+ public OllamaFunctionToolsBuilder addTool(OllamaFunctionTool tool, @MagicConstant(valuesFromClass = Core.Source.class) String source) {
+ this.tools.add(tool);
+ this.source.add(source);
+ return this;
+ }
+
+ public OllamaFunctionToolsBuilder addTools(HashMap tools) {
+ for (OllamaFunctionTool tool : tools.keySet()) {
+ this.tools.add(tool);
+ this.source.add(tools.get(tool));
+ }
+ return this;
+ }
+
+ public OllamaFunctionTools build() {
+ return new OllamaFunctionTools(tools, source);
+ }
+ }
+}
diff --git a/Core/src/main/java/me/zacharias/chat/ollama/OllamaObject.java b/Core/src/main/java/me/zacharias/chat/ollama/OllamaObject.java
index cbd6bbb..9f1bb3e 100644
--- a/Core/src/main/java/me/zacharias/chat/ollama/OllamaObject.java
+++ b/Core/src/main/java/me/zacharias/chat/ollama/OllamaObject.java
@@ -75,7 +75,7 @@ public class OllamaObject {
LaunchOptions launchOptions = new LaunchOptions();
if(launchOptions.isLoadOld()) {
System.out.println("Loading old data...");
- File f = new File("./cache/messages.json");
+ File f = new File(Core.DATA_DIR+"/messages.json");
if(f.exists()) {
try {
BufferedReader br = new BufferedReader(new FileReader(f));
@@ -375,7 +375,8 @@ public class OllamaObject {
FileHandler fileHandler = new FileHandler(baseDirectory);
if(false);
- return this;
+
+ throw new IllegalArgumentException("FileHandler is not supported yet!");
}
/**
diff --git a/Core/src/main/java/me/zacharias/chat/ollama/OllamaPerameter.java b/Core/src/main/java/me/zacharias/chat/ollama/OllamaPerameter.java
index c560cf4..1f798ed 100644
--- a/Core/src/main/java/me/zacharias/chat/ollama/OllamaPerameter.java
+++ b/Core/src/main/java/me/zacharias/chat/ollama/OllamaPerameter.java
@@ -192,7 +192,15 @@ public class OllamaPerameter {
/**
* Represents a boolean parameter.
*/
- BOOLEAN("boolean");
+ BOOLEAN("boolean"),
+ /**
+ * Represents a enum parameter.
+ */
+ ENUM("enum"),
+ /**
+ * Represents a array parameter.
+ */
+ ARRAY("array");
/**
* The type of the parameter.
diff --git a/Display/build.gradle b/Display/build.gradle
index a3a65f9..995f01c 100644
--- a/Display/build.gradle
+++ b/Display/build.gradle
@@ -7,6 +7,7 @@ version = '1.0-SNAPSHOT'
dependencies {
implementation project(":Core")
+ implementation project(":MALAPITool")
}
test {
diff --git a/Display/src/main/java/me/zacharias/chat/display/Display.java b/Display/src/main/java/me/zacharias/chat/display/Display.java
index c41c7b4..ff2ecc2 100644
--- a/Display/src/main/java/me/zacharias/chat/display/Display.java
+++ b/Display/src/main/java/me/zacharias/chat/display/Display.java
@@ -5,6 +5,7 @@ import me.zacharias.chat.core.Pair;
import me.zacharias.chat.core.PrintMessageHandler;
import me.zacharias.chat.core.files.FileHandlerLocation;
import me.zacharias.chat.core.memory.CoreMemory;
+import me.zacharias.chat.mal.api.MALAPITool;
import me.zacharias.chat.ollama.*;
import org.json.JSONObject;
@@ -42,16 +43,18 @@ public class Display {
public Display()
{
- core.setOllamaObject(OllamaObject.builder()
- .setModel("llama3.2")
- //.setModel("deepseek-r1")
+ core.setOllamaObject/*NoMemory*/(OllamaObject.builder()
+ //.setModel("llama3.2")
+ //.setModel("gemma3:12b")
+ .setModel("qwen3:8b")
.keep_alive(10)
//.stream(false)
- .addFileTools(FileHandlerLocation.DATA_FILES)
+ //.addFileTools(FileHandlerLocation.DATA_FILES)
.build());
- //core.addTool(new TimeTool(), Core.Source.INTERNAL);
+ core.addTool(new TimeTool(), Core.Source.INTERNAL);
//core.addTool(new PythonRunner(core), Core.Source.INTERNAL);
+ core.addTools(new MALAPITool().getOllamaTools());
//core.getOllamaObject().addMessage(new OllamaMessage(OllamaMessageRole.SYSTEM, "Have a nice tone and use formal wording"));
@@ -101,7 +104,7 @@ public class Display {
System.exit(0);
return;
case "write":
- core.flushLog();
+ Core.flushLog();
break;
case "peek":
CoreMemory coreMemory = CoreMemory.getInstance();
diff --git a/MALAPITool/README.md b/MALAPITool/README.md
new file mode 100644
index 0000000..1c8fa19
--- /dev/null
+++ b/MALAPITool/README.md
@@ -0,0 +1,17 @@
+# MAL API wrapper
+
+## Important notes
+### Scope
+This wrapper is not fully implemented, some endpoints are missing, as well as no user-specific endpoints are added.
+### Rate limits
+I'm yet to enforce the rate limit, due to in there the Ollama backend won't be fast enough, but this is subject to change
+### API Key Required
+You must provide your own API key
+
+Store the key in `${DATE_DIR}/malapi.json` using the following format:
+```jsonc
+{
+ "client_id": "",
+ "client_secret": ""// This is for the moment not used but shuld till be added
+}
+```
\ No newline at end of file
diff --git a/MALAPITool/src/main/java/me/zacharias/chat/mal/api/MALAPITool.java b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/MALAPITool.java
new file mode 100644
index 0000000..f87a414
--- /dev/null
+++ b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/MALAPITool.java
@@ -0,0 +1,108 @@
+package me.zacharias.chat.mal.api;
+
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ClassInfo;
+import io.github.classgraph.ClassInfoList;
+import io.github.classgraph.ScanResult;
+import me.zacharias.chat.core.Core;
+import me.zacharias.chat.ollama.*;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.InvocationTargetException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.HashMap;
+
+public class MALAPITool {
+
+ public final String Client_ID;
+ public final String Client_Secret;
+ public final String BaseURL = "https://api.myanimelist.net/v2";
+ public final OllamaFunctionTools MALAPITools;
+
+ public MALAPITool() {
+ super();
+ try {
+ JSONObject obj = new JSONObject(Files.readString(Path.of(Core.DATA_DIR + "/malapi.json")));
+ this.Client_ID = obj.getString("client_id");
+ this.Client_Secret = obj.getString("client_secret");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ OllamaFunctionTools.OllamaFunctionToolsBuilder builder = new OllamaFunctionTools.OllamaFunctionToolsBuilder();
+
+ try(ScanResult scanResult = new ClassGraph().enableAllInfo().acceptPackages("me.zacharias.chat.mal.api.endpoints").scan()) {
+ ClassInfoList endpoints = scanResult.getClassesWithAnnotation(MALEndpoint.class.getName());
+ for (ClassInfo classInfo : endpoints) {
+ Class> clazz = classInfo.loadClass();
+ if (OllamaFunctionTool.class.isAssignableFrom(clazz)) {
+ //System.out.println("Found endpoint: " + clazz.getName() + " With constructor: " + clazz.getDeclaredConstructors().f.getName() + " and arguments: " + Arrays.toString(clazz.getDeclaredConstructor().getParameterTypes()));
+ MALEndpointTool tool = (MALEndpointTool) clazz.getDeclaredConstructor(MALAPITool.class).newInstance(MALAPITool.this);
+ builder.addTool(tool, Core.Source.INTERNAL);
+ }
+ }
+ } catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+
+ this.MALAPITools = builder.build();
+ }
+
+ public OllamaFunctionTools getOllamaTools() {
+ return this.MALAPITools;
+ }
+
+ public JSONObject APIRequest(String endpoint, HashMap params) {
+ try {
+
+ String urlParams = ParameterStringBuilder.getParamsString(params);
+
+ URL url = new URI(this.BaseURL + endpoint + "?" + urlParams).toURL();
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", "application/json");
+ connection.setRequestProperty("X-MAL-CLIENT-ID", this.Client_ID);
+ connection.setDoOutput(true);
+ connection.setConnectTimeout(80 * 1000);
+
+ int responseCode = connection.getResponseCode();
+
+ // HTTP_OK or 200 response code generally means that the server ran successfully without any errors
+ StringBuilder response = new StringBuilder();
+
+ // Read response content
+ // connection.getInputStream() purpose is to obtain an input stream for reading the server's response.
+ try (
+ BufferedReader reader = new BufferedReader( new InputStreamReader( connection.getInputStream()))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ response.append(line); // Adds every line to response till the end of file.
+ }
+ }
+
+ if (responseCode == HttpURLConnection.HTTP_OK) {
+
+
+ connection.disconnect();
+ return new JSONObject(response.toString());
+ }
+ else {
+ connection.disconnect();
+ System.err.println("Error: HTTP Response code - " + responseCode + "\n"+response.toString());
+ throw new RuntimeException("HTTP Response code - " + responseCode);
+ }
+ }catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Error: " + e.getMessage());
+ }
+ }
+}
diff --git a/MALAPITool/src/main/java/me/zacharias/chat/mal/api/MALEndpoint.java b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/MALEndpoint.java
new file mode 100644
index 0000000..baba13d
--- /dev/null
+++ b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/MALEndpoint.java
@@ -0,0 +1,11 @@
+package me.zacharias.chat.mal.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MALEndpoint {
+}
diff --git a/MALAPITool/src/main/java/me/zacharias/chat/mal/api/MALEndpointTool.java b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/MALEndpointTool.java
new file mode 100644
index 0000000..5b8eaaf
--- /dev/null
+++ b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/MALEndpointTool.java
@@ -0,0 +1,11 @@
+package me.zacharias.chat.mal.api;
+
+import me.zacharias.chat.ollama.OllamaFunctionTool;
+
+public abstract class MALEndpointTool extends OllamaFunctionTool {
+ protected MALAPITool MALAPIToolInstance;
+ public MALEndpointTool(MALAPITool malAPITool) {
+ super();
+ this.MALAPIToolInstance = malAPITool;
+ }
+}
diff --git a/MALAPITool/src/main/java/me/zacharias/chat/mal/api/ParameterStringBuilder.java b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/ParameterStringBuilder.java
new file mode 100644
index 0000000..acbcafc
--- /dev/null
+++ b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/ParameterStringBuilder.java
@@ -0,0 +1,25 @@
+package me.zacharias.chat.mal.api;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+public class ParameterStringBuilder {
+ public static String getParamsString(Map params)
+ throws UnsupportedEncodingException {
+ StringBuilder result = new StringBuilder();
+
+ for (Map.Entry entry : params.entrySet()) {
+ result.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8));
+ result.append("=");
+ result.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
+ result.append("&");
+ }
+
+ String resultString = result.toString();
+ return !resultString.isEmpty()
+ ? resultString.substring(0, resultString.length() - 1)
+ : resultString;
+ }
+}
\ No newline at end of file
diff --git a/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetAnimeDetails.java b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetAnimeDetails.java
new file mode 100644
index 0000000..08c4383
--- /dev/null
+++ b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetAnimeDetails.java
@@ -0,0 +1,86 @@
+package me.zacharias.chat.mal.api.endpoints;
+
+import me.zacharias.chat.mal.api.MALAPITool;
+import me.zacharias.chat.mal.api.MALEndpoint;
+import me.zacharias.chat.mal.api.MALEndpointTool;
+import me.zacharias.chat.ollama.OllamaFunctionArgument;
+import me.zacharias.chat.ollama.OllamaPerameter;
+import me.zacharias.chat.ollama.OllamaToolRespnce;
+import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+@MALEndpoint
+public class GetAnimeDetails extends MALEndpointTool {
+ public GetAnimeDetails(MALAPITool malAPITool) {
+ super(malAPITool);
+ }
+
+ @Override
+ public String name() {
+ return "get_anime_details";
+ }
+
+ @Override
+ public String description() {
+ return "Gets the details of an anime from the MAL API";
+ }
+
+ @Override
+ public OllamaPerameter parameters() {
+ return OllamaPerameter.builder()
+ .addProperty("id", OllamaPerameter.OllamaPerameterBuilder.Type.INT, "The id of the anime", true)
+ .addProperty("fields", OllamaPerameter.OllamaPerameterBuilder.Type.ARRAY, "The fields to return, defaults to [\"id\", \"title\", \"synopsis\", \"genres\"]")
+ .build();
+ }
+
+ @Override
+ public OllamaToolRespnce function(OllamaFunctionArgument... args) {
+ int id = -1;
+ String[] fields = null;
+
+ for (OllamaFunctionArgument arg : args) {
+ switch (arg.argument()) {
+ case "id":
+ id = (Integer) arg.value();
+ break;
+ case "fields":
+ JSONArray jsonArray = (JSONArray) arg.value();
+ for (int i = 0; i < jsonArray.length(); i++) {
+ if (jsonArray.get(i) instanceof String) {
+ if (fields == null) {
+ fields = new String[jsonArray.length()];
+ }
+ fields[i] = jsonArray.getString(i);
+ } else {
+ throw new OllamaToolErrorException(this.name(), "The fields must be a string array");
+ }
+ }
+ break;
+ }
+ }
+
+ if (id == -1) {
+ throw new OllamaToolErrorException(this.name(), "The id must be specified");
+ }
+
+ if (fields == null) {
+ fields = new String[]{
+ "id",
+ "title",
+ "synopsis",
+ "genres"
+ };
+ }
+
+ HashMap map = new HashMap<>();
+ map.put("fields", String.join(",", fields));
+
+ JSONObject obj = MALAPIToolInstance.APIRequest("/anime/"+id, map);
+
+ return new OllamaToolRespnce(this.name(), obj.toString());
+ }
+}
diff --git a/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetAnimeList.java b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetAnimeList.java
new file mode 100644
index 0000000..128c635
--- /dev/null
+++ b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetAnimeList.java
@@ -0,0 +1,88 @@
+package me.zacharias.chat.mal.api.endpoints;
+
+import me.zacharias.chat.mal.api.MALAPITool;
+import me.zacharias.chat.mal.api.MALEndpoint;
+import me.zacharias.chat.mal.api.MALEndpointTool;
+import me.zacharias.chat.ollama.OllamaFunctionArgument;
+import me.zacharias.chat.ollama.OllamaPerameter;
+import me.zacharias.chat.ollama.OllamaToolRespnce;
+import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@MALEndpoint
+public class GetAnimeList extends MALEndpointTool {
+ public GetAnimeList(MALAPITool malAPITool) {
+ super(malAPITool);
+ }
+
+ @Override
+ public String name() {
+ return "get_anime_list";
+ }
+
+ @Override
+ public String description() {
+ return "Gets a list of anime from the MAL API";
+ }
+
+ @Override
+ public OllamaPerameter parameters() {
+ return OllamaPerameter.builder()
+ .addProperty("query", OllamaPerameter.OllamaPerameterBuilder.Type.STRING, "The query to search for",true)
+ .addProperty("offset", OllamaPerameter.OllamaPerameterBuilder.Type.INT, "The offset to start from")
+ .addProperty("fields", OllamaPerameter.OllamaPerameterBuilder.Type.ARRAY, "The fields to return")
+ .build();
+ }
+
+ @Override
+ public OllamaToolRespnce function(OllamaFunctionArgument... args) {
+ String query = "";
+ int offset = 0;
+ String[] fields = null;
+
+ for (OllamaFunctionArgument arg : args) {
+ switch (arg.argument()) {
+ case "query":
+ query = (String)arg.value();
+ break;
+ case "offset":
+ offset = (Integer) arg.value();
+ break;
+ case "fields":
+ JSONArray jsonArray = (JSONArray) arg.value();
+ if(!jsonArray.isEmpty()) {
+ fields = new String[jsonArray.length()];
+ for (int i = 0; i < jsonArray.length(); i++) {
+ if (jsonArray.get(i) instanceof String) {
+ fields[i] = jsonArray.getString(i);
+ } else {
+ throw new OllamaToolErrorException(this.name(), "The fields must be a string array");
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (query.isEmpty()) {
+ throw new OllamaToolErrorException(this.name(), "Query cannot be empty");
+ }
+
+ HashMap params = new HashMap<>();
+ params.put("q", query);
+ if (offset > 0) {
+ params.put("offset", String.valueOf(offset));
+ }
+ if (fields != null) {
+ params.put("fields", String.join(",", fields));
+ }
+
+ JSONObject response = MALAPIToolInstance.APIRequest("/anime", params);
+
+ return new OllamaToolRespnce(this.name(), response.toString());
+ }
+}
diff --git a/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetManagDetails.java b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetManagDetails.java
new file mode 100644
index 0000000..2992789
--- /dev/null
+++ b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetManagDetails.java
@@ -0,0 +1,85 @@
+package me.zacharias.chat.mal.api.endpoints;
+
+import me.zacharias.chat.mal.api.MALAPITool;
+import me.zacharias.chat.mal.api.MALEndpoint;
+import me.zacharias.chat.mal.api.MALEndpointTool;
+import me.zacharias.chat.ollama.OllamaFunctionArgument;
+import me.zacharias.chat.ollama.OllamaPerameter;
+import me.zacharias.chat.ollama.OllamaToolRespnce;
+import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+
+@MALEndpoint
+public class GetManagDetails extends MALEndpointTool {
+ public GetManagDetails(MALAPITool malAPITool) {
+ super(malAPITool);
+ }
+
+ @Override
+ public String name() {
+ return "get_manag_details";
+ }
+
+ @Override
+ public String description() {
+ return "Gets the details of an manga from the MAL API";
+ }
+
+ @Override
+ public OllamaPerameter parameters() {
+ return OllamaPerameter.builder()
+ .addProperty("id", OllamaPerameter.OllamaPerameterBuilder.Type.INT, "The id of the manga", true)
+ .addProperty("fields", OllamaPerameter.OllamaPerameterBuilder.Type.ARRAY, "The fields to return, defaults to [\"id\", \"title\", \"synopsis\", \"genres\"]")
+ .build();
+ }
+
+ @Override
+ public OllamaToolRespnce function(OllamaFunctionArgument... args) {
+ int id = -1;
+ String[] fields = null;
+
+ for (OllamaFunctionArgument arg : args) {
+ switch (arg.argument()) {
+ case "id":
+ id = (Integer) arg.value();
+ break;
+ case "fields":
+ JSONArray jsonArray = (JSONArray) arg.value();
+ for (int i = 0; i < jsonArray.length(); i++) {
+ if (jsonArray.get(i) instanceof String) {
+ if (fields == null) {
+ fields = new String[jsonArray.length()];
+ }
+ fields[i] = jsonArray.getString(i);
+ } else {
+ throw new OllamaToolErrorException(this.name(), "The fields must be a string array");
+ }
+ }
+ break;
+ }
+ }
+
+ if (id == -1) {
+ throw new OllamaToolErrorException(this.name(), "The id must be specified");
+ }
+
+ if (fields == null) {
+ fields = new String[]{
+ "id",
+ "title",
+ "synopsis",
+ "genres"
+ };
+ }
+
+ HashMap map = new HashMap<>();
+ map.put("fields", String.join(",", fields));
+
+ JSONObject obj = MALAPIToolInstance.APIRequest("/manga/"+id, map);
+
+ return new OllamaToolRespnce(this.name(), obj.toString());
+ }
+}
diff --git a/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetMangaList.java b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetMangaList.java
new file mode 100644
index 0000000..eba881d
--- /dev/null
+++ b/MALAPITool/src/main/java/me/zacharias/chat/mal/api/endpoints/GetMangaList.java
@@ -0,0 +1,87 @@
+package me.zacharias.chat.mal.api.endpoints;
+
+import me.zacharias.chat.mal.api.MALAPITool;
+import me.zacharias.chat.mal.api.MALEndpoint;
+import me.zacharias.chat.mal.api.MALEndpointTool;
+import me.zacharias.chat.ollama.OllamaFunctionArgument;
+import me.zacharias.chat.ollama.OllamaPerameter;
+import me.zacharias.chat.ollama.OllamaToolRespnce;
+import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+
+@MALEndpoint
+public class GetMangaList extends MALEndpointTool {
+ public GetMangaList(MALAPITool malAPITool) {
+ super(malAPITool);
+ }
+
+ @Override
+ public String name() {
+ return "get_manga_list";
+ }
+
+ @Override
+ public String description() {
+ return "Gets a list of manga from the MAL API";
+ }
+
+ @Override
+ public OllamaPerameter parameters() {
+ return OllamaPerameter.builder()
+ .addProperty("query", OllamaPerameter.OllamaPerameterBuilder.Type.STRING, "The query to search for",true)
+ .addProperty("offset", OllamaPerameter.OllamaPerameterBuilder.Type.INT, "The offset to start from")
+ .addProperty("fields", OllamaPerameter.OllamaPerameterBuilder.Type.ARRAY, "The fields to return")
+ .build();
+ }
+
+ @Override
+ public OllamaToolRespnce function(OllamaFunctionArgument... args) {
+ String query = "";
+ int offset = 0;
+ String[] fields = null;
+
+ for (OllamaFunctionArgument arg : args) {
+ switch (arg.argument()) {
+ case "query":
+ query = (String)arg.value();
+ break;
+ case "offset":
+ offset = (Integer) arg.value();
+ break;
+ case "fields":
+ JSONArray jsonArray = (JSONArray) arg.value();
+ if(!jsonArray.isEmpty()) {
+ fields = new String[jsonArray.length()];
+ for (int i = 0; i < jsonArray.length(); i++) {
+ if (jsonArray.get(i) instanceof String) {
+ fields[i] = jsonArray.getString(i);
+ } else {
+ throw new OllamaToolErrorException(this.name(), "The fields must be a string array");
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (query.isEmpty()) {
+ throw new OllamaToolErrorException(this.name(), "Query cannot be empty");
+ }
+
+ HashMap params = new HashMap<>();
+ params.put("q", query);
+ if (offset > 0) {
+ params.put("offset", String.valueOf(offset));
+ }
+ if (fields != null) {
+ params.put("fields", String.join(",", fields));
+ }
+
+ JSONObject response = MALAPIToolInstance.APIRequest("/manga", params);
+
+ return new OllamaToolRespnce(this.name(), response.toString());
+ }
+}
diff --git a/settings.gradle b/settings.gradle
index dcd3864..4d6d8b9 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,5 @@
rootProject.name = 'AI-test'
include 'API', 'Core', 'Display', 'launcher'
+
+include 'MALAPITool'
\ No newline at end of file