更换okhttp为apache httpclient,尝试减少插件体积

This commit is contained in:
ddaodan 2024-07-12 19:04:05 +08:00
parent 2b79f0e1e8
commit 65665d88df
9 changed files with 174 additions and 96 deletions

View File

@ -20,13 +20,14 @@ repositories {
dependencies { dependencies {
compileOnly "org.spigotmc:spigot-api:1.13-R0.1-SNAPSHOT" 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' implementation 'org.json:json:20231013'
} }
shadowJar { shadowJar {
archiveFileName = "MineChatGPT-${project.version}.jar" 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' relocate 'org.json', 'com.ddaodan.minechatgpt.libs.org.json'
} }

View File

@ -14,7 +14,19 @@
## 安装 ## 安装
- 下载插件放在plugins文件夹中 - 下载插件放在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` ## 配置文件`config.yml`
```yaml ```yaml
# API 相关设置 # API 相关设置
@ -48,7 +60,16 @@ messages:
available_models: "可用模型列表:" available_models: "可用模型列表:"
no_permission: "你没有权限使用这个指令。需要的权限:%s" no_permission: "你没有权限使用这个指令。需要的权限:%s"
``` ```
## 兼容的版本
✔ = 完全支持
= 部分支持
× = 不支持
只列出经过测试的版本
|服务端|支持情况|
|-|-|
|Mohist 1.20.1|✔|
|Spigot 1.20.1|✔|
|Spigot 1.12.2|✔|
## 常见问题 ## 常见问题
### `Failed to contact ChatGPT.` `无法联系ChatGPT。` ### `Failed to contact ChatGPT.` `无法联系ChatGPT。`

View File

@ -3,12 +3,15 @@ package com.ddaodan.MineChatGPT;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.ChatColor; import org.apache.http.client.methods.CloseableHttpResponse;
import okhttp3.*; 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.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.IOException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.List; import java.util.List;
@ -34,49 +37,49 @@ public class CommandHandler implements CommandExecutor {
String subCommand = args[0]; String subCommand = args[0];
if (subCommand.equalsIgnoreCase("reload")) { if (subCommand.equalsIgnoreCase("reload")) {
if (!sender.hasPermission("minechatgpt.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; return true;
} }
configManager.reloadConfig(); configManager.reloadConfig();
sender.sendMessage(ChatColor.GREEN + configManager.getReloadMessage()); sender.sendMessage(configManager.getReloadMessage());
return true; return true;
} else if (subCommand.equalsIgnoreCase("model")) { } else if (subCommand.equalsIgnoreCase("model")) {
if (!sender.hasPermission("minechatgpt.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; return true;
} }
if (args.length < 2) { if (args.length < 2) {
sender.sendMessage(ChatColor.RED + configManager.getUsageMessage()); sender.sendMessage(configManager.getUsageMessage());
return true; return true;
} }
String model = args[1]; String model = args[1];
List<String> models = configManager.getModels(); List<String> models = configManager.getModels();
if (models.contains(model)) { if (models.contains(model)) {
// Logic to switch model // Logic to switch model
sender.sendMessage(ChatColor.GREEN + String.format(configManager.getModelSwitchMessage(), model)); sender.sendMessage(configManager.getModelSwitchMessage().replace("%s", model));
} else { } else {
sender.sendMessage(ChatColor.RED + configManager.getInvalidModelMessage()); sender.sendMessage(configManager.getInvalidModelMessage());
} }
return true; return true;
} else if (subCommand.equalsIgnoreCase("modellist")) { } else if (subCommand.equalsIgnoreCase("modellist")) {
if (!sender.hasPermission("minechatgpt.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; return true;
} }
List<String> models = configManager.getModels(); List<String> models = configManager.getModels();
sender.sendMessage(ChatColor.YELLOW + configManager.getAvailableModelsMessage()); sender.sendMessage(configManager.getAvailableModelsMessage());
for (String model : models) { for (String model : models) {
sender.sendMessage(ChatColor.YELLOW + "- " + model); sender.sendMessage("- " + model);
} }
return true; return true;
} else { } else {
if (!sender.hasPermission("minechatgpt.use")) { 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; return true;
} }
String question = String.join(" ", args); String question = String.join(" ", args);
// Logic to send question to ChatGPT // 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); askChatGPT(sender, question);
return true; return true;
} }
@ -85,9 +88,6 @@ public class CommandHandler implements CommandExecutor {
} }
private void askChatGPT(CommandSender sender, String question) { private void askChatGPT(CommandSender sender, String question) {
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("model", configManager.getDefaultModel()); json.put("model", configManager.getDefaultModel());
JSONArray messages = new JSONArray(); JSONArray messages = new JSONArray();
@ -97,44 +97,35 @@ public class CommandHandler implements CommandExecutor {
messages.put(message); messages.put(message);
json.put("messages", messages); json.put("messages", messages);
RequestBody body = RequestBody.create(mediaType, json.toString()); try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
Request request = new Request.Builder() HttpPost request = new HttpPost(configManager.getBaseUrl() + "/chat/completions");
.url(configManager.getBaseUrl() + "/chat/completions") request.setHeader("Content-Type", "application/json");
.post(body) request.setHeader("Authorization", "Bearer " + configManager.getApiKey());
.addHeader("Content-Type", "application/json") request.setEntity(new StringEntity(json.toString(), "UTF-8"));
.addHeader("Authorization", "Bearer " + configManager.getApiKey())
.build();
client.newCall(request).enqueue(new Callback() { try (CloseableHttpResponse response = httpClient.execute(request)) {
@Override if (response.getStatusLine().getStatusCode() == 200) {
public void onFailure(Call call, IOException e) { String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
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();
JSONObject jsonResponse = new JSONObject(responseBody); JSONObject jsonResponse = new JSONObject(responseBody);
String answer = jsonResponse.getJSONArray("choices").getJSONObject(0).getJSONObject("message").getString("content"); 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 { } 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); 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) { private void sendHelpMessage(CommandSender sender) {
sender.sendMessage(ChatColor.YELLOW + configManager.getHelpMessage()); sender.sendMessage(configManager.getHelpMessage());
sender.sendMessage(ChatColor.YELLOW + configManager.getHelpAskMessage()); sender.sendMessage(configManager.getHelpAskMessage());
sender.sendMessage(ChatColor.YELLOW + configManager.getHelpReloadMessage()); sender.sendMessage(configManager.getHelpReloadMessage());
sender.sendMessage(ChatColor.YELLOW + configManager.getHelpModelMessage()); sender.sendMessage(configManager.getHelpModelMessage());
sender.sendMessage(ChatColor.YELLOW + configManager.getHelpModelListMessage()); sender.sendMessage(configManager.getHelpModelListMessage());
} }
} }

View File

@ -1,5 +1,6 @@
package com.ddaodan.MineChatGPT; package com.ddaodan.MineChatGPT;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import java.util.List; import java.util.List;
@ -17,6 +18,9 @@ public class ConfigManager {
config = plugin.getConfig(); config = plugin.getConfig();
} }
private String translateColorCodes(String message) {
return ChatColor.translateAlternateColorCodes('&', message);
}
public String getApiKey() { public String getApiKey() {
return config.getString("api.key"); return config.getString("api.key");
} }
@ -30,7 +34,7 @@ public class ConfigManager {
} }
public String getReloadMessage() { public String getReloadMessage() {
return config.getString("messages.reload"); return translateColorCodes(config.getString("messages.reload"));
} }
public List<String> getModels() { public List<String> getModels() {
@ -38,54 +42,54 @@ public class ConfigManager {
} }
public String getHelpMessage() { public String getHelpMessage() {
return config.getString("messages.help"); return translateColorCodes(config.getString("messages.help"));
} }
public String getHelpAskMessage() { public String getHelpAskMessage() {
return config.getString("messages.help_ask"); return translateColorCodes(config.getString("messages.help_ask"));
}
public String getHelpModelListMessage() {
return config.getString("messages.help_modellist");
} }
public String getHelpReloadMessage() { public String getHelpReloadMessage() {
return config.getString("messages.help_reload"); return translateColorCodes(config.getString("messages.help_reload"));
} }
public String getHelpModelMessage() { 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() { public String getUsageMessage() {
return config.getString("messages.usage"); return translateColorCodes(config.getString("messages.usage"));
} }
public String getModelSwitchMessage() { public String getModelSwitchMessage() {
return config.getString("messages.model_switch"); return translateColorCodes(config.getString("messages.model_switch"));
} }
public String getChatGPTErrorMessage() { public String getChatGPTErrorMessage() {
return config.getString("messages.chatgpt_error"); return translateColorCodes(config.getString("messages.chatgpt_error"));
} }
public String getChatGPTResponseMessage() { public String getChatGPTResponseMessage() {
return config.getString("messages.chatgpt_response"); return translateColorCodes(config.getString("messages.chatgpt_response"));
} }
public String getQuestionMessage() { public String getQuestionMessage() {
return config.getString("messages.question"); return translateColorCodes(config.getString("messages.question"));
} }
public String getInvalidModelMessage() { public String getInvalidModelMessage() {
return config.getString("messages.invalid_model"); return translateColorCodes(config.getString("messages.invalid_model"));
} }
public String getAvailableModelsMessage() { public String getAvailableModelsMessage() {
return config.getString("messages.available_models"); return translateColorCodes(config.getString("messages.available_models"));
} }
public String getNoPermissionMessage() { public String getNoPermissionMessage() {
return config.getString("messages.no_permission"); return translateColorCodes(config.getString("messages.no_permission"));
} }
} }

View File

@ -7,13 +7,16 @@ import java.util.Objects;
public final class Main extends JavaPlugin { public final class Main extends JavaPlugin {
private ConfigManager configManager; private ConfigManager configManager;
private CommandHandler commandHandler; private CommandHandler commandHandler;
private MineChatGPTTabCompleter tabCompleter;
@Override @Override
public void onEnable() { public void onEnable() {
saveDefaultConfig(); saveDefaultConfig();
configManager = new ConfigManager(this); configManager = new ConfigManager(this);
commandHandler = new CommandHandler(this, configManager); commandHandler = new CommandHandler(this, configManager);
tabCompleter = new MineChatGPTTabCompleter(configManager);
Objects.requireNonNull(getCommand("chatgpt")).setExecutor(commandHandler); Objects.requireNonNull(getCommand("chatgpt")).setExecutor(commandHandler);
Objects.requireNonNull(getCommand("chatgpt")).setTabCompleter(tabCompleter);
} }
@Override @Override

View File

@ -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<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
List<String> 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;
}
}

View File

@ -9,22 +9,33 @@ api:
models: models:
# OpenAI ChatGPT # OpenAI ChatGPT
- "gpt-3.5-turbo" - "gpt-3.5-turbo"
- "gpt-3.5-turbo-instruct"
- "gpt-4" - "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 # The default model to use
default_model: "gpt-3.5-turbo" default_model: "gpt-3.5-turbo"
# Message settings # Message settings
messages: messages:
reload: "Configuration reloaded successfully!" reload: "&aConfiguration reloaded successfully!"
help: "===== MineChatGPT Help =====" help: "&e===== MineChatGPT Help ====="
help_ask: "/chatgpt <text> - Ask ChatGPT a question." help_ask: "&e/chatgpt <text> - Ask ChatGPT a question."
help_reload: "/chatgpt reload - Reload the configuration file." help_reload: "&e/chatgpt reload - Reload the configuration file."
help_model: "/chatgpt model <model_name> - Switch to a different model." help_model: "&e/chatgpt model <model_name> - Switch to a different model."
help_modellist: "/chatgpt modellist - List available models." help_modellist: "&e/chatgpt modellist - List available models."
usage: "Usage: /chatgpt model <model_name>" usage: "&cUsage: /chatgpt model <model_name>"
model_switch: "Model switched to %s" model_switch: "&aModel switched to %s"
chatgpt_error: "Failed to contact ChatGPT." chatgpt_error: "&cFailed to contact ChatGPT."
chatgpt_response: "ChatGPT: %s" chatgpt_response: "&bChatGPT: %s"
question: "Question: %s" question: "&bYou: %s"
invalid_model: "Invalid model. Use /chatgpt modellist to see available models." invalid_model: "&cInvalid model. Use /chatgpt modellist to see available models."
available_models: "Available models:" available_models: "&eAvailable models:"
no_permission: "You do not have permission to use this command. Required permission: %s" no_permission: "&cYou do not have permission to use this command. Required permission: %s"

View File

@ -2,29 +2,40 @@
api: api:
# 你的 OpenAI API key用于身份验证 # 你的 OpenAI API key用于身份验证
# 获取 API key 的方法:访问 //platform.openai.com/account/api-keys 并创建一个新的 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用于构建请求 # OpenAI API 的基础 URL用于构建请求
base_url: "https://api.openai.com/v1" base_url: "https://api.openai.com/v1"
# 支持的模型列表 # 支持的模型列表
models: models:
# OpenAI ChatGPT # OpenAI ChatGPT
- "gpt-3.5-turbo" - "gpt-3.5-turbo"
- "gpt-3.5-turbo-instruct"
- "gpt-4" - "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" default_model: "gpt-3.5-turbo"
# 消息相关设置 # 消息相关设置
messages: messages:
reload: "已重新加载配置文件!" reload: "&a已重新加载配置文件!"
help: "===== MineChatGPT 帮助 =====" help: "&e===== MineChatGPT 帮助 ====="
help_ask: "/chatgpt <text> - 向ChatGPT提问" help_ask: "&e/chatgpt <text> - 向ChatGPT提问"
help_reload: "/chatgpt reload - 重新加载配置文件" help_reload: "&e/chatgpt reload - 重新加载配置文件"
help_model: "/chatgpt model <model_name> - 切换至其他模型" help_model: "&e/chatgpt model <model_name> - 切换至其他模型"
help_modellist: "/chatgpt modellist - 可用的模型列表" help_modellist: "&e/chatgpt modellist - 可用的模型列表"
usage: "输入: /chatgpt model <model_name>" usage: "&c输入: /chatgpt model <model_name>"
model_switch: "已切换至模型 %s" model_switch: "&a已切换至模型 %s"
chatgpt_error: "无法联系ChatGPT。" chatgpt_error: "&c无法联系ChatGPT。"
chatgpt_response: "ChatGPT: %s" chatgpt_response: "&bChatGPT: %s"
question: "你: %s" question: "&b你: %s"
invalid_model: "模型无效。使用 /chatgpt modellist 查看可用模型。" invalid_model: "&c模型无效。使用 /chatgpt modellist 查看可用模型。"
available_models: "可用模型列表:" available_models: "&e可用模型列表:"
no_permission: "你没有权限使用这个指令。需要的权限:%s" no_permission: "&c你没有权限使用这个指令。需要的权限:%s"

View File

@ -7,7 +7,7 @@ description: A Spigot plugin for interacting with ChatGPT
commands: commands:
chatgpt: chatgpt:
description: Interact with ChatGPT description: Interact with ChatGPT
usage: /chatgpt <question> usage: /chatgpt <text>
permissions: permissions:
minechatgpt.use: minechatgpt.use:
description: Allows using the /chatgpt command to interact with AI description: Allows using the /chatgpt command to interact with AI