From 65665d88df804ecbe63f708e4be7a11817bdc845 Mon Sep 17 00:00:00 2001 From: ddaodan <731882332@qq.com> Date: Fri, 12 Jul 2024 19:04:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=8D=A2okhttp=E4=B8=BAapache=20httpc?= =?UTF-8?q?lient=EF=BC=8C=E5=B0=9D=E8=AF=95=E5=87=8F=E5=B0=91=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E4=BD=93=E7=A7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 5 +- readme.md | 23 ++++- .../ddaodan/MineChatGPT/CommandHandler.java | 83 +++++++++---------- .../ddaodan/MineChatGPT/ConfigManager.java | 38 +++++---- .../java/com/ddaodan/MineChatGPT/Main.java | 3 + .../MineChatGPT/MineChatGPTTabCompleter.java | 36 ++++++++ src/main/resources/config.yml | 39 +++++---- src/main/resources/config_zh.yml | 41 +++++---- src/main/resources/plugin.yml | 2 +- 9 files changed, 174 insertions(+), 96 deletions(-) create mode 100644 src/main/java/com/ddaodan/MineChatGPT/MineChatGPTTabCompleter.java diff --git a/build.gradle b/build.gradle index 6af88e1..e8c892c 100644 --- a/build.gradle +++ b/build.gradle @@ -20,13 +20,14 @@ repositories { dependencies { compileOnly "org.spigotmc:spigot-api:1.13-R0.1-SNAPSHOT" - implementation 'com.squareup.okhttp3:okhttp:4.9.3' + implementation 'org.apache.httpcomponents:httpclient:4.5.14' + //implementation 'org.apache.httpcomponents.client5:httpclient5:5.4-beta1' implementation 'org.json:json:20231013' } shadowJar { archiveFileName = "MineChatGPT-${project.version}.jar" - relocate 'okhttp3', 'com.ddaodan.minechatgpt.libs.okhttp3' + relocate 'org.apache.http', 'com.ddaodan.shaded.org.apache.http' relocate 'org.json', 'com.ddaodan.minechatgpt.libs.org.json' } diff --git a/readme.md b/readme.md index cd07a92..d09be28 100644 --- a/readme.md +++ b/readme.md @@ -14,7 +14,19 @@ ## 安装 - 下载插件,放在plugins文件夹中 - 重启服务器 +> 为兼容更多版本,插件使用1.13版本进行构建,因此在较高版本加载插件时,控制台会出现以下错误信息,这属于正常现象。 +> ``` +> [Server thread/WARN]: Initializing Legacy Material Support. Unless you have legacy plugins and/or data this is a bug! +> [Server thread/WARN]: Legacy plugin MineChatGPT v1.0 does not specify an api-version. +> ``` +## 截图 +- 服务端截图(Spigot 1.20.1) +![](https://i.ddaodan.cn/images/CWindowssystem32cmd.exe_20240712406.png) +- 插件截图 +![](https://i.ddaodan.cn/images/Minecraft_1.20.1_-__20240712407.png) +- 对话截图(使用FastGPT训练的自定义知识库) +![](https://i.ddaodan.cn/images/Minecraft_1.20.1_-__20240712408.png) ## 配置文件`config.yml` ```yaml # API 相关设置 @@ -48,7 +60,16 @@ messages: available_models: "可用模型列表:" no_permission: "你没有权限使用这个指令。需要的权限:%s" ``` - +## 兼容的版本 +✔ = 完全支持 +? = 部分支持 +× = 不支持 +只列出经过测试的版本 +|服务端|支持情况| +|-|-| +|Mohist 1.20.1|✔| +|Spigot 1.20.1|✔| +|Spigot 1.12.2|✔| ## 常见问题 ### `Failed to contact ChatGPT.` `无法联系ChatGPT。` diff --git a/src/main/java/com/ddaodan/MineChatGPT/CommandHandler.java b/src/main/java/com/ddaodan/MineChatGPT/CommandHandler.java index 46e19d6..f503db0 100644 --- a/src/main/java/com/ddaodan/MineChatGPT/CommandHandler.java +++ b/src/main/java/com/ddaodan/MineChatGPT/CommandHandler.java @@ -3,12 +3,15 @@ package com.ddaodan.MineChatGPT; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; -import org.bukkit.ChatColor; -import okhttp3.*; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; import org.json.JSONArray; import org.json.JSONObject; -import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.List; @@ -34,49 +37,49 @@ public class CommandHandler implements CommandExecutor { String subCommand = args[0]; if (subCommand.equalsIgnoreCase("reload")) { if (!sender.hasPermission("minechatgpt.reload")) { - sender.sendMessage(ChatColor.RED + String.format(configManager.getNoPermissionMessage(), "minechatgpt.reload")); + sender.sendMessage(configManager.getNoPermissionMessage().replace("%s", "minechatgpt.reload")); return true; } configManager.reloadConfig(); - sender.sendMessage(ChatColor.GREEN + configManager.getReloadMessage()); + sender.sendMessage(configManager.getReloadMessage()); return true; } else if (subCommand.equalsIgnoreCase("model")) { if (!sender.hasPermission("minechatgpt.model")) { - sender.sendMessage(ChatColor.RED + String.format(configManager.getNoPermissionMessage(), "minechatgpt.model")); + sender.sendMessage(configManager.getNoPermissionMessage().replace("%s", "minechatgpt.model")); return true; } if (args.length < 2) { - sender.sendMessage(ChatColor.RED + configManager.getUsageMessage()); + sender.sendMessage(configManager.getUsageMessage()); return true; } String model = args[1]; List models = configManager.getModels(); if (models.contains(model)) { // Logic to switch model - sender.sendMessage(ChatColor.GREEN + String.format(configManager.getModelSwitchMessage(), model)); + sender.sendMessage(configManager.getModelSwitchMessage().replace("%s", model)); } else { - sender.sendMessage(ChatColor.RED + configManager.getInvalidModelMessage()); + sender.sendMessage(configManager.getInvalidModelMessage()); } return true; } else if (subCommand.equalsIgnoreCase("modellist")) { if (!sender.hasPermission("minechatgpt.modellist")) { - sender.sendMessage(ChatColor.RED + String.format(configManager.getNoPermissionMessage(), "minechatgpt.modellist")); + sender.sendMessage(configManager.getNoPermissionMessage().replace("%s", "minechatgpt.modellist")); return true; } List models = configManager.getModels(); - sender.sendMessage(ChatColor.YELLOW + configManager.getAvailableModelsMessage()); + sender.sendMessage(configManager.getAvailableModelsMessage()); for (String model : models) { - sender.sendMessage(ChatColor.YELLOW + "- " + model); + sender.sendMessage("- " + model); } return true; } else { if (!sender.hasPermission("minechatgpt.use")) { - sender.sendMessage(ChatColor.RED + String.format(configManager.getNoPermissionMessage(), "minechatgpt.use")); + sender.sendMessage(configManager.getNoPermissionMessage().replace("%s", "minechatgpt.use")); return true; } String question = String.join(" ", args); // Logic to send question to ChatGPT - sender.sendMessage(ChatColor.AQUA + String.format(configManager.getQuestionMessage(), question)); + sender.sendMessage(configManager.getQuestionMessage().replace("%s", question)); askChatGPT(sender, question); return true; } @@ -85,9 +88,6 @@ public class CommandHandler implements CommandExecutor { } private void askChatGPT(CommandSender sender, String question) { - OkHttpClient client = new OkHttpClient(); - - MediaType mediaType = MediaType.parse("application/json"); JSONObject json = new JSONObject(); json.put("model", configManager.getDefaultModel()); JSONArray messages = new JSONArray(); @@ -97,44 +97,35 @@ public class CommandHandler implements CommandExecutor { messages.put(message); json.put("messages", messages); - RequestBody body = RequestBody.create(mediaType, json.toString()); - Request request = new Request.Builder() - .url(configManager.getBaseUrl() + "/chat/completions") - .post(body) - .addHeader("Content-Type", "application/json") - .addHeader("Authorization", "Bearer " + configManager.getApiKey()) - .build(); + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost request = new HttpPost(configManager.getBaseUrl() + "/chat/completions"); + request.setHeader("Content-Type", "application/json"); + request.setHeader("Authorization", "Bearer " + configManager.getApiKey()); + request.setEntity(new StringEntity(json.toString(), "UTF-8")); - client.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(Call call, IOException e) { - e.printStackTrace(); - logger.log(Level.SEVERE, "Failed to contact ChatGPT: " + e.getMessage(), e); - sender.sendMessage(ChatColor.RED + configManager.getChatGPTErrorMessage()); - } - - @Override - public void onResponse(Call call, Response response) throws IOException { - if (response.isSuccessful()) { - String responseBody = response.body().string(); + try (CloseableHttpResponse response = httpClient.execute(request)) { + if (response.getStatusLine().getStatusCode() == 200) { + String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8"); JSONObject jsonResponse = new JSONObject(responseBody); String answer = jsonResponse.getJSONArray("choices").getJSONObject(0).getJSONObject("message").getString("content"); - sender.sendMessage(ChatColor.AQUA + String.format(configManager.getChatGPTResponseMessage(), answer)); + sender.sendMessage(configManager.getChatGPTResponseMessage().replace("%s", answer)); } else { - String errorBody = response.body().string(); + String errorBody = EntityUtils.toString(response.getEntity(), "UTF-8"); logger.log(Level.SEVERE, "Failed to get a response from ChatGPT: " + errorBody); - sender.sendMessage(ChatColor.RED + configManager.getChatGPTErrorMessage()); + sender.sendMessage(configManager.getChatGPTErrorMessage()); } - response.close(); } - }); + } catch (Exception e) { + logger.log(Level.SEVERE, "Failed to contact ChatGPT: " + e.getMessage(), e); + sender.sendMessage(configManager.getChatGPTErrorMessage()); + } } private void sendHelpMessage(CommandSender sender) { - sender.sendMessage(ChatColor.YELLOW + configManager.getHelpMessage()); - sender.sendMessage(ChatColor.YELLOW + configManager.getHelpAskMessage()); - sender.sendMessage(ChatColor.YELLOW + configManager.getHelpReloadMessage()); - sender.sendMessage(ChatColor.YELLOW + configManager.getHelpModelMessage()); - sender.sendMessage(ChatColor.YELLOW + configManager.getHelpModelListMessage()); + sender.sendMessage(configManager.getHelpMessage()); + sender.sendMessage(configManager.getHelpAskMessage()); + sender.sendMessage(configManager.getHelpReloadMessage()); + sender.sendMessage(configManager.getHelpModelMessage()); + sender.sendMessage(configManager.getHelpModelListMessage()); } } \ No newline at end of file diff --git a/src/main/java/com/ddaodan/MineChatGPT/ConfigManager.java b/src/main/java/com/ddaodan/MineChatGPT/ConfigManager.java index 6dd15b3..a6b14d2 100644 --- a/src/main/java/com/ddaodan/MineChatGPT/ConfigManager.java +++ b/src/main/java/com/ddaodan/MineChatGPT/ConfigManager.java @@ -1,5 +1,6 @@ package com.ddaodan.MineChatGPT; +import org.bukkit.ChatColor; import org.bukkit.configuration.file.FileConfiguration; import java.util.List; @@ -17,6 +18,9 @@ public class ConfigManager { config = plugin.getConfig(); } + private String translateColorCodes(String message) { + return ChatColor.translateAlternateColorCodes('&', message); + } public String getApiKey() { return config.getString("api.key"); } @@ -30,7 +34,7 @@ public class ConfigManager { } public String getReloadMessage() { - return config.getString("messages.reload"); + return translateColorCodes(config.getString("messages.reload")); } public List getModels() { @@ -38,54 +42,54 @@ public class ConfigManager { } public String getHelpMessage() { - return config.getString("messages.help"); + return translateColorCodes(config.getString("messages.help")); } public String getHelpAskMessage() { - return config.getString("messages.help_ask"); - } - - public String getHelpModelListMessage() { - return config.getString("messages.help_modellist"); + return translateColorCodes(config.getString("messages.help_ask")); } public String getHelpReloadMessage() { - return config.getString("messages.help_reload"); + return translateColorCodes(config.getString("messages.help_reload")); } public String getHelpModelMessage() { - return config.getString("messages.help_model"); + return translateColorCodes(config.getString("messages.help_model")); + } + + public String getHelpModelListMessage() { + return translateColorCodes(config.getString("messages.help_modellist")); } public String getUsageMessage() { - return config.getString("messages.usage"); + return translateColorCodes(config.getString("messages.usage")); } public String getModelSwitchMessage() { - return config.getString("messages.model_switch"); + return translateColorCodes(config.getString("messages.model_switch")); } public String getChatGPTErrorMessage() { - return config.getString("messages.chatgpt_error"); + return translateColorCodes(config.getString("messages.chatgpt_error")); } public String getChatGPTResponseMessage() { - return config.getString("messages.chatgpt_response"); + return translateColorCodes(config.getString("messages.chatgpt_response")); } public String getQuestionMessage() { - return config.getString("messages.question"); + return translateColorCodes(config.getString("messages.question")); } public String getInvalidModelMessage() { - return config.getString("messages.invalid_model"); + return translateColorCodes(config.getString("messages.invalid_model")); } public String getAvailableModelsMessage() { - return config.getString("messages.available_models"); + return translateColorCodes(config.getString("messages.available_models")); } public String getNoPermissionMessage() { - return config.getString("messages.no_permission"); + return translateColorCodes(config.getString("messages.no_permission")); } } \ No newline at end of file diff --git a/src/main/java/com/ddaodan/MineChatGPT/Main.java b/src/main/java/com/ddaodan/MineChatGPT/Main.java index 64649f4..09e1ffe 100644 --- a/src/main/java/com/ddaodan/MineChatGPT/Main.java +++ b/src/main/java/com/ddaodan/MineChatGPT/Main.java @@ -7,13 +7,16 @@ import java.util.Objects; public final class Main extends JavaPlugin { private ConfigManager configManager; private CommandHandler commandHandler; + private MineChatGPTTabCompleter tabCompleter; @Override public void onEnable() { saveDefaultConfig(); configManager = new ConfigManager(this); commandHandler = new CommandHandler(this, configManager); + tabCompleter = new MineChatGPTTabCompleter(configManager); Objects.requireNonNull(getCommand("chatgpt")).setExecutor(commandHandler); + Objects.requireNonNull(getCommand("chatgpt")).setTabCompleter(tabCompleter); } @Override diff --git a/src/main/java/com/ddaodan/MineChatGPT/MineChatGPTTabCompleter.java b/src/main/java/com/ddaodan/MineChatGPT/MineChatGPTTabCompleter.java new file mode 100644 index 0000000..5e4ae36 --- /dev/null +++ b/src/main/java/com/ddaodan/MineChatGPT/MineChatGPTTabCompleter.java @@ -0,0 +1,36 @@ +package com.ddaodan.MineChatGPT; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +import java.util.ArrayList; +import java.util.List; +public class MineChatGPTTabCompleter implements TabCompleter { + + private final ConfigManager configManager; + + public MineChatGPTTabCompleter(ConfigManager configManager) { + this.configManager = configManager; + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + List completions = new ArrayList<>(); + + if (args.length == 1) { + // 补全子命令 + completions.add("reload"); + completions.add("model"); + completions.add("modellist"); + } else if (args.length == 2 && args[0].equalsIgnoreCase("model")) { + // 补全模型名称 + completions.addAll(configManager.getModels()); + } + + // 过滤补全列表以匹配输入 + completions.removeIf(completion -> !completion.toLowerCase().startsWith(args[args.length - 1].toLowerCase())); + + return completions; + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b4e6a75..02f3aa0 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -9,22 +9,33 @@ api: models: # OpenAI ChatGPT - "gpt-3.5-turbo" + - "gpt-3.5-turbo-instruct" - "gpt-4" + - "gpt-4-turbo" + - "gpt-4-turbo-preview" + - "gpt-4o" + # Google Gemini + # - "gemini-pro" + # - "gemini-1.5-pro" + # Anthropic Claude + # - "claude-3-opus" + # - "claude-3-5-sonnet" + # And more... # The default model to use default_model: "gpt-3.5-turbo" # Message settings messages: - reload: "Configuration reloaded successfully!" - help: "===== MineChatGPT Help =====" - help_ask: "/chatgpt - Ask ChatGPT a question." - help_reload: "/chatgpt reload - Reload the configuration file." - help_model: "/chatgpt model - Switch to a different model." - help_modellist: "/chatgpt modellist - List available models." - usage: "Usage: /chatgpt model " - model_switch: "Model switched to %s" - chatgpt_error: "Failed to contact ChatGPT." - chatgpt_response: "ChatGPT: %s" - question: "Question: %s" - invalid_model: "Invalid model. Use /chatgpt modellist to see available models." - available_models: "Available models:" - no_permission: "You do not have permission to use this command. Required permission: %s" \ No newline at end of file + reload: "&aConfiguration reloaded successfully!" + help: "&e===== MineChatGPT Help =====" + help_ask: "&e/chatgpt - Ask ChatGPT a question." + help_reload: "&e/chatgpt reload - Reload the configuration file." + help_model: "&e/chatgpt model - Switch to a different model." + help_modellist: "&e/chatgpt modellist - List available models." + usage: "&cUsage: /chatgpt model " + model_switch: "&aModel switched to %s" + chatgpt_error: "&cFailed to contact ChatGPT." + chatgpt_response: "&bChatGPT: %s" + question: "&bYou: %s" + invalid_model: "&cInvalid model. Use /chatgpt modellist to see available models." + available_models: "&eAvailable models:" + no_permission: "&cYou do not have permission to use this command. Required permission: %s" \ No newline at end of file diff --git a/src/main/resources/config_zh.yml b/src/main/resources/config_zh.yml index 217d314..b7cbea8 100644 --- a/src/main/resources/config_zh.yml +++ b/src/main/resources/config_zh.yml @@ -2,29 +2,40 @@ api: # 你的 OpenAI API key,用于身份验证 # 获取 API key 的方法:访问 //platform.openai.com/account/api-keys 并创建一个新的 API key - key: "your_openai_api_key" + key: "sk-your_openai_api_key" # OpenAI API 的基础 URL,用于构建请求 base_url: "https://api.openai.com/v1" # 支持的模型列表 models: # OpenAI ChatGPT - "gpt-3.5-turbo" + - "gpt-3.5-turbo-instruct" - "gpt-4" + - "gpt-4-turbo" + - "gpt-4-turbo-preview" + - "gpt-4o" + # Google Gemini + # - "gemini-pro" + # - "gemini-1.5-pro" + # Anthropic Claude + # - "claude-3-opus" + # - "claude-3-5-sonnet" + # 以及更多... # 默认使用的模型 default_model: "gpt-3.5-turbo" # 消息相关设置 messages: - reload: "已重新加载配置文件!" - help: "===== MineChatGPT 帮助 =====" - help_ask: "/chatgpt - 向ChatGPT提问" - help_reload: "/chatgpt reload - 重新加载配置文件" - help_model: "/chatgpt model - 切换至其他模型" - help_modellist: "/chatgpt modellist - 可用的模型列表" - usage: "输入: /chatgpt model " - model_switch: "已切换至模型 %s" - chatgpt_error: "无法联系ChatGPT。" - chatgpt_response: "ChatGPT: %s" - question: "你: %s" - invalid_model: "模型无效。使用 /chatgpt modellist 查看可用模型。" - available_models: "可用模型列表:" - no_permission: "你没有权限使用这个指令。需要的权限:%s" \ No newline at end of file + reload: "&a已重新加载配置文件!" + help: "&e===== MineChatGPT 帮助 =====" + help_ask: "&e/chatgpt - 向ChatGPT提问" + help_reload: "&e/chatgpt reload - 重新加载配置文件" + help_model: "&e/chatgpt model - 切换至其他模型" + help_modellist: "&e/chatgpt modellist - 可用的模型列表" + usage: "&c输入: /chatgpt model " + model_switch: "&a已切换至模型 %s" + chatgpt_error: "&c无法联系ChatGPT。" + chatgpt_response: "&bChatGPT: %s" + question: "&b你: %s" + invalid_model: "&c模型无效。使用 /chatgpt modellist 查看可用模型。" + available_models: "&e可用模型列表:" + no_permission: "&c你没有权限使用这个指令。需要的权限:%s" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e233af4..d359219 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -7,7 +7,7 @@ description: A Spigot plugin for interacting with ChatGPT commands: chatgpt: description: Interact with ChatGPT - usage: /chatgpt + usage: /chatgpt permissions: minechatgpt.use: description: Allows using the /chatgpt command to interact with AI