refactor: me.zacharias.chat → me.neurodock, org rename cleanup

- Renamed package from me.zacharias.chat to me.neurodock across all 8 modules
- Updated Gradle group from me.zacharias.neurodock to me.neurodock
- Updated README and other files to reflect new Gitea org URL (Chat_things → neurodock)

Dev note: 95 files touched. The Great Refactor is complete, long may it rest.
This commit is contained in:
2026-05-27 23:34:22 +02:00
parent 88c593c47d
commit f50c04c828
97 changed files with 301 additions and 315 deletions
@@ -0,0 +1,127 @@
package me.neurodock.api;
import me.neurodock.api.payload.request.NewQurryResponceHook;
import me.neurodock.api.payload.request.NewToolRequest;
import me.neurodock.core.Core;
import me.neurodock.core.GlobalObjects;
import me.neurodock.core.PrintMessageHandler;
import me.neurodock.ollama.OllamaObject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
public class APIApplication {
public static void start(){
ConfigurableApplicationContext ctx = SpringApplication.run(APIApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(APIApplication.class, args);
}
private static APIApplication instance;
private final Map<String, APITool> tools = new HashMap<>();
private final ArrayList<QuerryResponceEndpoint> querryResponceEndpoints = new ArrayList<>();
private final Core core;
WebClient webClient = WebClient.create();
public APIApplication()
{
if(instance != null)
throw new IllegalStateException("APIApplication is already running!");
instance = this;
if(GlobalObjects.getObject("core") instanceof Core coreInstance) {
this.core = coreInstance;
} else {
this.core = new Core(new PrintMessageHandler() {
@Override
public void printMessage(String message) {
synchronized (querryResponceEndpoints) {
querryResponceEndpoints.forEach(endpoint -> {
webClient.post().uri(endpoint.getUrl()).bodyValue(message).retrieve()
.onStatus(
status -> status.is4xxClientError() || status.is5xxServerError() || status.isError(),
clientResponse -> {
return clientResponse.bodyToMono(String.class).flatMap(body -> {
endpoint.sendError("Failed to send message for qurry response");
querryResponceEndpoints.remove(endpoint);
return Mono.error(new RuntimeException("Webhook call failed with status: " + clientResponse.statusCode()));
});
})
.toBodilessEntity()
.doOnError(e -> {
})
.subscribe();
});
}
}
@Override
public boolean color() {
return false;
}
});
core.setOllamaObject(OllamaObject.builder()
.setModel("qwen3:8b")
.keep_alive(10)
.build());
}
}
public static APIApplication getInstance() {
return instance;
}
public boolean addTool(String name, NewToolRequest request) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Tool name cannot be null or empty");
}
if (tools.containsKey(name)) {
return false; // Tool with this name already exists
}
APITool tool = new APITool(request);
tools.put(name, tool);
core.addTool(tool, Core.Source.API);
return true;
}
public boolean removeTool(String name) {
if(name == null || name.isEmpty()) {
throw new IllegalArgumentException("Tool name cannot be null or empty");
}
if (!tools.containsKey(name)) {
return false; // Tool with this name does not exist
}
APITool tool = tools.remove(name);
core.removeTool(tool.name());
return true;
}
public void addQurryResponseHook(NewQurryResponceHook request) {
if (request == null || request.getUrl() == null || request.getUrl().isEmpty()) {
throw new IllegalArgumentException("Request and URL cannot be null or empty");
}
QuerryResponceEndpoint endpoint = new QuerryResponceEndpoint(request.getUrl(), request.getErrorUrl());
synchronized (querryResponceEndpoints) {
querryResponceEndpoints.add(endpoint);
}
}
public Core getCore() {
return core;
}
}
@@ -0,0 +1,94 @@
package me.neurodock.api;
import me.neurodock.api.payload.ToolArgument;
import me.neurodock.api.payload.request.NewToolRequest;
import me.neurodock.api.payload.webhook.responce.APIToolResponse;
import me.neurodock.ollama.OllamaFunctionArgument;
import me.neurodock.ollama.OllamaFunctionTool;
import me.neurodock.ollama.OllamaPerameter;
import me.neurodock.ollama.OllamaToolResponse;
import me.neurodock.ollama.exceptions.OllamaToolErrorException;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NonNull;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
public class APITool extends OllamaFunctionTool {
/**
* The name of the tool.
*/
private final String name;
/**
* The description of the tool.
*/
private final String description;
/**
* The arguments this tool will take.
*/
private final ToolArgument[] arguments;
/**
* The URL this api will call when the tool is used.
*/
private final String requestUrl;
RestTemplate restTemplate = new RestTemplate();
public APITool(NewToolRequest request) {
super();
this.name = request.getName();
this.description = request.getDescription();
this.arguments = request.getArguments();
this.requestUrl = request.getRequestUrl();
if (this.name == null || this.name.isEmpty()) {
throw new IllegalArgumentException("Tool name cannot be null or empty");
}
}
@Override
public @NonNull String name() {
return name;
}
@Override
public String description() {
return description;
}
@Override
public @NotNull OllamaPerameter parameters() {
OllamaPerameter.OllamaPerameterBuilder parameter = OllamaPerameter.builder();
for (ToolArgument argument : arguments) {
parameter.addProperty(argument.getName(), argument.getType(), argument.getDescription(), argument.isRequired());
}
return parameter.build();
}
@Override
public @NonNull OllamaToolResponse function(OllamaFunctionArgument... args) {
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(requestUrl);
for (OllamaFunctionArgument arg : args) {
builder.queryParam(arg.argument(), arg.value());
}
String url = builder.toUriString();
ResponseEntity<APIToolResponse> response = restTemplate.getForEntity(url, APIToolResponse.class);
if (response.getStatusCode().is2xxSuccessful()){
if (response.getBody() == null) {
throw new OllamaToolErrorException(name, "Response body is null");
}
if(response.getBody().getError() != null && !response.getBody().getError().isEmpty())
throw new OllamaToolErrorException(name, response.getBody().getError());
return new OllamaToolResponse(name, response.getBody().getResponse());
}
else {
if(response.getBody() == null) {
throw new OllamaToolErrorException(name, "Failed to call API: " + response.getStatusCode() + " - Response body is null");
}
throw new OllamaToolErrorException(name, "Failed to call API: " + response.getStatusCode() + " - " + response.getBody().getError());
}
}
}
@@ -0,0 +1,30 @@
package me.neurodock.api;
import me.neurodock.api.payload.webhook.WebhookError;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
public class QuerryResponceEndpoint {
String url;
String errorUrl;
public QuerryResponceEndpoint(String url, String errorUrl) {
this.url = url;
this.errorUrl = errorUrl;
}
public String getUrl() {
return url;
}
public void sendError(String error){
WebClient.create().post()
.uri(errorUrl)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(new WebhookError(url, error))
.retrieve()
.toBodilessEntity()
.doOnError(iggnore -> {})
.subscribe();
}
}
@@ -0,0 +1,13 @@
package me.neurodock.api.condations;
import me.neurodock.core.LaunchOptions;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class EnableIfNotDisplay implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return LaunchOptions.getInstance().isNotDisplay();
}
}
@@ -0,0 +1,58 @@
package me.neurodock.api.controllers;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import me.neurodock.api.APIApplication;
import me.neurodock.api.condations.EnableIfNotDisplay;
import me.neurodock.api.payload.request.NewQurryResponceHook;
import me.neurodock.ollama.OllamaMessage;
import me.neurodock.ollama.OllamaMessageRole;
import org.springframework.context.annotation.Conditional;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@Conditional(EnableIfNotDisplay.class)
@RestController
@RequestMapping("/v1/message")
public class Message {
private final APIApplication apiApplication;
public Message(APIApplication apiApplication) {
this.apiApplication = apiApplication;
}
@GetMapping("/query")
public ResponseEntity<String> query(@RequestParam(name = "query", required = true) String query) {
if (query == null || query.isEmpty()) {
return ResponseEntity.badRequest().body("Query cannot be null or empty");
}
Thread t = new Thread(() -> {
apiApplication.getCore().getOllamaObject().addMessage(new OllamaMessage(OllamaMessageRole.USER, query));
apiApplication.getCore().handleResponce(apiApplication.getCore().qurryOllama());
});
t.start();
return ResponseEntity.ok("Query received");
}
@PostMapping("/addResponseHook")
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Response hook added successfully"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "Invalid request data"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "500", description = "Internal server error")
})
public ResponseEntity<String> addResponseHook(@RequestBody NewQurryResponceHook request) {
if (request.getUrl() == null || request.getUrl().isEmpty()) {
return ResponseEntity.badRequest().body("URL cannot be null or empty");
}
try {
apiApplication.addQurryResponseHook(request);
return ResponseEntity.ok("Response hook added successfully: " + request.getUrl());
}catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body("Invalid request data: " + e.getMessage());
} catch (Exception e) {
return ResponseEntity.status(500).body("Internal server error: " + e.getMessage());
}
}
}
@@ -0,0 +1,39 @@
package me.neurodock.api.controllers;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import me.neurodock.api.APIApplication;
import me.neurodock.api.payload.request.NewToolRequest;
import me.neurodock.api.payload.response.NewToolResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/v1/tool")
public class Tool {
APIApplication application;
public Tool(APIApplication application) {
this.application = application;
}
/**
* Adds a new tool to the application.
*
* @param request The request containing the tool details.
* @return A response entity containing the tool details or an error message.
*/
@PostMapping("addTool")
@ApiResponse(responseCode = "200", description = "Tool added successfully", content = @io.swagger.v3.oas.annotations.media.Content(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = NewToolResponse.class)))
@ApiResponse(responseCode = "400", description = "Tool already exists", content = @io.swagger.v3.oas.annotations.media.Content(schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = String.class)))
public ResponseEntity<?> addTool(@RequestBody NewToolRequest request) {
if(application.addTool(request.getName(), request)) {
String[] arguments = new String[request.getArguments().length];
for(int i = 0; i < arguments.length; i++) {
arguments[i] = request.getArguments()[i].getName()+":("+request.getArguments()[i].getType()+")";
}
return ResponseEntity.ok(new NewToolResponse(request.getName(), request.getDescription(), arguments));
} else {
return ResponseEntity.badRequest().body("Tool already exists");
}
}
}
@@ -0,0 +1,19 @@
package me.neurodock.api.payload;
public class MessageResponce {
private final String message;
private final ToolRequest[] tool;
public MessageResponce(String message, ToolRequest[] tool) {
this.message = message;
this.tool = tool;
}
public String getMessage() {
return message;
}
public ToolRequest[] getTool() {
return tool;
}
}
@@ -0,0 +1,33 @@
package me.neurodock.api.payload;
import me.neurodock.ollama.OllamaPerameter;
public class ToolArgument {
String name;
String description;
OllamaPerameter.OllamaPerameterBuilder.Type type;
boolean required;
public ToolArgument(String name, String description, OllamaPerameter.OllamaPerameterBuilder.Type type, boolean required) {
this.name = name;
this.description = description;
this.type = type;
this.required = required;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public OllamaPerameter.OllamaPerameterBuilder.Type getType() {
return type;
}
public boolean isRequired() {
return required;
}
}
@@ -0,0 +1,19 @@
package me.neurodock.api.payload;
public class ToolRequest {
private final String name;
private final String[] args;
public ToolRequest(String name, String[] args) {
this.name = name;
this.args = args;
}
public String getName() {
return name;
}
public String[] getArgs() {
return args;
}
}
@@ -0,0 +1,45 @@
package me.neurodock.api.payload.request;
import io.swagger.v3.oas.annotations.media.Schema;
public class NewQurryResponceHook {
/**
* The URL to send the response to.
*/
@Schema(description = "The URL to send the response to.", example = "https://example.com/webhook")
private final String url;
/**
* The URL to send errors to.
*/
@Schema(description = "The URL to send errors to.", example = "https://example.com/error-webhook")
private final String errorUrl;
/**
* Constructor for NewQurryResponceHook.
*
* @param url The URL to send the response to.
* @param errorUrl The URL to send errors to.
*/
public NewQurryResponceHook(String url, String errorUrl) {
this.url = url;
this.errorUrl = errorUrl;
}
/**
* Gets the URL to send the response to.
*
* @return The URL for the response.
*/
public String getUrl() {
return url;
}
/**
* Gets the URL to send errors to.
*
* @return The URL for errors.
*/
public String getErrorUrl() {
return errorUrl;
}
}
@@ -0,0 +1,69 @@
package me.neurodock.api.payload.request;
import me.neurodock.api.payload.ToolArgument;
public class NewToolRequest {
/**
* The name of the tool.
*/
private String name;
/**
* The description of the tool.
*/
private String description;
/**
* The arguments this tool will take.
*/
private ToolArgument[] arguments;
/**
* The URL this api will call when the tool is used.
*/
private String requestUrl;
/**
* Constructor for NewToolRequest.
*
* @param name The name of the tool.
* @param description The description of the tool.
* @param arguments The arguments this tool will take.
* @param requestUrl The URL this api will call when the tool is used.
*/
public NewToolRequest(String name, String description, ToolArgument[] arguments, String requestUrl) {
this.name = name;
this.description = description;
this.arguments = arguments;
this.requestUrl = requestUrl;
}
/**
*
* @return the name of the tool.
*/
public String getName() {
return name;
}
/**
*
* @return the description of the tool.
*/
public String getDescription() {
return description;
}
/**
*
* @return the arguments this tool will take.
*/
public ToolArgument[] getArguments() {
return arguments;
}
/**
*
* @return the URL this api will call when the tool is used.
*/
public String getRequestUrl() {
return requestUrl;
}
}
@@ -0,0 +1,44 @@
package me.neurodock.api.payload.response;
public class NewToolResponse {
private String name;
private String description;
private String[] arguments;
/**
* Constructor for NewToolResponse.
*
* @param name The name of the tool.
* @param description The description of the tool.
* @param arguments The arguments this tool will take.
*/
public NewToolResponse(String name, String description, String[] arguments) {
this.name = name;
this.description = description;
this.arguments = arguments;
}
/**
*
* @return the name of the tool.
*/
public String getName() {
return name;
}
/**
*
* @return the description of the tool.
*/
public String getDescription() {
return description;
}
/**
*
* @return the arguments this tool will take.
*/
public String[] getArguments() {
return arguments;
}
}
@@ -0,0 +1,31 @@
package me.neurodock.api.payload.webhook;
public class WebhookError {
private final String originalUrl;
private final String errorMessage;
private final int statusCode;
private final String timestamp;
public WebhookError(String url, String error) {
this.originalUrl = url;
this.errorMessage = error;
this.statusCode = 500; // Default status code for errors
this.timestamp = java.time.Instant.now().toString(); // Current timestamp in ISO-8601 format
}
public String getOriginalUrl() {
return originalUrl;
}
public String getErrorMessage() {
return errorMessage;
}
public int getStatusCode() {
return statusCode;
}
public String getTimestamp() {
return timestamp;
}
}
@@ -0,0 +1,35 @@
package me.neurodock.api.payload.webhook.responce;
public class APIToolResponse {
private final String response;
private final String error;
/**
* Constructor for APIToolResponse.
*
* @param response The response from the API.
* @param error The error message if any.
*/
public APIToolResponse(String response, String error) {
this.response = response;
this.error = error;
}
/**
* Gets the response from the API.
*
* @return The response from the API.
*/
public String getResponse() {
return response;
}
/**
* Gets the error message if any.
*
* @return The error message.
*/
public String getError() {
return error;
}
}