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:
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,
|
||||
|
||||
// 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.OutputStreamWriter;
|
||||
Reference in New Issue
Block a user