Compare commits

13 Commits

Author SHA1 Message Date
943c8470a5 Honestly speaking... No clue what the updates are :/ 2026-01-17 14:30:26 +01:00
4262dd68c6 Enhanced tool management in OllamaObject and added Maven publishing configuration.
- Updated `OllamaObject` to support tool registration with sources.
- Improved error handling and debug logging in multiple classes.
- Added Maven plugin and publication setup in `build.gradle`.
- Updated version to `1.3`.

Signed-off-by: Zacharias <zacharias@4zellen.se>
2025-08-18 20:01:42 +02:00
2cf0428d2a Added legal disclaimers about scraping.. mostly to make sure i dont get into too mutch trouble about things 2025-08-05 01:33:48 +02:00
bbf3c645b0 Added README.md to GeniusAPI 2025-08-05 00:51:35 +02:00
4015d37657 Merge remote-tracking branch 'origin/master' 2025-08-05 00:43:19 +02:00
5886d164b4 Core.java
- Added a safe handle for if Core#logWriter is not initialized to prevent craching

GetLyrics.java
- Slowly modifying the http headers to avoid package due to catching this as a Scrapper
- Added so we skip extra calls if the song is cached
2025-08-05 00:38:58 +02:00
ab72e1ff78 Update README.md 2025-07-28 22:15:37 +02:00
db53028d1e Fixed an issue in the config 2025-07-16 01:03:02 +02:00
bf5ae6dd3c And again.... 2025-07-16 00:31:04 +02:00
fbf7c504b1 Testing again... *sigh* 2025-07-16 00:29:46 +02:00
8426bcac37 CI is confusing 2025-07-16 00:28:37 +02:00
5724a2342d Merge remote-tracking branch 'origin/master' 2025-07-16 00:12:55 +02:00
95ac78b2d2 Testing gitea act_runner 2025-07-16 00:11:56 +02:00
24 changed files with 573 additions and 52 deletions

View File

@@ -0,0 +1,22 @@
name: build
on:
push:
branches:
- master
jobs:
build:
runs-on: arch
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
- name: Check out repository code
uses: actions/checkout@v4
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ gitea.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."

3
.idea/gradle.xml generated
View File

@@ -12,8 +12,9 @@
<option value="$PROJECT_DIR$/API" />
<option value="$PROJECT_DIR$/Core" />
<option value="$PROJECT_DIR$/Display" />
<option value="$PROJECT_DIR$/GeniusAPI" />
<option value="$PROJECT_DIR$/MALAPITool" />
<option value="$PROJECT_DIR$/Plugin" />
<option value="$PROJECT_DIR$/WikipediaTool" />
<option value="$PROJECT_DIR$/launcher" />
</set>
</option>

View File

@@ -14,7 +14,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.0-M1'
//implementation 'org.springframework.boot:spring-boot-starter-actuator'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

View File

@@ -3,7 +3,7 @@ plugins {
}
group = 'me.zacharias'
version = '1.0-SNAPSHOT'
version = '1.3'
dependencies {

View File

@@ -23,6 +23,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static me.zacharias.chat.ollama.OllamaFunctionArgument.deconstructOllamaFunctionArguments;
/**
* The Main class for the System, responsible for managing the OllamaObject, tools, and the Ollama API.
*/
@@ -52,7 +54,7 @@ public class Core {
/**
* The IP of the Ollama API.
*/
private String ollamaIP = "192.168.5.178";//"192.168.5.184";
private String ollamaIP = "10.0.1.101";//"192.168.5.184";
/**
* The port of the Ollama API.
*/
@@ -71,11 +73,15 @@ public class Core {
*/
private boolean supportColor;
public static final String DATA;
public static final File DATA_DIR;
public static final File PLUGIN_DIRECTORY;
public static String DATA;
public static File DATA_DIR;
public static File PLUGIN_DIRECTORY;
static {
setDataDirectory("AI-Chat");
}
public static void setDataDirectory(String dataDirectory) {
String data;
if(System.getenv("AI_CHAT_DEBUG") != null) {
@@ -86,13 +92,13 @@ public class Core {
if(localappdata == null) {
localappdata = System.getenv("APPDATA");
}
data = localappdata + "/AI-CHAT";
data = localappdata + "/"+ dataDirectory;
}
else if (System.getProperty("os.name").toLowerCase().contains("linux")) {
data = System.getenv("HOME") + "/.local/share/AI-CHAT";
data = System.getenv("HOME") + "/.local/share/" + dataDirectory;
}
else if (System.getProperty("os.name").toLowerCase().contains("mac")) {
data = System.getProperty("user.home") + "/Library/Application Support/AI-CHAT";
data = System.getProperty("user.home") + "/Library/Application Support/"+ dataDirectory;
}
else {
data = "./data";
@@ -193,7 +199,7 @@ public class Core {
messagesWriter.write(messages.toString());
messagesWriter.close();
File f = new File("./data/messages.json");
File f = new File(DATA_DIR,"messages.json");
if(f.exists())
{
f.delete();
@@ -261,7 +267,7 @@ public class Core {
*/
public void addTool(OllamaFunctionTool functionTool, @MagicConstant(valuesFromClass = Source.class) String source) {
funtionTools.add(new Pair<>(functionTool, source));
ollamaObject.addTool(functionTool);
ollamaObject.addTool(functionTool, source);
}
/**
@@ -404,32 +410,34 @@ public class Core {
JSONObject function = jsonObject.getJSONObject("function");
List<Pair<OllamaFunctionTool, String>> functions = funtionTools.stream().filter(func -> (func.getKey().name()+func.getValue()).equalsIgnoreCase(function.getString("name"))).toList();
ArrayList<OllamaFunctionArgument> argumentArrayList = new ArrayList<>();
JSONObject arguments = function.getJSONObject("arguments");
for (String key : arguments.keySet()) {
argumentArrayList.add(new OllamaFunctionArgument(key, arguments.get(key)));
}
if(functions.isEmpty()) {
ollamaObject.addMessage(new OllamaToolError("Function '"+function.getString("name")+"' does not exist"));
printMessageHandler.printMessage((supportColor ?"\u001b[31m":"")+"Tried funtion call "+function.getString("name")+" but failed to find it."+(printMessageHandler.color()?"\u001b[0m":""));
printMessageHandler.printMessage((supportColor ?"\u001b[31m":"")+"Tried funtion call "+function.getString("name")+"("+deconstructOllamaFunctionArguments(argumentArrayList)+") but failed to find it."+(printMessageHandler.color()?"\u001b[0m":""));
writeLog("Failed function call to "+function.getString("name"));
}
else {
OllamaFunctionTool func = functions.getFirst().getKey();
ArrayList<OllamaFunctionArgument> argumentArrayList = new ArrayList<>();
JSONObject arguments = function.getJSONObject("arguments");
for (String key : arguments.keySet()) {
argumentArrayList.add(new OllamaFunctionArgument(key, arguments.get(key)));
}
// TODO: Check so all arguments is the correct type, else error out in a safe mannet.
try {
OllamaToolRespnce function1 = func.function(argumentArrayList.toArray(new OllamaFunctionArgument[0]));
ollamaObject.addMessage(function1);
printMessageHandler.printMessage((supportColor?"\u001b[34m":"")+"Call "+func.name() + (supportColor?"\u001b[0m":""));
printMessageHandler.printMessage((supportColor?"\u001b[34m":"")+"Call "+func.name() + "(" + deconstructOllamaFunctionArguments(argumentArrayList) + ")" + (supportColor?"\u001b[0m":""));
writeLog("Successfully function call " + func.name() + " output: " + function1.getResponse());
} catch (OllamaToolErrorException e) {
ollamaObject.addMessage(new OllamaToolError(e.getMessage()));
printMessageHandler.printMessage((supportColor?"\u001b[31m":"")+"Tried funtion call " + func.name() + " but failed due to " + e.getError() + (supportColor?"\u001b[0m":""));
writeLog(e.getMessage());
printMessageHandler.printMessage((supportColor?"\u001b[31m":"")+"Tried funtion call " + func.name() + "("+deconstructOllamaFunctionArguments(argumentArrayList)+") but failed due to " + e.getError() + (supportColor?"\u001b[0m":""));
writeLog("ERROR: "+e.getMessage());
}
}
}
@@ -462,6 +470,10 @@ public class Core {
*/
public static void writeLog(String message)
{
if(logWriter == null) {
System.err.println("!! Log writer is not initialized !!");
return;
}
try {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd%EEEE HH:mm:ss'#'SSS");

View File

@@ -15,6 +15,8 @@ public class LaunchOptions {
return instance;
}
private LaunchOptions() {}
private boolean loadOld = true;
private boolean autoAccept;
private boolean serverMode;

View File

@@ -18,4 +18,18 @@ public interface PrintMessageHandler {
* @return a boolean indicating if color is supported by the PrintMessageHandler.
*/
boolean color();
/**
* Default method to print error messages to the user or API Client.
* This uses ANSI escape codes to color the output red if color is supported.
* @param message The error message to be printed.
* If color is not supported, it will print the message without color.
*/
default void printError(String message) {
if (color()) {
printMessage("\u001B[31m" + message + "\u001B[0m"); // Red color for errors
} else {
printMessage(message);
}
}
}

View File

@@ -1,5 +1,7 @@
package me.zacharias.chat.ollama;
import java.util.ArrayList;
/**
* Represents an argument passed to a tool.
*
@@ -37,4 +39,24 @@ public record OllamaFunctionArgument(String argument, Object value) {
public Object value() {
return value;
}
public static String deconstructOllamaFunctionArgument(OllamaFunctionArgument argument) {
return argument.argument() + ": " + argument.value();
}
public static String deconstructOllamaFunctionArguments(OllamaFunctionArgument... arguments) {
StringBuilder sb = new StringBuilder();
for (OllamaFunctionArgument argument : arguments) {
sb.append(deconstructOllamaFunctionArgument(argument)).append(", ");
}
return sb.toString().replaceAll(", $", "");
}
public static String deconstructOllamaFunctionArguments(ArrayList<OllamaFunctionArgument> arguments) {
StringBuilder sb = new StringBuilder();
for (OllamaFunctionArgument argument : arguments) {
sb.append(deconstructOllamaFunctionArgument(argument)).append(", ");
}
return sb.toString().replaceAll(", $", "");
}
}

View File

@@ -9,13 +9,15 @@ import org.json.JSONObject;
*/
public abstract class OllamaFunctionTool implements OllamaTool {
protected String source = "";
@Override
public String toString() {
JSONObject ret = new JSONObject();
ret.put("tool", "function");
JSONObject function = new JSONObject();
function.put("name", name());
function.put("name", name()+(source != null ? source : ""));
function.put("description", description());
function.put("parameters", (parameters() == null?
new JSONObject() : new JSONObject(parameters().toString())));

View File

@@ -3,6 +3,7 @@ package me.zacharias.chat.ollama;
import com.sun.source.util.Plugin;
import me.zacharias.chat.core.Core;
import me.zacharias.chat.core.LaunchOptions;
import me.zacharias.chat.core.Pair;
import me.zacharias.chat.core.files.FileHandlerLocation;
import me.zacharias.chat.core.files.FileHandler;
@@ -13,6 +14,7 @@ import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
@@ -41,7 +43,7 @@ public class OllamaObject {
/**
* The tools of the Ollama Object.
*/
ArrayList<OllamaTool> tools;
ArrayList<Pair<OllamaTool, String>> tools;
/**
* The format of the Ollama Object.
*/
@@ -69,7 +71,7 @@ public class OllamaObject {
* @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<Pair<OllamaTool, String>> tools, JSONObject format, Map<String, Object> options, boolean stream, String keep_alive) {
this.model = model;
this.messages = messages;
this.tools = tools;
@@ -77,7 +79,7 @@ public class OllamaObject {
this.options = options;
this.stream = stream;
this.keep_alive = keep_alive;
LaunchOptions launchOptions = new LaunchOptions();
LaunchOptions launchOptions = LaunchOptions.getInstance();
if(launchOptions.isLoadOld()) {
System.out.println("Loading old data...");
File f = new File(Core.DATA_DIR+"/messages.json");
@@ -105,6 +107,10 @@ public class OllamaObject {
e.printStackTrace();
}
}
else
{
System.out.println("No old data found, skipping loading old data.");
}
}
}
@@ -128,7 +134,7 @@ public class OllamaObject {
* Gets the tools
* @return The tools
*/
public ArrayList<OllamaTool> getTools() {
public ArrayList<Pair<OllamaTool, String>> getTools() {
return tools;
}
@@ -136,8 +142,29 @@ public class OllamaObject {
* Adds a tool to the Ollama Object
* @param tool The tool to add
*/
public void addTool(OllamaTool tool) {
tools.add(tool);
public void addTool(OllamaTool tool, @MagicConstant(valuesFromClass = Core.Source.class) String source) {
// We inject the source into the tool's source field if it exists, This is to not cause issues with duplicate tools
Class<? extends Object> clazz = tool.getClass();
Field field = null;
while(!clazz.equals(Object.class)) {
try {
field = clazz.getDeclaredField("source");
if (field != null) {
break;
}
}
catch (NoSuchFieldException ignore){}
clazz = clazz.getSuperclass();
}
if (field != null) {
field.setAccessible(true);
try {
field.set(tool, source);
} catch (IllegalAccessException e) {
Core.writeLog("ERROR: "+e.getMessage());
}
}
tools.add(new Pair<>(tool, source));
}
public void removeTool(OllamaTool tool) {
@@ -189,8 +216,11 @@ public class OllamaObject {
JSONObject json = new JSONObject();
JSONArray tools = new JSONArray();
for (OllamaTool tool : this.tools) {
tools.put(new JSONObject(tool.toString()));
for (Pair<OllamaTool, String> tool : this.tools) {
if(tool.getKey().getClass().isInterface()) continue;
JSONObject obj = new JSONObject(tool.getKey().toString());
//obj.put("name", obj.getString("name") + tool.getValue()); // Injects the source of the tool into the name
tools.put(obj);
}
JSONArray messages = new JSONArray();
@@ -232,7 +262,7 @@ public class OllamaObject {
/**
* The tools of the Ollama Object.
*/
ArrayList<OllamaTool> tools = new ArrayList<>();
ArrayList<Pair<OllamaTool, String>> tools = new ArrayList<>();
/**
* The format of the Ollama Object.
*/
@@ -321,30 +351,72 @@ public class OllamaObject {
/**
* Adds a tool to the Ollama Object
* Assumes the tool is from an external source, see {@link OllamaObject.OllamaObjectBuilder#addTool(OllamaTool, String)} to specify the source
* @param tool The tool to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addTool(OllamaTool tool) {
this.tools.add(tool);
this.tools.add(new Pair<>(tool, Core.Source.EXTERNAL));
return this;
}
/**
* Adds a tool to the Ollama Object
* This allows you to specify the source of the tool, see {@link OllamaObject.OllamaObjectBuilder#addTool(OllamaTool)} to add a tool from an external source
* @param tool The tool to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addTool(OllamaTool tool, @MagicConstant(valuesFromClass = Core.Source.class) String source) {
this.tools.add(new Pair<>(tool, source));
return this;
}
/**
* Adds tools to the Ollama Object
* Assumes the tools are from an external source, see {@link OllamaObject.OllamaObjectBuilder#addTools(ArrayList)}} to specify the source
* @param tools The tools to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addTools(ArrayList<? extends OllamaTool> tools) {
this.tools.addAll(tools);
public OllamaObjectBuilder addToolsExternal(ArrayList<? extends OllamaTool> tools) {
for (OllamaTool tool : tools) {
this.tools.add(new Pair<>(tool, Core.Source.EXTERNAL));
}
return this;
}
/**
* Adds tools to the Ollama Object
* This allows you to specify the source of the tools, see {@link OllamaObject.OllamaObjectBuilder#addToolsExternal(ArrayList)}} to add tools from an external source
* @param tools The tools to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addTools(ArrayList<Pair<? extends OllamaTool, String>> tools) {
for(Pair<? extends OllamaTool, String> tool : tools) {
this.tools.add(new Pair<>(tool.getKey(), tool.getValue()));
}
return this;
}
/**
* Adds tools to the Ollama Object
* Assumes the tools are from an external source, see {@link OllamaObject.OllamaObjectBuilder#addTools(Pair[])}} to specify the source
* @param tools The tools to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addTools(OllamaTool... tools) {
for(OllamaTool tool : tools) {
this.tools.add(new Pair<>(tool, Core.Source.EXTERNAL));
}
return this;
}
/**
* Adds tools to the Ollama Object
* This allows you to specify the source of the tools, see {@link OllamaObject.OllamaObjectBuilder#addTools(OllamaTool[])} to add tools from an external source
* @param tools The tools to add
* @return The {@link OllamaObjectBuilder}
*/
public OllamaObjectBuilder addTools(Pair<OllamaTool, String>... tools) {
this.tools.addAll(List.of(tools));
return this;
}

View File

@@ -200,7 +200,11 @@ public class OllamaPerameter {
/**
* Represents a array parameter.
*/
ARRAY("array");
ARRAY("array"),
/**
* Represents a object parameter.
*/
OBJECT("object");
/**
* The type of the parameter.

View File

@@ -11,6 +11,9 @@ dependencies {
implementation project(":GeniusAPI")
implementation project(":API")
implementation project(":WikipediaTool")
implementation("com.github.docker-java:docker-java-core:3.6.0")
implementation("com.github.docker-java:docker-java-transport-httpclient5:3.6.0")
}
test {

View File

@@ -61,7 +61,7 @@ public class Display {
core.addTool(new TimeTool(), Core.Source.INTERNAL);
// TODO: Well Docker failes when luanched.... Fuck
// core.addTool(new PythonRunner(core), Core.Source.INTERNAL);
//core.addTool(new PythonRunner(core), Core.Source.INTERNAL);
core.addTools(new MALAPITool().getOllamaTools());
core.addTools(new GeniusTools().getGeniusTools());
core.addTools(new WikipediaTool().getWikipediaToolsInstance());
@@ -109,6 +109,7 @@ public class Display {
/bye Exits the program.
/write Flushes the current log stream to file.
/list Lists all available tools.
/corelist Lists all tools according to the OllamaObject.
/working Prints the current working directories.
/peek Peeks the current memory.
""");
@@ -153,6 +154,14 @@ public class Display {
writeLog("Function: " + funtion.getKey().name() + "(" + args + ") [" + funtion.getValue() + "]");
}
break;
case "corelist":
writeLog("Tools installed in this instance acording to the coire OllamaObject");
for(Pair<OllamaTool, String> funtion : core.getOllamaObject().getTools()) {
System.out.println("> Function: " + funtion.getKey().toString());
writeLog("Function: " + funtion.getKey().toString());
}
break;
case "working":
System.out.println("Working directories:\n" +
" Data: " + Core.DATA_DIR.getAbsolutePath() + "\n" +

View File

@@ -8,19 +8,23 @@ import com.github.dockerjava.api.model.BuildResponseItem;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.api.model.Statistics;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
import com.github.dockerjava.transport.DockerHttpClient;
import me.zacharias.chat.core.Core;
import me.zacharias.chat.core.Pair;
import me.zacharias.chat.ollama.*;
import me.zacharias.chat.ollama.exceptions.OllamaToolErrorException;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -112,13 +116,48 @@ public class PythonRunner extends OllamaFunctionTool {
e.printStackTrace();
}
DefaultDockerClientConfig.Builder config
DefaultDockerClientConfig config
= DefaultDockerClientConfig.createDefaultConfigBuilder()
.withDockerHost("tcp://localhost:2375")
.withDockerTlsVerify(false);
dockerClient = DockerClientBuilder
.getInstance(config)
.withDockerTlsVerify(false)
.withDockerCertPath("~/.docker")
.build();
DockerHttpClient dockerHttpClient = new ApacheDockerHttpClient.Builder()
.dockerHost(config.getDockerHost())
.maxConnections(10)
.connectionTimeout(Duration.ofSeconds(100))
.responseTimeout(Duration.ofSeconds(100))
.sslConfig(config.getSSLConfig())
.build();
DockerHttpClient.Request ping = DockerHttpClient.Request.builder()
.method(DockerHttpClient.Request.Method.GET)
.path("/_ping")
.build();
try(DockerHttpClient.Response response = dockerHttpClient.execute(ping))
{
if(!(response.getStatusCode() == 200))
{
writeLog("Failed to ping docker");
System.out.println("Failed to ping docker. Docker components is disabled.");
dockerClient = null;
return;
}
if(!(IOUtils.toString(response.getBody(), Charset.defaultCharset()).equals("OK")))
{
writeLog("Failed to ping docker");
System.out.println("Failed to ping docker. Docker components is disabled.");
dockerClient = null;
return;
}
}
catch (Exception e)
{
writeLog("Failed to ping docker");
System.out.println("Failed to ping docker. Docker components is disabled.");
dockerClient = null;
}
}
@Override
@@ -142,6 +181,10 @@ public class PythonRunner extends OllamaFunctionTool {
@Override
public OllamaToolRespnce function(OllamaFunctionArgument... args) {
if(dockerClient == null)
{
return new OllamaToolRespnce(name(), "Docker is disabled");
}
if(args.length == 0)
{
throw new OllamaToolErrorException(name(), "Missing code argument");

View File

@@ -0,0 +1,165 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.hc.client5.http.ssl;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.function.Factory;
import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
import org.apache.hc.core5.reactor.ssl.SSLBufferMode;
import org.apache.hc.core5.reactor.ssl.TlsDetails;
import org.apache.hc.core5.ssl.SSLContexts;
/**
* TLS upgrade strategy for non-blocking client connections.
*
* @since 5.0
*/
@Contract(threading = ThreadingBehavior.STATELESS)
public class DefaultClientTlsStrategy extends AbstractClientTlsStrategy {
/**
* @since 5.4
*/
public static DefaultClientTlsStrategy createDefault() {
return new DefaultClientTlsStrategy(
SSLContexts.createDefault(),
HostnameVerificationPolicy.BOTH,
HttpsSupport.getDefaultHostnameVerifier());
}
/**
* @since 5.4
*/
public static DefaultClientTlsStrategy createSystemDefault() {
return new DefaultClientTlsStrategy(
SSLContexts.createSystemDefault(),
HttpsSupport.getSystemProtocols(),
HttpsSupport.getSystemCipherSuits(),
SSLBufferMode.STATIC,
HostnameVerificationPolicy.BOTH,
HttpsSupport.getDefaultHostnameVerifier());
}
/**
* @deprecated Use {@link #createDefault()}.
*/
@Deprecated
public static TlsStrategy getDefault() {
return createDefault();
}
/**
* @deprecated Use {@link #createSystemDefault()}.
*/
@Deprecated
public static TlsStrategy getSystemDefault() {
return createSystemDefault();
}
/**
* @deprecated To be removed.
*/
@Deprecated
private Factory<SSLEngine, TlsDetails> tlsDetailsFactory;
/**
* @deprecated Use {@link DefaultClientTlsStrategy#DefaultClientTlsStrategy(SSLContext, String[], String[], SSLBufferMode, HostnameVerifier)}
*/
@Deprecated
public DefaultClientTlsStrategy(
final SSLContext sslContext,
final String[] supportedProtocols,
final String[] supportedCipherSuites,
final SSLBufferMode sslBufferManagement,
final HostnameVerifier hostnameVerifier,
final Factory<SSLEngine, TlsDetails> tlsDetailsFactory) {
super(sslContext, supportedProtocols, supportedCipherSuites, sslBufferManagement, HostnameVerificationPolicy.CLIENT, hostnameVerifier);
this.tlsDetailsFactory = tlsDetailsFactory;
}
/**
* @since 5.4
*/
public DefaultClientTlsStrategy(
final SSLContext sslContext,
final String[] supportedProtocols,
final String[] supportedCipherSuites,
final SSLBufferMode sslBufferManagement,
final HostnameVerificationPolicy hostnameVerificationPolicy,
final HostnameVerifier hostnameVerifier) {
super(sslContext, supportedProtocols, supportedCipherSuites, sslBufferManagement, hostnameVerificationPolicy, hostnameVerifier);
}
public DefaultClientTlsStrategy(
final SSLContext sslContext,
final String[] supportedProtocols,
final String[] supportedCipherSuites,
final SSLBufferMode sslBufferManagement,
final HostnameVerifier hostnameVerifier) {
this(sslContext, supportedProtocols, supportedCipherSuites, sslBufferManagement, HostnameVerificationPolicy.CLIENT, hostnameVerifier);
}
public DefaultClientTlsStrategy(
final SSLContext sslContext,
final HostnameVerifier hostnameVerifier) {
this(sslContext, null, null, SSLBufferMode.STATIC, hostnameVerifier);
}
/**
* @since 5.4
*/
public DefaultClientTlsStrategy(
final SSLContext sslContext,
final HostnameVerificationPolicy hostnameVerificationPolicy,
final HostnameVerifier hostnameVerifier) {
this(sslContext, null, null, SSLBufferMode.STATIC, hostnameVerificationPolicy, hostnameVerifier);
}
public DefaultClientTlsStrategy(final SSLContext sslContext) {
this(sslContext, HttpsSupport.getDefaultHostnameVerifier());
}
@Override
void applyParameters(final SSLEngine sslEngine, final SSLParameters sslParameters, final String[] appProtocols) {
sslParameters.setApplicationProtocols(appProtocols);
sslEngine.setSSLParameters(sslParameters);
}
@Override
@SuppressWarnings("deprecated")
TlsDetails createTlsDetails(final SSLEngine sslEngine) {
return tlsDetailsFactory != null ? tlsDetailsFactory.create(sslEngine) : null;
}
}

View File

@@ -0,0 +1,26 @@
package org.apache.hc.client5.http.ssl;
/**
* Hostname verification policy.
*
* @see javax.net.ssl.HostnameVerifier
* @see DefaultHostnameVerifier
*
* @since 5.4
*/
public enum HostnameVerificationPolicy {
/**
* Hostname verification is delegated to the JSSE provider, usually executed during the TLS handshake.
*/
BUILTIN,
/**
* Hostname verification is executed by HttpClient post TLS handshake.
*/
CLIENT,
/**
* Hostname verification is executed by the JSSE provider and by HttpClient post TLS handshake.
*/
BOTH
}

View File

@@ -0,0 +1,31 @@
package org.apache.hc.client5.http.ssl;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.http.protocol.HttpContext;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.net.Socket;
@Contract(threading = ThreadingBehavior.STATELESS)
public interface TlsSocketStrategy {
/**
* Upgrades the given plain socket and executes the TLS handshake over it.
*
* @param socket the existing plain socket
* @param target the name of the target host.
* @param port the port to connect to on the target host.
* @param context the actual HTTP context.
* @param attachment connect request attachment.
* @return socket upgraded to TLS.
*/
SSLSocket upgrade(
Socket socket,
String target,
int port,
Object attachment,
HttpContext context) throws IOException;
}

25
GeniusAPI/README.md Normal file
View File

@@ -0,0 +1,25 @@
# Genius API
## Important notes
### Legal Notice
This tool is provided for educational and experimental purposes only.
Please be aware that the Genius API Terms of Service **prohibit** web scraping of their website. This project contains code that performs scraping to retrieve song lyrics directly from Genius.com, which may violate those terms.
Since Genius does not provide official API endpoints for lyrics due to copyright restrictions, this tool includes scraping functionality as a workaround. However, scraping may result in legal or technical consequences such as IP bans, rate limiting, or other restrictions imposed by Genius.
**Use this tool responsibly and at your own risk.** The author does not encourage or endorse violating any third-party terms of service or applicable laws and disclaims any liability arising from misuse.
Whenever possible, prefer using official API endpoints and respect copyright laws.
## API key required
This tool requires a Genius API key to work since it fetches song metadata from the Genius API.
The API key shuld be stored in `${DATA_DIR}/geniusapi.json` using the following format:
```json
{
"client_id": "<your_client_id>",
"client_secret": "<your_client_secret>"
}
```

View File

@@ -1,6 +1,5 @@
package me.zacharias.neuro.dock.genius;
import com.google.common.reflect.ClassPath;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import io.github.classgraph.ClassInfoList;

View File

@@ -19,6 +19,20 @@ import java.util.stream.Collectors;
import static me.zacharias.chat.core.Core.writeLog;
/**
* This class is an Ollama tool that fetches the lyrics of a song by its ID from the Genius API.
* It extends the GeniusEndpointTool to utilize the GeniusTools instance for API calls and caching.
* <p>
* <h1>Legal Notice</h1>
* <p>
* I (the developer) do NOT own the rights to the lyrics fetched by this tool, nor do I endorse scraping lyrics from Genius.com,
* which may violate their Terms of Service.
* </p>
* <p>
* I disclaim any responsibility or liability for how this tool is used.
* Use this tool at your own risk, and please respect all applicable copyright laws and third-party terms.
* </p>
*/
@GeniusEndpoint
public class GetLyrics extends GeniusEndpointTool {
public GetLyrics(GeniusTools geniusTools) {
@@ -45,19 +59,27 @@ public class GetLyrics extends GeniusEndpointTool {
@Override
public OllamaToolRespnce function(OllamaFunctionArgument... args) {
if(!( args[0].value() instanceof Integer)) {
throw new OllamaToolErrorException(this.name(), "The song_id must be an integer.");
}
String lyricsStr = geniusToolsInstance.hasCache((int) args[0].value());
if(lyricsStr != null)
{
// If we have a cached response, return it
return new OllamaToolRespnce(this.name(), lyricsStr.trim());
}
JSONObject obj = geniusToolsInstance.getGeniusEndpoint("/songs/" + args[0].value(), null);
String lyrics_path = obj.getJSONObject("response").getJSONObject("song").getString("url");
try {
// WARNING: This request scrapes the lyrics from the Genius website.
// Which is against their Terms of Service. Use responsibly
Document doc = Jsoup.connect(lyrics_path)
.userAgent("Mozilla/5.0")
.userAgent("insomnia/11.1.0") // TODO: replace with somthing else then insomnia! since we in no way support what ever Insomnia's User-Agent says we do
.header("host", "genius.com")
.header("accept", "*/*")
.get();
writeLog("Fetching lyrics from: " + lyrics_path);

View File

@@ -1,5 +1,6 @@
# Chat thing
(better name pending probably)
# NeuroDock
Note:
This project is not in colabiration with Neuro-Sama, Vedal987, Alexcra. This is an independent project and name, aswell as use case similarities are cucidental.
## What is it?
Well it's basically a font end for Ollama like [Open-WebUI](https://openwebui.com/), but meant to run a local model and open up a somewhat easy to use API system for tools.
@@ -9,6 +10,14 @@ While the primary goal is providing a somewhat more modular frontend for Ollama,
simple examples are in the Display module where i gave it the ability to access python through docker and get the current date and time both with the [OllamaFunctionTool](https://server.4zellen.se:3000/Zacharias/chat_thing/src/branch/master/Core/src/main/java/me/zacharias/chat/ollama/OllamaFunctionTool.java) thru my Ollama framework
## Legal Notice Regarding Scraping
A submodule of this project includes functionality that scrapes song lyrics directly from Genius.com, which violates Genius API's Terms of Service.
The author **does not endorse or encourage** scraping or any other use that violates third-party terms or copyright laws.
Use this software **at your own risk**. The author disclaims any liability for legal or technical consequences arising from its use.
## API
The documentation for the API is available at the gitea wiki under [API docs](https://server.4zellen.se:3000/Chat_things/NeuroDock/wiki/API-Docs)

View File

@@ -7,6 +7,9 @@ group = 'me.zacharias'
version = '1.0-SNAPSHOT'
allprojects {
apply plugin: 'maven-publish'
repositories {
mavenCentral()
}
@@ -19,7 +22,6 @@ subprojects {
dependencies {
implementation("org.json:json:20250107")
implementation("com.github.docker-java:docker-java:3.4.1")
implementation("org.jetbrains:annotations:23.1.0")
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
@@ -43,4 +45,32 @@ subprojects {
archives sourcesJar
archives javadocJar
}
// Make Javadoc generation non-fatal to avoid publish failures on bad Javadoc
tasks.withType(Javadoc).configureEach {
options.addBooleanOption('Xdoclint:none', true)
failOnError = false
}
// Configure local Maven publishing for modules that have a Java component
afterEvaluate { proj ->
if (components.findByName("java") != null) {
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
if (tasks.findByName('sourcesJar')) artifact tasks.sourcesJar
if (tasks.findByName('javadocJar')) artifact tasks.javadocJar
pom {
name = proj.name
description = "${proj.name} module of AI-test"
}
}
}
repositories {
mavenLocal()
}
}
}
}
}

View File

@@ -47,7 +47,7 @@ public class Launcher {
}
}
case "--api" -> {
System.out.println("API available at https://server.4zellen.se:3000/Zacharias/chat_thing/wiki/API-Docs");
System.out.println("API available at https://git.server.4zellen.se/Zacharias/chat_thing/wiki/API-Docs");
return;
}
case "--help", "-h" -> {

View File

@@ -3,5 +3,13 @@ include 'API', 'Core', 'Display', 'launcher'
include 'MALAPITool'
/**
* LEGAL WARNING:
* This module contains code that scrapes lyrics from Genius.com, which is against Genius API's Terms of Service.
*
* If you wish to avoid any potential legal issues, comment out or remove the line below and ensure no modules depend on this.
* The core NeuroDock system will still function without this module.
*/
include 'GeniusAPI'
include 'WikipediaTool'