mirror of
https://github.com/ritonioz/minecraft-ai-companion-mod-EMVs12-Project.git
synced 2026-06-20 20:25:01 +02:00
Fixed chat not working in multiplayer and added method to delete api key
This commit is contained in:
@@ -4,12 +4,14 @@ import AiCompanion.aicompanion2_0.AIEntity;
|
|||||||
import AiCompanion.aicompanion2_0.Aicompanion2_0;
|
import AiCompanion.aicompanion2_0.Aicompanion2_0;
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
|
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
|
||||||
import net.fabricmc.fabric.api.event.player.UseEntityCallback;
|
import net.fabricmc.fabric.api.event.player.UseEntityCallback;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.entity.BipedEntityRenderer;
|
import net.minecraft.client.render.entity.BipedEntityRenderer;
|
||||||
import net.minecraft.client.render.entity.model.EntityModelLayers;
|
import net.minecraft.client.render.entity.model.EntityModelLayers;
|
||||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
@@ -39,28 +41,89 @@ public class AiCompanionClient implements ClientModInitializer {
|
|||||||
currentSession = null;
|
currentSession = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(Aicompanion2_0.QUESTION_PACKET_ID, (client, handler, buf, responseSender) -> {
|
||||||
|
String question = buf.readString(32767);
|
||||||
|
client.execute(() -> ensureApiKeyAndRun(client, () -> askQuestion(client, question)));
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(Aicompanion2_0.DELETE_KEY_PACKET_ID, (client, handler, buf, responseSender) -> {
|
||||||
|
client.execute(() -> {
|
||||||
|
currentSession = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
boolean deleted = ClientConfig.deleteApiKey();
|
||||||
|
if (deleted) {
|
||||||
|
sendChatMessage(client, Text.literal("§6[AI] §fAPI key deleted."));
|
||||||
|
} else {
|
||||||
|
sendChatMessage(client, Text.literal("§6[AI] §fno api key deleted: none found"));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
String error = e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName();
|
||||||
|
sendChatMessage(client, Text.literal("§c[AI] Could not delete API key: " + error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Open chat GUI on right-click
|
// Open chat GUI on right-click
|
||||||
UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> {
|
UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> {
|
||||||
if (world.isClient() && entity instanceof AIEntity) {
|
if (world.isClient() && entity instanceof AIEntity) {
|
||||||
MinecraftClient client = MinecraftClient.getInstance();
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
|
||||||
client.execute(() -> {
|
client.execute(() -> ensureApiKeyAndRun(client, () -> openChatScreen(client)));
|
||||||
if (!ClientConfig.hasApiKey()) {
|
|
||||||
// First time: ask for API key, then open chat
|
|
||||||
client.setScreen(new ApiKeyScreen(() -> {
|
|
||||||
currentSession = null; // reset so session uses new key
|
|
||||||
openChatScreen(client);
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
openChatScreen(client);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return ActionResult.SUCCESS;
|
return ActionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
return ActionResult.PASS;
|
return ActionResult.PASS;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ensureApiKeyAndRun(MinecraftClient client, Runnable action) {
|
||||||
|
if (!ClientConfig.hasApiKey()) {
|
||||||
|
currentSession = null;
|
||||||
|
client.setScreen(new ApiKeyScreen(() -> {
|
||||||
|
currentSession = null;
|
||||||
|
action.run();
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
action.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void askQuestion(MinecraftClient client, String question) {
|
||||||
|
sendChatMessage(client, Text.literal("§6[AI] §fThink about: " + question));
|
||||||
|
|
||||||
|
AiChatSession session = new AiChatSession(
|
||||||
|
Aicompanion2_0.getApiBaseUrl(),
|
||||||
|
ClientConfig.getApiKey(),
|
||||||
|
Aicompanion2_0.getModel()
|
||||||
|
);
|
||||||
|
|
||||||
|
session.sendMessage(question, response -> client.execute(() -> {
|
||||||
|
if (response == null || response.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.startsWith("§cError: ")) {
|
||||||
|
String error = response.substring("§cError: ".length());
|
||||||
|
sendChatMessage(client, Text.literal("§c[AI] Error with /ai question: " + error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String answer = response;
|
||||||
|
if (answer.length() > 2000) {
|
||||||
|
answer = answer.substring(0, 2000) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
sendChatMessage(client, Text.literal("§6[AI] §fAnswer: " + answer));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendChatMessage(MinecraftClient client, Text message) {
|
||||||
|
if (client.player != null) {
|
||||||
|
client.player.sendMessage(message, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void openChatScreen(MinecraftClient client) {
|
private static void openChatScreen(MinecraftClient client) {
|
||||||
if (currentSession == null) {
|
if (currentSession == null) {
|
||||||
currentSession = new AiChatSession(
|
currentSession = new AiChatSession(
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public class ApiKeyScreen extends Screen {
|
|||||||
private final Runnable onSuccess;
|
private final Runnable onSuccess;
|
||||||
|
|
||||||
public ApiKeyScreen(Runnable onSuccess) {
|
public ApiKeyScreen(Runnable onSuccess) {
|
||||||
super(Text.literal("Enter API Key"));
|
super(Text.literal("Enter API Key (available on ai.cametendo.org)"));
|
||||||
this.onSuccess = onSuccess;
|
this.onSuccess = onSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class ClientConfig {
|
|||||||
private static String apiKey = null;
|
private static String apiKey = null;
|
||||||
|
|
||||||
public static String getApiKey() {
|
public static String getApiKey() {
|
||||||
if (apiKey == null) load();
|
load();
|
||||||
return apiKey;
|
return apiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,8 +20,15 @@ public class ClientConfig {
|
|||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean deleteApiKey() throws IOException {
|
||||||
|
boolean deleted = deleteApiKeyFrom(SHARED_CONFIG_PATH, "AI Companion Shared Config");
|
||||||
|
deleted = deleteApiKeyFrom(CONFIG_PATH, "AI Companion Client Config") || deleted;
|
||||||
|
apiKey = null;
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean hasApiKey() {
|
public static boolean hasApiKey() {
|
||||||
if (apiKey == null) load();
|
load();
|
||||||
return apiKey != null && !apiKey.isBlank();
|
return apiKey != null && !apiKey.isBlank();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +40,7 @@ public class ClientConfig {
|
|||||||
apiKey = loadApiKeyFrom(CONFIG_PATH);
|
apiKey = loadApiKeyFrom(CONFIG_PATH);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
apiKey = null;
|
||||||
System.out.println("[aicompanion2_0] Could not load Client Config.");
|
System.out.println("[aicompanion2_0] Could not load Client Config.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,4 +76,23 @@ public class ClientConfig {
|
|||||||
props.store(out, comment);
|
props.store(out, comment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean deleteApiKeyFrom(Path path, String comment) throws IOException {
|
||||||
|
if (!Files.exists(path)) return false;
|
||||||
|
|
||||||
|
Properties props = new Properties();
|
||||||
|
try (FileInputStream in = new FileInputStream(path.toFile())) {
|
||||||
|
props.load(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
String existingKey = props.getProperty("api.key", null);
|
||||||
|
if (existingKey == null || existingKey.isBlank()) return false;
|
||||||
|
|
||||||
|
props.remove("api.key");
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
try (FileOutputStream out = new FileOutputStream(path.toFile())) {
|
||||||
|
props.store(out, comment);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import com.mojang.brigadier.arguments.StringArgumentType;
|
|||||||
|
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
|
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
|
||||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
|
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
|
||||||
import net.minecraft.entity.EntityDimensions;
|
import net.minecraft.entity.EntityDimensions;
|
||||||
@@ -29,10 +31,17 @@ import net.minecraft.util.Identifier;
|
|||||||
public class Aicompanion2_0 implements ModInitializer {
|
public class Aicompanion2_0 implements ModInitializer {
|
||||||
|
|
||||||
public static final String MOD_ID = "aicompanion2_0";
|
public static final String MOD_ID = "aicompanion2_0";
|
||||||
private static String API_BASE_URL = "https://ai.cametendo.org";
|
private static final String DEFAULT_API_BASE_URL = "https://ai.cametendo.org";
|
||||||
private static String MODEL = "minecraft-helper";
|
private static final String DEFAULT_MODEL = "minecraft-helper";
|
||||||
|
private static final String DEFAULT_API_PATH = "/api/chat/completions";
|
||||||
|
private static String API_BASE_URL = DEFAULT_API_BASE_URL;
|
||||||
|
private static String MODEL = DEFAULT_MODEL;
|
||||||
private static String API_KEY = "";
|
private static String API_KEY = "";
|
||||||
private static String API_PATH = "/api/chat/completions";
|
private static String API_PATH = DEFAULT_API_PATH;
|
||||||
|
private static final Path SHARED_CONFIG_PATH = Path.of("config", "aicompanion2_0.properties");
|
||||||
|
private static final Path CLIENT_CONFIG_PATH = Path.of("config", "aicompanion2_0_client.properties");
|
||||||
|
public static final Identifier QUESTION_PACKET_ID = new Identifier(MOD_ID, "question");
|
||||||
|
public static final Identifier DELETE_KEY_PACKET_ID = new Identifier(MOD_ID, "delete_key");
|
||||||
|
|
||||||
public static final EntityType<AIEntity> AI_COMPANION = Registry.register(
|
public static final EntityType<AIEntity> AI_COMPANION = Registry.register(
|
||||||
Registries.ENTITY_TYPE,
|
Registries.ENTITY_TYPE,
|
||||||
@@ -94,6 +103,39 @@ public class Aicompanion2_0 implements ModInitializer {
|
|||||||
return 1;
|
return 1;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
// /ai delete-key
|
||||||
|
.then(CommandManager.literal("delete-key")
|
||||||
|
.executes(ctx -> {
|
||||||
|
var player = ctx.getSource().getPlayer();
|
||||||
|
if (player != null) {
|
||||||
|
if (!ServerPlayNetworking.canSend(player, DELETE_KEY_PACKET_ID)) {
|
||||||
|
ctx.getSource().sendFeedback(
|
||||||
|
() -> Text.literal("§c[AI] delete-key requires the AI Companion client mod."), false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerPlayNetworking.send(player, DELETE_KEY_PACKET_ID, PacketByteBufs.create());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
boolean deleted = deleteStoredApiKey();
|
||||||
|
if (deleted) {
|
||||||
|
ctx.getSource().sendFeedback(
|
||||||
|
() -> Text.literal("§6[AI] §fAPI key deleted."), false);
|
||||||
|
} else {
|
||||||
|
ctx.getSource().sendFeedback(
|
||||||
|
() -> Text.literal("§6[AI] §fno api key deleted: none found"), false);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
} catch (IOException e) {
|
||||||
|
String error = e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName();
|
||||||
|
ctx.getSource().sendFeedback(
|
||||||
|
() -> Text.literal("§c[AI] Could not delete API key: " + error), false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
// /ai question <question>
|
// /ai question <question>
|
||||||
.then(CommandManager.literal("question")
|
.then(CommandManager.literal("question")
|
||||||
.then(CommandManager.argument("question", StringArgumentType.greedyString())
|
.then(CommandManager.argument("question", StringArgumentType.greedyString())
|
||||||
@@ -103,8 +145,16 @@ public class Aicompanion2_0 implements ModInitializer {
|
|||||||
String frage = StringArgumentType.getString(ctx, "question");
|
String frage = StringArgumentType.getString(ctx, "question");
|
||||||
|
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
player.sendMessage(
|
if (!ServerPlayNetworking.canSend(player, QUESTION_PACKET_ID)) {
|
||||||
Text.literal("§6[AI] §fThink about: " + frage), false);
|
ctx.getSource().sendFeedback(
|
||||||
|
() -> Text.literal("§c[AI] question requires the AI Companion client mod."), false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf = PacketByteBufs.create();
|
||||||
|
buf.writeString(frage);
|
||||||
|
ServerPlayNetworking.send(player, QUESTION_PACKET_ID, buf);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
@@ -140,33 +190,40 @@ public class Aicompanion2_0 implements ModInitializer {
|
|||||||
// Innerhalb deiner Klasse Aicompanion2_0
|
// Innerhalb deiner Klasse Aicompanion2_0
|
||||||
|
|
||||||
private String callOllama(String prompt) throws Exception {
|
private String callOllama(String prompt) throws Exception {
|
||||||
String json = "{\"model\":\"" + jsonEscape(MODEL) + "\",\"messages\":[{\"role\":\"user\",\"content\":\""
|
loadConfig();
|
||||||
|
|
||||||
|
String apiBaseUrl = API_BASE_URL;
|
||||||
|
String apiPath = API_PATH;
|
||||||
|
String model = MODEL;
|
||||||
|
String apiKey = API_KEY;
|
||||||
|
|
||||||
|
String json = "{\"model\":\"" + jsonEscape(model) + "\",\"messages\":[{\"role\":\"user\",\"content\":\""
|
||||||
+ jsonEscape(prompt) + "\"}],\"stream\":false}";
|
+ jsonEscape(prompt) + "\"}],\"stream\":false}";
|
||||||
|
|
||||||
HttpResult primary = postChatCompletion(API_PATH, json);
|
HttpResult primary = postChatCompletion(apiBaseUrl, apiPath, apiKey, json);
|
||||||
if (primary.status == 200) {
|
if (primary.status == 200) {
|
||||||
return extractAssistantContent(primary.body);
|
return extractAssistantContent(primary.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some deployments expose OpenAI-compatible chat under /v1/chat/completions.
|
// Some deployments expose OpenAI-compatible chat under /v1/chat/completions.
|
||||||
if ((primary.status >= 500 || primary.status == 404) && !"/v1/chat/completions".equals(API_PATH)) {
|
if ((primary.status >= 500 || primary.status == 404) && !"/v1/chat/completions".equals(apiPath)) {
|
||||||
HttpResult fallback = postChatCompletion("/v1/chat/completions", json);
|
HttpResult fallback = postChatCompletion(apiBaseUrl, "/v1/chat/completions", apiKey, json);
|
||||||
if (fallback.status == 200) {
|
if (fallback.status == 200) {
|
||||||
return extractAssistantContent(fallback.body);
|
return extractAssistantContent(fallback.body);
|
||||||
}
|
}
|
||||||
return formatHttpError(fallback.status, fallback.body, "/v1/chat/completions");
|
return formatHttpError(fallback.status, fallback.body, "/v1/chat/completions");
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatHttpError(primary.status, primary.body, API_PATH);
|
return formatHttpError(primary.status, primary.body, apiPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpResult postChatCompletion(String path, String json) throws Exception {
|
private HttpResult postChatCompletion(String apiBaseUrl, String path, String apiKey, String json) throws Exception {
|
||||||
URL url = new URL(API_BASE_URL + path);
|
URL url = new URL(apiBaseUrl + path);
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
conn.setRequestMethod("POST");
|
conn.setRequestMethod("POST");
|
||||||
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
|
conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
|
||||||
if (API_KEY != null && !API_KEY.isBlank()) {
|
if (apiKey != null && !apiKey.isBlank()) {
|
||||||
conn.setRequestProperty("Authorization", "Bearer " + API_KEY);
|
conn.setRequestProperty("Authorization", "Bearer " + apiKey);
|
||||||
}
|
}
|
||||||
conn.setDoOutput(true);
|
conn.setDoOutput(true);
|
||||||
|
|
||||||
@@ -230,38 +287,42 @@ public class Aicompanion2_0 implements ModInitializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadConfig() {
|
private synchronized void loadConfig() {
|
||||||
|
API_BASE_URL = DEFAULT_API_BASE_URL;
|
||||||
|
API_PATH = DEFAULT_API_PATH;
|
||||||
|
MODEL = DEFAULT_MODEL;
|
||||||
|
API_KEY = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Path configPath = Path.of("config", "aicompanion2_0.properties");
|
if (Files.exists(SHARED_CONFIG_PATH)) {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
try (FileInputStream in = new FileInputStream(configPath.toFile())) {
|
try (FileInputStream in = new FileInputStream(SHARED_CONFIG_PATH.toFile())) {
|
||||||
props.load(in);
|
props.load(in);
|
||||||
|
}
|
||||||
|
API_BASE_URL = props.getProperty("api.baseUrl", DEFAULT_API_BASE_URL);
|
||||||
|
API_PATH = props.getProperty("api.path", DEFAULT_API_PATH);
|
||||||
|
MODEL = props.getProperty("api.model", DEFAULT_MODEL);
|
||||||
|
API_KEY = props.getProperty("api.key", "").trim();
|
||||||
}
|
}
|
||||||
API_BASE_URL = props.getProperty("api.baseUrl", API_BASE_URL);
|
|
||||||
API_PATH = props.getProperty("api.path", API_PATH);
|
|
||||||
MODEL = props.getProperty("api.model", MODEL);
|
|
||||||
API_KEY = props.getProperty("api.key", API_KEY);
|
|
||||||
|
|
||||||
if (API_KEY == null || API_KEY.isBlank()) {
|
if (API_KEY == null || API_KEY.isBlank()) {
|
||||||
String clientFallbackKey = readApiKeyFrom(Path.of("config", "aicompanion2_0_client.properties"));
|
String clientFallbackKey = readApiKeyFrom(CLIENT_CONFIG_PATH);
|
||||||
if (clientFallbackKey != null && !clientFallbackKey.isBlank()) {
|
if (clientFallbackKey != null && !clientFallbackKey.isBlank()) {
|
||||||
API_KEY = clientFallbackKey;
|
API_KEY = clientFallbackKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("[" + MOD_ID + "] Keine Config gefunden, benutze Default-API.");
|
System.out.println("[" + MOD_ID + "] Could not reload config, using defaults.");
|
||||||
|
|
||||||
try {
|
|
||||||
String clientFallbackKey = readApiKeyFrom(Path.of("config", "aicompanion2_0_client.properties"));
|
|
||||||
if (clientFallbackKey != null && !clientFallbackKey.isBlank()) {
|
|
||||||
API_KEY = clientFallbackKey;
|
|
||||||
}
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
// Keep defaults when no config files are available.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean deleteStoredApiKey() throws IOException {
|
||||||
|
boolean deleted = deleteApiKeyFrom(SHARED_CONFIG_PATH, "AI Companion Shared Config");
|
||||||
|
deleted = deleteApiKeyFrom(CLIENT_CONFIG_PATH, "AI Companion Client Config") || deleted;
|
||||||
|
API_KEY = "";
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
private String readApiKeyFrom(Path configPath) throws IOException {
|
private String readApiKeyFrom(Path configPath) throws IOException {
|
||||||
if (!Files.exists(configPath)) return null;
|
if (!Files.exists(configPath)) return null;
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
@@ -270,4 +331,23 @@ public class Aicompanion2_0 implements ModInitializer {
|
|||||||
}
|
}
|
||||||
return props.getProperty("api.key", null);
|
return props.getProperty("api.key", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean deleteApiKeyFrom(Path configPath, String comment) throws IOException {
|
||||||
|
if (!Files.exists(configPath)) return false;
|
||||||
|
|
||||||
|
Properties props = new Properties();
|
||||||
|
try (FileInputStream in = new FileInputStream(configPath.toFile())) {
|
||||||
|
props.load(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
String existingKey = props.getProperty("api.key", null);
|
||||||
|
if (existingKey == null || existingKey.isBlank()) return false;
|
||||||
|
|
||||||
|
props.remove("api.key");
|
||||||
|
Files.createDirectories(configPath.getParent());
|
||||||
|
try (OutputStream out = Files.newOutputStream(configPath)) {
|
||||||
|
props.store(out, comment);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user