From cd7cc341ab1d63f7454b2f2313e05cf7f97a6b89 Mon Sep 17 00:00:00 2001 From: RTAkland Date: Sun, 15 Sep 2024 13:27:14 +0800 Subject: [PATCH] feat: add gpt command --- src/main/kotlin/cn/rtast/fancybot/Const.kt | 4 +- src/main/kotlin/cn/rtast/fancybot/FancyBot.kt | 3 +- .../fancybot/commands/lookup/GPTCommand.kt | 69 +++++++++++++++++++ .../kotlin/cn/rtast/fancybot/entity/Config.kt | 2 + .../fancybot/entity/enums/GPTUserRole.kt | 12 ++++ .../entity/gpt/ChatCompletionsPayload.kt | 21 ++++++ .../entity/gpt/ChatCompletionsResponse.kt | 23 +++++++ .../cn/rtast/fancybot/entity/gpt/ModelList.kt | 16 +++++ .../kotlin/cn/rtast/fancybot/util/Http.kt | 22 ------ .../rtast/fancybot/util/file/ConfigManager.kt | 2 + src/main/resources/config.json | 5 +- 11 files changed, 154 insertions(+), 25 deletions(-) create mode 100644 src/main/kotlin/cn/rtast/fancybot/commands/lookup/GPTCommand.kt create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/enums/GPTUserRole.kt create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/gpt/ChatCompletionsPayload.kt create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/gpt/ChatCompletionsResponse.kt create mode 100644 src/main/kotlin/cn/rtast/fancybot/entity/gpt/ModelList.kt diff --git a/src/main/kotlin/cn/rtast/fancybot/Const.kt b/src/main/kotlin/cn/rtast/fancybot/Const.kt index 31f837a..fba1dd5 100644 --- a/src/main/kotlin/cn/rtast/fancybot/Const.kt +++ b/src/main/kotlin/cn/rtast/fancybot/Const.kt @@ -29,7 +29,9 @@ val DEFAULT_CONFIG = Config( listeningGroups = listOf(114514, 1919810), qweatherKey = "114514", githubKey = "1919810", - imageType = ImageType.PNG + imageType = ImageType.PNG, + openAIAPIHost = "https://api.moonshot.cn", + openAIAPIKey = "114514" ) val ADMINS = listOf( diff --git a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt index 4209606..6e6358c 100644 --- a/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt +++ b/src/main/kotlin/cn/rtast/fancybot/FancyBot.kt @@ -10,6 +10,7 @@ package cn.rtast.fancybot import cn.rtast.fancybot.commands.* import cn.rtast.fancybot.commands.CompilerCommand import cn.rtast.fancybot.commands.lookup.CigaretteCommand +import cn.rtast.fancybot.commands.lookup.GPTCommand import cn.rtast.fancybot.commands.lookup.MCPingCommand import cn.rtast.fancybot.commands.lookup.MusicCommand import cn.rtast.fancybot.commands.lookup.NslookupCommand @@ -147,7 +148,7 @@ val commands = listOf( RUACommand(), NslookupCommand(), NiuziSignCommand(), MyNiuziCommand(), JiJianCommand(), LikeMeCommand(), - CompilerCommand() + CompilerCommand(), GPTCommand() ) suspend fun main() { diff --git a/src/main/kotlin/cn/rtast/fancybot/commands/lookup/GPTCommand.kt b/src/main/kotlin/cn/rtast/fancybot/commands/lookup/GPTCommand.kt new file mode 100644 index 0000000..1946c79 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/commands/lookup/GPTCommand.kt @@ -0,0 +1,69 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/15 + */ + + +package cn.rtast.fancybot.commands.lookup + +import cn.rtast.fancybot.configManager +import cn.rtast.fancybot.entity.gpt.ChatCompletionsPayload +import cn.rtast.fancybot.entity.gpt.ChatCompletionsResponse +import cn.rtast.fancybot.entity.gpt.ModelList +import cn.rtast.fancybot.util.Http +import cn.rtast.fancybot.util.str.toJson +import cn.rtast.rob.entity.GroupMessage +import cn.rtast.rob.util.BaseCommand +import cn.rtast.rob.util.ob.MessageChain +import cn.rtast.rob.util.ob.OBMessage + +class GPTCommand : BaseCommand() { + override val commandNames = listOf("/gpt") + + override suspend fun executeGroup(listener: OBMessage, message: GroupMessage, args: List) { + if (args.isEmpty()) { + val msg = MessageChain.Builder() + .addAt(message.sender.userId) + .addText("发送`/gpt [模型] <问题>`即可询问AI哦~") + .addNewLine() + .addText("不指定模型默认为`moonshot-v1-8k`") + .addNewLine() + .addText("发送`/gpt list`可以获取可用的模型列表~") + .build() + listener.sendGroupMessage(message.groupId, msg) + return + } + + if (args.first() == "列表" || args.first() == "list") { + val models = Http.get( + "${configManager.openAIAPIHost}/v1/models", + headers = mapOf("Authorization" to "Bearer ${configManager.openAIAPIKey}") + ) + val modelsString = models.data.joinToString(", ") { it.id } + val msg = MessageChain.Builder() + .addReply(message.messageId) + .addText("可用的模型列表如下: ") + .addNewLine() + .addText(modelsString) + .build() + listener.sendGroupMessage(message.groupId, msg) + return + } + + val model = if (args.size == 1) "moonshot-v1-8k" else args.first() + val content = if (args.size == 1) args.joinToString(" ") else args.drop(1).joinToString(" ") + val messages = ChatCompletionsPayload(model, listOf(ChatCompletionsPayload.Message(content))) + val response = Http.post( + "${configManager.openAIAPIHost}/v1/chat/completions", + messages.toJson(), + mapOf("Authorization" to "Bearer ${configManager.openAIAPIKey}") + ) + val msg = MessageChain.Builder() + .addReply(message.messageId) + .addNewLine() + .addText(response.choices.first().message.content) + .build() + listener.sendGroupMessage(message.groupId, msg) + } +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt b/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt index 0c6a665..3c65428 100644 --- a/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt +++ b/src/main/kotlin/cn/rtast/fancybot/entity/Config.kt @@ -20,4 +20,6 @@ data class Config( val qweatherKey: String, val githubKey: String, val imageType: ImageType, + val openAIAPIHost: String, + val openAIAPIKey: String ) \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/enums/GPTUserRole.kt b/src/main/kotlin/cn/rtast/fancybot/entity/enums/GPTUserRole.kt new file mode 100644 index 0000000..d691be2 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/enums/GPTUserRole.kt @@ -0,0 +1,12 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/15 + */ + + +package cn.rtast.fancybot.entity.enums + +enum class GPTUserRole { + user, system, assistant +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/gpt/ChatCompletionsPayload.kt b/src/main/kotlin/cn/rtast/fancybot/entity/gpt/ChatCompletionsPayload.kt new file mode 100644 index 0000000..af9403e --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/gpt/ChatCompletionsPayload.kt @@ -0,0 +1,21 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/15 + */ + + +package cn.rtast.fancybot.entity.gpt + +import cn.rtast.fancybot.entity.enums.GPTUserRole + +data class ChatCompletionsPayload( + val model: String, + val messages: List +) { + data class Message( + val content: String, + val role: GPTUserRole = GPTUserRole.user, + val temperature: Float = 0.3f + ) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/gpt/ChatCompletionsResponse.kt b/src/main/kotlin/cn/rtast/fancybot/entity/gpt/ChatCompletionsResponse.kt new file mode 100644 index 0000000..6d55af2 --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/gpt/ChatCompletionsResponse.kt @@ -0,0 +1,23 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/15 + */ + + +package cn.rtast.fancybot.entity.gpt + +import cn.rtast.fancybot.entity.enums.GPTUserRole + +data class ChatCompletionsResponse( + val choices: List +) { + data class Choice( + val message: Message + ) + + data class Message( + val role: GPTUserRole, + val content: String, + ) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/entity/gpt/ModelList.kt b/src/main/kotlin/cn/rtast/fancybot/entity/gpt/ModelList.kt new file mode 100644 index 0000000..be3aa1b --- /dev/null +++ b/src/main/kotlin/cn/rtast/fancybot/entity/gpt/ModelList.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2024 RTAkland + * Author: RTAkland + * Date: 2024/9/15 + */ + + +package cn.rtast.fancybot.entity.gpt + +data class ModelList( + val data: List +) { + data class Data( + val id: String, + ) +} \ No newline at end of file diff --git a/src/main/kotlin/cn/rtast/fancybot/util/Http.kt b/src/main/kotlin/cn/rtast/fancybot/util/Http.kt index 528cfe1..b25dc8a 100644 --- a/src/main/kotlin/cn/rtast/fancybot/util/Http.kt +++ b/src/main/kotlin/cn/rtast/fancybot/util/Http.kt @@ -8,15 +8,11 @@ package cn.rtast.fancybot.util import cn.rtast.fancybot.util.str.fromJson -import okhttp3.Call -import okhttp3.Callback import okhttp3.FormBody import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.Response -import java.io.IOException object Http { @@ -56,24 +52,6 @@ object Http { return okHttpClient.newCall(request).execute().body.string() } - fun executeRequestAsync( - requestBuilder: Request.Builder, - headers: Map?, - callback: (String) -> Unit - ) { - this.addHeaders(requestBuilder, headers) - okHttpClient.newCall(requestBuilder.build()).enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - val responseBody = response.body.string() - callback(responseBody) - } - - override fun onFailure(call: Call, e: IOException) { - callback(e.toString()) - } - }) - } - @JvmOverloads fun get( url: String, diff --git a/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt b/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt index 7c99437..488e847 100644 --- a/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt +++ b/src/main/kotlin/cn/rtast/fancybot/util/file/ConfigManager.kt @@ -20,4 +20,6 @@ class ConfigManager : JsonFileHandler("config.json") { val qweatherKey get() = this.read().qweatherKey val githubKey get() = this.read().githubKey val imageType get() = this.read().imageType + val openAIAPIHost get() = this.read().openAIAPIHost + val openAIAPIKey get() = this.read().openAIAPIKey } \ No newline at end of file diff --git a/src/main/resources/config.json b/src/main/resources/config.json index 164fab3..9b828f8 100644 --- a/src/main/resources/config.json +++ b/src/main/resources/config.json @@ -9,5 +9,8 @@ 1919810 ], "qweatherKey": "114514", - "githubKey": "1919810" + "githubKey": "1919810", + "imageType": "PNG", + "openAIAPIHost": "https://api.moonshot.cn", + "openAIAPIKey": "114514" } \ No newline at end of file