mirror of
https://github.com/ddaodan/minechatgpt.git
synced 2025-11-03 13:14:13 +08:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c753d51e6b | |||
| 478a1077a6 | |||
| b2e38e09d0 | |||
| f021715cec | |||
| fa5d79e252 | |||
| acdfcda8db |
@@ -4,7 +4,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = 'com'
|
||||
version = '2.3'
|
||||
version = '2.5'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
# 更新日志
|
||||
## 2.5
|
||||
- 允许插件在Folia加载
|
||||
- 修复 #4:[BUG]部分情况下回复乱码
|
||||
## 2.4
|
||||
- 添加自定义prompt
|
||||
- 移除了没有任何效果的配置文件自动更新功能
|
||||
## 2.3
|
||||
- 修复 #3:[BUG]提问乱码/答非所问
|
||||
## 2.2
|
||||
|
||||
64
readme.md
64
readme.md
@@ -5,17 +5,18 @@
|
||||
所有的代码都是ChatGPT写的哦
|
||||
|
||||
## 功能
|
||||
- [x] OpenAPI格式
|
||||
- [x] 自定义模型
|
||||
- [x] ChatGPT反代
|
||||
- [x] 指令补全
|
||||
- [ ] 上下文对话
|
||||
- [ ] 自定义prompt
|
||||
- OpenAPI格式
|
||||
- 自定义模型
|
||||
- ChatGPT反代
|
||||
- 指令补全
|
||||
- 上下文对话
|
||||
- 自定义prompt
|
||||
- Folia支持
|
||||
|
||||
## 安装
|
||||
1. 下载插件,放在plugins文件夹中
|
||||
2. 重启服务器
|
||||
> 为兼容更多版本,插件使用1.13版本进行构建,因此在较高版本加载插件时,控制台会出现以下错误信息,这属于正常现象。
|
||||
> 为兼容更多版本,插件没有规定Bukkit API version,因此在较高版本加载插件时,控制台可能会出现以下错误信息,这属于正常现象。
|
||||
> ```
|
||||
> [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.
|
||||
@@ -30,7 +31,7 @@ api:
|
||||
# OpenAI API 的基础 URL,用于构建请求
|
||||
base_url: "https://api.openai.com/v1"
|
||||
```
|
||||
4. 输入`/chatgpt reload`重新加载配置文件
|
||||
4. 在控制台中输入`/chatgpt reload`重新加载配置文件
|
||||
|
||||
## 截图
|
||||
- 服务端截图(Spigot 1.20.1)
|
||||
@@ -71,14 +72,21 @@ conversation:
|
||||
# 连续对话开关
|
||||
context_enabled: false
|
||||
max_history_size: 10
|
||||
prompt: "You are a helpful assistant.use Chinese."
|
||||
# 消息相关设置
|
||||
messages:
|
||||
reload: "&a已重新加载配置文件!"
|
||||
clear: "&a对话历史已清空!"
|
||||
help: "&e===== MineChatGPT 帮助 ====="
|
||||
help_ask: "&e/chatgpt <text> - 向ChatGPT提问"
|
||||
help_reload: "&e/chatgpt reload - 重新加载配置文件"
|
||||
help_model: "&e/chatgpt model <model_name> - 切换至其他模型"
|
||||
help_modellist: "&e/chatgpt modellist - 可用的模型列表"
|
||||
help_context: "&e/chatgpt context - 切换连续对话模式"
|
||||
help_clear: "/chatgpt clear - 清空对话历史"
|
||||
context_toggle: "&a连续对话模式已%s。"
|
||||
context_toggle_enabled: "开启"
|
||||
context_toggle_disabled: "关闭"
|
||||
current_model_info: "&e当前模型:%s,输入 /chatgpt model <model_name> 来切换模型。"
|
||||
model_switch: "&a已切换至模型 %s"
|
||||
chatgpt_error: "&c无法联系ChatGPT。"
|
||||
@@ -87,42 +95,44 @@ messages:
|
||||
invalid_model: "&c模型无效。使用 /chatgpt modellist 查看可用模型。"
|
||||
available_models: "&e可用模型列表:"
|
||||
no_permission: "&c你没有权限使用这个指令。需要的权限:%s"
|
||||
# 不要动!!!!!
|
||||
version: 2.3
|
||||
# 如果你不知道这是什么,请不要动
|
||||
debug: false
|
||||
```
|
||||
|
||||
## 指令与权限
|
||||
|指令|权限|描述|
|
||||
|-|-|-|
|
||||
|`/chatgpt`|chatgpt.use|查看插件帮助|
|
||||
|`/chatgpt <text>`|chatgpt.use|向ChatGPT提问|
|
||||
|`/chatgpt reload`|chatgpt.reload|重新加载配置文件|
|
||||
|`/chatgpt model <model_name>`|chatgpt.model|切换至其他模型|
|
||||
|`/chatgpt modellist`|chatgpt.modellist|查看可用的模型列表|
|
||||
|`/chatgpt`|minechatgpt.use|查看插件帮助|
|
||||
|`/chatgpt <text>`|minechatgpt.use|向ChatGPT提问|
|
||||
|`/chatgpt reload`|minechatgpt.reload|重新加载配置文件|
|
||||
|`/chatgpt model <model_name>`|minechatgpt.model|切换至其他模型|
|
||||
|`/chatgpt modellist`|minechatgpt.modellist|查看可用的模型列表|
|
||||
|`/chatgpt context`|minechatgpt.context|切换连续对话模式|
|
||||
|`/chatgpt clear`|minechatgpt.clear|清空对话历史|
|
||||
|
||||
## 兼容的版本
|
||||
✔ = 完全支持
|
||||
? = 部分支持
|
||||
× = 不支持
|
||||
只列出经过测试的版本
|
||||
|
||||
|服务端|支持情况|
|
||||
|-|-|
|
||||
|Mohist 1.20.1|✔|
|
||||
|Spigot 1.20.1|✔|
|
||||
|Spigot 1.12.2|✔|
|
||||
|KCauldron 1.7.10|×|
|
||||
|Luminol 1.21|✔ 支持|
|
||||
|Mohist 1.20.1|✔ 支持|
|
||||
|Spigot 1.20.1|✔ 支持|
|
||||
|Spigot 1.12.2|✔ 支持|
|
||||
|KCauldron 1.7.10|× 不支持|
|
||||
|
||||
## 常见问题
|
||||
### `Failed to contact ChatGPT.` `无法联系ChatGPT。`
|
||||
### 提问后显示`Failed to contact ChatGPT.` `无法联系ChatGPT。`
|
||||
检查控制台输出的错误内容。
|
||||
### `connect timeout` `connect reset`
|
||||
### 提问后后台有`connect timeout` `connect reset`等类似的提示
|
||||
检查`config.yml`中的`base_url`能否正常访问。如果你无法连接到OpenAI官方的API地址,可以考虑使用其他反代。
|
||||
### 我可以添加其他模型吗?
|
||||
可以,只要模型支持OpenAI的API,就可以使用。
|
||||
## 我没有ChatGPT的账号,可以用吗?
|
||||
### 我没有ChatGPT的账号,可以用吗?
|
||||
可以,目前有很多代理网站,可以很轻松地使用,而且还支持其他模型,费用通常来说也会比官方便宜。如果你愿意,也可以使用我的代理,目前仅在我的QQ群:226385797中提供。
|
||||
### 是否会支持Folia
|
||||
不会。Folia仍然在开发中,短期内不会支持。
|
||||
理论上插件可以在Folia上运行,但插件的代码并没有针对Folia进行过优化,因此可能会有一些问题。如果你愿意,可以尝试使用Folia运行插件,但不保证插件可以正常运行。
|
||||
## 赞助
|
||||

|
||||
[](https://afdian.com/a/ddaodan)
|
||||
## 统计
|
||||
[](https://bstats.org/plugin/bukkit/MineChatGPT/22635)
|
||||
@@ -11,8 +11,8 @@ import java.util.logging.Logger;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import jodd.http.HttpRequest;
|
||||
import jodd.http.HttpResponse;
|
||||
@@ -36,7 +36,7 @@ public class CommandHandler implements CommandExecutor {
|
||||
|
||||
if (!userContexts.containsKey(userId)) {
|
||||
userContexts.put(userId, new ConversationContext(configManager.getMaxHistorySize()));
|
||||
userContextEnabled.put(userId, configManager.isContextEnabled()); // 使用配置文件中的默认值
|
||||
userContextEnabled.put(userId, configManager.isContextEnabled());
|
||||
}
|
||||
|
||||
ConversationContext conversationContext = userContexts.get(userId);
|
||||
@@ -69,7 +69,6 @@ public class CommandHandler implements CommandExecutor {
|
||||
String model = args[1];
|
||||
List<String> models = configManager.getModels();
|
||||
if (models.contains(model)) {
|
||||
// Logic to switch model
|
||||
configManager.setCurrentModel(model);
|
||||
sender.sendMessage(configManager.getModelSwitchMessage().replace("%s", model));
|
||||
} else {
|
||||
@@ -88,7 +87,7 @@ public class CommandHandler implements CommandExecutor {
|
||||
}
|
||||
return true;
|
||||
} else if (args.length > 0 && args[0].equalsIgnoreCase("context")) {
|
||||
contextEnabled = !contextEnabled; // 切换上下文开关状态
|
||||
contextEnabled = !contextEnabled;
|
||||
userContextEnabled.put(userId, contextEnabled);
|
||||
String status = contextEnabled ? configManager.getContextToggleEnabledMessage() : configManager.getContextToggleDisabledMessage();
|
||||
sender.sendMessage(configManager.getContextToggleMessage().replace("%s", status));
|
||||
@@ -107,9 +106,8 @@ public class CommandHandler implements CommandExecutor {
|
||||
return true;
|
||||
}
|
||||
String question = String.join(" ", args);
|
||||
// Logic to send question to ChatGPT
|
||||
if (contextEnabled) {
|
||||
conversationContext.addMessage(question); // 仅在启用上下文时添加到历史记录
|
||||
conversationContext.addMessage(question);
|
||||
}
|
||||
sender.sendMessage(configManager.getQuestionMessage().replace("%s", question));
|
||||
askChatGPT(sender, question, conversationContext, contextEnabled);
|
||||
@@ -120,18 +118,21 @@ public class CommandHandler implements CommandExecutor {
|
||||
}
|
||||
|
||||
private void askChatGPT(CommandSender sender, String question, ConversationContext conversationContext, boolean contextEnabled) {
|
||||
|
||||
logger.info("Original question: " + question);
|
||||
// 尝试将问题转换为 UTF-8 编码
|
||||
String utf8Question = convertToUTF8(question);
|
||||
logger.info("Converted question: " + utf8Question);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("model", configManager.getDefaultModel());
|
||||
JSONArray messages = new JSONArray();
|
||||
// 添加自定义 prompt
|
||||
String customPrompt = configManager.getCustomPrompt();
|
||||
if (!customPrompt.isEmpty()) {
|
||||
JSONObject promptMessage = new JSONObject();
|
||||
promptMessage.put("role", "system");
|
||||
promptMessage.put("content", customPrompt);
|
||||
messages.put(promptMessage);
|
||||
}
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("role", "user");
|
||||
message.put("content", utf8Question);
|
||||
//message.put("content", question);
|
||||
messages.put(message);
|
||||
if (contextEnabled) {
|
||||
String history = conversationContext.getConversationHistory();
|
||||
@@ -144,8 +145,9 @@ public class CommandHandler implements CommandExecutor {
|
||||
}
|
||||
json.put("messages", messages);
|
||||
json.put("model", configManager.getCurrentModel());
|
||||
// 记录构建的请求
|
||||
logger.info("Built request: " + json.toString());
|
||||
if (configManager.isDebugMode()) {
|
||||
logger.info("Built request: " + json.toString());
|
||||
}
|
||||
|
||||
HttpRequest request = HttpRequest.post(configManager.getBaseUrl() + "/chat/completions")
|
||||
.header("Content-Type", "application/json; charset=UTF-8")
|
||||
@@ -156,26 +158,34 @@ public class CommandHandler implements CommandExecutor {
|
||||
logger.info("Sending request to ChatGPT: " + request.toString());
|
||||
}
|
||||
|
||||
HttpResponse response = request.send();
|
||||
|
||||
if (configManager.isDebugMode()) {
|
||||
logger.info("Received response from ChatGPT: " + response.toString());
|
||||
}
|
||||
|
||||
if (response.statusCode() == 200) {
|
||||
String responseBody = response.bodyText();
|
||||
JSONObject jsonResponse = new JSONObject(responseBody);
|
||||
String answer = jsonResponse.getJSONArray("choices").getJSONObject(0).getJSONObject("message").getString("content");
|
||||
sender.sendMessage(configManager.getChatGPTResponseMessage().replace("%s", answer));
|
||||
if (contextEnabled) {
|
||||
conversationContext.addMessage(answer); // 仅在启用上下文时添加AI响应到历史记录
|
||||
}
|
||||
} else {
|
||||
String errorBody = response.bodyText();
|
||||
logger.log(Level.SEVERE, "Failed to get a response from ChatGPT: " + errorBody);
|
||||
sender.sendMessage(configManager.getChatGPTErrorMessage());
|
||||
}
|
||||
//HttpResponse response = request.send();
|
||||
CompletableFuture.supplyAsync(() -> request.send())
|
||||
.thenAccept(response -> {
|
||||
if (configManager.isDebugMode()) {
|
||||
logger.info("Received response from ChatGPT: " + response.toString());
|
||||
}
|
||||
if (response.statusCode() == 200) {
|
||||
String responseBody = response.bodyText();
|
||||
String utf8ResponseBody = new String(responseBody.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
|
||||
JSONObject jsonResponse = new JSONObject(utf8ResponseBody);
|
||||
String answer = jsonResponse.getJSONArray("choices").getJSONObject(0).getJSONObject("message").getString("content");
|
||||
sender.sendMessage(configManager.getChatGPTResponseMessage().replace("%s", answer));
|
||||
if (contextEnabled) {
|
||||
conversationContext.addMessage(answer); // 仅在启用上下文时添加AI响应到历史记录
|
||||
}
|
||||
} else {
|
||||
String errorBody = response.bodyText();
|
||||
logger.log(Level.SEVERE, "Failed to get a response from ChatGPT: " + errorBody);
|
||||
sender.sendMessage(configManager.getChatGPTErrorMessage());
|
||||
}
|
||||
})
|
||||
.exceptionally(e -> {
|
||||
logger.log(Level.SEVERE, "Exception occurred while processing request: " + e.getMessage(), e);
|
||||
sender.sendMessage(configManager.getChatGPTErrorMessage());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private String convertToUTF8(String input) {
|
||||
try {
|
||||
// 尝试将输入字符串转换为 UTF-8 编码
|
||||
|
||||
@@ -25,117 +25,90 @@ public class ConfigManager {
|
||||
private String translateColorCodes(String message) {
|
||||
return ChatColor.translateAlternateColorCodes('&', message);
|
||||
}
|
||||
|
||||
public String getCurrentModel() {
|
||||
return currentModel;
|
||||
}
|
||||
|
||||
public void setCurrentModel(String model) {
|
||||
currentModel = model;
|
||||
}
|
||||
public String getConfigVersion() {
|
||||
return config.getString("version", "1.0");
|
||||
}
|
||||
public String getApiKey() {
|
||||
return config.getString("api.key");
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return config.getString("api.base_url");
|
||||
}
|
||||
|
||||
public String getDefaultModel() {
|
||||
return config.getString("default_model");
|
||||
}
|
||||
|
||||
public String getReloadMessage() {
|
||||
return translateColorCodes(config.getString("messages.reload"));
|
||||
}
|
||||
|
||||
public List<String> getModels() {
|
||||
return config.getStringList("models");
|
||||
}
|
||||
|
||||
public String getCustomPrompt() {
|
||||
return config.getString("prompt", "You are a helpful assistant.");
|
||||
}
|
||||
public String getHelpMessage() {
|
||||
return translateColorCodes(config.getString("messages.help"));
|
||||
}
|
||||
|
||||
public String getHelpAskMessage() {
|
||||
return translateColorCodes(config.getString("messages.help_ask"));
|
||||
}
|
||||
|
||||
public String getHelpReloadMessage() {
|
||||
return translateColorCodes(config.getString("messages.help_reload"));
|
||||
}
|
||||
|
||||
public String getHelpModelMessage() {
|
||||
return translateColorCodes(config.getString("messages.help_model"));
|
||||
}
|
||||
|
||||
public String getHelpModelListMessage() {
|
||||
return translateColorCodes(config.getString("messages.help_modellist"));
|
||||
}
|
||||
|
||||
|
||||
public String getHelpContextMessage() {
|
||||
return translateColorCodes(config.getString("messages.help_context", "/chatgpt context - Toggle context mode."));
|
||||
}
|
||||
|
||||
public String getHelpClearMessage() {
|
||||
return translateColorCodes(config.getString("messages.help_clear", "/chatgpt clear - Clear conversation history."));
|
||||
}
|
||||
|
||||
public String getModelSwitchMessage() {
|
||||
return translateColorCodes(config.getString("messages.model_switch"));
|
||||
}
|
||||
|
||||
public String getChatGPTErrorMessage() {
|
||||
return translateColorCodes(config.getString("messages.chatgpt_error"));
|
||||
}
|
||||
|
||||
public String getChatGPTResponseMessage() {
|
||||
return translateColorCodes(config.getString("messages.chatgpt_response"));
|
||||
}
|
||||
|
||||
public String getQuestionMessage() {
|
||||
return translateColorCodes(config.getString("messages.question"));
|
||||
}
|
||||
|
||||
public String getInvalidModelMessage() {
|
||||
return translateColorCodes(config.getString("messages.invalid_model"));
|
||||
}
|
||||
|
||||
public String getAvailableModelsMessage() {
|
||||
return translateColorCodes(config.getString("messages.available_models"));
|
||||
}
|
||||
|
||||
public String getNoPermissionMessage() {
|
||||
return translateColorCodes(config.getString("messages.no_permission"));
|
||||
}
|
||||
|
||||
public String getCurrentModelInfoMessage() {
|
||||
return translateColorCodes(config.getString("messages.current_model_info"));
|
||||
}
|
||||
|
||||
public int getMaxHistorySize() {
|
||||
return config.getInt("conversation.max_history_size", 10);
|
||||
}
|
||||
|
||||
public boolean isContextEnabled() {
|
||||
return config.getBoolean("conversation.context_enabled", false);
|
||||
}
|
||||
|
||||
public String getContextToggleMessage() {
|
||||
return translateColorCodes(config.getString("messages.context_toggle", "Context is now %s."));
|
||||
}
|
||||
public String getContextToggleEnabledMessage() {
|
||||
return translateColorCodes(config.getString("messages.context_toggle_enabled", "enabled"));
|
||||
}
|
||||
|
||||
public String getContextToggleDisabledMessage() {
|
||||
return translateColorCodes(config.getString("messages.context_toggle_disabled", "disabled"));
|
||||
}
|
||||
|
||||
public String getClearMessage() {
|
||||
return translateColorCodes(config.getString("messages.clear", "Conversation history has been cleared."));
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ public class ConversationContext {
|
||||
|
||||
public void addMessage(String message) {
|
||||
if (conversationHistory.size() >= maxHistorySize) {
|
||||
conversationHistory.poll(); // Remove the oldest message
|
||||
conversationHistory.poll();
|
||||
}
|
||||
conversationHistory.offer(message); // Add the new message
|
||||
conversationHistory.offer(message);
|
||||
}
|
||||
|
||||
public String getConversationHistory() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.ddaodan.MineChatGPT;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
|
||||
@@ -19,7 +18,6 @@ public final class Main extends JavaPlugin {
|
||||
tabCompleter = new MineChatGPTTabCompleter(configManager);
|
||||
Objects.requireNonNull(getCommand("chatgpt")).setExecutor(commandHandler);
|
||||
Objects.requireNonNull(getCommand("chatgpt")).setTabCompleter(tabCompleter);
|
||||
checkAndUpdateConfig();
|
||||
if (configManager.isDebugMode()) {
|
||||
getLogger().info( "DEBUG MODE IS TRUE!!!!!");
|
||||
}
|
||||
@@ -32,27 +30,4 @@ public final class Main extends JavaPlugin {
|
||||
public void onDisable() {
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
private void checkAndUpdateConfig() {
|
||||
String currentVersion = getConfig().getString("version", "1.0");
|
||||
String pluginVersion = getDescription().getVersion();
|
||||
|
||||
if (!currentVersion.equals(pluginVersion)) {
|
||||
// 加载默认配置文件
|
||||
FileConfiguration defaultConfig = getConfig();
|
||||
reloadConfig();
|
||||
FileConfiguration newConfig = getConfig();
|
||||
|
||||
// 合并配置文件
|
||||
for (String key : defaultConfig.getKeys(true)) {
|
||||
if (!newConfig.contains(key)) {
|
||||
newConfig.set(key, defaultConfig.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
// 更新版本号
|
||||
newConfig.set("version", pluginVersion);
|
||||
saveConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ conversation:
|
||||
# Continuous conversation switch
|
||||
context_enabled: false
|
||||
max_history_size: 10
|
||||
prompt: "You are a helpful assistant."
|
||||
# Message settings
|
||||
messages:
|
||||
reload: "&aConfiguration reloaded successfully!"
|
||||
@@ -51,6 +52,4 @@ messages:
|
||||
available_models: "&eAvailable models:"
|
||||
no_permission: "&cYou do not have permission to use this command. Required permission: %s"
|
||||
# If you don't know what this is, don't change it
|
||||
debug: false
|
||||
# DO NOT EDIT!!!!!
|
||||
version: 2.3
|
||||
debug: false
|
||||
@@ -28,6 +28,7 @@ conversation:
|
||||
# 连续对话开关
|
||||
context_enabled: false
|
||||
max_history_size: 10
|
||||
prompt: "You are a helpful assistant.use Chinese."
|
||||
# 消息相关设置
|
||||
messages:
|
||||
reload: "&a已重新加载配置文件!"
|
||||
@@ -51,6 +52,4 @@ messages:
|
||||
available_models: "&e可用模型列表:"
|
||||
no_permission: "&c你没有权限使用这个指令。需要的权限:%s"
|
||||
# 如果你不知道这是什么,请不要动
|
||||
debug: false
|
||||
# 不要动!!!!!
|
||||
version: 2.3
|
||||
debug: false
|
||||
@@ -2,6 +2,7 @@ name: MineChatGPT
|
||||
version: '${version}'
|
||||
main: com.ddaodan.MineChatGPT.Main
|
||||
author: ddaodan
|
||||
folia-supported: true
|
||||
description: A Spigot plugin for interacting with ChatGPT
|
||||
|
||||
commands:
|
||||
@@ -24,6 +25,6 @@ permissions:
|
||||
minechatgpt.context:
|
||||
description: Allows toggling context mode
|
||||
default: true
|
||||
chatgpt.clear:
|
||||
minechatgpt.clear:
|
||||
description: Allows clearing conversation history
|
||||
default: true
|
||||
Reference in New Issue
Block a user