Commit c8c7eeea by Jonathan Thomas

Added support for both Json mode and text mode. Connected Save/Load methods when…

Added support for both Json mode and text mode. Connected Save/Load methods when world loads, writing to local json file in level save folder.
parent 3d22ffe0
Pipeline #11666 passed with stage
in 30 seconds
...@@ -4,6 +4,7 @@ import com.owlmaddie.json.QuestJson; ...@@ -4,6 +4,7 @@ import com.owlmaddie.json.QuestJson;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.WorldSavePath;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
...@@ -14,13 +15,23 @@ import java.util.regex.Pattern; ...@@ -14,13 +15,23 @@ import java.util.regex.Pattern;
import com.google.gson.Gson; import com.google.gson.Gson;
import net.minecraft.util.Rarity; import net.minecraft.util.Rarity;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import net.minecraft.server.MinecraftServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChatDataManager { public class ChatDataManager {
// Use a static instance to manage our data globally // Use a static instance to manage our data globally
private static final ChatDataManager SERVER_INSTANCE = new ChatDataManager(true); private static final ChatDataManager SERVER_INSTANCE = new ChatDataManager(true);
private static final ChatDataManager CLIENT_INSTANCE = new ChatDataManager(false); private static final ChatDataManager CLIENT_INSTANCE = new ChatDataManager(false);
public static final Logger LOGGER = LoggerFactory.getLogger("mobgpt");
public static int MAX_CHAR_PER_LINE = 22; public static int MAX_CHAR_PER_LINE = 22;
public QuestJson quest = null; public QuestJson quest = null;
private static final Gson GSON = new Gson();
public enum ChatStatus { public enum ChatStatus {
NONE, // No chat status yet NONE, // No chat status yet
...@@ -118,16 +129,16 @@ public class ChatDataManager { ...@@ -118,16 +129,16 @@ public class ChatDataManager {
} }
// Generate greeting // Generate greeting
public void generateMessage(ServerPlayerEntity player, String systemPrompt, String user_message) { public void generateMessage(ServerPlayerEntity player, String systemPrompt, String userMessage) {
this.status = ChatStatus.PENDING; this.status = ChatStatus.PENDING;
// Add USER Message // Add USER Message
this.addMessage(user_message, ChatSender.USER); this.addMessage(userMessage, ChatSender.USER);
// Add PLAYER context information // Add PLAYER context information
Map<String, String> contextData = getPlayerContext(player); Map<String, String> contextData = getPlayerContext(player);
// fetch HTTP response from ChatGPT // fetch HTTP response from ChatGPT
ChatGPTRequest.fetchMessageFromChatGPT(systemPrompt, contextData, previousMessages).thenAccept(output_message -> { ChatGPTRequest.fetchMessageFromChatGPT(systemPrompt, contextData, previousMessages, false).thenAccept(output_message -> {
if (output_message != null && systemPrompt == "system-character") { if (output_message != null && systemPrompt == "system-character") {
// Add NEW CHARACTER sheet & greeting // Add NEW CHARACTER sheet & greeting
this.characterSheet = output_message; this.characterSheet = output_message;
...@@ -195,7 +206,7 @@ public class ChatDataManager { ...@@ -195,7 +206,7 @@ public class ChatDataManager {
if (server_only) { if (server_only) {
// Generate initial quest // Generate initial quest
// TODO: Complete the quest flow // TODO: Complete the quest flow
//generateQuest(); generateQuest();
} }
} }
...@@ -240,10 +251,40 @@ public class ChatDataManager { ...@@ -240,10 +251,40 @@ public class ChatDataManager {
messages.add(new ChatMessage("Generate me a new fantasy story with ONLY the 1st character in the story", ChatSender.USER)); messages.add(new ChatMessage("Generate me a new fantasy story with ONLY the 1st character in the story", ChatSender.USER));
// Generate Quest: fetch HTTP response from ChatGPT // Generate Quest: fetch HTTP response from ChatGPT
ChatGPTRequest.fetchMessageFromChatGPT("system-quest", contextData, messages).thenAccept(output_message -> { ChatGPTRequest.fetchMessageFromChatGPT("system-quest", contextData, messages, true).thenAccept(output_message -> {
// New Quest // New Quest
Gson gson = new Gson(); Gson gson = new Gson();
quest = gson.fromJson(output_message, QuestJson.class); quest = gson.fromJson(output_message, QuestJson.class);
}); });
} }
// Save chat data to file
public void saveChatData(MinecraftServer server) {
try {
File saveFile = new File(server.getSavePath(WorldSavePath.ROOT).toFile(), "chatdata.json");
LOGGER.info("Save chat data to " + saveFile.getAbsolutePath());
try (FileWriter writer = new FileWriter(saveFile)) {
GSON.toJson(this.entityChatDataMap, writer);
}
} catch (Exception e) {
// Handle exceptions
}
}
// Load chat data from file
@SuppressWarnings("unchecked")
public void loadChatData(MinecraftServer server) {
try {
File loadFile = new File(server.getSavePath(WorldSavePath.ROOT).toFile(), "chatdata.json");
LOGGER.info("Load chat data from " + loadFile.getAbsolutePath());
if (loadFile.exists()) {
Type type = new TypeToken<HashMap<Integer, EntityChatData>>(){}.getType();
try (FileReader reader = new FileReader(loadFile)) {
this.entityChatDataMap = GSON.fromJson(reader, type);
}
}
} catch (Exception e) {
// Handle exceptions
}
}
} }
\ No newline at end of file
...@@ -38,10 +38,14 @@ public class ChatGPTRequest { ...@@ -38,10 +38,14 @@ public class ChatGPTRequest {
List<ChatGPTRequestMessage> messages; List<ChatGPTRequestMessage> messages;
ResponseFormat response_format; ResponseFormat response_format;
public ChatGPTRequestPayload(String model, List<ChatGPTRequestMessage> messages) { public ChatGPTRequestPayload(String model, List<ChatGPTRequestMessage> messages, Boolean jsonMode) {
this.model = model; this.model = model;
this.messages = messages; this.messages = messages;
if (jsonMode) {
this.response_format = new ResponseFormat("json_object"); this.response_format = new ResponseFormat("json_object");
} else {
this.response_format = new ResponseFormat("text");
}
} }
} }
...@@ -80,7 +84,7 @@ public class ChatGPTRequest { ...@@ -80,7 +84,7 @@ public class ChatGPTRequest {
return result.replace("\"", "") ; return result.replace("\"", "") ;
} }
public static CompletableFuture<String> fetchMessageFromChatGPT(String systemPrompt, Map<String, String> context, List<ChatDataManager.ChatMessage> messageHistory) { public static CompletableFuture<String> fetchMessageFromChatGPT(String systemPrompt, Map<String, String> context, List<ChatDataManager.ChatMessage> messageHistory, Boolean jsonMode) {
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
try { try {
// Load and prepare the system prompt template // Load and prepare the system prompt template
...@@ -110,7 +114,7 @@ public class ChatGPTRequest { ...@@ -110,7 +114,7 @@ public class ChatGPTRequest {
} }
// Convert JSON to String // Convert JSON to String
ChatGPTRequestPayload payload = new ChatGPTRequestPayload("gpt-3.5-turbo-1106", messages); ChatGPTRequestPayload payload = new ChatGPTRequestPayload("gpt-3.5-turbo-1106", messages, jsonMode);
Gson gsonInput = new Gson(); Gson gsonInput = new Gson();
String jsonInputString = gsonInput.toJson(payload); String jsonInputString = gsonInput.toJson(payload);
......
...@@ -53,7 +53,9 @@ public class ModInit implements ModInitializer { ...@@ -53,7 +53,9 @@ public class ModInit implements ModInitializer {
chatData.status == ChatDataManager.ChatStatus.END) { chatData.status == ChatDataManager.ChatStatus.END) {
// Only generate a new greeting if not already doing so // Only generate a new greeting if not already doing so
LOGGER.info("Generate greeting for: " + entity.getType().toString()); LOGGER.info("Generate greeting for: " + entity.getType().toString());
chatData.generateMessage(player, "system-character", "Please generate a new background character who lives near the {{player_biome}}"); String player_biome = player.getWorld().getBiome(player.getBlockPos()).getKey().get().getValue().getPath();
String userMessage = "Please generate a new background character who lives near the " + player_biome;
chatData.generateMessage(player, "system-character", userMessage);
} }
} }
}); });
...@@ -118,14 +120,18 @@ public class ModInit implements ModInitializer { ...@@ -118,14 +120,18 @@ public class ModInit implements ModInitializer {
}); });
ServerWorldEvents.LOAD.register((server, world) -> { ServerWorldEvents.LOAD.register((server, world) -> {
// Load chat data... String world_name = world.getRegistryKey().getValue().getPath();
LOGGER.info("LOAD chat data from NBT: " + world.getRegistryKey().getValue()); if (world_name == "overworld") {
serverInstance = server; serverInstance = server;
ChatDataManager.getServerInstance().loadChatData(server);
}
}); });
ServerWorldEvents.UNLOAD.register((server, world) -> { ServerWorldEvents.UNLOAD.register((server, world) -> {
// Save chat data... String world_name = world.getRegistryKey().getValue().getPath();
LOGGER.info("SAVE chat data to NBT: " + world.getRegistryKey().getValue()); if (world_name == "overworld") {
ChatDataManager.getServerInstance().saveChatData(server);
serverInstance = null; serverInstance = null;
}
}); });
LOGGER.info("MobGPT Initialized!"); LOGGER.info("MobGPT Initialized!");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment