Added javadoc, and fixed spelling errors.

This commit is contained in:
2025-03-14 14:32:38 +01:00
parent e7e8b445bf
commit 907f2e42e5
30 changed files with 1177 additions and 194 deletions

1
.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
AI-test

124
.idea/uiDesigner.xml generated Normal file
View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

View File

@@ -1,12 +1,28 @@
package me.zacharias.chat.api; package me.zacharias.chat.api;
/**
* API Endpoints
* see <a href="https://server.4zellen.se:3000/Zacharias/chat_thing/wiki/API-Docs">API Docs</a>
*/
public enum APIEndpoints { public enum APIEndpoints {
// API request endpoints // API request endpoints
/**
* Requests a tool to be added to the environment
*/
ADD_TOOL, ADD_TOOL,
/**
* Requests a query to be executed on the environment
*/
QUERY, QUERY,
// API response endpoints // API response endpoints
/**
* Response to a tool request containing the Ollama response
*/
RESPONSE, RESPONSE,
/**
* Response to use a tool defined by the API Client
*/
USE_TOOL, USE_TOOL,
} }

View File

@@ -15,11 +15,29 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Scanner; import java.util.Scanner;
/**
* The API server.<br>
* This class is responsible for handling the server socket and the clients for the API.<br>
* It also handles the output redirection and the message printing.<br>
* And the Registration of Tools on the {@link Core} object.
*/
public class APIServer { public class APIServer {
/**
* The list of clients connected to the server.
*/
ArrayList<Client> clientsList = new ArrayList<>(); ArrayList<Client> clientsList = new ArrayList<>();
/**
* The server socket.
*/
ServerSocket serverSocket; ServerSocket serverSocket;
/**
* The output stream for the server.
*/
PrintStream dataOut; PrintStream dataOut;
/**
* The message handler for the server.
*/
PrintMessageHandler printMessageHandler = new PrintMessageHandler() { PrintMessageHandler printMessageHandler = new PrintMessageHandler() {
@Override @Override
public void printMessage(String message) { public void printMessage(String message) {
@@ -40,11 +58,14 @@ public class APIServer {
return false; return false;
} }
}; };
/**
* The core object for the server.
*/
Core core = new Core(printMessageHandler); Core core = new Core(printMessageHandler);
/** /**
* Options foir this is expected to be passed thru the {@link LaunchOptions#instance} object.<br> * Options for this is expected to be passed through the {@link LaunchOptions#instance} object.<br>
* Used objects:<br> * Used objects:<br>
* - {@link LaunchOptions#autoAccept}<br> * - {@link LaunchOptions#autoAccept}<br>
* - {@link LaunchOptions#redirectOutput}<br> * - {@link LaunchOptions#redirectOutput}<br>
@@ -58,12 +79,15 @@ public class APIServer {
core.setOllamaObject(OllamaObject.builder() core.setOllamaObject(OllamaObject.builder()
.setModel("llama3-AI") .setModel("llama3-AI")
.keep_alive(10) .keep_alive(10)
.stream(false) //.stream(false)
.build()); .build());
if (!Paths.get(redirectedOutput).toFile().getParentFile().exists()) { if (redirectedOutput != null && !Paths.get(redirectedOutput).toFile().getParentFile().exists()) {
System.out.println("Failed to be able to open the redirected output file due to missing directory"); System.out.println("Failed to be able to open the redirected output file due to missing directory");
} }
else {
redirectedOutput = "./out.txt";
}
File f = new File(redirectedOutput); File f = new File(redirectedOutput);
@@ -121,6 +145,19 @@ public class APIServer {
System.exit(1); System.exit(1);
return; return;
} }
System.out.println("Redirecting output to [" + redirectedOutput + "]");
System.out.println("Starting server on port [" + port + "]");
try{
serverSocket = new ServerSocket(port);
}
catch(Exception e){
System.out.println("Failed to start server on port [" + port + "]");
System.exit(1);
return;
}
//serverSocket = new ServerSocket(port); //serverSocket = new ServerSocket(port);
} }

View File

@@ -4,16 +4,28 @@ import java.io.BufferedWriter;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.Socket; import java.net.Socket;
/**
* The client object for the API server.
*/
public class Client { public class Client {
/**
* The socket for the client.
*/
Socket socket; Socket socket;
/**
* Creates a new client object.
* @param socket the socket for the client.
*/
public Client(Socket socket) { public Client(Socket socket) {
this.socket = socket; this.socket = socket;
} }
/** /**
* Returnes true unless if the method failes * Returnes true unless if the method failes
* @param message the message to send to the client.
* @return true if the message was sent successfully, false otherwise.
*/ */
public boolean sendMessage(String message) { public boolean sendMessage(String message) {
try(BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) { try(BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {

View File

@@ -5,6 +5,7 @@ import me.zacharias.chat.core.memory.GetMemoryFunction;
import me.zacharias.chat.core.memory.RemoveMemoryFunction; import me.zacharias.chat.core.memory.RemoveMemoryFunction;
import me.zacharias.chat.ollama.*; import me.zacharias.chat.ollama.*;
import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException; import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
import org.intellij.lang.annotations.MagicConstant;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
@@ -18,19 +19,52 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/**
* The Main class for the System, responsible for managing the OllamaObject, tools, and the Ollama API.
*/
public class Core { public class Core {
/**
* The file to write the logs to.
*/
private static File logFile = new File("./logs/latest.log"); private static File logFile = new File("./logs/latest.log");
/**
* The writer to write the logs to.
*/
private static BufferedWriter logWriter; private static BufferedWriter logWriter;
/**
* The scheduler to schedule the log flushing.
*/
private ScheduledExecutorService scheduler; private ScheduledExecutorService scheduler;
/**
* The OllamaObject to use.
*/
private OllamaObject ollamaObject; private OllamaObject ollamaObject;
private ArrayList<Pair<OllamaFuntionTool, String>> funtionTools = new ArrayList<>(); /**
* The list of tools to use.
*/
private ArrayList<Pair<OllamaFunctionTool, String>> funtionTools = new ArrayList<>();
/**
* The IP of the Ollama API.
*/
private String ollamaIP = "localhost";//"192.168.5.184"; private String ollamaIP = "localhost";//"192.168.5.184";
/**
* The port of the Ollama API.
*/
private int ollamaPort = 11434; private int ollamaPort = 11434;
/**
* The URL of the Ollama API.
*/
private URL url; private URL url;
/**
* The PrintMessageHandler to use.
*/
private final PrintMessageHandler printMessageHandler; private final PrintMessageHandler printMessageHandler;
/**
* If color is supported by the PrintMessageHandler.
*/
private boolean supportColor; private boolean supportColor;
{ {
@@ -125,24 +159,28 @@ public class Core {
} }
})); }));
} }
/**
* Creates a new instance of Core with the provided PrintMessageHandler
* @param printMessageHandler The PrintMessageHandler to use as the default Output
*/
public Core(PrintMessageHandler printMessageHandler) { public Core(PrintMessageHandler printMessageHandler) {
this.printMessageHandler = printMessageHandler; this.printMessageHandler = printMessageHandler;
supportColor = printMessageHandler.color(); supportColor = printMessageHandler.color();
} }
/** /**
* Sets the {@link ollamaObject} object to the provided argument, * Sets the {@link #ollamaObject} object to the provided argument,
* Aslo adds the memory base system. see {@link Core#setOllamaObjectNoMemory} if you don't want to add memory functions * Also adds the memory base system. see {@link Core#setOllamaObjectNoMemory} if you don't want to add memory functions
* @param ollamaObject * @param ollamaObject The OllamaObject to use
*/ */
public void setOllamaObject(OllamaObject ollamaObject) { public void setOllamaObject(OllamaObject ollamaObject) {
if(this.ollamaObject == null) { if(this.ollamaObject == null) {
this.ollamaObject = ollamaObject; this.ollamaObject = ollamaObject;
addTool(new AddMemoryFunction(), "Core"); addTool(new AddMemoryFunction(), Source.CORE);
addTool(new RemoveMemoryFunction(), "Core"); addTool(new RemoveMemoryFunction(), Source.CORE);
addTool(new GetMemoryFunction(), "Core"); addTool(new GetMemoryFunction(), Source.CORE);
} }
else { else {
throw new IllegalArgumentException("Ollama object is already set"); throw new IllegalArgumentException("Ollama object is already set");
@@ -150,9 +188,9 @@ public class Core {
} }
/** /**
* Sets the {@link Core#ollamaObject} object to the provided argument, * Sets the {@link #ollamaObject} object to the provided argument,
* Dose not add the base system for memory. see {@link Core#setOllamaObject} if you want to add memory function * Dose not add the base system for memory. see {@link #setOllamaObject} if you want to add memory function
* @param ollamaObject * @param ollamaObject The OllamaObject to use
*/ */
public void setOllamaObjectNoMemory(OllamaObject ollamaObject) { public void setOllamaObjectNoMemory(OllamaObject ollamaObject) {
if(this.ollamaObject == null) { if(this.ollamaObject == null) {
@@ -162,30 +200,56 @@ public class Core {
throw new IllegalArgumentException("Ollama object is already set"); throw new IllegalArgumentException("Ollama object is already set");
} }
} }
public void addTool(OllamaFuntionTool funtionTool, String source) { /**
* Adds a new tool to the System
* @param funtionTool 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)); funtionTools.add(new Pair<>(funtionTool, source));
ollamaObject.addTool(funtionTool); ollamaObject.addTool(funtionTool);
} }
public ArrayList<Pair<OllamaFuntionTool, String>> getFuntionTools() { /**
* 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
*/
public ArrayList<Pair<OllamaFunctionTool, String>> getFuntionTools() {
return funtionTools; return funtionTools;
} }
/**
* Gets the Ollama Object
* @return The Ollama Object
*/
public OllamaObject getOllamaObject() { public OllamaObject getOllamaObject() {
return ollamaObject; return ollamaObject;
} }
public void addFuntionTool(OllamaFuntionTool funtionTool) { /**
* Adds a new tool to the System
* @deprecated Use {@link Core#addTool(OllamaFunctionTool, String)} instead
* @param funtionTool The tool to add
*/
@Deprecated
public void addFuntionTool(OllamaFunctionTool funtionTool) {
funtionTools.add(new Pair<>(funtionTool, "External")); funtionTools.add(new Pair<>(funtionTool, "External"));
} }
/**
* Flushes the log file
*/
public static void flushLog() { public static void flushLog() {
try { try {
logWriter.flush(); logWriter.flush();
}catch (IOException e) {} }catch (IOException e) {}
} }
/**
* Sends the OllamaObject to Ollama
* @return The response from Ollama
*/
public JSONObject qurryOllama() public JSONObject qurryOllama()
{ {
try { try {
@@ -230,7 +294,12 @@ public class Core {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
/**
* Handles the response from Ollama
* By Processing the response, handles Function Calls, Logs relevant information, Appends information to the OllamaObject, Prints messages to the User.
* @param responce The response from Ollama
*/
public void handleResponce(JSONObject responce) public void handleResponce(JSONObject responce)
{ {
//System.out.println("Responce: "+responce); //System.out.println("Responce: "+responce);
@@ -248,7 +317,7 @@ public class Core {
if(jsonObject.has("function")) if(jsonObject.has("function"))
{ {
JSONObject function = jsonObject.getJSONObject("function"); JSONObject function = jsonObject.getJSONObject("function");
List<Pair<OllamaFuntionTool, String>> functions = funtionTools.stream().filter(func -> func.getKey().name().equalsIgnoreCase(function.getString("name"))).toList(); List<Pair<OllamaFunctionTool, String>> functions = funtionTools.stream().filter(func -> func.getKey().name().equalsIgnoreCase(function.getString("name"))).toList();
if(functions.isEmpty()) { if(functions.isEmpty()) {
ollamaObject.addMessage(new OllamaToolError("Function '"+function.getString("name")+"' does not exist")); ollamaObject.addMessage(new OllamaToolError("Function '"+function.getString("name")+"' does not exist"));
@@ -257,7 +326,7 @@ public class Core {
} }
else { else {
OllamaFuntionTool func = functions.getFirst().getKey(); OllamaFunctionTool func = functions.getFirst().getKey();
ArrayList<OllamaFunctionArgument> argumentArrayList = new ArrayList<>(); ArrayList<OllamaFunctionArgument> argumentArrayList = new ArrayList<>();
@@ -287,7 +356,11 @@ public class Core {
else checkIfResponceMessage(responce); else checkIfResponceMessage(responce);
} }
} }
/**
* Checks if the response contains a message and if so, prints it to the user
* @param responce the Ollama response
*/
private void checkIfResponceMessage(JSONObject responce) { private void checkIfResponceMessage(JSONObject responce) {
if(responce.getJSONObject("message").has("content") && !responce.getJSONObject("message").getString("content").isBlank()) if(responce.getJSONObject("message").has("content") && !responce.getJSONObject("message").getString("content").isBlank())
{ {
@@ -296,7 +369,11 @@ public class Core {
ollamaObject.addMessage(new OllamaMessage(OllamaMessageRole.ASSISTANT, responce.getJSONObject("message").getString("content"))); ollamaObject.addMessage(new OllamaMessage(OllamaMessageRole.ASSISTANT, responce.getJSONObject("message").getString("content")));
} }
} }
/**
* Writes a message to the log file
* @param message The message to write
*/
public static void writeLog(String message) public static void writeLog(String message)
{ {
try { try {
@@ -307,4 +384,36 @@ public class Core {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
/**
* Represents the source of a tool.
* <p>
* This is intended for use with {@link Core#addTool(OllamaFunctionTool, String)}
* to indicate the module from which a tool originates.
*/
public static class Source {
/**
* Represents an external tool that is not derived from the Core.
* Instead, it belongs to an internally defined system or module within the project/program.
*/
public static final String EXTERNAL = "External";
/**
* Represents an internally defined tool that is part of the Core system.
* This is meant for tools that are strictly part of the Core and should not be used for definitions outside of it.
*/
public static final String CORE = "Core";
/**
* Represents a tool defined through an API system.
* These tools are more dynamic, as they originate from fully external sources using the API.
*/
public static final String API = "Api";
/**
* Represents an internally defined tool that is derived from Core Components but not the Core itself.
* This is used for tools that are part of the Core Components, such as internal modules, but do not belong directly to the Core.
*/
public static final String INTERNAL = "Internal";
}
} }

View File

@@ -1,8 +1,16 @@
package me.zacharias.chat.core; package me.zacharias.chat.core;
/**
* The Configuration class, where arguments are stored and retrieved. This is used to configure the running of the program from the Launcher.
*/
public class LaunchOptions { public class LaunchOptions {
private static LaunchOptions instance = new LaunchOptions(); private static LaunchOptions instance = new LaunchOptions();
/**
* Gets the singleton instance of the LaunchOptions class.
* Meant to be used to get or set ant option.
* @return The singleton instance of the LaunchOptions class.
*/
public static LaunchOptions getInstance() { public static LaunchOptions getInstance() {
return instance; return instance;
} }
@@ -12,47 +20,92 @@ public class LaunchOptions {
private boolean serverMode; private boolean serverMode;
private int port = 39075; private int port = 39075;
private String redirectOutput; private String redirectOutput;
/**
* Sets the singleton instance of the LaunchOptions class.
* Used to reset the LaunchOptions to their default values.
* @param instance The instance to set.
*/
public static void setInstance(LaunchOptions instance) { public static void setInstance(LaunchOptions instance) {
LaunchOptions.instance = instance; LaunchOptions.instance = instance;
} }
/**
* Retries if old messages should be loaded.
* @return a boolean indicating if old messages should be loaded.
*/
public boolean isLoadOld() { public boolean isLoadOld() {
return loadOld; return loadOld;
} }
/**
* Sets if old messages should be loaded.
* @param loadOld a boolean indicating if old messages should be loaded.
*/
public void setLoadOld(boolean loadOld) { public void setLoadOld(boolean loadOld) {
this.loadOld = loadOld; this.loadOld = loadOld;
} }
/**
* Gets if the program should automatically accept prompts.
* @return a boolean indicating if the program should automatically accept prompts.
*/
public boolean isAutoAccept() { public boolean isAutoAccept() {
return autoAccept; return autoAccept;
} }
/**
* Sets if the program should automatically accept prompts.
* @param autoAccept a boolean indicating if the program should automatically accept prompts.
*/
public void setAutoAccept(boolean autoAccept) { public void setAutoAccept(boolean autoAccept) {
this.autoAccept = autoAccept; this.autoAccept = autoAccept;
} }
/**
* Gets the port number that the API server should use.
* @return the port number that the API server should use.
*/
public int getPort() { public int getPort() {
return port; return port;
} }
/**
* Sets the port number that the API server should use.
* @param port the port number that the API server should use.
*/
public void setPort(int port) { public void setPort(int port) {
this.port = port; this.port = port;
} }
/**
* Gets the file path that the program should redirect output to.
* @return the file path that the program should redirect output to.
*/
public String getRedirectOutput() { public String getRedirectOutput() {
return redirectOutput; return redirectOutput;
} }
/**
* Sets the file path that the program should redirect output to.
* @param redirectOutput the file path that the program should redirect output to.
*/
public void setRedirectOutput(String redirectOutput) { public void setRedirectOutput(String redirectOutput) {
this.redirectOutput = redirectOutput; this.redirectOutput = redirectOutput;
} }
/**
* Gets if the program is running in API server mode.
* @return a boolean indicating if the program is running in API server mode.
*/
public boolean isServerMode() { public boolean isServerMode() {
return serverMode; return serverMode;
} }
/**
* Sets if the program is running in API server mode.
* @param serverMode a boolean indicating if the program is running in API server mode.
*/
public void setServerMode(boolean serverMode) { public void setServerMode(boolean serverMode) {
this.serverMode = serverMode; this.serverMode = serverMode;
} }

View File

@@ -1,26 +1,58 @@
package me.zacharias.chat.core; package me.zacharias.chat.core;
/**
* A simple Pair class.
* @param <K> The key type
* @param <V> The value type
*/
public class Pair<K, V> { public class Pair<K, V> {
/**
* The key of the pair.
*/
private K key; private K key;
/**
* The value of the pair.
*/
private V value; private V value;
/**
* Creates a new instance of Pair.
* @param key The key of the pair
* @param value The value of the pair
*/
public Pair(K key, V value) { public Pair(K key, V value) {
this.key = key; this.key = key;
this.value = value; this.value = value;
} }
/**
* Gets the key of the pair.
* @return The key of the pair
*/
public K getKey() { public K getKey() {
return key; return key;
} }
/**
* Gets the value of the pair.
* @return The value of the pair
*/
public V getValue() { public V getValue() {
return value; return value;
} }
/**
* Sets the key of the pair.
* @param key The key of the pair
*/
public void setKey(K key) { public void setKey(K key) {
this.key = key; this.key = key;
} }
/**
* Sets the value of the pair.
* @param value The value of the pair
*/
public void setValue(V value) { public void setValue(V value) {
this.value = value; this.value = value;
} }

View File

@@ -1,6 +1,21 @@
package me.zacharias.chat.core; package me.zacharias.chat.core;
/**
* Represents a PrintMessageHandler.
* This is used by the Core to print messages to the user or API Clients.
*/
public interface PrintMessageHandler { public interface PrintMessageHandler {
/**
* Handles the printing of a message.
* This is meant to output the message to the user or API Client.
* @param message The message to be printed.
*/
void printMessage(String message); void printMessage(String message);
/**
* Gets if color is supported by the PrintMessageHandler.
* This uses ANSI escape codes to color the output.
* @return a boolean indicating if color is supported by the PrintMessageHandler.
*/
boolean color(); boolean color();
} }

View File

@@ -1,13 +1,19 @@
package me.zacharias.chat.core.memory; package me.zacharias.chat.core.memory;
import me.zacharias.chat.ollama.OllamaFunctionArgument; import me.zacharias.chat.ollama.OllamaFunctionArgument;
import me.zacharias.chat.ollama.OllamaFuntionTool; import me.zacharias.chat.ollama.OllamaFunctionTool;
import me.zacharias.chat.ollama.OllamaPerameter; import me.zacharias.chat.ollama.OllamaPerameter;
import me.zacharias.chat.ollama.OllamaToolRespnce; import me.zacharias.chat.ollama.OllamaToolRespnce;
import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException; import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
import org.json.JSONArray;
public class AddMemoryFunction extends OllamaFuntionTool { /**
* Provides the add_memory function.<br>
* This function adds a string to the memory.
*/
public class AddMemoryFunction extends OllamaFunctionTool {
/**
* The CoreMemory instance.
*/
CoreMemory memory = CoreMemory.getInstance(); CoreMemory memory = CoreMemory.getInstance();
@Override @Override
@@ -32,7 +38,7 @@ public class AddMemoryFunction extends OllamaFuntionTool {
if (args.length == 0) { if (args.length == 0) {
throw new OllamaToolErrorException(name(), "Missing memory argument"); throw new OllamaToolErrorException(name(), "Missing memory argument");
} }
String value = (String) args[0].getValue(); String value = (String) args[0].value();
memory.addMemory(value); memory.addMemory(value);
return new OllamaToolRespnce(name(), "Added "+value+" to the memory"); return new OllamaToolRespnce(name(), "Added "+value+" to the memory");
} }

View File

@@ -6,13 +6,28 @@ import org.json.JSONObject;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
/**
* CoreMemory is a class that provides a way to store and retrieve strings from a file.<br>
* This is meant to be used as a way to store and retrieve strings from a file.
*/
public class CoreMemory { public class CoreMemory {
/**
* The singleton instance of CoreMemory.
*/
private static CoreMemory instance = new CoreMemory("./cache/CoreMemory.json"); private static CoreMemory instance = new CoreMemory("./cache/CoreMemory.json");
/**
* Gets the singleton instance of CoreMemory.
* @return The singleton instance of CoreMemory
*/
public static CoreMemory getInstance() { public static CoreMemory getInstance() {
return instance; return instance;
} }
/**
* Creates a new instance of CoreMemory.
* @param memoryFile The file to store the memory in
*/
public CoreMemory(String memoryFile) { public CoreMemory(String memoryFile) {
File f = new File(memoryFile); File f = new File(memoryFile);
if (f.exists()) { if (f.exists()) {
@@ -64,18 +79,36 @@ public class CoreMemory {
} }
}); });
} }
/**
* The memory.
*/
private ArrayList<String> memory = new ArrayList<>(); private ArrayList<String> memory = new ArrayList<>();
/**
* The file to store the memory in.
*/
private final String memoryFile; private final String memoryFile;
/**
* Gets the memory.
* @return The memory
*/
public ArrayList<String> getMemory() { public ArrayList<String> getMemory() {
return memory; return memory;
} }
/**
* Sets the memory.
* @param memory The memory
*/
public void addMemory(String memory) { public void addMemory(String memory) {
this.memory.add(memory); this.memory.add(memory);
} }
/**
* Removes the memory.
* @param memory The memory to remove
*/
public void removeMemory(String memory) { public void removeMemory(String memory) {
this.memory.remove(memory); this.memory.remove(memory);
} }

View File

@@ -1,12 +1,18 @@
package me.zacharias.chat.core.memory; package me.zacharias.chat.core.memory;
import me.zacharias.chat.ollama.OllamaFunctionArgument; import me.zacharias.chat.ollama.OllamaFunctionArgument;
import me.zacharias.chat.ollama.OllamaFuntionTool; import me.zacharias.chat.ollama.OllamaFunctionTool;
import me.zacharias.chat.ollama.OllamaPerameter; import me.zacharias.chat.ollama.OllamaPerameter;
import me.zacharias.chat.ollama.OllamaToolRespnce; import me.zacharias.chat.ollama.OllamaToolRespnce;
import org.json.JSONArray;
public class GetMemoryFunction extends OllamaFuntionTool { /**
* Provides the get_memory function.<br>
* This function retrives all the memory.
*/
public class GetMemoryFunction extends OllamaFunctionTool {
/**
* The CoreMemory instance.
*/
CoreMemory memory = CoreMemory.getInstance(); CoreMemory memory = CoreMemory.getInstance();
@Override @Override

View File

@@ -1,12 +1,19 @@
package me.zacharias.chat.core.memory; package me.zacharias.chat.core.memory;
import me.zacharias.chat.ollama.OllamaFunctionArgument; import me.zacharias.chat.ollama.OllamaFunctionArgument;
import me.zacharias.chat.ollama.OllamaFuntionTool; import me.zacharias.chat.ollama.OllamaFunctionTool;
import me.zacharias.chat.ollama.OllamaPerameter; import me.zacharias.chat.ollama.OllamaPerameter;
import me.zacharias.chat.ollama.OllamaToolRespnce; import me.zacharias.chat.ollama.OllamaToolRespnce;
import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException; import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
public class RemoveMemoryFunction extends OllamaFuntionTool { /**
* Provides the remove_memory function.<br>
* This function removes a value from the memory.
*/
public class RemoveMemoryFunction extends OllamaFunctionTool {
/**
* The CoreMemory instance.
*/
CoreMemory memory = CoreMemory.getInstance(); CoreMemory memory = CoreMemory.getInstance();
@Override @Override
@@ -31,7 +38,7 @@ public class RemoveMemoryFunction extends OllamaFuntionTool {
if (args.length == 0) { if (args.length == 0) {
throw new OllamaToolErrorException(name(), "Missing memory argument"); throw new OllamaToolErrorException(name(), "Missing memory argument");
} }
String value = (String) args[0].getValue(); String value = (String) args[0].value();
memory.removeMemory(value); memory.removeMemory(value);
return new OllamaToolRespnce(name(), "Removed "+value+" to the memory"); return new OllamaToolRespnce(name(), "Removed "+value+" to the memory");
} }

View File

@@ -1,19 +1,40 @@
package me.zacharias.chat.ollama; package me.zacharias.chat.ollama;
public class OllamaFunctionArgument { /**
private final String argument; * Represents an argument passed to a tool.
private final Object value; *
* @param argument The argument name
public OllamaFunctionArgument(String argument, Object value) { * @param value The argument value
this.argument = argument; */
this.value = value; public record OllamaFunctionArgument(String argument, Object value) {
/**
* Creates a new instance of OllamaFunctionArgument.<br>
* This is used by Ollama to pass arguments to a tool.
*
* @param argument The argument name
* @param value The argument value
*/
public OllamaFunctionArgument {
} }
public String getArgument() { /**
* Gets the argument name
*
* @return The argument name
*/
@Override
public String argument() {
return argument; return argument;
} }
public Object getValue() { /**
* Gets the argument value.<br>
* This needs to be cast to the correct type by the tool itself
*
* @return The argument value
*/
@Override
public Object value() {
return value; return value;
} }
} }

View File

@@ -0,0 +1,59 @@
package me.zacharias.chat.ollama;
import me.zacharias.chat.core.Core;
import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
import org.json.JSONObject;
/**
* Represents a tool that can be called by Ollama.
*/
public abstract class OllamaFunctionTool implements OllamaTool {
@Override
public String toString() {
JSONObject ret = new JSONObject();
ret.put("tool", "function");
JSONObject function = new JSONObject();
function.put("name", name());
function.put("description", description());
function.put("parameters", (parameters() == null?
new JSONObject() : new JSONObject(parameters().toString())));
ret.put("function", function);
return ret.toString();
}
/**
* The name of the tool
* This is used by Ollama to know what the tool is
* @return The name of the tool
*/
abstract public String name();
/**
* The description of the tool
* This is used by Ollama to know what the tool does
* @return The description of the tool
*/
abstract public String description();
/**
* The parameters of the tool
* This is used by Ollama to know what parameters the tool takes
* If null, the tool does not take any parameters
* @return The parameters of the tool or null if the tool does not take any parameters
*/
abstract public OllamaPerameter parameters();
/**
* The function of the tool.<br>
* This is used by Ollama to call the tool.<br>
* Throw {@link OllamaToolErrorException} if the tool encounters an error instead of normal exceptions. The {@link OllamaToolErrorException} gets handled more gracefully by {@link Core#handleResponce(JSONObject)}
* @param args The arguments to pass to the tool, if any
* @return The response from the tool
* @throws OllamaToolErrorException If the tool encounters an error
*/
abstract public OllamaToolRespnce function(OllamaFunctionArgument... args);
}

View File

@@ -1,28 +0,0 @@
package me.zacharias.chat.ollama;
import org.json.JSONObject;
public abstract class OllamaFuntionTool implements OllamaTool {
@Override
public String toString() {
JSONObject ret = new JSONObject();
ret.put("tool", "function");
JSONObject function = new JSONObject();
function.put("name", name());
function.put("description", description());
function.put("parameters", (parameters() == null?
new JSONObject() : new JSONObject(parameters().toString())));
ret.put("function", function);
return ret.toString();
}
abstract public String name();
abstract public String description();
abstract public OllamaPerameter parameters();
abstract public OllamaToolRespnce function(OllamaFunctionArgument... args);
}

View File

@@ -2,10 +2,24 @@ package me.zacharias.chat.ollama;
import org.json.JSONObject; import org.json.JSONObject;
/**
* Represents a message sent by a Tool, Assistant(Ollama), or User.
*/
public class OllamaMessage { public class OllamaMessage {
/**
* The role of the message.
*/
OllamaMessageRole role; OllamaMessageRole role;
/**
* The content of the message.
*/
String content; String content;
/**
* Creates a new instance of OllamaMessage.
* @param role The role of the message
* @param content The content of the message
*/
public OllamaMessage(OllamaMessageRole role, String content) { public OllamaMessage(OllamaMessageRole role, String content) {
this.role = role; this.role = role;
this.content = content; this.content = content;

View File

@@ -1,21 +1,53 @@
package me.zacharias.chat.ollama; package me.zacharias.chat.ollama;
/**
* Represents the role of a message.
* This is used by Ollama to determine the role of a message.
*/
public enum OllamaMessageRole { public enum OllamaMessageRole {
/**
* Represents a user message.
*/
USER("user"), USER("user"),
/**
* Represents an assistant message.
*/
ASSISTANT("assistant"), ASSISTANT("assistant"),
/**
* Represents a tool message
*/
TOOL("tool"), TOOL("tool"),
/**
* Represents a system message.
*/
SYSTEM("system"); SYSTEM("system");
/**
* The role of the message.
*/
private String role; private String role;
/**
* Creates a new instance of OllamaMessageRole.
* @param role The role of the message
*/
OllamaMessageRole(String role) { OllamaMessageRole(String role) {
this.role = role; this.role = role;
} }
/**
* Gets the role of the message.
* @return The role of the message
*/
public String getRole() { public String getRole() {
return role; return role;
} }
/**
* Gets the role of the message from a string.
* @param role The role of the message as a string
* @return The role of the message
*/
public static OllamaMessageRole fromRole(String role) { public static OllamaMessageRole fromRole(String role) {
for(OllamaMessageRole roleRole : values()) { for(OllamaMessageRole roleRole : values()) {
if(roleRole.role.equals(role.toLowerCase())) if(roleRole.role.equals(role.toLowerCase()))

View File

@@ -3,10 +3,22 @@ package me.zacharias.chat.ollama;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
/**
* Represents a message sent by a Tool.
*/
public class OllamaMessageToolCall extends OllamaMessage{ public class OllamaMessageToolCall extends OllamaMessage{
/**
* The tool calls in the message
*/
private JSONArray tool_calls; private JSONArray tool_calls;
/**
* Creates a new instance of OllamaMessage
* @param role The role of the message
* @param content The content of the message
* @param tool_calls The tool calls in the message
*/
public OllamaMessageToolCall(OllamaMessageRole role, String content, JSONArray tool_calls) { public OllamaMessageToolCall(OllamaMessageRole role, String content, JSONArray tool_calls) {
super(role, content); super(role, content);
this.tool_calls = tool_calls; this.tool_calls = tool_calls;

View File

@@ -1,5 +1,6 @@
package me.zacharias.chat.ollama; package me.zacharias.chat.ollama;
import me.zacharias.chat.core.Core;
import me.zacharias.chat.core.LaunchOptions; import me.zacharias.chat.core.LaunchOptions;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
@@ -12,15 +13,53 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/**
* Represents an Ollama Object.
* This is used to represent the state of the Ollama Object.
* This is used by the Core to store the state of the Ollama Object.
* This is used by the API to send the state of the Ollama Object to the client.
* @see Core#setOllamaObject(OllamaObject)
*/
public class OllamaObject { public class OllamaObject {
/**
* The model of the Ollama Object.
*/
String model; String model;
/**
* The messages of the Ollama Object.
*/
ArrayList<OllamaMessage> messages; ArrayList<OllamaMessage> messages;
/**
* The tools of the Ollama Object.
*/
ArrayList<OllamaTool> tools; ArrayList<OllamaTool> tools;
/**
* The format of the Ollama Object.
*/
JSONObject format; JSONObject format;
/**
* The options of the Ollama Object.
*/
Map<String, Object> options; Map<String, Object> options;
/**
* If the Ollama Object is streamed.
*/
boolean stream; boolean stream;
/**
* The keep alive of the Ollama Object.
*/
String keep_alive; String keep_alive;
/**
* Creates a new instance of OllamaObject.
* @param model The model of the Ollama Object. see {@link OllamaObject#model}
* @param messages The messages of the Ollama Object. see {@link OllamaObject#messages}
* @param tools The tools of the Ollama Object. see {@link OllamaObject#tools}
* @param format The format of the Ollama Object. see {@link OllamaObject#format}
* @param options The options of the Ollama Object. see {@link OllamaObject#options}
* @param stream If the Ollama Object is streamed. see {@link OllamaObject#stream}
* @param keep_alive The keep alive of the Ollama Object. see {@link OllamaObject#keep_alive}
*/
private OllamaObject(String model, ArrayList<OllamaMessage> messages, ArrayList<OllamaTool> tools, JSONObject format, Map<String, Object> options, boolean stream, String keep_alive) { private OllamaObject(String model, ArrayList<OllamaMessage> messages, ArrayList<OllamaTool> tools, JSONObject format, Map<String, Object> options, boolean stream, String keep_alive) {
this.model = model; this.model = model;
this.messages = messages; this.messages = messages;
@@ -59,39 +98,75 @@ public class OllamaObject {
} }
} }
} }
/**
* Gets the model of the Ollama Object.
* @return The model of the Ollama Object
*/
public String getModel() { public String getModel() {
return model; return model;
} }
/**
* Gets the messages
* @return The messages
*/
public ArrayList<OllamaMessage> getMessages() { public ArrayList<OllamaMessage> getMessages() {
return messages; return messages;
} }
/**
* Gets the tools
* @return The tools
*/
public ArrayList<OllamaTool> getTools() { public ArrayList<OllamaTool> getTools() {
return tools; return tools;
} }
/**
* Adds a tool to the Ollama Object
* @param tool The tool to add
*/
public void addTool(OllamaTool tool) { public void addTool(OllamaTool tool) {
tools.add(tool); tools.add(tool);
} }
/**
* Gets the format of the Ollama Object.
* @return The format of the Ollama Object
*/
public JSONObject getFormat() { public JSONObject getFormat() {
return format; return format;
} }
/**
* Gets the options of the Ollama Object.
* @return The options of the Ollama Object
*/
public Map<String, Object> getOptions() { public Map<String, Object> getOptions() {
return options; return options;
} }
/**
* Gets if the Ollama Object is streamed.
* @return If the Ollama Object is streamed
*/
public boolean isStream() { public boolean isStream() {
return stream; return stream;
} }
/**
* Gets the keep alive of the Ollama Object.
* @return The keep alive of the Ollama Object
*/
public String getKeep_alive() { public String getKeep_alive() {
return keep_alive; return keep_alive;
} }
/**
* Adds a message to the Ollama Object
* @param message The message to add
*/
public void addMessage(OllamaMessage message) { public void addMessage(OllamaMessage message) {
messages.add(message); messages.add(message);
} }
@@ -119,83 +194,182 @@ public class OllamaObject {
json.put("keep_alive", keep_alive); json.put("keep_alive", keep_alive);
return json.toString(); return json.toString();
} }
/**
* Creates a new instance of OllamaObjectBuilder.
* @return The {@link OllamaObjectBuilder}
*/
public static OllamaObjectBuilder builder() public static OllamaObjectBuilder builder()
{ {
return new OllamaObjectBuilder(); return new OllamaObjectBuilder();
} }
/**
* Represents a builder for OllamaObject.
*/
public static class OllamaObjectBuilder { public static class OllamaObjectBuilder {
/**
* The model of the Ollama Object.
*/
String model; String model;
/**
* The messages of the Ollama Object.
*/
ArrayList<OllamaMessage> messages = new ArrayList<>(); ArrayList<OllamaMessage> messages = new ArrayList<>();
/**
* The tools of the Ollama Object.
*/
ArrayList<OllamaTool> tools = new ArrayList<>(); ArrayList<OllamaTool> tools = new ArrayList<>();
/**
* The format of the Ollama Object.
*/
JSONObject format; JSONObject format;
/**
* The options of the Ollama Object.
*/
Map<String, Object> options = new HashMap<>(); Map<String, Object> options = new HashMap<>();
boolean stream; /**
* If the Ollama Object is streamed.
*/
boolean stream = false;
/**
* The keep alive of the Ollama Object.
*/
String keep_alive; String keep_alive;
/**
* Creates a new instance of {@link OllamaObjectBuilder}.
*/
public OllamaObjectBuilder() {} public OllamaObjectBuilder() {}
/**
* Sets the format of the Ollama Object as a JSON schema.
* @param format The format of the Ollama Object as a JSON schema
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder format(String format) { public OllamaObjectBuilder format(String format) {
this.format = new JSONObject(format); this.format = new JSONObject(format);
return this; return this;
} }
/**
* Sets the options of the Ollama Object.
* @param options The options of the Ollama Object
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder options(Map<String, Object> options) { public OllamaObjectBuilder options(Map<String, Object> options) {
this.options.putAll(options); this.options.putAll(options);
return this; return this;
} }
/**
* Sets an option of the Ollama Object.
* @param key The key of the option
* @param value The value of the option
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder option(String key, String value) { public OllamaObjectBuilder option(String key, String value) {
this.options.put(key, value); this.options.put(key, value);
return this; return this;
} }
/**
* Sets if the Ollama Object is streamed.
* @param stream If the Ollama Object is streamed
* @deprecated This should be false due to being broken in the current version of this system
* @return The {@link OllamaObjectBuilder}
*/
@Deprecated
public OllamaObjectBuilder stream(boolean stream) { public OllamaObjectBuilder stream(boolean stream) {
this.stream = stream; this.stream = stream;
return this; return this;
} }
/**
* Sets the keep alive of the Ollama Object.<br>
* This is a string formated as "minutes"m or "hours"h or "days"d
* @param keep_alive The keep alive of the Ollama Object
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder keep_alive(String keep_alive) { public OllamaObjectBuilder keep_alive(String keep_alive) {
this.keep_alive = keep_alive; this.keep_alive = keep_alive;
return this; return this;
} }
/**
* Sets the keep alive of the Ollama Object.<br>
* @param minutes The keep alive of the Ollama Object in minutes
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder keep_alive(int minutes) { public OllamaObjectBuilder keep_alive(int minutes) {
this.keep_alive = minutes+"m"; this.keep_alive = minutes+"m";
return this; return this;
} }
public OllamaObjectBuilder addTool(OllamaTool tools) { /**
this.tools.add(tools); * Adds a tool to the Ollama Object
* @param tool The tool to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addTool(OllamaTool tool) {
this.tools.add(tool);
return this; return this;
} }
/**
* Adds tools to the Ollama Object
* @param tools The tools to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addTools(ArrayList<? extends OllamaTool> tools) { public OllamaObjectBuilder addTools(ArrayList<? extends OllamaTool> tools) {
this.tools.addAll(tools); this.tools.addAll(tools);
return this; return this;
} }
/**
* Adds tools to the Ollama Object
* @param tools The tools to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addTools(OllamaTool... tools) { public OllamaObjectBuilder addTools(OllamaTool... tools) {
this.tools.addAll(List.of(tools)); this.tools.addAll(List.of(tools));
return this; return this;
} }
/**
* Adds messages to the Ollama Object
* @param messages The messages to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addMessages(OllamaMessage... messages) { public OllamaObjectBuilder addMessages(OllamaMessage... messages) {
this.messages.addAll(List.of(messages)); this.messages.addAll(List.of(messages));
return this; return this;
} }
/**
* Adds a message to the Ollama Object
* @param messages The message to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addMessage(OllamaMessage messages) { public OllamaObjectBuilder addMessage(OllamaMessage messages) {
this.messages.add(messages); this.messages.add(messages);
return this; return this;
} }
/**
* Sets the model of the Ollama Object
* @param model The model of the Ollama Object
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder setModel(String model) { public OllamaObjectBuilder setModel(String model) {
this.model = model; this.model = model;
return this; return this;
} }
/**
* Builds the {@link OllamaObject}
* @return The {@link OllamaObject}
*/
public OllamaObject build() { public OllamaObject build() {
return new OllamaObject(model, messages, tools, format, options, stream, keep_alive); return new OllamaObject(model, messages, tools, format, options, stream, keep_alive);
} }

View File

@@ -6,12 +6,22 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
* Represents the parameters of a tool.
* This is used by Ollama to determine the parameters of a tool.
*/
public class OllamaPerameter { public class OllamaPerameter {
/**
* Creates a new instance of {@link OllamaPerameter}.
* @param properties The properties of the parameters
* @param required The required parameters
*/
private OllamaPerameter(JSONObject properties, String[] required) { private OllamaPerameter(JSONObject properties, String[] required) {
this.properties = properties; this.properties = properties;
this.required = required; this.required = required;
}; };
@Override @Override
public String toString() { public String toString() {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
@@ -22,26 +32,60 @@ public class OllamaPerameter {
return json.toString(); return json.toString();
} }
/**
* the properties of the parameters
*/
JSONObject properties; JSONObject properties;
/**
* the required parameters
*/
String[] required; String[] required;
/**
* Gets the properties of the {@link OllamaPerameter}
* @return The properties of the {@link OllamaPerameter}
*/
public JSONObject getProperties() { public JSONObject getProperties() {
return properties; return properties;
} }
/**
* Gets the required parameters of the {@link OllamaPerameter}
* @return The required parameters of the {@link OllamaPerameter}
*/
public String[] getRequired() { public String[] getRequired() {
return required; return required;
} }
/**
* Creates a new instance of {@link OllamaPerameterBuilder}.
* @return The {@link OllamaPerameterBuilder}
*/
public static OllamaPerameterBuilder builder() { public static OllamaPerameterBuilder builder() {
return new OllamaPerameterBuilder(); return new OllamaPerameterBuilder();
} }
/**
* Represents a builder for {@link OllamaPerameter}.
*/
public static class OllamaPerameterBuilder { public static class OllamaPerameterBuilder {
/**
* The properties of the parameters.
*/
Map<String, Property> propertyMap = new HashMap<>(); Map<String, Property> propertyMap = new HashMap<>();
/**
* The required parameters.
*/
ArrayList<String> required = new ArrayList<>(); ArrayList<String> required = new ArrayList<>();
/**
* Creates a new instance of {@link OllamaPerameterBuilder}.
* @param name The name of the parameter
* @param type The type of the parameter
* @param description The description of the parameter
* @return The {@link OllamaPerameterBuilder}
*/
public OllamaPerameterBuilder addProperty(String name, Type type, String description) { public OllamaPerameterBuilder addProperty(String name, Type type, String description) {
if(name == null || type == null || description == null) { if(name == null || type == null || description == null) {
return this; return this;
@@ -49,7 +93,15 @@ public class OllamaPerameter {
propertyMap.put(name, new Property(type.getType(), description)); propertyMap.put(name, new Property(type.getType(), description));
return this; return this;
} }
/**
* Creates a new instance of {@link OllamaPerameterBuilder}.
* @param name The name of the parameter
* @param type The type of the parameter
* @param description The description of the parameter
* @param required The required state of the parameter
* @return The {@link OllamaPerameterBuilder}
*/
public OllamaPerameterBuilder addProperty(String name, Type type, String description, boolean required) { public OllamaPerameterBuilder addProperty(String name, Type type, String description, boolean required) {
if(name == null || type == null || description == null) { if(name == null || type == null || description == null) {
return this; return this;
@@ -58,17 +110,31 @@ public class OllamaPerameter {
this.required.add(name); this.required.add(name);
return this; return this;
} }
/**
* Creates a new instance of {@link OllamaPerameterBuilder}.
* @param name The name of the parameter
* @return The {@link OllamaPerameterBuilder}
*/
public OllamaPerameterBuilder required(String name) { public OllamaPerameterBuilder required(String name) {
required.add(name); required.add(name);
return this; return this;
} }
/**
* Removes a property from the parameters.
* @param name The name of the property to remove
* @return The {@link OllamaPerameterBuilder}
*/
public OllamaPerameterBuilder removeProperty(String name) { public OllamaPerameterBuilder removeProperty(String name) {
propertyMap.remove(name); propertyMap.remove(name);
return this; return this;
} }
/**
* Builds the {@link OllamaPerameter}
* @return The {@link OllamaPerameter}
*/
public OllamaPerameter build() { public OllamaPerameter build() {
JSONObject properties = new JSONObject(); JSONObject properties = new JSONObject();
for(String name : propertyMap.keySet()) { for(String name : propertyMap.keySet()) {
@@ -76,11 +142,25 @@ public class OllamaPerameter {
} }
return new OllamaPerameter(properties, required.toArray(new String[0])); return new OllamaPerameter(properties, required.toArray(new String[0]));
} }
/**
* Represents a property of a parameter.
*/
private class Property { private class Property {
/**
* The type of the property.
*/
String type; String type;
/**
* The description of the property.
*/
String description; String description;
/**
* Creates a new instance of {@link Property}.
* @param type The type of the property
* @param description The description of the property
*/
public Property(String type, String description) { public Property(String type, String description) {
this.type = type; this.type = type;
this.description = description; this.description = description;
@@ -96,18 +176,41 @@ public class OllamaPerameter {
return json.toString(); return json.toString();
} }
} }
/**
* Represents the type of parameter.
*/
public enum Type { public enum Type {
/**
* Represents a string parameter.
*/
STRING("string"), STRING("string"),
/**
* Represents an integer parameter.
*/
INT("int"), INT("int"),
/**
* Represents a boolean parameter.
*/
BOOLEAN("boolean"); BOOLEAN("boolean");
/**
* The type of the parameter.
*/
private String type; private String type;
/**
* Gets the type of the parameter.
* @return The type of the parameter
*/
public String getType() { public String getType() {
return type; return type;
} }
/**
* Creates a new instance of {@link Type}.
* @param type The type of the parameter
*/
Type(String type) { Type(String type) {
this.type = type; this.type = type;
} }

View File

@@ -1,5 +1,7 @@
package me.zacharias.chat.ollama; package me.zacharias.chat.ollama;
/**
* Represents a tool.
*/
public interface OllamaTool { public interface OllamaTool {
} }

View File

@@ -2,13 +2,29 @@ package me.zacharias.chat.ollama;
import org.json.JSONObject; import org.json.JSONObject;
/**
* Represents an error from a tool.<br>
* This is used by a tool to indicate to Ollama that an error occurred.
*/
public class OllamaToolError extends OllamaMessage { public class OllamaToolError extends OllamaMessage {
/**
* The error from the tool.
*/
String error; String error;
/**
* Creates a new instance of OllamaToolError.
* @param error The error from the tool
*/
public OllamaToolError(String error) { public OllamaToolError(String error) {
super(OllamaMessageRole.TOOL, new JSONObject().put("error", error).toString()); super(OllamaMessageRole.TOOL, new JSONObject().put("error", error).toString());
this.error = error; this.error = error;
} }
/**
* Gets the error from the tool.
* @return The error from the tool
*/
public String getError() { public String getError() {
return error; return error;
} }

View File

@@ -2,19 +2,42 @@ package me.zacharias.chat.ollama;
import org.json.JSONObject; import org.json.JSONObject;
/**
* Represents a response from a tool.
*/
public class OllamaToolRespnce extends OllamaMessage { public class OllamaToolRespnce extends OllamaMessage {
/**
* The tool that responded.
*/
private final String tool; private final String tool;
/**
* The response from the tool.
*/
private final String response; private final String response;
/**
* Creates a new instance of {@link OllamaToolRespnce}.
* @param tool The tool that responded
* @param response The response from the tool
*/
public OllamaToolRespnce(String tool, String response) { public OllamaToolRespnce(String tool, String response) {
super(OllamaMessageRole.TOOL, new JSONObject().put("tool", tool).put("result", response).toString()); super(OllamaMessageRole.TOOL, new JSONObject().put("tool", tool).put("result", response).toString());
this.tool = tool; this.tool = tool;
this.response = response; this.response = response;
} }
/**
* Gets the tool that responded.
* @return The tool that responded
*/
public String getTool() { public String getTool() {
return tool; return tool;
} }
/**
* Gets the response from the tool.
* @return The response from the tool
*/
public String getResponse() { public String getResponse() {
return response; return response;
} }

View File

@@ -1,18 +1,45 @@
package me.zacharias.chat.ollama.exceptions; package me.zacharias.chat.ollama.exceptions;
import me.zacharias.chat.core.Core;
import org.json.JSONObject;
/**
* Represents an error from a tool.<br>
* This is used internally by tools instead of {@link Exception}, to then be handled gracefully by {@link Core#handleResponce(JSONObject)}
*/
public class OllamaToolErrorException extends RuntimeException { public class OllamaToolErrorException extends RuntimeException {
/**
* The tool that caused the error.
*/
private final String tool; private final String tool;
/**
* The error from the tool.
*/
private final String error; private final String error;
/**
* Creates a new instance of OllamaToolErrorException.
* @param tool The tool that caused the error
* @param error The error from the tool
*/
public OllamaToolErrorException(String tool, String error) { public OllamaToolErrorException(String tool, String error) {
super(tool + ": " + error); super(tool + ": " + error);
this.tool = tool; this.tool = tool;
this.error = error; this.error = error;
} }
/**
* Gets the tool that caused the error.
* @return The tool that caused the error
*/
public String getTool() { public String getTool() {
return tool; return tool;
} }
/**
* Gets the error from the tool.
* @return The error from the tool
*/
public String getError() { public String getError() {
return error; return error;
} }

View File

@@ -11,8 +11,16 @@ import java.util.*;
import static me.zacharias.chat.core.Core.writeLog; import static me.zacharias.chat.core.Core.writeLog;
/**
* The main class of the Display.<br>
* This is the main class for running as a Terminal application.<br>
* Somewhat meant to be used as a Debug tool for testing your API.
*/
public class Display { public class Display {
/**
* The Core instance.
*/
Core core = new Core(new PrintMessageHandler() { Core core = new Core(new PrintMessageHandler() {
@Override @Override
public void printMessage(String message) { public void printMessage(String message) {
@@ -24,25 +32,29 @@ public class Display {
return true; return true;
} }
}); });
/**
* Creates a new instance of Display.<br>
* This Creates the OllamaObject and adds the tools to it. as well as handles the display of the messages. and the input from the user.
*/
public Display() public Display()
{ {
core.setOllamaObject(OllamaObject.builder() core.setOllamaObject(OllamaObject.builder()
.setModel("llama3-AI") .setModel("llama3-AI")
.keep_alive(10) .keep_alive(10)
.stream(false) //.stream(false)
.build()); .build());
core.addTool(new TimeTool(), "Internal"); core.addTool(new TimeTool(), Core.Source.EXTERNAL);
core.addTool(new PythonRunner(core), "Internal"); core.addTool(new PythonRunner(core), Core.Source.INTERNAL);
writeLog("Creating base OllamaObject with model: "+core.getOllamaObject().getModel()); writeLog("Creating base OllamaObject with model: "+core.getOllamaObject().getModel());
System.out.println("Installed tools"); System.out.println("Installed tools");
writeLog("Tools installed in this instance"); writeLog("Tools installed in this instance");
for(Pair<OllamaFuntionTool, String> funtion : core.getFuntionTools()) for(Pair<OllamaFunctionTool, String> funtion : core.getFuntionTools())
{ {
StringBuilder args = new StringBuilder(); StringBuilder args = new StringBuilder();
OllamaPerameter perameter = funtion.getKey().parameters(); OllamaPerameter perameter = funtion.getKey().parameters();

View File

@@ -10,7 +10,6 @@ import me.zacharias.chat.core.Core;
import me.zacharias.chat.core.Pair; import me.zacharias.chat.core.Pair;
import me.zacharias.chat.ollama.*; import me.zacharias.chat.ollama.*;
import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException; import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
import org.apache.http.conn.HttpHostConnectException;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
@@ -26,11 +25,30 @@ import java.util.logging.Logger;
import static me.zacharias.chat.core.Core.writeLog; import static me.zacharias.chat.core.Core.writeLog;
public class PythonRunner extends OllamaFuntionTool { /**
DockerClient dockerClient; * A tool that runs python code.
Core core; * This is a wrapper around a docker container.
* This is partly meant as a proof of concept, but also as a way to run python code while keeping the executed code in a secure environment.
ServerSocket serverSocket; */
public class PythonRunner extends OllamaFunctionTool {
/**
* The DockerClient instance.
*/
private DockerClient dockerClient;
/**
* The Core instance.
*/
private Core core;
/**
* The ServerSocket instance.
*/
private ServerSocket serverSocket;
/**
* Creates a new instance of PythonRunner.
* @param core The Core instance
*/
public PythonRunner(Core core) { public PythonRunner(Core core) {
this.core = core; this.core = core;
@@ -49,7 +67,7 @@ public class PythonRunner extends OllamaFuntionTool {
try { try {
JSONObject data = new JSONObject(inputLine); JSONObject data = new JSONObject(inputLine);
List<Pair<OllamaFuntionTool, String>> list = core.getFuntionTools().stream().filter(funtionTool -> funtionTool.getKey().name().equalsIgnoreCase(data.optString("function", ""))).toList(); List<Pair<OllamaFunctionTool, String>> list = core.getFuntionTools().stream().filter(funtionTool -> funtionTool.getKey().name().equalsIgnoreCase(data.optString("function", ""))).toList();
if (list.isEmpty()) { if (list.isEmpty()) {
out.write(new JSONObject().put("error", "Function dose't exist").toString()); out.write(new JSONObject().put("error", "Function dose't exist").toString());
@@ -79,7 +97,7 @@ public class PythonRunner extends OllamaFuntionTool {
} catch (Exception e) { } catch (Exception e) {
} }
} catch (Exception e) { } catch (Exception e) {
} }
} }
}); });
@@ -128,15 +146,15 @@ public class PythonRunner extends OllamaFuntionTool {
for(OllamaFunctionArgument arg : args) for(OllamaFunctionArgument arg : args)
{ {
if(arg.getArgument().equals("name")) if(arg.argument().equals("name"))
{ {
name = (String) arg.getValue(); name = (String) arg.value();
if(!name.endsWith(".py")) if(!name.endsWith(".py"))
{ {
name += ".py"; name += ".py";
} }
} else if (arg.getArgument().equals("code")) { } else if (arg.argument().equals("code")) {
code = (String) arg.getValue(); code = (String) arg.value();
} }
} }
@@ -144,7 +162,7 @@ public class PythonRunner extends OllamaFuntionTool {
{ {
try { try {
MessageDigest digest = MessageDigest.getInstance("SHA-256"); MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] encodedhash = digest.digest(String.valueOf(args[0].getValue()).getBytes(StandardCharsets.UTF_8)); byte[] encodedhash = digest.digest(String.valueOf(args[0].value()).getBytes(StandardCharsets.UTF_8));
StringBuffer hexString = new StringBuffer(); StringBuffer hexString = new StringBuffer();
for(byte b : encodedhash) for(byte b : encodedhash)
{ {
@@ -221,7 +239,12 @@ public class PythonRunner extends OllamaFuntionTool {
throw new OllamaToolErrorException(name(), "Docker unavalible"); throw new OllamaToolErrorException(name(), "Docker unavalible");
} }
} }
/**
* Generates the external_tools.py file.<br>
* This is meant to provide the python code with all ExternalTools defined in the OllamaObject.
* @return The generated external_tools.py file
*/
private String generateExternalTools() { private String generateExternalTools() {
StringBuilder code = new StringBuilder(); StringBuilder code = new StringBuilder();
@@ -243,9 +266,9 @@ public class PythonRunner extends OllamaFuntionTool {
"""); """);
for(Pair<OllamaFuntionTool, String> funtionTool : core.getFuntionTools()) for(Pair<OllamaFunctionTool, String> funtionTool : core.getFuntionTools())
{ {
OllamaFuntionTool tool = funtionTool.getKey(); OllamaFunctionTool tool = funtionTool.getKey();
String name = tool.name(); String name = tool.name();
@@ -293,7 +316,10 @@ public class PythonRunner extends OllamaFuntionTool {
return code.toString(); return code.toString();
} }
/**
* A Helper class to get the logs from a docker container.
*/
public class GetContainerLog { public class GetContainerLog {
private DockerClient dockerClient; private DockerClient dockerClient;
private String containerId; private String containerId;
@@ -301,13 +327,22 @@ public class PythonRunner extends OllamaFuntionTool {
private static String nameOfLogger = "dockertest.PrintContainerLog"; private static String nameOfLogger = "dockertest.PrintContainerLog";
private static Logger myLogger = Logger.getLogger(nameOfLogger); private static Logger myLogger = Logger.getLogger(nameOfLogger);
/**
* Creates a new instance of {@link GetContainerLog}
* @param dockerClient The DockerClient instance
* @param containerId The container id
*/
public GetContainerLog(DockerClient dockerClient, String containerId) { public GetContainerLog(DockerClient dockerClient, String containerId) {
this.dockerClient = dockerClient; this.dockerClient = dockerClient;
this.containerId = containerId; this.containerId = containerId;
this.lastLogTime = (int) (System.currentTimeMillis() / 1000); this.lastLogTime = (int) (System.currentTimeMillis() / 1000);
} }
/**
* Gets the logs of the container.
* @return The logs of the container
*/
public List<String> getDockerLogs() { public List<String> getDockerLogs() {
final List<String> logs = new ArrayList<>(); final List<String> logs = new ArrayList<>();

View File

@@ -1,13 +1,17 @@
package me.zacharias.chat.display; package me.zacharias.chat.display;
import me.zacharias.chat.ollama.OllamaFunctionArgument; import me.zacharias.chat.ollama.OllamaFunctionArgument;
import me.zacharias.chat.ollama.OllamaFuntionTool; import me.zacharias.chat.ollama.OllamaFunctionTool;
import me.zacharias.chat.ollama.OllamaPerameter; import me.zacharias.chat.ollama.OllamaPerameter;
import me.zacharias.chat.ollama.OllamaToolRespnce; import me.zacharias.chat.ollama.OllamaToolRespnce;
import java.util.Date; import java.util.Date;
public class TimeTool extends OllamaFuntionTool { /**
* A tool that returns the current date.
* This gives Ollama the ability to get the current date.
*/
public class TimeTool extends OllamaFunctionTool {
@Override @Override
public OllamaToolRespnce function(OllamaFunctionArgument... arguments) { public OllamaToolRespnce function(OllamaFunctionArgument... arguments) {

View File

@@ -20,5 +20,21 @@ subprojects {
dependencies { dependencies {
implementation("org.json:json:20250107") implementation("org.json:json:20250107")
implementation("com.github.docker-java:docker-java:3.4.1") implementation("com.github.docker-java:docker-java:3.4.1")
implementation("org.jetbrains:annotations:23.1.0")
}
task sourcesJar(type: Jar, dependsOn: classes) {
archiveClassifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
archiveClassifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives sourcesJar
archives javadocJar
} }
} }

View File

@@ -4,7 +4,17 @@ import me.zacharias.chat.api.APIServer;
import me.zacharias.chat.core.LaunchOptions; import me.zacharias.chat.core.LaunchOptions;
import me.zacharias.chat.display.Display; import me.zacharias.chat.display.Display;
/**
* The launcher for AI_chat.<br>
* This is the main class of the application and is responsible for handling the command line arguments.
*/
public class Launcher { public class Launcher {
/**
* The Entry point of the application.<br>
* This is the main method of the application and is responsible for handling the command line arguments.
* and adding them to the LaunchOptions instance.
* @param args The command line arguments passed from JVM
*/
public static void main(String[] args) { public static void main(String[] args) {
LaunchOptions options = LaunchOptions.getInstance(); LaunchOptions options = LaunchOptions.getInstance();
@@ -42,10 +52,10 @@ public class Launcher {
Launch options for AI_chat Launch options for AI_chat
-h --help Provides this help message -h --help Provides this help message
-s --server Starts the application as API server -s --server Starts the application as API server
-p --port Provides the port number that the API server shuld use, defaults to 39075 -p --port Provides the port number that the API server should use, defaults to 39075
-o --output Redirects the API Server output to another file -o --output Redirects the API Server output to another file
-y Auto accepts to prompts, used for a seamless run. Not recomended when running as Display -y Auto accepts to prompts, used for a seamless run. Not recomended when running as Display
-d --dontloadOld Don't load old messages -d --dontLoadOld Don't load old messages
--api Provides API docs --api Provides API docs
"""); """);
return; return;