diff --git a/build.gradle b/build.gradle index 05279c8..8fa7550 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,13 @@ plugins { id 'java' + id 'com.github.johnrengelman.shadow' version '6.0.0' } group = 'codes.mii' version = '1.0-SNAPSHOT' +compileJava.options.encoding = 'UTF-8' +compileTestJava.options.encoding = 'UTF-8' +javadoc.options.encoding = 'UTF-8' repositories { mavenCentral() @@ -19,6 +23,8 @@ repositories { dependencies { compileOnly "org.spigotmc:spigot-api:1.19.3-R0.1-SNAPSHOT" + implementation 'com.theokanning.openai-gpt3-java:service:0.11.0' + implementation 'com.google.code.gson:gson:2.10.1' } def targetJavaVersion = 17 @@ -45,3 +51,8 @@ processResources { expand props } } + +shadowJar { + project.configurations.implementation.canBeResolved = true + configurations = [project.configurations.implementation] +} \ No newline at end of file diff --git a/src/main/java/codes/mii/chatgptbot/ChatGPT.java b/src/main/java/codes/mii/chatgptbot/ChatGPT.java new file mode 100644 index 0000000..14994b5 --- /dev/null +++ b/src/main/java/codes/mii/chatgptbot/ChatGPT.java @@ -0,0 +1,28 @@ +package codes.mii.chatgptbot; + +import com.theokanning.openai.completion.chat.ChatCompletionRequest; +import com.theokanning.openai.completion.chat.ChatMessage; +import com.theokanning.openai.service.OpenAiService; +import com.google.gson.Gson; +import org.bukkit.configuration.file.FileConfiguration; + +import java.util.List; + +public class ChatGPT { + public static ChatGPTResponse chat(ChatGPTInput input) { + FileConfiguration config = ChatGPTBot.getPlugin(ChatGPTBot.class).getConfig(); + + Gson gson = new Gson(); + String message = config.getString("base_input") + "\n" + gson.toJson(input); + + OpenAiService service = new OpenAiService(config.getString("openai_api_key")); + ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() + .model(config.getString("model")) + .messages(List.of(new ChatMessage("user", message))) + .build(); + + String response = service.createChatCompletion(chatCompletionRequest).getChoices().get(0).getMessage().getContent(); + + return gson.fromJson(response, ChatGPTResponse.class); + } +} diff --git a/src/main/java/codes/mii/chatgptbot/ChatGPTBot.java b/src/main/java/codes/mii/chatgptbot/ChatGPTBot.java index 57e87d1..d66851c 100644 --- a/src/main/java/codes/mii/chatgptbot/ChatGPTBot.java +++ b/src/main/java/codes/mii/chatgptbot/ChatGPTBot.java @@ -3,15 +3,9 @@ package codes.mii.chatgptbot; import org.bukkit.plugin.java.JavaPlugin; public final class ChatGPTBot extends JavaPlugin { - @Override public void onEnable() { - // Plugin startup logic - - } - - @Override - public void onDisable() { - // Plugin shutdown logic + saveDefaultConfig(); + getServer().getPluginManager().registerEvents(new OnAsyncPlayerChatEvent(), this); } } diff --git a/src/main/java/codes/mii/chatgptbot/ChatGPTInput.java b/src/main/java/codes/mii/chatgptbot/ChatGPTInput.java new file mode 100644 index 0000000..5295212 --- /dev/null +++ b/src/main/java/codes/mii/chatgptbot/ChatGPTInput.java @@ -0,0 +1,15 @@ +package codes.mii.chatgptbot; + +import java.util.List; + +public class ChatGPTInput { + public String username; + public String message; + public List position; + + public ChatGPTInput(String username, String message, List position) { + this.username = username; + this.message = message; + this.position = position; + } +} diff --git a/src/main/java/codes/mii/chatgptbot/ChatGPTResponse.java b/src/main/java/codes/mii/chatgptbot/ChatGPTResponse.java new file mode 100644 index 0000000..708d410 --- /dev/null +++ b/src/main/java/codes/mii/chatgptbot/ChatGPTResponse.java @@ -0,0 +1,15 @@ +package codes.mii.chatgptbot; + +import java.util.List; + +public class ChatGPTResponse { + public String response_message; + public String to; + public List commands; + + public ChatGPTResponse(String response_message, String to, List commands) { + this.response_message = response_message; + this.to = to; + this.commands = commands; + } +} diff --git a/src/main/java/codes/mii/chatgptbot/OnAsyncPlayerChatEvent.java b/src/main/java/codes/mii/chatgptbot/OnAsyncPlayerChatEvent.java new file mode 100644 index 0000000..6ca82a3 --- /dev/null +++ b/src/main/java/codes/mii/chatgptbot/OnAsyncPlayerChatEvent.java @@ -0,0 +1,61 @@ +package codes.mii.chatgptbot; + +import org.bukkit.Location; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.List; +import java.util.Objects; + +import static org.bukkit.Bukkit.getServer; + +public class OnAsyncPlayerChatEvent implements Listener { + @EventHandler + public void onAsyncPlayerChatEvent(AsyncPlayerChatEvent e) { + FileConfiguration config = ChatGPTBot.getPlugin(ChatGPTBot.class).getConfig(); + + // check prefix + String prefix = config.getString("chat_prefix"); + if (!e.getMessage().startsWith(Objects.requireNonNull(prefix))) return; + + String message = e.getMessage().replaceFirst(prefix, ""); + String username = e.getPlayer().getName(); + Location location = e.getPlayer().getLocation(); + List position = List.of(location.getX(), location.getY(), location.getZ()); + + BukkitRunnable runnable = new BukkitRunnable() { + @Override + public void run() { + // generate response + ChatGPTInput request = new ChatGPTInput(username, message, position); + ChatGPTResponse response = ChatGPT.chat(request); + + // format + String response_message = Objects.requireNonNull(config.getString("response_format")) + .replace("%TO%", response.to) + .replace("%MESSAGE%", response.response_message); + getServer().broadcastMessage(response_message); + + // dispatch commands + getServer().getScheduler().runTask(ChatGPTBot.getPlugin(ChatGPTBot.class), () -> { + response.commands.forEach(raw_command -> { + String command = raw_command.replaceFirst("/", ""); + getServer().getLogger().info("ChatGPT: /" + command); + + if (config.getBoolean("dispatch_command_as_player")) { + getServer().dispatchCommand(e.getPlayer(), command); + } else { + getServer().dispatchCommand(ChatGPTBot.getPlugin(ChatGPTBot.class).getServer().getConsoleSender(), command); + } + }); + }); + } + }; + + Thread chatgptThread = new Thread(runnable); + chatgptThread.start(); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..20ee219 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,16 @@ +openai_api_key: "YOUR OPENAI API KEY" +model: "gpt-3.5-turbo" +response_format: " %MESSAGE%" +chat_prefix: "chatgpt " +dispatch_command_as_player: true + +base_input: | + あなたはMinecraftサーバー内で全権限を持っています。プレイヤーの指示に従ってください。 + + 入力 + {"username": 名,"message": メッセージ,"position": [x, y, z]} + + 出力 + {"response_message": 返信,"to": 相手の名前,"commands": [Minecraftコマンドをこの配列へ記述。]} + + 会話がこれから始まります。 \ No newline at end of file