forked from Chat_things/NeuroDock
Well lot's in this
Some API modifications/additions Starting the implementation of a local file system for the AI to use Staring to try to migrate the ./cache, ./logs, ./messages, and ./pythonFiles to more appropiet locations depenidng on OS
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -44,4 +44,5 @@ bin/
|
|||||||
/pythonFiles/
|
/pythonFiles/
|
||||||
/messages/
|
/messages/
|
||||||
/logs/
|
/logs/
|
||||||
/cache/
|
/data/
|
||||||
|
/cache/
|
||||||
8
API/src/main/java/me/zacharias/chat/api/APICodes.java
Normal file
8
API/src/main/java/me/zacharias/chat/api/APICodes.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package me.zacharias.chat.api;
|
||||||
|
|
||||||
|
public enum APICodes {
|
||||||
|
CREDENTIALS,
|
||||||
|
ERROR,
|
||||||
|
API,
|
||||||
|
SUCCESS,
|
||||||
|
}
|
||||||
@@ -25,4 +25,9 @@ public enum APIEndpoints {
|
|||||||
*/
|
*/
|
||||||
USE_TOOL,
|
USE_TOOL,
|
||||||
|
|
||||||
|
// API endpoints that doesn't require credentials even if the server has them required
|
||||||
|
/**
|
||||||
|
* Returns info about the server
|
||||||
|
*/
|
||||||
|
INFO
|
||||||
}
|
}
|
||||||
|
|||||||
19
API/src/main/java/me/zacharias/chat/api/APIErrorCodes.java
Normal file
19
API/src/main/java/me/zacharias/chat/api/APIErrorCodes.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package me.zacharias.chat.api;
|
||||||
|
|
||||||
|
public enum APIErrorCodes {
|
||||||
|
/**
|
||||||
|
* If the format is not a JSON or not having the expected JSON keys present
|
||||||
|
*/
|
||||||
|
FORMAT_ERROR,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error with credentials<br>
|
||||||
|
* Can be that the credentials is not matching or other credentials related issue
|
||||||
|
*/
|
||||||
|
CREDENTIALS_ERROR,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An error describing that the APIEndpoint is unavailable, invalid, or related issue
|
||||||
|
*/
|
||||||
|
API_ERROR,
|
||||||
|
}
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
package me.zacharias.chat.api;
|
|
||||||
|
|
||||||
import me.zacharias.chat.core.Core;
|
|
||||||
import me.zacharias.chat.core.LaunchOptions;
|
|
||||||
import me.zacharias.chat.core.PrintMessageHandler;
|
|
||||||
import me.zacharias.chat.ollama.OllamaObject;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
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 {
|
|
||||||
/**
|
|
||||||
* The list of clients connected to the server.
|
|
||||||
*/
|
|
||||||
ArrayList<Client> clientsList = new ArrayList<>();
|
|
||||||
/**
|
|
||||||
* The server socket.
|
|
||||||
*/
|
|
||||||
ServerSocket serverSocket;
|
|
||||||
/**
|
|
||||||
* The output stream for the server.
|
|
||||||
*/
|
|
||||||
PrintStream dataOut;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The message handler for the server.
|
|
||||||
*/
|
|
||||||
PrintMessageHandler printMessageHandler = new PrintMessageHandler() {
|
|
||||||
@Override
|
|
||||||
public void printMessage(String message) {
|
|
||||||
|
|
||||||
synchronized (clientsList) {
|
|
||||||
for (Client client : clientsList) {
|
|
||||||
boolean success = client.sendMessage(message);
|
|
||||||
if (!success) {
|
|
||||||
clientsList.remove(client);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean color() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The core object for the server.
|
|
||||||
*/
|
|
||||||
Core core = new Core(printMessageHandler);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for this is expected to be passed through the {@link LaunchOptions#instance} object.<br>
|
|
||||||
* Used objects:<br>
|
|
||||||
* - {@link LaunchOptions#autoAccept}<br>
|
|
||||||
* - {@link LaunchOptions#redirectOutput}<br>
|
|
||||||
* - {@link LaunchOptions#port}<br>
|
|
||||||
*/
|
|
||||||
public APIServer() {
|
|
||||||
LaunchOptions options = LaunchOptions.getInstance();
|
|
||||||
String redirectedOutput = options.getRedirectOutput();
|
|
||||||
int port = options.getPort();
|
|
||||||
|
|
||||||
core.setOllamaObject(OllamaObject.builder()
|
|
||||||
.setModel("llama3-AI")
|
|
||||||
.keep_alive(10)
|
|
||||||
//.stream(false)
|
|
||||||
.build());
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
redirectedOutput = "./out.txt";
|
|
||||||
}
|
|
||||||
|
|
||||||
File f = new File(redirectedOutput);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (f.exists()) {
|
|
||||||
System.out.println("Output already exists");
|
|
||||||
System.out.print("Overwrite the existing output file? [y/N]: ");
|
|
||||||
Scanner sc = new Scanner(System.in);
|
|
||||||
char c;
|
|
||||||
|
|
||||||
if (options.isAutoAccept()) {
|
|
||||||
c = 'y';
|
|
||||||
} else {
|
|
||||||
String s = sc.nextLine();
|
|
||||||
c = s.isBlank() ? 'n' : s.charAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Character.toLowerCase(c) == 'y') {
|
|
||||||
f.delete();
|
|
||||||
f.createNewFile();
|
|
||||||
dataOut = new PrintStream(new FileOutputStream(f), true);
|
|
||||||
} else {
|
|
||||||
System.out.print("Rename existing output file? [y/N]: ");
|
|
||||||
String s = sc.nextLine();
|
|
||||||
c = s.isBlank() ? 'n' : s.charAt(0);
|
|
||||||
if (c == 'y') {
|
|
||||||
System.out.println("New file name for [" + f.getName() + "]: ");
|
|
||||||
File newFile = new File(f.getParentFile(), sc.nextLine().trim());
|
|
||||||
if (f.renameTo(newFile)) {
|
|
||||||
System.out.println("Old file placed in [" + newFile.getPath() + "]");
|
|
||||||
f = new File(redirectedOutput);
|
|
||||||
} else {
|
|
||||||
System.out.println("Failed to rename file. Proceeding with appending data.");
|
|
||||||
}
|
|
||||||
if (f.exists()) {
|
|
||||||
f.delete();
|
|
||||||
}
|
|
||||||
f.createNewFile();
|
|
||||||
dataOut = new PrintStream(new FileOutputStream(f), true);
|
|
||||||
} else {
|
|
||||||
System.out.print("Appending new data to [" + f.getPath() + "]");
|
|
||||||
dataOut = new PrintStream(new FileOutputStream(f, true), true);
|
|
||||||
Date date = new Date();
|
|
||||||
dataOut.println("\n\nNew instance started at: " + date.toString() + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sc.close();
|
|
||||||
} else {
|
|
||||||
f.createNewFile();
|
|
||||||
dataOut = new PrintStream(new FileOutputStream(f, true), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package me.zacharias.chat.api.client;
|
||||||
|
|
||||||
|
public class APIClient {
|
||||||
|
}
|
||||||
329
API/src/main/java/me/zacharias/chat/api/server/APIServer.java
Normal file
329
API/src/main/java/me/zacharias/chat/api/server/APIServer.java
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
package me.zacharias.chat.api.server;
|
||||||
|
|
||||||
|
import me.zacharias.chat.api.APICodes;
|
||||||
|
import me.zacharias.chat.api.APIEndpoints;
|
||||||
|
import me.zacharias.chat.api.APIErrorCodes;
|
||||||
|
import me.zacharias.chat.core.Core;
|
||||||
|
import me.zacharias.chat.core.LaunchOptions;
|
||||||
|
import me.zacharias.chat.core.PrintMessageHandler;
|
||||||
|
import me.zacharias.chat.ollama.OllamaObject;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
import static me.zacharias.chat.api.APIErrorCodes.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
/**
|
||||||
|
* The list of clients connected to the server.
|
||||||
|
*/
|
||||||
|
ArrayList<Client> clientsList = new ArrayList<>();
|
||||||
|
/**
|
||||||
|
* The server socket.
|
||||||
|
*/
|
||||||
|
ServerSocket serverSocket;
|
||||||
|
|
||||||
|
Thread clientAcceptThread = new Thread(() -> {
|
||||||
|
while (true) {
|
||||||
|
try{
|
||||||
|
Socket s = serverSocket.accept();
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
|
||||||
|
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
|
||||||
|
|
||||||
|
JSONObject outObj = new JSONObject();
|
||||||
|
|
||||||
|
if(in.ready()) {
|
||||||
|
String line = in.readLine();
|
||||||
|
JSONObject obj;
|
||||||
|
try{
|
||||||
|
obj = new JSONObject(line);
|
||||||
|
}catch(Exception e){
|
||||||
|
errorOutClient(out,"Invalid JSON object", FORMAT_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!obj.has("code"))
|
||||||
|
{
|
||||||
|
errorOutClient(out, "Missing APICode", FORMAT_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(obj.getEnum(APICodes.class, "code") != APICodes.API)
|
||||||
|
{
|
||||||
|
errorOutClient(out, "Invalid APICode", FORMAT_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!obj.has("api"))
|
||||||
|
{
|
||||||
|
errorOutClient(out, "Missing API", FORMAT_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject apiObj = obj.getJSONObject("api");
|
||||||
|
|
||||||
|
if(!apiObj.has("code"))
|
||||||
|
{
|
||||||
|
errorOutClient(out, "Missing APIEndpoint", FORMAT_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
APIEndpoints apiEndpoint;
|
||||||
|
|
||||||
|
if((apiEndpoint = apiObj.getEnum(APIEndpoints.class, "code")) != APIEndpoints.INFO)
|
||||||
|
{
|
||||||
|
errorOutClient(out, "APIEndpoint \""+apiEndpoint+"\" requires setup", API_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
outObj.put("code", APICodes.API);
|
||||||
|
JSONObject endpointObj = new JSONObject();
|
||||||
|
|
||||||
|
JSONObject infoObj = new JSONObject();
|
||||||
|
infoObj.put("requires_credentials", LaunchOptions.getInstance().isServerCredentialsEnabled());
|
||||||
|
|
||||||
|
endpointObj.put("message", infoObj);
|
||||||
|
|
||||||
|
outObj.put("api", endpointObj);
|
||||||
|
|
||||||
|
out.println(outObj);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LaunchOptions.getInstance().isServerCredentialsEnabled())
|
||||||
|
{
|
||||||
|
outObj.put("code", APICodes.CREDENTIALS);
|
||||||
|
out.println(outObj);
|
||||||
|
|
||||||
|
String line = in.readLine();
|
||||||
|
JSONObject lineObj;
|
||||||
|
try{
|
||||||
|
lineObj = new JSONObject(line);
|
||||||
|
}catch(Exception e)
|
||||||
|
{
|
||||||
|
errorOutClient(out, "Missing credentials or Incorrect format", FORMAT_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!lineObj.has("code"))
|
||||||
|
{
|
||||||
|
errorOutClient(out, "Missing APICode", FORMAT_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(lineObj.getEnum(APICodes.class, "code") == APICodes.CREDENTIALS))
|
||||||
|
{
|
||||||
|
errorOutClient(out, "Missing Credentials", CREDENTIALS_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!lineObj.has("credentials"))
|
||||||
|
{
|
||||||
|
errorOutClient(out, "Missing Credentials", FORMAT_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Objects.equals(lineObj.getString("credentials"), LaunchOptions.getInstance().getServerCredentials()))
|
||||||
|
{
|
||||||
|
errorOutClient(out, "Invalid Credentials", CREDENTIALS_ERROR);
|
||||||
|
s.shutdownOutput();
|
||||||
|
s.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
outObj = new JSONObject();
|
||||||
|
outObj.put("code", APICodes.SUCCESS);
|
||||||
|
out.println(outObj);
|
||||||
|
clientsList.add(new Client(s));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outObj.put("code", APICodes.SUCCESS);
|
||||||
|
out.println(outObj);
|
||||||
|
clientsList.add(new Client(s));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}catch(Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output stream for the server.
|
||||||
|
*/
|
||||||
|
PrintStream dataOut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message handler for the server.
|
||||||
|
*/
|
||||||
|
PrintMessageHandler printMessageHandler = new PrintMessageHandler() {
|
||||||
|
@Override
|
||||||
|
public void printMessage(String message) {
|
||||||
|
|
||||||
|
synchronized (clientsList) {
|
||||||
|
for (Client client : clientsList) {
|
||||||
|
boolean success = client.sendMessage(message);
|
||||||
|
if (!success) {
|
||||||
|
clientsList.remove(client);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean color() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The core object for the server.
|
||||||
|
*/
|
||||||
|
Core core = new Core(printMessageHandler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for this is expected to be passed through the {@link LaunchOptions#instance} object.<br>
|
||||||
|
* Used objects:<br>
|
||||||
|
* - {@link LaunchOptions#autoAccept}<br>
|
||||||
|
* - {@link LaunchOptions#redirectOutput}<br>
|
||||||
|
* - {@link LaunchOptions#port}<br>
|
||||||
|
*/
|
||||||
|
public APIServer() {
|
||||||
|
LaunchOptions options = LaunchOptions.getInstance();
|
||||||
|
String redirectedOutput = options.getRedirectOutput();
|
||||||
|
int port = options.getPort();
|
||||||
|
|
||||||
|
core.setOllamaObject(OllamaObject.builder()
|
||||||
|
.setModel("llama3-AI")
|
||||||
|
.keep_alive(10)
|
||||||
|
//.stream(false)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
redirectedOutput = "./out.txt";
|
||||||
|
}
|
||||||
|
|
||||||
|
File f = new File(redirectedOutput);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (f.exists()) {
|
||||||
|
System.out.println("Output already exists");
|
||||||
|
System.out.print("Overwrite the existing output file? [y/N]: ");
|
||||||
|
Scanner sc = new Scanner(System.in);
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (options.isAutoAccept()) {
|
||||||
|
c = 'y';
|
||||||
|
} else {
|
||||||
|
String s = sc.nextLine();
|
||||||
|
c = s.isBlank() ? 'n' : s.charAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Character.toLowerCase(c) == 'y') {
|
||||||
|
f.delete();
|
||||||
|
f.createNewFile();
|
||||||
|
dataOut = new PrintStream(new FileOutputStream(f), true);
|
||||||
|
} else {
|
||||||
|
System.out.print("Rename existing output file? [y/N]: ");
|
||||||
|
String s = sc.nextLine();
|
||||||
|
c = s.isBlank() ? 'n' : s.charAt(0);
|
||||||
|
if (c == 'y') {
|
||||||
|
System.out.println("New file name for [" + f.getName() + "]: ");
|
||||||
|
File newFile = new File(f.getParentFile(), sc.nextLine().trim());
|
||||||
|
if (f.renameTo(newFile)) {
|
||||||
|
System.out.println("Old file placed in [" + newFile.getPath() + "]");
|
||||||
|
f = new File(redirectedOutput);
|
||||||
|
} else {
|
||||||
|
System.out.println("Failed to rename file. Proceeding with appending data.");
|
||||||
|
}
|
||||||
|
if (f.exists()) {
|
||||||
|
f.delete();
|
||||||
|
}
|
||||||
|
f.createNewFile();
|
||||||
|
dataOut = new PrintStream(new FileOutputStream(f), true);
|
||||||
|
} else {
|
||||||
|
System.out.print("Appending new data to [" + f.getPath() + "]");
|
||||||
|
dataOut = new PrintStream(new FileOutputStream(f, true), true);
|
||||||
|
Date date = new Date();
|
||||||
|
dataOut.println("\n\nNew instance started at: " + date.toString() + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sc.close();
|
||||||
|
} else {
|
||||||
|
f.createNewFile();
|
||||||
|
dataOut = new PrintStream(new FileOutputStream(f, true), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void errorOutClient(PrintWriter writer, String errorMessage, APIErrorCodes apiErrorCodes) {
|
||||||
|
JSONObject outObj = new JSONObject();
|
||||||
|
outObj.put("code", APICodes.ERROR);
|
||||||
|
JSONObject errObj = new JSONObject();
|
||||||
|
errObj.put("code", apiErrorCodes);
|
||||||
|
errObj.put("message", errorMessage);
|
||||||
|
outObj.put("error", errObj);
|
||||||
|
writer.println(outObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.zacharias.chat.api;
|
package me.zacharias.chat.api.server;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
@@ -67,6 +67,39 @@ public class Core {
|
|||||||
*/
|
*/
|
||||||
private boolean supportColor;
|
private boolean supportColor;
|
||||||
|
|
||||||
|
public static final String DATA;
|
||||||
|
public static final File DATA_DIR;
|
||||||
|
|
||||||
|
static {
|
||||||
|
String data;
|
||||||
|
|
||||||
|
if(System.getenv("AI-CHAT-DEBUG") != null) {
|
||||||
|
data = "./data";
|
||||||
|
}
|
||||||
|
else if(System.getProperty("os.name").toLowerCase().contains("windows")) {
|
||||||
|
String localappdata = System.getenv("LOCALAPPDATA");
|
||||||
|
if(localappdata == null) {
|
||||||
|
localappdata = System.getenv("APPDATA");
|
||||||
|
}
|
||||||
|
data = localappdata + "/AI-CHAT";
|
||||||
|
}
|
||||||
|
else if (System.getProperty("os.name").toLowerCase().contains("linux")) {
|
||||||
|
data = System.getenv("HOME") + "/.local/share/AI-CHAT";
|
||||||
|
}
|
||||||
|
else if (System.getProperty("os.name").toLowerCase().contains("mac")) {
|
||||||
|
data = System.getProperty("user.home") + "/Library/Application Support/AI-CHAT";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data = "./data";
|
||||||
|
}
|
||||||
|
|
||||||
|
DATA = data;
|
||||||
|
DATA_DIR = new File(DATA);
|
||||||
|
if(!DATA_DIR.exists()) {
|
||||||
|
DATA_DIR.mkdirs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
File dir = new File("./logs/");
|
File dir = new File("./logs/");
|
||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ public class LaunchOptions {
|
|||||||
private boolean loadOld = true;
|
private boolean loadOld = true;
|
||||||
private boolean autoAccept;
|
private boolean autoAccept;
|
||||||
private boolean serverMode;
|
private boolean serverMode;
|
||||||
|
private boolean serverCredentialsEnabled;
|
||||||
private int port = 39075;
|
private int port = 39075;
|
||||||
private String redirectOutput;
|
private String redirectOutput;
|
||||||
|
private String serverCredentials;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the singleton instance of the LaunchOptions class.
|
* Sets the singleton instance of the LaunchOptions class.
|
||||||
@@ -109,4 +111,36 @@ public class LaunchOptions {
|
|||||||
public void setServerMode(boolean serverMode) {
|
public void setServerMode(boolean serverMode) {
|
||||||
this.serverMode = serverMode;
|
this.serverMode = serverMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets weather or not the API Server requires credentials
|
||||||
|
* @return if credentials is required
|
||||||
|
*/
|
||||||
|
public boolean isServerCredentialsEnabled() {
|
||||||
|
return serverCredentialsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets weather credentials are needed for the API Server
|
||||||
|
* @param serverCredentialsEnabled a boolean indicating if the APIServer needs credentials from clients
|
||||||
|
*/
|
||||||
|
public void setServerCredentialsEnabled(boolean serverCredentialsEnabled) {
|
||||||
|
this.serverCredentialsEnabled = serverCredentialsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the credentials for the API Server
|
||||||
|
* @return the credentials
|
||||||
|
*/
|
||||||
|
public String getServerCredentials() {
|
||||||
|
return serverCredentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the credentials used by the API Server
|
||||||
|
* @param serverCredentials a String of the API Server
|
||||||
|
*/
|
||||||
|
public void setServerCredentials(String serverCredentials) {
|
||||||
|
this.serverCredentials = serverCredentials;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package me.zacharias.chat.core.files;
|
||||||
|
|
||||||
|
import me.zacharias.chat.core.Core;
|
||||||
|
import org.intellij.lang.annotations.MagicConstant;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class responsible for the {@link me.zacharias.chat.core.files} related systems
|
||||||
|
*/
|
||||||
|
public class FileHandler {
|
||||||
|
/**
|
||||||
|
* The current instance of {@link FileHandler}
|
||||||
|
*/
|
||||||
|
private static FileHandler instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directory used as base for this instance of {@link FileHandler}. This is where all files that can be read or writen will be located
|
||||||
|
*/
|
||||||
|
private final File directory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance as well as setting the {@link #instance} to this new one
|
||||||
|
* @param baseDirectory the directory to be used as base directory
|
||||||
|
*/
|
||||||
|
public FileHandler(@MagicConstant(valuesFromClass = FileHandlerLocation.class) String baseDirectory) {
|
||||||
|
|
||||||
|
directory = new File(baseDirectory);
|
||||||
|
if(!directory.exists())
|
||||||
|
directory.mkdirs();
|
||||||
|
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param filename
|
||||||
|
* @return
|
||||||
|
* @throws FileHandlerException
|
||||||
|
*/
|
||||||
|
public String readFile(String filename) throws FileHandlerException {
|
||||||
|
if(filename.contains(".."))
|
||||||
|
{
|
||||||
|
throw new FileHandlerException("File \"" + filename + "\" tries to retrace path");
|
||||||
|
}
|
||||||
|
File file = new File(directory, filename);
|
||||||
|
if(file.exists())
|
||||||
|
{
|
||||||
|
try{
|
||||||
|
BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||||
|
StringBuilder data = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while((line = reader.readLine()) != null)
|
||||||
|
{
|
||||||
|
data.append(line);
|
||||||
|
}
|
||||||
|
return data.toString();
|
||||||
|
} catch(FileNotFoundException e){
|
||||||
|
Core.writeLog(e.getMessage());
|
||||||
|
for(StackTraceElement st : e.getStackTrace())
|
||||||
|
{
|
||||||
|
Core.writeLog(st.toString());
|
||||||
|
}
|
||||||
|
throw new FileHandlerException("Cant find file \""+filename+"\"");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Core.writeLog(e.getMessage());
|
||||||
|
for(StackTraceElement st : e.getStackTrace())
|
||||||
|
{
|
||||||
|
Core.writeLog(st.toString());
|
||||||
|
}
|
||||||
|
throw new FileHandlerException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new FileHandlerException("Cant find file \""+filename+"\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package me.zacharias.chat.core.files;
|
||||||
|
|
||||||
|
public class FileHandlerException extends RuntimeException {
|
||||||
|
public FileHandlerException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package me.zacharias.chat.core.files;
|
||||||
|
|
||||||
|
import me.zacharias.chat.core.Core;
|
||||||
|
|
||||||
|
public class FileHandlerLocation {
|
||||||
|
public static final String DATA_FILES = Core.DATA+"/files";
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package me.zacharias.chat.core.files;
|
||||||
|
|
||||||
|
public class ListFiles {
|
||||||
|
}
|
||||||
@@ -23,13 +23,13 @@ public class AddMemoryFunction extends OllamaFunctionTool {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String description() {
|
public String description() {
|
||||||
return "Add to the memory";
|
return "Remember somthing";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OllamaPerameter parameters() {
|
public OllamaPerameter parameters() {
|
||||||
return OllamaPerameter.builder()
|
return OllamaPerameter.builder()
|
||||||
.addProperty("memory", OllamaPerameter.OllamaPerameterBuilder.Type.STRING, "The memory to store", true)
|
.addProperty("memory", OllamaPerameter.OllamaPerameterBuilder.Type.STRING, "The memory to remember", true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class GetMemoryFunction extends OllamaFunctionTool {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String description() {
|
public String description() {
|
||||||
return "Retrives all the memory";
|
return "Retrieves all the memory's";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ public class RemoveMemoryFunction extends OllamaFunctionTool {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String description() {
|
public String description() {
|
||||||
return "Remove from the memory";
|
return "Forget a memory";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OllamaPerameter parameters() {
|
public OllamaPerameter parameters() {
|
||||||
return OllamaPerameter.builder()
|
return OllamaPerameter.builder()
|
||||||
.addProperty("memory", OllamaPerameter.OllamaPerameterBuilder.Type.STRING, "The memory to remove", true)
|
.addProperty("memory", OllamaPerameter.OllamaPerameterBuilder.Type.STRING, "The memory to forget", true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ package me.zacharias.chat.ollama;
|
|||||||
|
|
||||||
import me.zacharias.chat.core.Core;
|
import me.zacharias.chat.core.Core;
|
||||||
import me.zacharias.chat.core.LaunchOptions;
|
import me.zacharias.chat.core.LaunchOptions;
|
||||||
|
import me.zacharias.chat.core.files.FileHandlerLocation;
|
||||||
|
import me.zacharias.chat.core.files.FileHandler;
|
||||||
|
|
||||||
|
import org.intellij.lang.annotations.MagicConstant;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
@@ -365,6 +369,14 @@ public class OllamaObject {
|
|||||||
this.model = model;
|
this.model = model;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OllamaObjectBuilder addFileTools(@MagicConstant(valuesFromClass = FileHandlerLocation.class) String baseDirectory)
|
||||||
|
{
|
||||||
|
FileHandler fileHandler = new FileHandler(baseDirectory);
|
||||||
|
|
||||||
|
if(false);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the {@link OllamaObject}
|
* Builds the {@link OllamaObject}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package me.zacharias.chat.display;
|
|||||||
import me.zacharias.chat.core.Core;
|
import me.zacharias.chat.core.Core;
|
||||||
import me.zacharias.chat.core.Pair;
|
import me.zacharias.chat.core.Pair;
|
||||||
import me.zacharias.chat.core.PrintMessageHandler;
|
import me.zacharias.chat.core.PrintMessageHandler;
|
||||||
|
import me.zacharias.chat.core.files.FileHandlerLocation;
|
||||||
|
import me.zacharias.chat.core.memory.CoreMemory;
|
||||||
import me.zacharias.chat.ollama.*;
|
import me.zacharias.chat.ollama.*;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
@@ -45,10 +47,11 @@ public class Display {
|
|||||||
//.setModel("deepseek-r1")
|
//.setModel("deepseek-r1")
|
||||||
.keep_alive(10)
|
.keep_alive(10)
|
||||||
//.stream(false)
|
//.stream(false)
|
||||||
|
.addFileTools(FileHandlerLocation.DATA_FILES)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
core.addTool(new TimeTool(), Core.Source.INTERNAL);
|
//core.addTool(new TimeTool(), Core.Source.INTERNAL);
|
||||||
core.addTool(new PythonRunner(core), Core.Source.INTERNAL);
|
//core.addTool(new PythonRunner(core), Core.Source.INTERNAL);
|
||||||
|
|
||||||
//core.getOllamaObject().addMessage(new OllamaMessage(OllamaMessageRole.SYSTEM, "Have a nice tone and use formal wording"));
|
//core.getOllamaObject().addMessage(new OllamaMessage(OllamaMessageRole.SYSTEM, "Have a nice tone and use formal wording"));
|
||||||
|
|
||||||
@@ -100,6 +103,21 @@ public class Display {
|
|||||||
case "write":
|
case "write":
|
||||||
core.flushLog();
|
core.flushLog();
|
||||||
break;
|
break;
|
||||||
|
case "peek":
|
||||||
|
CoreMemory coreMemory = CoreMemory.getInstance();
|
||||||
|
StringBuilder buffer = new StringBuilder("[");
|
||||||
|
ArrayList<String> memory = new ArrayList<>(coreMemory.getMemory());
|
||||||
|
for(int i = 0; i < memory.size(); i++) {
|
||||||
|
String mem = memory.get(i);
|
||||||
|
buffer.append("\"").append(mem).append("\"");
|
||||||
|
if(i+1 < memory.size()) {
|
||||||
|
buffer.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.append("]");
|
||||||
|
writeLog("Memory peek: "+buffer.toString());
|
||||||
|
System.out.println(buffer.toString());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
System.out.println("Unknown command: " + message);
|
System.out.println("Unknown command: " + message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.zacharias.chat.launcher;
|
package me.zacharias.chat.launcher;
|
||||||
|
|
||||||
import me.zacharias.chat.api.APIServer;
|
import me.zacharias.chat.api.server.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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user