From 30845848f03991121be632494881676243264fa5 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 02:57:02 +0900 Subject: [PATCH 01/46] =?UTF-8?q?chore:=20=EB=94=94=ED=8E=9C=EB=8D=98?= =?UTF-8?q?=EC=8B=9C=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 9701aa0..675f66c 100644 --- a/build.gradle +++ b/build.gradle @@ -3,28 +3,27 @@ plugins { id 'com.github.johnrengelman.shadow' version '7.1.2' } -group = 'org.example' +group = 'skywolf46' version = rootProject.properties["version"] repositories { mavenCentral() + maven { + url = "https://repo.trinarywolf.net/releases" + } } dependencies { String ktor_version = "2.1.0" - testImplementation 'org.jetbrains.kotlin:kotlin-test' implementation("net.dv8tion:JDA:5.0.0-beta.5") { exclude module: 'opus-java' } - implementation "io.ktor:ktor-client-core:$ktor_version" - implementation "io.ktor:ktor-client-cio:$ktor_version" - implementation "io.ktor:ktor-client-websockets:$ktor_version" - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") - implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1' - implementation "io.arrow-kt:arrow-core:${rootProject.properties["arrow_version"]}" - implementation("org.xerial:sqlite-jdbc:3.41.2.1") + implementation("org.xerial:sqlite-jdbc:3.44.1.0") implementation("io.insert-koin:koin-core:3.4.0") - implementation 'com.knuddels:jtokkit:0.4.0' + implementation ("com.knuddels:jtokkit:0.4.0") + implementation ("org.jetbrains.kotlin:kotlin-reflect:1.8.20") + implementation ("org.yaml:snakeyaml:2.2") + implementation("skywolf46:devain-api-call:1.3.1") } test { From f1fc85f02eb390a8371f646168cb84c991b10f32 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 02:57:47 +0900 Subject: [PATCH 02/46] =?UTF-8?q?bump:=20=EB=B2=84=EC=A0=84=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EB=B3=80=EA=B2=BD=20(Radioactive=20Emmer=20Bread)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devain/controller/api/APICall.kt | 24 ------------------- .../devain/controller/api/APIError.kt | 5 ---- .../controller/api/error/APICallError.kt | 5 ---- 3 files changed, 34 deletions(-) delete mode 100644 src/main/kotlin/skywolf46/devain/controller/api/APICall.kt delete mode 100644 src/main/kotlin/skywolf46/devain/controller/api/APIError.kt delete mode 100644 src/main/kotlin/skywolf46/devain/controller/api/error/APICallError.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/api/APICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/APICall.kt deleted file mode 100644 index dfe30b1..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/api/APICall.kt +++ /dev/null @@ -1,24 +0,0 @@ -package skywolf46.devain.controller.api - -import arrow.core.Either -import org.koin.core.component.KoinComponent -import skywolf46.devain.model.EmptyRequest -import skywolf46.devain.model.Request -import skywolf46.devain.model.Response - -interface APICall, RESPONSE : Response> : KoinComponent { - suspend fun call(request: REQUEST): Either -} - -suspend inline fun APICall.call(): Either { - return call(EmptyRequest()) -} - -suspend inline fun , RESPONSE : Response> APICall.certainly(request: REQUEST): RESPONSE { - return call(request).getOrNull()!! -} - - -suspend inline fun APICall.certainly(): RESPONSE { - return call(EmptyRequest()).getOrNull()!! -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/api/APIError.kt b/src/main/kotlin/skywolf46/devain/controller/api/APIError.kt deleted file mode 100644 index af9c99f..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/api/APIError.kt +++ /dev/null @@ -1,5 +0,0 @@ -package skywolf46.devain.controller.api - -interface APIError { - fun getErrorMessage(): String -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/api/error/APICallError.kt b/src/main/kotlin/skywolf46/devain/controller/api/error/APICallError.kt deleted file mode 100644 index c06fd2b..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/api/error/APICallError.kt +++ /dev/null @@ -1,5 +0,0 @@ -package skywolf46.devain.controller.api.error - -import skywolf46.devain.controller.api.APIError - -interface APICallError : APIError \ No newline at end of file From ec9de4682f8e7bd4c02c3bbd32295c3ca72da2ec Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 02:58:37 +0900 Subject: [PATCH 03/46] =?UTF-8?q?feat:=20REST=20=ED=86=B5=EC=8B=A0=20?= =?UTF-8?q?=EC=99=B8=EB=B6=80=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC?= =?UTF-8?q?=EB=A6=AC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devain/controller/api/RESTAPICall.kt | 65 ----------------- .../controller/api/error/PreconditionError.kt | 9 --- .../api/error/StandardRestAPIError.kt | 73 ------------------- .../controller/api/error/UnexpectedError.kt | 9 --- .../devain/model/EmptyJSONRequest.kt | 11 --- .../skywolf46/devain/model/EmptyRequest.kt | 10 --- .../skywolf46/devain/model/EmptyResponse.kt | 3 - .../devain/model/GenericJSONObjectResponse.kt | 7 -- .../devain/model/GenericListResponse.kt | 3 - .../devain/model/GenericMapResponse.kt | 9 --- .../kotlin/skywolf46/devain/model/Request.kt | 8 -- .../kotlin/skywolf46/devain/model/Response.kt | 3 - .../devain/model/api/openai/GetRequest.kt | 14 ---- .../devain/model/api/openai/GetResponse.kt | 5 -- 14 files changed, 229 deletions(-) delete mode 100644 src/main/kotlin/skywolf46/devain/controller/api/RESTAPICall.kt delete mode 100644 src/main/kotlin/skywolf46/devain/controller/api/error/PreconditionError.kt delete mode 100644 src/main/kotlin/skywolf46/devain/controller/api/error/StandardRestAPIError.kt delete mode 100644 src/main/kotlin/skywolf46/devain/controller/api/error/UnexpectedError.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/EmptyJSONRequest.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/EmptyRequest.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/EmptyResponse.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/GenericJSONObjectResponse.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/GenericListResponse.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/GenericMapResponse.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/Request.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/Response.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/api/openai/GetRequest.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/api/openai/GetResponse.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/api/RESTAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/RESTAPICall.kt deleted file mode 100644 index 2bd802e..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/api/RESTAPICall.kt +++ /dev/null @@ -1,65 +0,0 @@ -package skywolf46.devain.controller.api - -import arrow.core.* -import io.ktor.client.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import org.json.simple.JSONObject -import org.json.simple.parser.JSONParser -import org.koin.core.component.get -import org.koin.core.component.inject -import skywolf46.devain.controller.api.error.PreconditionError -import skywolf46.devain.controller.api.error.StandardRestAPIError -import skywolf46.devain.controller.api.error.UnexpectedError -import skywolf46.devain.model.Request -import skywolf46.devain.model.Response - -abstract class RESTAPICall, RESPONSE : Response>( - val endpointProvider: (REQUEST) -> String, - client: Option = None, - val apiMethod: HttpMethod = HttpMethod.Get -) : APICall { - - private val client by lazy { - client.getOrElse { get() } - } - private val jsonParser by inject() - - override suspend fun call(request: REQUEST): Either { - val prebuiltRequest = request.asJson().getOrElse { return PreconditionError(it).left() } - println(endpointProvider(request)) - println(prebuiltRequest) - return Either.catch { - val result = client.request(endpointProvider(request)) { - method = apiMethod - contentType(ContentType.Application.Json) - headers { - applyCredential() - } - setBody(prebuiltRequest.toJSONString()) - } - if (result.status.value != 200) { - parseHttpError(request, result, result.status.value).left() - } else { - parseResult(request, jsonParser.parse(result.bodyAsText()) as JSONObject) - } - }.getOrElse { - onError(it).left() - } - } - - protected abstract suspend fun parseResult(request: REQUEST, response: JSONObject): Either - - protected open suspend fun parseHttpError(request: REQUEST, response: HttpResponse, errorCode: Int): APIError { - return StandardRestAPIError(errorCode, response.bodyAsText()) - } - - protected open suspend fun onError(throwable: Throwable): APIError { - return UnexpectedError(throwable) - } - - protected open fun HeadersBuilder.applyCredential() { - // Do nothing - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/api/error/PreconditionError.kt b/src/main/kotlin/skywolf46/devain/controller/api/error/PreconditionError.kt deleted file mode 100644 index c88556a..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/api/error/PreconditionError.kt +++ /dev/null @@ -1,9 +0,0 @@ -package skywolf46.devain.controller.api.error - -import skywolf46.devain.controller.api.APIError - -open class PreconditionError(val exception: Throwable) : APIError { - override fun getErrorMessage(): String { - return exception.message!! - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/api/error/StandardRestAPIError.kt b/src/main/kotlin/skywolf46/devain/controller/api/error/StandardRestAPIError.kt deleted file mode 100644 index 48baf77..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/api/error/StandardRestAPIError.kt +++ /dev/null @@ -1,73 +0,0 @@ -package skywolf46.devain.controller.api.error - -@Suppress("MemberVisibilityCanBePrivate") -open class StandardRestAPIError(val errorCode: Int, val message: String) : APICallError { - override fun getErrorMessage(): String { - return "요청 처리 중 오류가 발생하였습니다. (${errorCode}: ${getErrorType()}) -> ($message)" - } - - fun getErrorType(): String { - return when (errorCode) { - 200 -> "OK" - 201 -> "Created" - 202 -> "Accepted" - 203 -> "Non-Authoritative Information" - 204 -> "No Content" - 205 -> "Reset Content" - 206 -> "Partial Content" - 207 -> "Multi-Status" - 208 -> "Already Reported" - 226 -> "IM Used" - 300 -> "Multiple Choices" - 301 -> "Moved Permanently" - 302 -> "Found" - 303 -> "See Other" - 304 -> "Not Modified" - 305 -> "Use Proxy" - 306 -> "Switch Proxy" - 307 -> "Temporary Redirect" - 308 -> "Permanent Redirect" - 400 -> "Bad Request" - 401 -> "Unauthorized" - 402 -> "Payment Required" - 403 -> "Forbidden" - 404 -> "Not Found" - 405 -> "Method Not Allowed" - 406 -> "Not Acceptable" - 407 -> "Proxy Authentication Required" - 408 -> "Request Timeout" - 409 -> "Conflict" - 410 -> "Gone" - 411 -> "Length Required" - 412 -> "Precondition Failed" - 413 -> "Payload Too Large" - 414 -> "URI Too Long" - 415 -> "Unsupported Media Type" - 416 -> "Range Not Satisfiable" - 417 -> "Expectation Failed" - 418 -> "I'm a teapot" - 421 -> "Misdirected Request" - 422 -> "Unprocessable Entity" - 423 -> "Locked" - 424 -> "Failed Dependency" - 425 -> "Too Early" - 426 -> "Upgrade Required" - 428 -> "Precondition Required" - 429 -> "Too Many Requests" - 431 -> "Request Header Fields Too Large" - 451 -> "Unavailable For Legal Reasons" - 500 -> "Internal Server Error" - 501 -> "Not Implemented" - 502 -> "Bad Gateway" - 503 -> "Service Unavailable" - 504 -> "Gateway Timeout" - 505 -> "HTTP Version Not Supported" - 506 -> "Variant Also Negotiates" - 507 -> "Insufficient Storage" - 508 -> "Loop Detected" - 510 -> "Not Extended" - 511 -> "Network Authentication Required" - else -> "Unknown" - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/api/error/UnexpectedError.kt b/src/main/kotlin/skywolf46/devain/controller/api/error/UnexpectedError.kt deleted file mode 100644 index 99b3039..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/api/error/UnexpectedError.kt +++ /dev/null @@ -1,9 +0,0 @@ -package skywolf46.devain.controller.api.error - -import skywolf46.devain.controller.api.APIError - -open class UnexpectedError(val exception: Throwable) : APIError { - override fun getErrorMessage(): String { - return "${exception.javaClass.name} : ${exception.message}" - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/EmptyJSONRequest.kt b/src/main/kotlin/skywolf46/devain/model/EmptyJSONRequest.kt deleted file mode 100644 index 58653d5..0000000 --- a/src/main/kotlin/skywolf46/devain/model/EmptyJSONRequest.kt +++ /dev/null @@ -1,11 +0,0 @@ -package skywolf46.devain.model - -import arrow.core.Either -import arrow.core.right -import org.json.simple.JSONObject - -open class EmptyJSONRequest : Request { - override fun asJson(): Either { - return JSONObject().right() - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/EmptyRequest.kt b/src/main/kotlin/skywolf46/devain/model/EmptyRequest.kt deleted file mode 100644 index c849a6d..0000000 --- a/src/main/kotlin/skywolf46/devain/model/EmptyRequest.kt +++ /dev/null @@ -1,10 +0,0 @@ -package skywolf46.devain.model - -import arrow.core.Either -import arrow.core.right - -open class EmptyRequest : Request { - override fun asJson(): Either { - return Unit.right() - } -} diff --git a/src/main/kotlin/skywolf46/devain/model/EmptyResponse.kt b/src/main/kotlin/skywolf46/devain/model/EmptyResponse.kt deleted file mode 100644 index c44b69d..0000000 --- a/src/main/kotlin/skywolf46/devain/model/EmptyResponse.kt +++ /dev/null @@ -1,3 +0,0 @@ -package skywolf46.devain.model - -class EmptyResponse : Response \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/GenericJSONObjectResponse.kt b/src/main/kotlin/skywolf46/devain/model/GenericJSONObjectResponse.kt deleted file mode 100644 index b7c36bd..0000000 --- a/src/main/kotlin/skywolf46/devain/model/GenericJSONObjectResponse.kt +++ /dev/null @@ -1,7 +0,0 @@ -package skywolf46.devain.model - -import org.json.simple.JSONObject -import skywolf46.devain.model.EmptyResponse -import skywolf46.devain.model.Response - -data class GenericJSONObjectResponse(val json: JSONObject) : Response \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/GenericListResponse.kt b/src/main/kotlin/skywolf46/devain/model/GenericListResponse.kt deleted file mode 100644 index 2cb6f69..0000000 --- a/src/main/kotlin/skywolf46/devain/model/GenericListResponse.kt +++ /dev/null @@ -1,3 +0,0 @@ -package skywolf46.devain.model - -class GenericListResponse : ArrayList(), Response \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/GenericMapResponse.kt b/src/main/kotlin/skywolf46/devain/model/GenericMapResponse.kt deleted file mode 100644 index 13b1537..0000000 --- a/src/main/kotlin/skywolf46/devain/model/GenericMapResponse.kt +++ /dev/null @@ -1,9 +0,0 @@ -package skywolf46.devain.model - -class GenericMapResponse : LinkedHashMap(), Response, Cloneable { - override fun clone(): GenericMapResponse { - return GenericMapResponse().also { - it.putAll(this) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/Request.kt b/src/main/kotlin/skywolf46/devain/model/Request.kt deleted file mode 100644 index 0972b28..0000000 --- a/src/main/kotlin/skywolf46/devain/model/Request.kt +++ /dev/null @@ -1,8 +0,0 @@ -package skywolf46.devain.model - -import arrow.core.Either -import org.koin.core.component.KoinComponent - -interface Request : KoinComponent{ - fun asJson(): Either -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/Response.kt b/src/main/kotlin/skywolf46/devain/model/Response.kt deleted file mode 100644 index 4e65c13..0000000 --- a/src/main/kotlin/skywolf46/devain/model/Response.kt +++ /dev/null @@ -1,3 +0,0 @@ -package skywolf46.devain.model - -interface Response \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/GetRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/GetRequest.kt deleted file mode 100644 index e620fc9..0000000 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/GetRequest.kt +++ /dev/null @@ -1,14 +0,0 @@ -package skywolf46.devain.model.api.openai - -import arrow.core.Either -import arrow.core.None -import arrow.core.Option -import arrow.core.right -import org.json.simple.JSONObject -import skywolf46.devain.model.Request - -data class GetRequest(val key: String, val section: Option = None) : Request { - override fun asJson(): Either { - return JSONObject().right() - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/GetResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/GetResponse.kt deleted file mode 100644 index 44e94d9..0000000 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/GetResponse.kt +++ /dev/null @@ -1,5 +0,0 @@ -package skywolf46.devain.model.api.openai - -import skywolf46.devain.model.Response - -data class GetResponse(val value: T) : Response \ No newline at end of file From 30827040bae86ec7666dbd180617991975feee2e Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 02:59:16 +0900 Subject: [PATCH 04/46] =?UTF-8?q?feat:=20=EC=8B=A4=ED=97=98=EC=A0=81=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../discord/openai/GPTFunctionCommand.kt | 78 ----- .../discord/openai/GPTGroupCommand.kt | 329 ------------------ .../devain/model/api/openai/OpenAIWorld.kt | 276 --------------- .../api/openai/completion/OpenAIGPTGroup.kt | 82 ----- .../openai/completion/OpenAIGPTInstance.kt | 3 - .../openai/completion/OpenAIGPTPersonality.kt | 3 - .../devain/model/store/OpenAIGPTGroupStore.kt | 17 - .../devain/model/store/OpenAIWorldStore.kt | 21 -- 8 files changed, 809 deletions(-) delete mode 100644 src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTFunctionCommand.kt delete mode 100644 src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTGroupCommand.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/api/openai/OpenAIWorld.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTGroup.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTInstance.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTPersonality.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/store/OpenAIGPTGroupStore.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/store/OpenAIWorldStore.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTFunctionCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTFunctionCommand.kt deleted file mode 100644 index 0bac53d..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTFunctionCommand.kt +++ /dev/null @@ -1,78 +0,0 @@ -package skywolf46.devain.controller.commands.discord.openai - -import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent -import net.dv8tion.jda.api.interactions.commands.OptionType -import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData -import org.koin.core.component.get -import org.koin.core.component.inject -import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceUserDataCall -import skywolf46.devain.model.api.openai.completion.OpenAIFunctionKey -import skywolf46.devain.model.store.OpenAIFunctionStore -import skywolf46.devain.platform.discord.ImprovedDiscordCommand - -class GPTFunctionCommand : ImprovedDiscordCommand("gpt-function", "GPT 펑션 사용 여부를 변경합니다.") { - val builtInChoices = listOf( - "weather", - "exchange-rate" - ) - - private val store = get() - - private val apiCall by inject() - - override fun modifyCommandData(options: SlashCommandData) { - options - .addOption(OptionType.STRING, "function", "대상 펑션 이름을 지정합니다. 빌트인이 아닌 경우, '유저/펑션명'으로 지정합니다.", true, true) - .addOption(OptionType.BOOLEAN, "enable", "펑션을 활성화할지 여부를 지정합니다.", true) - } - - override suspend fun onCommand(event: SlashCommandInteractionEvent) { - val function = event.getOption("function")!!.asString - - if (function.contains("/")) { - val user = function.substringBefore('/') - val func = function.substringAfter('/') - if (store.getFunction(OpenAIFunctionKey(function)).isEmpty()) { - event.reply("해당 유저의 펑션을 찾을 수 없습니다.").queue() - return - } - if (event.getOption("enable")!!.asBoolean) { - event.reply("펑션 ${function}을 활성화했습니다.").queue() - } else { - event.reply("펑션 ${function}을 비활성화했습니다.").queue() - } - } else { - if (function !in builtInChoices) { - event.reply("해당 펑션을 찾을 수 없습니다.").queue() - return - } - if (event.getOption("enable")!!.asBoolean) { - event.reply("펑션 ${function}을 활성화했습니다.").queue() - } else { - event.reply("펑션 ${function}을 비활성화했습니다.").queue() - } - } - } - - override suspend fun onAutoComplete(event: CommandAutoCompleteInteractionEvent) { - if (event.focusedOption.name == "function") { - val currentValue = event.focusedOption.value -// if (currentValue.contains('/')) { -// val user = currentValue.substringBefore('/') -// val func = currentValue.substringAfter('/') -// if (userChoices.containsKey(user)) { -// event.replyChoiceStrings( -// userChoices[user]!!.filter { it.startsWith(func) }.map { "$user/$it" } -// ).queue() -// } else { -// event.replyChoiceStrings(emptyList()).queue() -// } -// } else { -// event.replyChoiceStrings( -// builtInChoices.filter { it.startsWith(currentValue) } -// ).queue() -// } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTGroupCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTGroupCommand.kt deleted file mode 100644 index e7c8848..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTGroupCommand.kt +++ /dev/null @@ -1,329 +0,0 @@ -package skywolf46.devain.controller.commands.discord.openai - -import arrow.core.getOrElse -import arrow.core.toOption -import net.dv8tion.jda.api.EmbedBuilder -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent -import net.dv8tion.jda.api.interactions.commands.OptionType -import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData -import net.dv8tion.jda.api.interactions.commands.build.SubcommandData -import net.dv8tion.jda.api.interactions.commands.build.SubcommandGroupData -import org.koin.core.component.get -import skywolf46.devain.model.api.openai.completion.OpenAIGPTMessage -import skywolf46.devain.model.store.OpenAIGPTGroupStore -import skywolf46.devain.model.store.OpenAIWorldStore -import skywolf46.devain.platform.discord.ImprovedDiscordCommand -import java.awt.Color - -class GPTGroupCommand : ImprovedDiscordCommand("gpt-group", "새로운 GPT 그룹을 생성합니다. ") { - private val groupStore = get() - private val worldStore = get() - - override fun modifyCommandData(options: SlashCommandData) { - options - .addSubcommandGroups( - SubcommandGroupData("group", "GPT 그룹을 관리합니다.").addSubcommands( - SubcommandData("create", "새로운 GPT 그룹을 생성합니다.") - .addOption(OptionType.STRING, "name", "생성할 GPT 그룹 이름입니다.", true), - SubcommandData("info", "GPT 그룹 목록을 조회합니다.") - .addOption(OptionType.STRING, "name", "생성할 GPT 그룹 이름입니다.", true), - SubcommandData("turn-end", "턴 종료 프롬프트를 추가합니다.") - .addOption(OptionType.STRING, "name", "생성할 GPT 그룹 이름입니다.", true) - .addOption(OptionType.STRING, "prompt", "턴 종료 프롬프트입니다.", true), - SubcommandData("game-end", "게임 종료 프롬프트를 추가합니다.") - .addOption(OptionType.STRING, "name", "생성할 GPT 그룹 이름입니다.", true) - .addOption(OptionType.STRING, "prompt", "게임 종료 프롬프트입니다.", true), - SubcommandData("base-prompt", "기반 프롬프트를 추가합니다.") - .addOption(OptionType.STRING, "name", "생성할 GPT 그룹 이름입니다.", true) - .addOption(OptionType.STRING, "prompt", "기반 프롬프트입니다.", true), - ) - ).addSubcommandGroups( - SubcommandGroupData("personality", "GPT 인스턴스의 인격을 관리합니다.") - .addSubcommands( -// SubcommandData("create", "새 GPT 인스턴스를 생성합니다.") -// .addOption(OptionType.STRING, "name", "GPT 인스턴스의 이름입니다.", true), - - SubcommandData("add", "등록된 GPT 인스턴스의 인격 지침을 추가합니다. GPT는 등록된 지침을 자신이라고 인식할것입니다.") - .addOption(OptionType.STRING, "group", "GPT 그룹의 이름입니다.", true) - .addOption(OptionType.STRING, "name", "GPT 인스턴스의 이름입니다.", true) - .addOption(OptionType.STRING, "prompt", "GPT 인스턴스의 인격 지침입니다.", true), - ) - ) - .addSubcommandGroups( - SubcommandGroupData("world", "GPT 그룹이 실행되고 있는 세계를 관리합니다.") - .addSubcommands( - SubcommandData("create", "GPT 그룹을 사용하여 새 세계를 추가합니다.") - .addOption(OptionType.STRING, "name", "세계관의 이름입니다.", true) - .addOption(OptionType.STRING, "group", "사용할 GPT 그룹의 이름입니다.", true), - SubcommandData("join", "세계에 참가합니다. 이 명령은 지정된 세계가 시작되기 전에만 작동합니다.") - .addOption(OptionType.STRING, "name", "세계의 이름입니다.", true) - .addOption(OptionType.STRING, "nickname", "당신의 이름입니다.", true), - SubcommandData("start", "세계를 시작합니다.") - .addOption(OptionType.STRING, "name", "세계의 이름입니다.", true), - SubcommandData("step", "다음 단계를 진행합니다.") - .addOption(OptionType.STRING, "name", "세계의 이름입니다.", true), - SubcommandData("submit", "자신의 단계를 진행합니다.") - .addOption(OptionType.STRING, "name", "세계의 이름입니다.", true) - .addOption(OptionType.STRING, "prompt", "GPT에 전달할 프롬프트입니다.", true), - ) - ) - } - - override suspend fun onCommand(event: SlashCommandInteractionEvent) { - when (event.subcommandGroup!!) { - "group" -> onGroupCommand(event) - "personality" -> onPersonalityCommand(event) - "world" -> onWorldCommand(event) - } - } - - private fun onGroupCommand(event: SlashCommandInteractionEvent) { - when (event.subcommandName) { - "create" -> onCreateGroupCommand(event) - "info" -> onGroupInfoCommand(event) - "turn-end" -> onGroupTurnPromptCommand(event) - "game-end" -> onGameTurnPromptCommand(event) - "base-prompt" -> onAddBasePrompt(event) - } - } - - private fun onPersonalityCommand(event: SlashCommandInteractionEvent) { - when (event.subcommandName) { - "add" -> onAddPersonalityPrompt(event) - } - } - - private suspend fun onWorldCommand(event: SlashCommandInteractionEvent) { - when (event.subcommandName) { - "create" -> onCreateWorldCommand(event) - "join" -> onJoinWorldCommand(event) -// "start" -> onStartWorldCommand(event) - "step" -> onStepWorldCommand(event) - "submit" -> onSubmitWorldCommand(event) - } - } - - private suspend fun onSubmitWorldCommand(event: SlashCommandInteractionEvent) { - worldStore.getWorld(event.getOption("name")!!.asString).getOrElse { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("세계 진행 실패") - .setDescription("세계 ${event.getOption("name")!!.asString}은(는) 등록된 세계가 아닙니다.") - .build() - ).queue() - return - }.playerNextStep(event) - } - - private fun onCreateWorldCommand(event: SlashCommandInteractionEvent) { - val group = groupStore.getGroup(event.getOption("group")!!.asString).getOrElse { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("세계 생성 실패") - .setDescription("GPT 그룹 ${event.getOption("group")!!.asString}은(는) 등록된 그룹이 아닙니다.") - .build() - ).queue() - return - } - if (worldStore.createWorld(event.getOption("name")!!.asString, group)) { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.CYAN) - .setTitle("세계 생성 성공") - .setDescription("세계 ${event.getOption("name")!!.asString}을(를) 생성하였습니다.") - .build() - ).queue() - } else { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("세계 생성 실패") - .setDescription("세계 ${event.getOption("name")!!.asString}은(는) 이미 등록된 세계입니다.") - .build() - ).queue() - } - } - - private suspend fun onStepWorldCommand(event: SlashCommandInteractionEvent) { - worldStore.getWorld(event.getOption("name")!!.asString).getOrElse { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("세계 진행 실패") - .setDescription("세계 ${event.getOption("name")!!.asString}은(는) 등록된 세계가 아닙니다.") - .build() - ).queue() - return - }.nextStep(event) - } - - private fun onJoinWorldCommand(event: SlashCommandInteractionEvent) { - val world = worldStore.getWorld(event.getOption("name")!!.asString).getOrElse { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("세계 참가 실패") - .setDescription("세계 ${event.getOption("name")!!.asString}은(는) 등록된 세계가 아닙니다.") - .build() - ).queue() - return - } - world.joinPlayer(event.user.idLong, event.getOption("nickname")!!.asString) - } - - - private fun onAddPersonalityPrompt(event: SlashCommandInteractionEvent) { - val group = groupStore.getGroup(event.getOption("group")!!.asString).getOrElse { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("AI 인격 생성 실패") - .setDescription("GPT 그룹 ${event.getOption("group")!!.asString}은(는) 이미 등록된 그룹입니다.") - .build() - ).queue() - return - } - val personality = group.getOrCreatePersonality(event.getOption("name")!!.asString) - personality.personality.add( - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER_PRECONDITION, - event.getOption("prompt")!!.asString.toOption() - ) - ) - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.CYAN) - .setTitle("AI 인격 프롬프트 추가 성공") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}의 인격 ${event.getOption("name")!!.asString}에 새 프롬프트를 추가하였습니다.") - .build() - ).queue() - } - - private fun onCreateGroupCommand(event: SlashCommandInteractionEvent) { - event.replyEmbeds( - if (groupStore.createGroup(event.getOption("name")!!.asString)) - EmbedBuilder() - .setColor(Color.CYAN) - .setTitle("GPT 그룹 생성 성공") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}을(를) 생성하였습니다.") - .build() - else - EmbedBuilder() - .setColor(Color.RED) - .setTitle("GPT 그룹 생성 실패") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}은(는) 이미 등록된 그룹입니다.") - .build() - ).queue() - - } - - private fun onGroupInfoCommand(event: SlashCommandInteractionEvent) { - groupStore.getGroup(event.getOption("name")!!.asString).tap { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.LIGHT_GRAY) - .setTitle("GPT 그룹 정보") - .setDescription("## ${event.getOption("name")!!.asString}") - .addField("회상", box("${it.allowedHistorySize} 프롬프트"), true) - .addField("기반 프롬프트", box("${it.getBasePrompts().size}개"), true) - .addField("턴 종료 프롬프트", box("${it.getTurnCheckTokens().size}개"), true) - .addField("인스턴스 (${it.getInstances().size})", - box(it.getInstances().map { instance -> "- ${instance.gptName}" } - .joinToString("\n")), - false - ) - .build() - ).queue() - }.tapNone { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("GPT 그룹 조회 실패") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}은(는) 등록된 그룹이 아닙니다.") - .build() - ).queue() - } - } - - - private fun onGroupTurnPromptCommand(event: SlashCommandInteractionEvent) { - groupStore.getGroup(event.getOption("name")!!.asString).tap { - it.addTurnCheckToken( - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER_PRECONDITION, - event.getOption("prompt")!!.asString.toOption() - ) - ) - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.CYAN) - .setTitle("기반 프롬프트 추가 성공") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}에 새 턴 종료 프롬프트를 추가하였습니다.") - .build() - ).queue() - }.tapNone { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("GPT 그룹 조회 실패") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}은(는) 등록된 그룹이 아닙니다.") - .build() - ).queue() - } - } - - private fun onGameTurnPromptCommand(event: SlashCommandInteractionEvent) { - groupStore.getGroup(event.getOption("name")!!.asString).tap { - it.addGameEndCheckToken( - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER_PRECONDITION, - event.getOption("prompt")!!.asString.toOption() - ) - ) - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.CYAN) - .setTitle("기반 프롬프트 추가 성공") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}에 새 게임 종료 프롬프트를 추가하였습니다.") - .build() - ).queue() - }.tapNone { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("GPT 그룹 조회 실패") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}은(는) 등록된 그룹이 아닙니다.") - .build() - ).queue() - } - } - - - private fun onAddBasePrompt(event: SlashCommandInteractionEvent) { - groupStore.getGroup(event.getOption("name")!!.asString).tap { - it.addBasePrompt( - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER_PRECONDITION, - event.getOption("prompt")!!.asString.toOption() - ) - ) - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.CYAN) - .setTitle("기반 프롬프트 추가 성공") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}에 새 기반 프롬프트를 추가하였습니다.") - .build() - ).queue() - }.tapNone { - event.replyEmbeds( - EmbedBuilder() - .setColor(Color.RED) - .setTitle("GPT 그룹 조회 실패") - .setDescription("GPT 그룹 ${event.getOption("name")!!.asString}은(는) 등록된 그룹이 아닙니다.") - .build() - ).queue() - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/OpenAIWorld.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/OpenAIWorld.kt deleted file mode 100644 index 4848952..0000000 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/OpenAIWorld.kt +++ /dev/null @@ -1,276 +0,0 @@ -package skywolf46.devain.model.api.openai - -import arrow.core.* -import kotlinx.coroutines.runBlocking -import net.dv8tion.jda.api.EmbedBuilder -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent -import net.dv8tion.jda.api.interactions.InteractionHook -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.error.UnexpectedError -import skywolf46.devain.controller.api.requests.openai.GPTCompletionAPICall -import skywolf46.devain.model.api.openai.completion.OpenAIGPTMessage -import skywolf46.devain.model.api.openai.completion.OpenAIGPTGroup -import skywolf46.devain.model.api.openai.completion.OpenAIGPTPersonality -import skywolf46.devain.model.api.openai.completion.OpenAIGPTRequest -import java.util.concurrent.atomic.AtomicInteger - -data class OpenAIWorld(val group: OpenAIGPTGroup) : KoinComponent { - private val prompts = mutableListOf() - - private val currentIndex = AtomicInteger(0) - - private val apiCall by inject() - - private var turn = 0 - - private val personality = mutableListOf().apply { - addAll(group.getInstances().map { AIPersonality(it) }) - } - - fun buildPrompts(): MutableList { - val currentPersonality = personality[currentIndex.get()] - val promptBuilt = mutableListOf() - promptBuilt.addAll(group.getBasePrompts()) - promptBuilt.addAll( - prompts.map { - if (it.from.getName() == currentPersonality.getName()) - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER_PRECONDITION, - "${it.message.content.orNull()}".toOption() - ) - else - OpenAIGPTMessage( - OpenAIGPTMessage.Role.ASSISTANT, - "${it.from.getName()}: ${it.message.content.orNull()}".toOption() - ) - }) - promptBuilt.addAll((currentPersonality as AIPersonality).personality.personality) - promptBuilt.add( - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER, - "당신은 ${currentPersonality.personality.gptName}입니다. 당신이 말하고 싶은 내용만 말하십시오. 다른 사용자를 언급하는것은 해당되나, 해당 사람처럼 연기하는것은 허용되지 않습니다.".toOption() - ) - ) - promptBuilt.addAll(group.getTurnCheckTokens().map { - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER_PRECONDITION, - "${it.content.orNull()}".replace( - "{turn}", (group.turn - turn).toString() - ).toOption() - ) - }) - return promptBuilt - } - - fun buildEndPrompts(gptName: String): MutableList { - val currentPersonality = personality[currentIndex.get()] - val promptBuilt = mutableListOf() - promptBuilt.addAll(group.getBasePrompts()) - promptBuilt.addAll( - prompts.map { - if (it.from.getName() == currentPersonality.getName()) - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER_PRECONDITION, - "${it.message.content.orNull()}".toOption() - ) - else - OpenAIGPTMessage( - OpenAIGPTMessage.Role.ASSISTANT, - "${it.from.getName()}: ${it.message.content.orNull()}".toOption() - ) - }) - promptBuilt.addAll((currentPersonality as AIPersonality).personality.personality) - promptBuilt.add( - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER, - "당신은 ${gptName}입니다.".toOption() - ) - ) - - promptBuilt.addAll(group.getGameEndTokens().map { - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER_PRECONDITION, - "${it.content.orNull()}".replace( - "{turn}", (group.turn - turn).toString() - ).toOption() - ) - }) - return promptBuilt - } - - suspend fun nextStep(event: SlashCommandInteractionEvent) { - event.deferReply().queue { hook -> - runBlocking { - if (turn == group.turn) { - hook.sendMessageEmbeds( - EmbedBuilder().setTitle("게임 종료").setDescription("게임이 종료되었습니다. 게임을 집계합니다..").build() - ).queue { - runBlocking { - val list = personality.associateWith { it.requestEnd(event, hook, turn) } - val builder = EmbedBuilder().setTitle("게임 결과") - list.forEach { (t, u) -> - builder.addField( - "${t.getName()}의 의견", - u.map { it.content.orNull()!! }.getOrElse { "오류가 발생했습니다." }, - false - ) - } - it.editMessageEmbeds(builder.build()).queue() - } - } - return@runBlocking - } else if (turn >= group.turn) { - hook.sendMessage("이미 게임이 종료되었습니다.").queue() - return@runBlocking - } - val currentPersonality = personality[currentIndex.get()] - val message = currentPersonality.requestMessage(event, hook, ++turn).getOrElse { - hook.sendMessage(it.getErrorMessage()).queue() - return@runBlocking - } - addPromptLog(message) - currentPersonality.replyAfter(hook) - } - } - } - - - suspend fun playerNextStep(event: SlashCommandInteractionEvent) { - event.deferReply().queue { hook -> - runBlocking { - val currentPersonality = personality[currentIndex.get()] - if (currentPersonality !is PlayerPersonality || currentPersonality.idLong != event.user.idLong) { - hook.sendMessage("당신의 차례가 아닙니다.").queue() - return@runBlocking - } - val message = currentPersonality.requestMessage(event, hook, ++turn).getOrElse { - hook.sendMessage(it.getErrorMessage()).queue() - return@runBlocking - } - addPromptLog(message) - currentPersonality.replyAfter(hook) - } - } - } - - fun addPromptLog(prompt: OpenAIGPTMessage) { - val currentPersonality = personality[currentIndex.get()] - prompts.add(OpenAIWorldLog(currentPersonality, prompt)) - if (prompts.size > group.allowedHistorySize) prompts.removeAt(0) - checkIndex() - } - - - fun checkIndex() { - if (currentIndex.incrementAndGet() >= group.getInstances().size) { - currentIndex.set(0) - } - } - - fun joinPlayer(idLong: Long, name: String) { - personality.add(PlayerPersonality(idLong, name)) - } - - interface Personality : KoinComponent { - suspend fun requestMessage( - event: SlashCommandInteractionEvent, hook: InteractionHook, turn: Int - ): Either - - suspend fun requestEnd( - event: SlashCommandInteractionEvent, hook: InteractionHook, turn: Int - ): Either - - suspend fun replyAfter(hook: InteractionHook) - - fun getName(): String - } - - inner class AIPersonality(val personality: OpenAIGPTPersonality) : Personality { - override suspend fun requestMessage( - event: SlashCommandInteractionEvent, hook: InteractionHook, turn: Int - ): Either { - return apiCall.call( - OpenAIGPTRequest( - "gpt-4-0613", buildPrompts(), 1, maxTokens = 60.toOption() - ) - ).map { - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER, "${it.answers[0].message.content.orNull()}".toOption() - ) - }.onRight { - hook.sendMessageEmbeds( - EmbedBuilder() - .setTitle(personality.gptName) - .setDescription(it.content.orNull().toString()) - .addField("세계관 턴", turn.toString(), false) - .build() - ).queue() - } - } - - override suspend fun requestEnd( - event: SlashCommandInteractionEvent, hook: InteractionHook, turn: Int - ): Either { - return apiCall.call( - OpenAIGPTRequest( - "gpt-4-0613", buildEndPrompts(personality.gptName), 1, maxTokens = 60.toOption() - ) - ).map { - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER, "${it.answers[0].message.content.orNull()}".toOption() - ) - } - } - - override suspend fun replyAfter(hook: InteractionHook) { - - } - - override fun getName(): String { - return personality.gptName - } - } - - inner class PlayerPersonality(val idLong: Long, private val name: String) : Personality { - override suspend fun requestMessage( - event: SlashCommandInteractionEvent, hook: InteractionHook, turn: Int - ): Either { - if (event.user.idLong != idLong) return UnexpectedError(RuntimeException("당신의 차례가 아닙니다.")).left() - hook.sendMessage(event.getOption("prompt")!!.asString).queue() - return OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER, event.getOption("prompt")!!.asString.toOption() - ).right() - } - - override suspend fun requestEnd( - event: SlashCommandInteractionEvent, - hook: InteractionHook, - turn: Int - ): Either { - TODO("Not yet implemented") - } - - override suspend fun replyAfter(hook: InteractionHook) { - hook.sendMessage("<@${idLong}>님의 차례입니다.").queue() - return - } - - override fun getName(): String { - return name - } - - } - - data class OpenAIWorldLog(val from: Personality, val message: OpenAIGPTMessage) { - fun asPrompt(currentPersonality: Personality): OpenAIGPTMessage { - return if (from == currentPersonality) { - OpenAIGPTMessage(OpenAIGPTMessage.Role.ASSISTANT, message.content) - } else { - OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, message.content) - } - } - } - -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTGroup.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTGroup.kt deleted file mode 100644 index 4c159e4..0000000 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTGroup.kt +++ /dev/null @@ -1,82 +0,0 @@ -package skywolf46.devain.model.api.openai.completion - -import java.util.concurrent.locks.ReentrantLock -import kotlin.concurrent.withLock - -class OpenAIGPTGroup(val allowedHistorySize: Int, val turn: Int) { - private val promptLock = ReentrantLock() - - private val basePrompts = mutableListOf() - - private val gameEndPrompts = mutableListOf() - - private val turnCheckTokens = mutableListOf() - - private val groups = mutableListOf() - - - - fun addBasePrompt(message: OpenAIGPTMessage): OpenAIGPTGroup { - promptLock.withLock { - basePrompts += message - } - return this - } - - fun addGPTPersonality(personality: OpenAIGPTPersonality): OpenAIGPTGroup { - promptLock.withLock { - groups += personality - } - return this - } - - fun addTurnCheckToken(message: OpenAIGPTMessage): OpenAIGPTGroup { - promptLock.withLock { - turnCheckTokens += message - } - return this - } - - fun addGameEndCheckToken(message: OpenAIGPTMessage): OpenAIGPTGroup { - promptLock.withLock { - gameEndPrompts += message - } - return this - } - - - - fun getBasePrompts(): List { - return promptLock.withLock { - basePrompts.toList() - } - } - - fun getTurnCheckTokens(): List { - return promptLock.withLock { - turnCheckTokens.toList() - } - } - - - fun getGameEndTokens(): List { - return promptLock.withLock { - gameEndPrompts.toList() - } - } - - fun getInstances(): List { - return promptLock.withLock { - groups.toList() - } - } - - fun getOrCreatePersonality(name: String): OpenAIGPTPersonality { - return promptLock.withLock { - groups.firstOrNull { it.gptName == name } ?: OpenAIGPTPersonality(name, mutableListOf()).also { - groups += it - } - } - } - -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTInstance.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTInstance.kt deleted file mode 100644 index 9907624..0000000 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTInstance.kt +++ /dev/null @@ -1,3 +0,0 @@ -package skywolf46.devain.model.api.openai.completion - -data class OpenAIGPTInstance(val personality: OpenAIGPTPersonality, val prompts : MutableList = mutableListOf()) \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTPersonality.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTPersonality.kt deleted file mode 100644 index 9ae3d3b..0000000 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTPersonality.kt +++ /dev/null @@ -1,3 +0,0 @@ -package skywolf46.devain.model.api.openai.completion - -data class OpenAIGPTPersonality(val gptName: String, val personality: MutableList) \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/store/OpenAIGPTGroupStore.kt b/src/main/kotlin/skywolf46/devain/model/store/OpenAIGPTGroupStore.kt deleted file mode 100644 index 827acbb..0000000 --- a/src/main/kotlin/skywolf46/devain/model/store/OpenAIGPTGroupStore.kt +++ /dev/null @@ -1,17 +0,0 @@ -package skywolf46.devain.model.store - -import arrow.core.Option -import arrow.core.toOption -import skywolf46.devain.model.api.openai.completion.OpenAIGPTGroup - -class OpenAIGPTGroupStore { - private val store = mutableMapOf() - - fun getGroup(name: String): Option { - return store[name].toOption() - } - - fun createGroup(name: String) : Boolean { - return store.putIfAbsent(name, OpenAIGPTGroup(60, 20)) == null - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/store/OpenAIWorldStore.kt b/src/main/kotlin/skywolf46/devain/model/store/OpenAIWorldStore.kt deleted file mode 100644 index 476d98f..0000000 --- a/src/main/kotlin/skywolf46/devain/model/store/OpenAIWorldStore.kt +++ /dev/null @@ -1,21 +0,0 @@ -package skywolf46.devain.model.store - -import arrow.core.Option -import arrow.core.toOption -import skywolf46.devain.model.api.openai.OpenAIWorld -import skywolf46.devain.model.api.openai.completion.OpenAIGPTGroup - -class OpenAIWorldStore { - private val worlds = mutableMapOf() - - fun getWorld(name: String): Option { - return worlds[name].toOption() - } - - fun createWorld(name: String, group: OpenAIGPTGroup): Boolean { - if (worlds.containsKey(name)) - return false - worlds[name] = OpenAIWorld(group) - return true - } -} \ No newline at end of file From e29263e2923f7b8027f77c4e389b2c7fc6e3dd19 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 02:59:36 +0900 Subject: [PATCH 05/46] =?UTF-8?q?feat:=20JSON=20=EC=9C=A0=ED=8B=B8?= =?UTF-8?q?=EB=A6=AC=ED=8B=B0=20=ED=8E=91=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/skywolf46/devain/util/JSONUtil.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/kotlin/skywolf46/devain/util/JSONUtil.kt b/src/main/kotlin/skywolf46/devain/util/JSONUtil.kt index 2abe496..39c8a06 100644 --- a/src/main/kotlin/skywolf46/devain/util/JSONUtil.kt +++ b/src/main/kotlin/skywolf46/devain/util/JSONUtil.kt @@ -63,4 +63,21 @@ fun JSONArray.addMap(vararg data: Pair): JSONArray { } }) return this +} + +fun JSONObject.putNotNull(key: String, data: Any?) { + if (data != null) { + put(key, data) + } +} + +inline fun JSONObject.putNotNullOrFatal(key: String, data: Double?, range: ClosedRange, fatal: (ClosedRange) -> Unit) { + if (data == null) return + put(key, data.checkRangeAndFatal(range, fatal)) +} + + +inline fun JSONObject.putNotNullOrFatal(key: String, data: Int?, range: IntRange, fatal: (ClosedRange) -> Unit) { + if (data == null) return + put(key, data.checkRangeAndFatal(range, fatal)) } \ No newline at end of file From 078347648095c4a6580f803eacab6234e828a3a3 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:00:00 +0900 Subject: [PATCH 06/46] =?UTF-8?q?feat:=20StringUtil=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/skywolf46/devain/util/StringUtil.kt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/util/StringUtil.kt diff --git a/src/main/kotlin/skywolf46/devain/util/StringUtil.kt b/src/main/kotlin/skywolf46/devain/util/StringUtil.kt new file mode 100644 index 0000000..13d8a68 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/util/StringUtil.kt @@ -0,0 +1,7 @@ +package skywolf46.devain.util + +fun String.replaceAllArgument(args: Map) : String{ + return (listOf(this to "") + args.toList()).reduce { acc, pair -> + acc.first.replace("{${pair.first}}", pair.second) to "" + }.first +} \ No newline at end of file From d7d62338ecf7d3733c3214af415f2e360b425082 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:00:13 +0900 Subject: [PATCH 07/46] =?UTF-8?q?bump:=20=EB=B2=84=EC=A0=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index b593fa1..97f8d4c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ kotlin.code.style=official arrow_version=1.1.5 -version=1.2.0-Grenade-Muffin \ No newline at end of file +version=1.3.0-Radioactive-Emmer-Bread \ No newline at end of file From 75c79f6eb73982f4be9f72ba6c490b0eb347af03 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:00:57 +0900 Subject: [PATCH 08/46] =?UTF-8?q?feat:=20AnnotatedParameterDiscordCommand?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skywolf46/devain/annotations/Required.kt | 6 + .../annotations/config/MarkConfigElement.kt | 5 + .../AnnotatedParameterDiscordCommand.kt | 115 ++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/annotations/Required.kt create mode 100644 src/main/kotlin/skywolf46/devain/annotations/config/MarkConfigElement.kt create mode 100644 src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt diff --git a/src/main/kotlin/skywolf46/devain/annotations/Required.kt b/src/main/kotlin/skywolf46/devain/annotations/Required.kt new file mode 100644 index 0000000..18d5318 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/annotations/Required.kt @@ -0,0 +1,6 @@ +package skywolf46.devain.annotations + + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.VALUE_PARAMETER) +annotation class Required \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/annotations/config/MarkConfigElement.kt b/src/main/kotlin/skywolf46/devain/annotations/config/MarkConfigElement.kt new file mode 100644 index 0000000..bf1fe5a --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/annotations/config/MarkConfigElement.kt @@ -0,0 +1,5 @@ +package skywolf46.devain.annotations.config + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.VALUE_PARAMETER) +annotation class MarkConfigElement(val name: String = "") \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt b/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt new file mode 100644 index 0000000..7c401e0 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt @@ -0,0 +1,115 @@ +package skywolf46.devain.platform.discord + +import arrow.core.Option +import arrow.core.none +import arrow.core.toOption +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.interactions.commands.OptionType +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData +import skywolf46.devain.annotations.CommandParameter +import skywolf46.devain.annotations.Required +import skywolf46.devain.util.replaceAllArgument +import kotlin.reflect.KClass +import kotlin.reflect.KParameter +import kotlin.reflect.full.findAnnotations +import kotlin.reflect.full.valueParameters + +abstract class AnnotatedParameterDiscordCommand( + command: String, val parameterClass: KClass, descrption: String = "제공된 명령어 설명이 존재하지 않습니다." +) : ImprovedDiscordCommand(command, descrption) { + private val parsed = ParsedParameter(parameterClass) + + override fun modifyCommandData(options: SlashCommandData) { + for ((_, data) in parsed.parameters) { + options.addOption(data.type.option, data.name, data.description.replaceAllArgument(onCommandParameterDataRequested()), data.required) + } + } + + override suspend fun onCommand(event: SlashCommandInteractionEvent) { + val constructed = parameterClass.constructors.first().callBy( + parsed.parameters.mapValues { + it.value.type.converter(event, it.value.name) + }.filterValues { it != null } + ) + onParameterCommand(CommandEvent(event), constructed) + } + + abstract suspend fun onParameterCommand(event: CommandEvent, data: T) + + open fun onCommandParameterDataRequested() : Map = emptyMap() + + private class ParsedParameter(private val cls: KClass<*>) { + val parameters = mutableMapOf() + + init { + verify().tap { + throw RuntimeException(it) + } + inspect() + } + + fun verify(): Option { + for (field in cls.constructors.first().valueParameters) { + if (!field.isOptional) { + if (field.findAnnotations(CommandParameter::class).isEmpty()) { + return "Cannot use field \"${field.name}\" as parameter constructor : Non-optional field must have @Require and @CommandParameter annotation".toOption() + } + if (field.findAnnotations(Required::class).isEmpty()) { + return "Cannot use field \"${field.name}\" as parameter constructor : Non-optional field must have @Require and @CommandParameter annotation".toOption() + } + } + } + return none() + } + + fun inspect() { + for (field in cls.constructors.first().valueParameters) { + val data = field.findAnnotations(CommandParameter::class).firstOrNull() + if (data != null) { + parameters[field] = ParsedParameterInfo( + field.findAnnotations(Required::class).isNotEmpty(), when (field.type.classifier as KClass<*>) { + Long::class -> OptionClassConverter.LONG + Double::class -> OptionClassConverter.DOUBLE + Float::class -> OptionClassConverter.FLOAT + String::class -> OptionClassConverter.STRING + Boolean::class -> OptionClassConverter.BOOLEAN + Int::class -> OptionClassConverter.INTEGER + else -> throw IllegalStateException("Class ${field.type.classifier} is unexpected for command parameter") + }, data.name, data.description + ) + } + } + } + + data class ParsedParameterInfo( + val required: Boolean, val type: OptionClassConverter, val name: String, val description: String + ) + } + + enum class OptionClassConverter( + val option: OptionType, val converter: SlashCommandInteractionEvent.(String) -> Any? + ) { + STRING(OptionType.STRING, { + getOption(it)?.asString + }), + LONG(OptionType.INTEGER, { + getOption(it)?.asLong + }), + BOOLEAN(OptionType.BOOLEAN, { + getOption(it)?.asBoolean + }), + DOUBLE(OptionType.NUMBER, { + getOption(it)?.asDouble + }), + FLOAT(OptionType.NUMBER, { + getOption(it)?.asDouble?.toFloat() + }), + INTEGER(OptionType.INTEGER, { + getOption(it)?.asInt?.toFloat() + }) + } + + data class CommandEvent(val origin: SlashCommandInteractionEvent, val executedOn: Long = System.currentTimeMillis()) { + fun elapsed() : Long = (System.currentTimeMillis() - executedOn) + } +} \ No newline at end of file From f3af8b1ceb355cf5dae6b43770e2e219f83ede56 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:01:25 +0900 Subject: [PATCH 09/46] =?UTF-8?q?fix:=20CohereGenerationAPICall=EC=9D=98?= =?UTF-8?q?=20=EC=9E=98=EB=AA=BB=EB=90=9C=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/{ => requests}/cohere/CohereGenerationAPICall.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename src/main/kotlin/skywolf46/devain/controller/api/{ => requests}/cohere/CohereGenerationAPICall.kt (91%) diff --git a/src/main/kotlin/skywolf46/devain/controller/api/cohere/CohereGenerationAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/cohere/CohereGenerationAPICall.kt similarity index 91% rename from src/main/kotlin/skywolf46/devain/controller/api/cohere/CohereGenerationAPICall.kt rename to src/main/kotlin/skywolf46/devain/controller/api/requests/cohere/CohereGenerationAPICall.kt index 588bbf9..a5fe66f 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/cohere/CohereGenerationAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/cohere/CohereGenerationAPICall.kt @@ -1,4 +1,4 @@ -package skywolf46.devain.controller.api.cohere +package skywolf46.devain.controller.api.requests.cohere import arrow.core.Either import arrow.core.None @@ -10,8 +10,8 @@ import io.ktor.http.* import org.json.simple.JSONObject import org.koin.core.component.inject import skywolf46.devain.KEY_COHERE_GENERATION_PROCEED_COUNT -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.RESTAPICall +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall import skywolf46.devain.controller.api.requests.devain.DevAinUpdatePersistenceCountAPICall import skywolf46.devain.model.api.cohere.CohereGenerationRequest import skywolf46.devain.model.api.cohere.CohereGenerationResponse From 94d8f1cd4bc5a0d2bf3ac2c585a951074caac56a Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:01:38 +0900 Subject: [PATCH 10/46] =?UTF-8?q?feat:=20=EB=88=84=EB=9D=BD=EB=90=9C=20?= =?UTF-8?q?=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/skywolf46/devain/annotations/CommandParameter.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/annotations/CommandParameter.kt diff --git a/src/main/kotlin/skywolf46/devain/annotations/CommandParameter.kt b/src/main/kotlin/skywolf46/devain/annotations/CommandParameter.kt new file mode 100644 index 0000000..7a7eaab --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/annotations/CommandParameter.kt @@ -0,0 +1,5 @@ +package skywolf46.devain.annotations + +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.RUNTIME) +annotation class CommandParameter(val name: String, val description: String) \ No newline at end of file From 7bfb7f54c002d73822a34cef798d46ca5fb41346 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:02:21 +0900 Subject: [PATCH 11/46] =?UTF-8?q?feat:=20=EC=BD=98=ED=94=BC=EA=B7=B8=20?= =?UTF-8?q?=ED=98=95=ED=83=9C=20=EA=B0=9C=EB=B3=84=20=EC=BD=98=ED=94=BC?= =?UTF-8?q?=EA=B7=B8=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotations/config/ConfigDefault.kt | 7 ++ .../skywolf46/devain/config/BotConfig.kt | 96 --------------- .../devain/model/data/config/ConfigAdaptor.kt | 10 ++ .../model/data/config/ConfigDocumentRoot.kt | 109 ++++++++++++++++++ .../devain/model/data/config/ConfigElement.kt | 3 + 5 files changed, 129 insertions(+), 96 deletions(-) create mode 100644 src/main/kotlin/skywolf46/devain/annotations/config/ConfigDefault.kt delete mode 100644 src/main/kotlin/skywolf46/devain/config/BotConfig.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/data/config/ConfigElement.kt diff --git a/src/main/kotlin/skywolf46/devain/annotations/config/ConfigDefault.kt b/src/main/kotlin/skywolf46/devain/annotations/config/ConfigDefault.kt new file mode 100644 index 0000000..9e810e9 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/annotations/config/ConfigDefault.kt @@ -0,0 +1,7 @@ +package skywolf46.devain.annotations.config + +class ConfigDefault { + annotation class Int(val default: kotlin.Int) + + annotation class String(val default: kotlin.String) +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/config/BotConfig.kt b/src/main/kotlin/skywolf46/devain/config/BotConfig.kt deleted file mode 100644 index 8e5c1a2..0000000 --- a/src/main/kotlin/skywolf46/devain/config/BotConfig.kt +++ /dev/null @@ -1,96 +0,0 @@ -package skywolf46.devain.config - -import arrow.core.getOrElse -import skywolf46.devain.util.TimeUtil -import java.io.File -import java.io.FileReader -import java.io.FileWriter -import java.util.* - -class BotConfig { - val botToken: String - val openAIToken: String - val cohereToken: String - val openWeatherToken: String - val googleApiToken: String - val googleSearchEngineId: String - val deepLToken: String - val dreamStudioToken: String - val maxInput: Int - val maxDialogCache: Int - val maxUserPresetPerServer: Int - val maxServerPreset: Int - val sessionTokenRestoreTimer: Long - val sessionTokenRestoreAmount: Long - val maxSessionToken: Long - - init { - val file = File("settings.properties") - val defaultProperty = Properties().apply { - setProperty("bot-token", "your-bot-token-here") - setProperty("cohere-token", "your-cohere-token-here") - setProperty("openai-token", "your-openai-token-here") - setProperty("deepl-token", "your-deepl-token-here") - setProperty("dream-studio-token", "your-dream-studio-token-here") - setProperty("open-weather-token", "your-open-weather-token-here") - setProperty("google-api-token", "your-google-api-token-here") - setProperty("google-search-engine-id", "your-google-search-engine-id-here") - setProperty("max-input", "150") - setProperty("max-dialog-cache", "10") - setProperty("max-user-pattern-per-server", "10") - setProperty("max-server-preset", "15") - setProperty("session-token-restore-timer", "1h") - setProperty("session-token-restore-amount", "3000") - setProperty("max-session-token", "15000") - } - if (!file.exists()) { - FileWriter(file).use { - defaultProperty.store(it, "DevAin Config") - } - } - val property = FileReader(file).use { - Properties(defaultProperty).apply { - load(it) - } - } - botToken = property.getProperty("bot-token") ?: throw IllegalStateException("초기화 실패; 봇 토큰이 존재하지 않습니다.") - cohereToken = property.getProperty("cohere-token") - ?: throw IllegalStateException("초기화 실패; Cohere 토큰이 존재하지 않습니다.") - openAIToken = - property.getProperty("openai-token") ?: throw IllegalStateException("초기화 실패; OpenAI 토큰이 존재하지 않습니다.") - dreamStudioToken = - property.getProperty("dream-studio-token") - ?: throw IllegalStateException("초기화 실패; DreamStudio 토큰이 존재하지 않습니다.") - deepLToken = - property.getProperty("deepl-token") - ?: throw IllegalStateException("초기화 실패; DeepL 토큰이 존재하지 않습니다.") - openWeatherToken = - property.getProperty("open-weather-token") - ?: throw IllegalStateException("초기화 실패; OpenWeather 토큰이 존재하지 않습니다.") - googleApiToken = - property.getProperty("google-api-token") ?: throw IllegalStateException("초기화 실패; Google API 토큰이 존재하지 않습니다.") - googleSearchEngineId = - property.getProperty("google-search-engine-id") - ?: throw IllegalStateException("초기화 실패; Google Search Engine ID가 존재하지 않습니다.") - maxInput = property.getProperty("max-input")?.toIntOrNull() - ?: throw IllegalStateException("초기화 실패; 최대 입력 텍스트가 숫자가 아닙니다.") - maxDialogCache = property.getProperty("max-dialog-cache")?.toIntOrNull() - ?: throw IllegalStateException("초기화 실패; 최대 다이얼로그 캐싱 개수가 숫자가 아닙니다.") - maxUserPresetPerServer = property.getProperty("max-user-pattern-per-server")?.toIntOrNull() - ?: throw IllegalStateException("초기화 실패; 유저당 최대 패턴 개수가 숫자가 아닙니다.") - maxServerPreset = property.getProperty("max-server-preset")?.toIntOrNull() - ?: throw IllegalStateException("초기화 실패; 서버당 최대 프리셋 개수가 숫자가 아닙니다.") - sessionTokenRestoreTimer = - TimeUtil.parseToLong(property.getProperty("session-token-restore-timer") ?: "1h").getOrElse { - throw IllegalStateException("초기화 실패; 세션 토큰 재생 주기가 시간 포맷이 아닙니다.") - } - sessionTokenRestoreAmount = property.getProperty("session-token-restore-amount")?.toLongOrNull() - ?: throw IllegalStateException("초기화 실패; 재생 주기당 토큰 재생 개수가 숫자가 아닙니다.") - maxSessionToken = property.getProperty("max-session-token")?.toLongOrNull() - ?: throw IllegalStateException("초기화 실패; 최대 세션 토큰 개수가 숫자가 아닙니다.") - println("..설정 불러오기 완료 : ") - println("..최대 입력 허용: ${maxInput}자") - println("..최대 다이얼로그 캐싱: ${maxDialogCache}개") - } - -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt new file mode 100644 index 0000000..7ffe0e9 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt @@ -0,0 +1,10 @@ +package skywolf46.devain.model.data.config + +import java.io.InputStream +import java.io.OutputStream + +interface ConfigAdaptor { + fun serializeTo(stream: OutputStream, data: Map) + + fun serializeFrom(stream: InputStream) : Map +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt new file mode 100644 index 0000000..c88635b --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt @@ -0,0 +1,109 @@ +package skywolf46.devain.model.data.config + +import org.yaml.snakeyaml.DumperOptions +import org.yaml.snakeyaml.Yaml +import skywolf46.devain.annotations.config.ConfigDefault +import skywolf46.devain.annotations.config.MarkConfigElement +import java.io.File +import java.nio.charset.StandardCharsets +import java.util.concurrent.locks.ReentrantReadWriteLock +import kotlin.concurrent.read +import kotlin.concurrent.write +import kotlin.reflect.KClass +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation + +class ConfigDocumentRoot(private val fileRoot: File) { + private val expectedDocuments = mutableListOf() + + init { + if (!fileRoot.exists()) + fileRoot.mkdirs() + } + + fun loadSharedDocument() { + val file = fileRoot.resolve("config.yml") + if (!file.exists()) { + file.createNewFile() + file.writeText(Yaml(DumperOptions().apply { + defaultFlowStyle = DumperOptions.FlowStyle.BLOCK + }).dump(expectedDocuments.map { it.extractDefaultValue() }.apply { + println(this) + })) + } + val loaded = Yaml().load>(file.readText(StandardCharsets.UTF_8)) + println("Order: ${expectedDocuments.map { it.key }}") + expectedDocuments.forEach { + if (loaded[it.key] == null) + return@forEach + it.callFromMap(loaded[it.key] as Map) + } + + } + + fun fetchDocument(expected: KClass, adaptor: ConfigAdaptor, key: String): T { + return fileRoot.resolve(key).inputStream().use { + adaptor.serializeFrom(it) + } as T + } + + fun fetchSharedDocument(expected: KClass, key: String, unit: (T) -> Unit) { + val expectedDocument = expectedDocuments.firstOrNull { it.key == key } + ?: ExpectedDocument(key, expected).also { + expectedDocuments.add(it) + } + expectedDocument.addListener { + unit(it as T) + } + } + + class ExpectedDocument(val key: String, val cls: KClass) { + private val listeners = mutableListOf<(Any) -> Unit>() + + private val lock = ReentrantReadWriteLock() + + fun addListener(unit: (Any) -> Unit) { + lock.write { + listeners.add(unit) + } + } + + fun callListener(data: Any) { + lock.read { + listeners.forEach { + it(data) + } + } + } + + fun constructFromMap(map: Map): Any { + return cls.constructors.first().callBy( + cls.constructors.first().parameters.filter { it.hasAnnotation() }.map { + it to (map[it.findAnnotation()!!.name.ifBlank { it.name!! }] + ?: if (it.isOptional) null else throw IllegalStateException("Missing key: ${it.name}")) + }.associate { it } + ) + } + + fun callFromMap(map: Map) { + callListener(constructFromMap(map)) + } + + fun extractDefaultValue(): Map { + return cls.constructors.first().parameters.filter { it.hasAnnotation() }.map { + (it.findAnnotation()!!.name.ifBlank { it.name!! }) to (it.findAnnotation()?.default + ?: it.findAnnotation()?.default) + }.filter { it.second != null }.associate { it } + } + } +} + +inline fun ConfigDocumentRoot.fetchDocument(adaptor: ConfigAdaptor, key: String): T { + return fetchDocument(T::class, adaptor, key) +} + + +inline fun ConfigDocumentRoot.fetchSharedDocument(key: String, noinline unit: (T) -> Unit) { + fetchSharedDocument(T::class, key, unit) +} + diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigElement.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigElement.kt new file mode 100644 index 0000000..3e1f82d --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigElement.kt @@ -0,0 +1,3 @@ +package skywolf46.devain.model.data.config + +interface ConfigElement \ No newline at end of file From fb98452c05e6a268e47f4d24241bf7964ec20f00 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:02:48 +0900 Subject: [PATCH 12/46] =?UTF-8?q?feat:=20Command=20R+=20=EC=A7=80=EC=9B=90?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../requests/cohere/CommandRPlusAPICall.kt | 45 +++++++ .../commands/discord/cohere/CohereCommand.kt | 76 ++++-------- .../discord/cohere/CommandRCommand.kt | 36 ++++++ .../discord/cohere/CommandRPlusCommand.kt | 35 ++++++ .../devain/controller/modules/CohereModule.kt | 36 +++--- .../api/cohere/CohereGenerationRequest.kt | 111 +++++++++--------- .../api/cohere/CohereGenerationResponse.kt | 2 +- .../devain/model/api/cohere/CohereMessage.kt | 1 - 8 files changed, 213 insertions(+), 129 deletions(-) create mode 100644 src/main/kotlin/skywolf46/devain/controller/api/requests/cohere/CommandRPlusAPICall.kt create mode 100644 src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRCommand.kt create mode 100644 src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRPlusCommand.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/cohere/CommandRPlusAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/cohere/CommandRPlusAPICall.kt new file mode 100644 index 0000000..6e2f0e0 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/cohere/CommandRPlusAPICall.kt @@ -0,0 +1,45 @@ +package skywolf46.devain.controller.api.requests.cohere + +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.right +import io.ktor.client.* +import io.ktor.client.statement.* +import io.ktor.http.* +import org.json.simple.JSONObject +import org.koin.core.component.inject +import skywolf46.devain.KEY_COMMAND_R_PLUS_GENERATION_PROCEED_COUNT +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall +import skywolf46.devain.controller.api.requests.devain.DevAinUpdatePersistenceCountAPICall +import skywolf46.devain.model.api.openai.UpdateRequest +import skywolf46.devain.model.api.rplus.RPlusRequest +import skywolf46.devain.model.api.rplus.RPlusResponse + +class CommandRPlusAPICall(val apiKey: String, client: Option = None) : + RESTAPICall({ + "https://api.cohere.ai/v1/chat" + }, client, HttpMethod.Post) { + + private val updateCall by inject() + + override suspend fun parseResult( + request: RPlusRequest, + response: JSONObject + ): Either { + return RPlusResponse.fromJson(response).apply { + updateCall.call(UpdateRequest(KEY_COMMAND_R_PLUS_GENERATION_PROCEED_COUNT, 1L)) + }.right() + } + + override fun HeadersBuilder.applyCredential() { + append("authorization", "Bearer $apiKey") + } + + override suspend fun parseHttpError(request: RPlusRequest, response: HttpResponse, errorCode: Int): APIError { + println(response.headers) + return super.parseHttpError(request, response, errorCode) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CohereCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CohereCommand.kt index 60afb66..79b0720 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CohereCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CohereCommand.kt @@ -1,66 +1,36 @@ package skywolf46.devain.controller.commands.discord.cohere -import arrow.core.toOption -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent -import net.dv8tion.jda.api.interactions.commands.OptionType -import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData import org.koin.core.component.inject -import skywolf46.devain.controller.api.cohere.CohereGenerationAPICall +import skywolf46.devain.controller.api.requests.cohere.CohereGenerationAPICall import skywolf46.devain.model.api.cohere.CohereGenerationRequest -import skywolf46.devain.platform.discord.ImprovedDiscordCommand +import skywolf46.devain.platform.discord.AnnotatedParameterDiscordCommand +import skywolf46.devain.util.GenerationResultTextBuilder +import skywolf46.devain.util.TimeUtil -class CohereCommand : ImprovedDiscordCommand("cohere") { +class CohereCommand : AnnotatedParameterDiscordCommand("cohere", CohereGenerationRequest::class) { private val apiCall by inject() - override fun modifyCommandData(options: SlashCommandData) { - options.addOption(OptionType.STRING, "prompt", "요청 프롬프트입니다.", true) - options.addOption(OptionType.INTEGER, "max-tokens", "최대 토큰입니다.") - options.addOption( - OptionType.NUMBER, - "temperature", - "temperature 값입니다. 낮을수록 예측 가능한 값을, 높을수록 예측 불가능한 결과를 제공합니다. (기본 0.75, 0.0 ~ 5.0)" - ) - options.addOption( - OptionType.INTEGER, - "top_k", - "top_k 값입니다. 각 단계에서 생성할 가능성이 높은 상위 k개의 값만 고려되도록 합니다. (기본 0, 0 ~ 500)" - ) - options.addOption( - OptionType.NUMBER, - "top_p", - "top_p 값입니다. 각 단계에서 총 확률 질량이 p인 가장 가능성이 높은 토큰만 고려되도록 합니다. (기본 0.0, 0.0 ~ 0.99)" - ) - options.addOption( - OptionType.NUMBER, - "frequency_penalty", - "frequency_penalty 값입니다. 높을수록, 이전에 반복된 토큰에 대하여 횟수에 비례해 더 강력한 패널티를 가합니다. (기본 0.0, 0.0 ~ 1.0)" - ) - options.addOption( - OptionType.NUMBER, - "presence_penalty", - "presence_penalty 값입니다. 높을수록, 이전에 반복된 값에 대해 동일한 패널티를 가합니다. (기본 0.0, 0.0 ~ 1.0)" - ) - } - - override suspend fun onCommand(event: SlashCommandInteractionEvent) { - val request = CohereGenerationRequest( - event.getOption("prompt")!!.asString, - "command", - 1, - false, - maxTokens = (event.getOption("max-tokens")?.asInt ?: 1024).toOption(), - temperature = event.getOption("temperature")?.asDouble.toOption(), - top_k = event.getOption("top_k")?.asInt.toOption(), - top_p = event.getOption("top_p")?.asDouble.toOption(), - frequencyPenalty = event.getOption("frequency_penalty")?.asDouble.toOption(), - presencePenalty = event.getOption("presence_penalty")?.asDouble.toOption(), - ) - event.defer { _, hook -> - apiCall.call(request).fold({ + override suspend fun onParameterCommand(event: CommandEvent, data: CohereGenerationRequest) { + event.origin.defer { _, hook -> + apiCall.call(data.copy(model = "command")).fold({ hook.sendMessage("오류가 발생했습니다. ${it.getErrorMessage()}").queue() }) { - hook.sendMessage(it.generations[0].text).queue() + val builder = GenerationResultTextBuilder( + "Request Complete - Cohere Command", data.prompt, listOf( + mapOf( + "Model" to box("Command (Cohere)"), + "Elapsed" to box(TimeUtil.toTimeString(event.elapsed())), + ), mapOf("Response" to it.generations[0].text) + ) + ) + hook.sendMessageOrEmbed(1000, it.generations[0].text) { embed -> + builder.asEmbed(embed) + } } } } + + override fun onCommandParameterDataRequested(): Map { + return mapOf("model" to "Cohere Command") + } } \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRCommand.kt new file mode 100644 index 0000000..2c11945 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRCommand.kt @@ -0,0 +1,36 @@ +package skywolf46.devain.controller.commands.discord.cohere + +import org.koin.core.component.inject +import skywolf46.devain.controller.api.requests.cohere.CommandRPlusAPICall +import skywolf46.devain.model.api.rplus.RPlusRequest +import skywolf46.devain.platform.discord.AnnotatedParameterDiscordCommand +import skywolf46.devain.util.GenerationResultTextBuilder +import skywolf46.devain.util.TimeUtil + +class CommandRCommand : AnnotatedParameterDiscordCommand("rminus", RPlusRequest::class) { + private val apiCall by inject() + + override suspend fun onParameterCommand(event: CommandEvent, data: RPlusRequest) { + event.origin.defer { _, hook -> + apiCall.call(data.copy(model = "command-r")).fold({ + hook.sendMessage("오류가 발생했습니다. ${it.getErrorMessage()}").queue() + }) { + val builder = GenerationResultTextBuilder( + "Request Complete - Command R", data.message, listOf( + mapOf( + "Model" to box("Command R (Cohere)"), + "Elapsed" to box(TimeUtil.toTimeString(event.elapsed())), + ), mapOf("Response" to it.text) + ) + ) + hook.sendMessageOrEmbed(1000, it.text) { embed -> + builder.asEmbed(embed) + } + } + } + } + + override fun onCommandParameterDataRequested(): Map { + return mapOf("model" to "Command R") + } +} diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRPlusCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRPlusCommand.kt new file mode 100644 index 0000000..5052e8e --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRPlusCommand.kt @@ -0,0 +1,35 @@ +package skywolf46.devain.controller.commands.discord.cohere + +import org.koin.core.component.inject +import skywolf46.devain.controller.api.requests.cohere.CommandRPlusAPICall +import skywolf46.devain.model.api.rplus.RPlusRequest +import skywolf46.devain.platform.discord.AnnotatedParameterDiscordCommand +import skywolf46.devain.util.GenerationResultTextBuilder +import skywolf46.devain.util.TimeUtil + +class CommandRPlusCommand : AnnotatedParameterDiscordCommand("rplus", RPlusRequest::class) { + private val apiCall by inject() + + override suspend fun onParameterCommand(event: CommandEvent, data: RPlusRequest) { + event.origin.defer { _, hook -> + apiCall.call(data.copy(model = "command-r-plus")).fold({ + hook.sendMessage("오류가 발생했습니다. ${it.getErrorMessage()}").queue() + }) { + val builder = GenerationResultTextBuilder("Request Complete - Command R+", data.message, listOf( + mapOf( + "Model" to box("Command R+ (Cohere)"), + "Elapsed" to box(TimeUtil.toTimeString(event.elapsed())), + ), + mapOf("Response" to it.text) + )) + hook.sendMessageOrEmbed(1000, it.text) { embed -> + builder.asEmbed(embed) + } + } + } + } + + override fun onCommandParameterDataRequested(): Map { + return mapOf("model" to "Command R+") + } +} diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/CohereModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/CohereModule.kt index f20e545..e5c15c6 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/CohereModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/CohereModule.kt @@ -4,32 +4,36 @@ import org.koin.core.component.inject import org.koin.core.context.loadKoinModules import org.koin.dsl.module import skywolf46.devain.KEY_COHERE_GENERATION_PROCEED_COUNT -import skywolf46.devain.controller.api.certainly -import skywolf46.devain.controller.api.cohere.CohereGenerationAPICall +import skywolf46.devain.apicall.certainly +import skywolf46.devain.apicall.networking.GetRequest +import skywolf46.devain.controller.api.requests.cohere.CohereGenerationAPICall +import skywolf46.devain.controller.api.requests.cohere.CommandRPlusAPICall import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall import skywolf46.devain.controller.commands.discord.cohere.CohereCommand -import skywolf46.devain.model.api.openai.GetRequest +import skywolf46.devain.controller.commands.discord.cohere.CommandRCommand +import skywolf46.devain.controller.commands.discord.cohere.CommandRPlusCommand +import skywolf46.devain.model.data.config.APITokenElement +import skywolf46.devain.model.data.config.fetchSharedDocument import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule -class CohereModule(private val apiKey: String) : PluginModule("Cohere Integration") { - private val module = module { - single { CohereGenerationAPICall(apiKey) } - } - +class CohereModule : PluginModule("Cohere Integration") { private val discord by inject() private val apiCall by inject() - - override fun onPostInitialize() { - loadKoinModules(module) - } - override fun onInitialize() { - discord.registerCommands( - CohereCommand() - ) + document.fetchSharedDocument(pluginName) { config -> + loadKoinModules(module { + single { CohereGenerationAPICall(config.apiToken) } + single { CommandRPlusAPICall(config.apiToken) } + }) + discord.registerCommands( + CohereCommand(), + CommandRCommand(), + CommandRPlusCommand() + ) + } } override suspend fun getStatistics(): Map> { diff --git a/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereGenerationRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereGenerationRequest.kt index fc1a6f9..4ae4c2e 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereGenerationRequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereGenerationRequest.kt @@ -1,83 +1,78 @@ package skywolf46.devain.model.api.cohere -import arrow.core.* +import arrow.core.Either +import arrow.core.left +import arrow.core.right import org.json.simple.JSONObject -import skywolf46.devain.model.Request -import skywolf46.devain.util.checkRangeAndFatal +import skywolf46.devain.annotations.CommandParameter +import skywolf46.devain.annotations.Required +import skywolf46.devain.apicall.networking.Request +import skywolf46.devain.util.putNotNull +import skywolf46.devain.util.putNotNullOrFatal /** * Cohere Generate API Request. * @see [https://docs.cohere.com/reference/generate] */ data class CohereGenerationRequest( - val prompt: String, - val model: String, - val totalGeneration: Int, - val stream: Boolean, - val truncate: Option = None, - val maxTokens: Option = None, - val temperature: Option = None, - val top_k: Option = None, - val top_p: Option = None, - val frequencyPenalty: Option = None, - val presencePenalty: Option = None, - val likeliHoods: Option = None, - val endSequence: Option> = None, - val stopSequence: Option> = None, + @Required @CommandParameter("prompt", "{model}에 질의할 내용입니다.") val prompt: String, + val model: String = "command", + @CommandParameter("max-token", "모델이 응답으로 제공할 수 있는 최대 토큰 수를 제한합니다. (기본 2048, 최대 4096)") val maxTokens: Int? = null, + @CommandParameter( + "temperature", "낮을수록 예측 가능한 값을, 높을수록 예측 불가능한 결과를 제공합니다. (기본 0.75, 0.0 ~ 2.0)" + ) val temperature: Double? = null, + @CommandParameter( + "frequency-penalty", "해당 값이 높을수록, 이전에 반복된 토큰에 대하여 횟수에 비례해 더 강력한 패널티를 가합니다. (기본 0.0, 0.0 ~ 1.0)" + ) val frequencyPenalty: Double? = null, + @CommandParameter( + "presence-penalty", "해당 값이 높을수록, 이전에 반복된 값에 대해 동일한 패널티를 가합니다. (기본 0.0, 0.0 ~ 1.0)" + ) val presencePenalty: Double? = null, + @CommandParameter( + "k", "top_k 값입니다. 각 단계에서 생성할 가능성이 높은 상위 k개의 값만 고려되도록 합니다. (기본 0, 0 ~ 500)" + ) val top_k: Int? = null, + @CommandParameter( + "p", "각 단계에서 총 확률 질량이 p인 가장 가능성이 높은 토큰만 고려되도록 합니다. (기본 0.0, 0.0 ~ 0.99)" + ) val top_p: Double? = null, + val totalGeneration: Int? = null, + val stream: Boolean? = null, + val truncate: TruncateType? = null, + val likeliHoods: LikeliHoods? = null, + val endSequence: List? = null, + val stopSequence: List? = null, ) : Request { - override fun asJson(): Either { + override fun serialize(): Either { val json = JSONObject() json["prompt"] = prompt json["model"] = model - json["num_generations"] = totalGeneration.checkRangeAndFatal(1..5) { - return IllegalArgumentException("Total generation must be in range of ${it.first}..${it.last}").left() - } json["stream"] = stream - maxTokens.tap { - json["max_tokens"] = - it.checkRangeAndFatal((if (likeliHoods.getOrElse { null } == LikeliHoods.ALL) 0 else 1)..Integer.MAX_VALUE) { - return IllegalArgumentException("Max tokens must be in range of ${it.first}..${it.last}").left() - } - } - - truncate.tap { - json["truncate"] = it.name - } - temperature.tap { - json["temperature"] = it.checkRangeAndFatal(0.0..5.0) { - return IllegalArgumentException("Max tokens must be in range of ${it.start}..${it.endInclusive}").left() - } - } - endSequence.tap { - json["end_sequence"] = it + json.putNotNull("end_sequence", endSequence) + json.putNotNull("stop_sequence", stopSequence) + json.putNotNull("truncate", truncate) + json.putNotNullOrFatal("num_generations", totalGeneration, 1..5) { + return IllegalArgumentException("Total generation must be in range of ${it.start}..${it.endInclusive}").left() } - stopSequence.tap { - json["stop_sequence"] = it + json.putNotNullOrFatal( + "max_tokens", maxTokens, (if (likeliHoods == LikeliHoods.ALL) 0 else 1)..Integer.MAX_VALUE + ) { + return IllegalArgumentException("Max tokens must be in range of ${it.start}..${it.endInclusive}").left() } - top_k.tap { - json["k"] = it.checkRangeAndFatal(0..500) { - return IllegalArgumentException("Top k must be in range of ${it.start}..${it.endInclusive}").left() - } + json.putNotNullOrFatal("temperature", temperature, 0.0..5.0) { + return IllegalArgumentException("Temperature must be in range of ${it.start}..${it.endInclusive}").left() } - top_p.tap { - json["p"] = it.checkRangeAndFatal(0.0..0.99) { - return IllegalArgumentException("Top p must be in range of ${it.start}..${it.endInclusive}").left() - } + json.putNotNullOrFatal("k", top_k, 0..500) { + return IllegalArgumentException("Top k must be in range of ${it.start}..${it.endInclusive}").left() } - frequencyPenalty.tap { - json["frequency_penalty"] = it.checkRangeAndFatal(0.0..1.0) { - return IllegalArgumentException("Frequency penalty must be in range of ${it.start}..${it.endInclusive}").left() - } + json.putNotNullOrFatal("p", top_p, 0.0..0.99) { + return IllegalArgumentException("Top p must be in range of ${it.start}..${it.endInclusive}").left() } - presencePenalty.tap { - json["presence_penalty"] = it.checkRangeAndFatal(0.0..1.0) { - return IllegalArgumentException("Presence penalty must be in range of ${it.start}..${it.endInclusive}").left() - } + json.putNotNullOrFatal("frequency_penalty", frequencyPenalty, 0.0..1.0) { + return IllegalArgumentException("Frequency penalty must be in range of ${it.start}..${it.endInclusive}").left() } - likeliHoods.tap { - json["return_likelihoods"] = it.name + json.putNotNullOrFatal("presence_penalty", presencePenalty, 0.0..1.0) { + return IllegalArgumentException("Presence penalty must be in range of ${it.start}..${it.endInclusive}").left() } + json.putNotNull("return_likelihoods", likeliHoods?.name) return json.right() } diff --git a/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereGenerationResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereGenerationResponse.kt index 34f53d6..b382b40 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereGenerationResponse.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereGenerationResponse.kt @@ -1,7 +1,7 @@ package skywolf46.devain.model.api.cohere import org.json.simple.JSONObject -import skywolf46.devain.model.Response +import skywolf46.devain.apicall.networking.Response import skywolf46.devain.util.getList data class CohereGenerationResponse(val id: String, val prompt: String, val generations: List) : diff --git a/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereMessage.kt b/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereMessage.kt index 847e32a..c62c4dc 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereMessage.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereMessage.kt @@ -1,6 +1,5 @@ package skywolf46.devain.model.api.cohere -import arrow.core.Option import org.json.simple.JSONObject data class CohereMessage(val id: String, val text: String) { From 430e432e666214a2155be69b5acdde3258d05565 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:03:18 +0900 Subject: [PATCH 13/46] =?UTF-8?q?feat:=20Claude=20=EC=A7=80=EC=9B=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/requests/anthropic/ClaudeAPICall.kt | 30 ++++++++++++++ .../discord/anthropic/ClaudeCommand.kt | 40 +++++++++++++++++++ .../api/anthropic/ClaudeGenerationRequest.kt | 22 ++++++++++ .../api/anthropic/ClaudeGenerationResponse.kt | 19 +++++++++ .../model/api/anthropic/ClaudeMessage.kt | 20 ++++++++++ 5 files changed, 131 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/controller/api/requests/anthropic/ClaudeAPICall.kt create mode 100644 src/main/kotlin/skywolf46/devain/controller/commands/discord/anthropic/ClaudeCommand.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationRequest.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationResponse.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeMessage.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/anthropic/ClaudeAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/anthropic/ClaudeAPICall.kt new file mode 100644 index 0000000..6844a37 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/anthropic/ClaudeAPICall.kt @@ -0,0 +1,30 @@ +package skywolf46.devain.controller.api.requests.anthropic + +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.right +import io.ktor.client.* +import io.ktor.http.* +import org.json.simple.JSONObject +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall +import skywolf46.devain.model.api.anthropic.ClaudeGenerationRequest +import skywolf46.devain.model.api.anthropic.ClaudeGenerationResponse + +class ClaudeAPICall(private val apiKey: String, client: Option = None) : + RESTAPICall( + { req -> "https://api.anthropic.com/v1/messages" }, client, HttpMethod.Post + ) { + override suspend fun parseResult( + request: ClaudeGenerationRequest, + response: JSONObject + ): Either { + return ClaudeGenerationResponse.fromJson(response).right() + } + + override fun HeadersBuilder.applyCredential() { + append("x-api-key", apiKey) + append("anthropic-version", "2023-06-01") + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/anthropic/ClaudeCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/anthropic/ClaudeCommand.kt new file mode 100644 index 0000000..51d18e5 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/anthropic/ClaudeCommand.kt @@ -0,0 +1,40 @@ +package skywolf46.devain.controller.commands.discord.anthropic + +import arrow.core.toOption +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.interactions.commands.OptionType +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData +import org.koin.core.component.inject +import skywolf46.devain.controller.api.requests.anthropic.ClaudeAPICall +import skywolf46.devain.model.api.anthropic.ClaudeGenerationRequest +import skywolf46.devain.model.api.anthropic.ClaudeMessage +import skywolf46.devain.platform.discord.ImprovedDiscordCommand + +class ClaudeCommand : ImprovedDiscordCommand("claude") { + private val apiCall by inject() + + override fun modifyCommandData(options: SlashCommandData) { + options.addOption(OptionType.STRING, "prompt", "요청 프롬프트입니다.", true) + options.addOption(OptionType.INTEGER, "max-tokens", "최대 토큰입니다.") + } + + override suspend fun onCommand(event: SlashCommandInteractionEvent) { + val request = ClaudeGenerationRequest( + "claude-3-opus-20240229", + listOf( + ClaudeMessage( + ClaudeMessage.ClaudeGenerationRole.USER, event.getOption("prompt")!!.asString + + ) + ), + 4096.toOption() + ) + event.defer { _, hook -> + apiCall.call(request).fold({ + hook.sendMessage("오류가 발생했습니다. ${it.getErrorMessage()}").queue() + }) { + hook.sendMessage(it.message.joinToString("\n")).queue() + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationRequest.kt new file mode 100644 index 0000000..762fb38 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationRequest.kt @@ -0,0 +1,22 @@ +package skywolf46.devain.model.api.anthropic + +import arrow.core.Either +import arrow.core.Option +import arrow.core.right +import org.json.simple.JSONObject +import skywolf46.devain.apicall.networking.Request + +class ClaudeGenerationRequest( + val model: String, + val messages: List, + val maxTokens: Option, +) : Request { + override fun serialize(): Either { + val obj = JSONObject() + obj["model"] = model + obj["messages"] = messages.map { it.serialize().orNull() } + maxTokens.map { obj["max_tokens"] = it } + return obj.right() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationResponse.kt new file mode 100644 index 0000000..1fce3bc --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationResponse.kt @@ -0,0 +1,19 @@ +package skywolf46.devain.model.api.anthropic + +import org.json.simple.JSONObject +import skywolf46.devain.apicall.networking.Response +import skywolf46.devain.util.getList + +class ClaudeGenerationResponse( + val message: List +) : Response { + companion object { + fun fromJson(data: JSONObject): ClaudeGenerationResponse { + if ("content" in data) { + val list = data.getList("content") + return ClaudeGenerationResponse(list.map { (it as JSONObject)["text"].toString() }) + } + return ClaudeGenerationResponse(listOf()) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeMessage.kt b/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeMessage.kt new file mode 100644 index 0000000..5730aa4 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeMessage.kt @@ -0,0 +1,20 @@ +package skywolf46.devain.model.api.anthropic + +import arrow.core.Either +import arrow.core.right +import org.json.simple.JSONObject +import skywolf46.devain.apicall.networking.Request + +class ClaudeMessage(val type: ClaudeGenerationRole, val content: String) : Request { + + enum class ClaudeGenerationRole(val type: String) { + USER("user"), ASSISTANT("assistant") + } + + override fun serialize(): Either { + return JSONObject().apply { + this["role"] = type.type + this["content"] = content + }.right() + } +} \ No newline at end of file From 6a5023a8ad3224f7ea2c59b4dadc55f6571c435b Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:03:32 +0900 Subject: [PATCH 14/46] =?UTF-8?q?chore:=20=EC=9D=BC=EB=B6=80=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devain/model/{ => data}/store/OpenAIFunctionStore.kt | 2 +- .../skywolf46/devain/model/{ => data}/store/SqliteStore.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/kotlin/skywolf46/devain/model/{ => data}/store/OpenAIFunctionStore.kt (95%) rename src/main/kotlin/skywolf46/devain/model/{ => data}/store/SqliteStore.kt (94%) diff --git a/src/main/kotlin/skywolf46/devain/model/store/OpenAIFunctionStore.kt b/src/main/kotlin/skywolf46/devain/model/data/store/OpenAIFunctionStore.kt similarity index 95% rename from src/main/kotlin/skywolf46/devain/model/store/OpenAIFunctionStore.kt rename to src/main/kotlin/skywolf46/devain/model/data/store/OpenAIFunctionStore.kt index 1204758..580d3ee 100644 --- a/src/main/kotlin/skywolf46/devain/model/store/OpenAIFunctionStore.kt +++ b/src/main/kotlin/skywolf46/devain/model/data/store/OpenAIFunctionStore.kt @@ -1,4 +1,4 @@ -package skywolf46.devain.model.store +package skywolf46.devain.model.data.store import arrow.core.Option import arrow.core.getOrElse diff --git a/src/main/kotlin/skywolf46/devain/model/store/SqliteStore.kt b/src/main/kotlin/skywolf46/devain/model/data/store/SqliteStore.kt similarity index 94% rename from src/main/kotlin/skywolf46/devain/model/store/SqliteStore.kt rename to src/main/kotlin/skywolf46/devain/model/data/store/SqliteStore.kt index 6ef18af..5d4dad7 100644 --- a/src/main/kotlin/skywolf46/devain/model/store/SqliteStore.kt +++ b/src/main/kotlin/skywolf46/devain/model/data/store/SqliteStore.kt @@ -1,4 +1,4 @@ -package skywolf46.devain.model.store +package skywolf46.devain.model.data.store import java.sql.Connection import java.sql.DriverManager From 6a004d593e4d607dc515c97b4299c331cb517347 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:03:58 +0900 Subject: [PATCH 15/46] =?UTF-8?q?feat:=20=EB=88=84=EB=9D=BD=EB=90=9C=20Com?= =?UTF-8?q?mand=20R+=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/api/rplus/RPlusMessageHistory.kt | 23 ++++++++ .../devain/model/api/rplus/RPlusRequest.kt | 55 +++++++++++++++++++ .../devain/model/api/rplus/RPlusResponse.kt | 14 +++++ 3 files changed, 92 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusMessageHistory.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusRequest.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusResponse.kt diff --git a/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusMessageHistory.kt b/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusMessageHistory.kt new file mode 100644 index 0000000..742d75e --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusMessageHistory.kt @@ -0,0 +1,23 @@ +package skywolf46.devain.model.api.rplus + +import arrow.core.Either +import arrow.core.right +import org.json.simple.JSONObject +import skywolf46.devain.apicall.networking.Request + +class RPlusMessageHistory( + val role: RPlusMessageType, + val message: String +) : Request { + override fun serialize(): Either { + return JSONObject().apply { + this["role"] = role.name + this["message"] = message + }.right() + } + + enum class RPlusMessageType { + USER, SYSTEM, CHATBOT + } + +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusRequest.kt new file mode 100644 index 0000000..06dfd66 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusRequest.kt @@ -0,0 +1,55 @@ +package skywolf46.devain.model.api.rplus + +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.right +import org.json.simple.JSONObject +import skywolf46.devain.annotations.CommandParameter +import skywolf46.devain.annotations.Required +import skywolf46.devain.apicall.networking.Request +import skywolf46.devain.util.putNotNull + +data class RPlusRequest( + @Required + @CommandParameter("prompt", "{model}에 질의할 내용입니다.") + val message: String, + val model: String = "command-r", + @CommandParameter("temperature", "낮을수록 예측 가능한 값을, 높을수록 예측 불가능한 결과를 제공합니다. (기본 0.75, 0.0 ~ 2.0)") + val temperature: Float? = null, + @CommandParameter("max-token", "모델이 응답으로 제공할 수 있는 최대 토큰 수를 제한합니다. (기본 2048, 최대 4096)") + val maxTokens: Long? = null, + @CommandParameter("max-input-token", "모델에 최대로 입력 가능한 토큰 수를 제한합니다. (기본 2048, 최대 4096)") + val maxInputTokens: Long? = null, + @CommandParameter("k", "제공된 설명이 존재하지 않습니다.") + val k: Long? = null, + @CommandParameter("p", "제공된 설명이 존재하지 않습니다.") + val p: Long? = null, + @CommandParameter("seed", "프롬프트의 기초로 사용될 시드 값입니다.") + val seed: Long? = null, + @CommandParameter("frequency-penalty", "해당 값이 높을수록, 이전에 반복된 토큰에 대하여 횟수에 비례해 더 강력한 패널티를 가합니다. (기본 0.0, 0.0 ~ 1.0)") + val frequencyPenalty: Float? = null, + @CommandParameter("presence-penalty", "해당 값이 높을수록, 이전에 반복된 값에 대해 동일한 패널티를 가합니다. (기본 0.0, 0.0 ~ 1.0)") + val presencePenalty: Float? = null, + @CommandParameter("preamble", "AI의 역할 및 규칙을 미리 제정합니다.") + val preamble: String? = null, + val stream: Boolean? = null, + val truncation: Option = None, + val history: Option> = None, +) : Request { + + + override fun serialize(): Either { + val json = JSONObject() + json["message"] = message + json["model"] = model + json.putNotNull("preamble", preamble) + return json.right() + } + + enum class PromptTruncation { + AUTO, AUTO_PRESERVE_ORDER, OFF + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusResponse.kt new file mode 100644 index 0000000..9a292c6 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusResponse.kt @@ -0,0 +1,14 @@ +package skywolf46.devain.model.api.rplus + +import org.json.simple.JSONObject +import skywolf46.devain.apicall.networking.Response + +class RPlusResponse(val text: String) : Response { + companion object { + fun fromJson(jsonObject: JSONObject) : RPlusResponse { + return RPlusResponse( + jsonObject["text"].toString() + ) + } + } +} \ No newline at end of file From dd27650f787c114efc5dbfae406c479de47dd4a8 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:05:04 +0900 Subject: [PATCH 16/46] =?UTF-8?q?feat:=20OpenAI=20API=20=EC=8A=A4=ED=82=A4?= =?UTF-8?q?=EB=A7=88=20=EB=B3=80=EA=B2=BD=20=EB=8C=80=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../discord/openai/SimpleGPTCommand.kt | 5 ++- .../api/openai/completion/OpenAIGPTMessage.kt | 34 ++++++++++++++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt index 5237384..cd31a44 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt @@ -1,6 +1,5 @@ package skywolf46.devain.controller.commands.discord.openai -import arrow.core.None import arrow.core.toOption import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent @@ -178,12 +177,12 @@ class SimpleGPTCommand( } private fun appendRequest(builder: StringBuilder, request: OpenAIGPTRequest) { - builder.append("**요청:** \n${request.messages.last().content.orNull()}") + builder.append("**요청:** \n${request.messages.last().content.find { it.first == "text" }?.second}") builder.appendNewLine(2) } private fun appendResult(builder: StringBuilder, result: OpenAIGPTResponse) { - builder.append("**응답:** \n${result.answers[0].message.content.orNull()}") + builder.append("**응답:** \n${result.answers[0].message.content.find { it.first == "text" }?.second}") } private fun StringBuilder.appendNewLine(count: Int = 1) { diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTMessage.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTMessage.kt index 6ffc08f..d29226a 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTMessage.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTMessage.kt @@ -2,7 +2,7 @@ package skywolf46.devain.model.api.openai.completion import arrow.core.* import org.json.simple.JSONObject -import skywolf46.devain.model.Request +import skywolf46.devain.apicall.networking.Request open class OpenAIGPTMessage( /** @@ -12,7 +12,7 @@ open class OpenAIGPTMessage( /** * Message content. */ - val content: Option, + val content: List>, val functionCall: Option = None, val functionName: Option = None ) : Request { @@ -29,13 +29,39 @@ open class OpenAIGPTMessage( data["name"]?.toString().toOption(), ) } + + operator fun invoke( + /** + * Message role. + */ + role: Role, + /** + * Message content. + */ + content: Option, + functionCall: Option = None, + functionName: Option = None + ) = OpenAIGPTMessage( + role, + if (content.isEmpty()) emptyList() else listOf("text" to content.orNull()!!), + functionCall, + functionName + ) } - override fun asJson(): Either { + override fun serialize(): Either { return JSONObject().apply { this["role"] = role.gptType.lowercase() - this["content"] = content.orNull() + this["content"] = content.map { + JSONObject().apply { + this["type"] = it.first + when (this["type"]) { + "image_url" -> this["image_url"] = it.second + else -> this["text"] = it.second + } + } + } functionCall.tap { this["function_call"] = it } From fc014c4bc8042f66eceaf77ff96656ca7d2e68a1 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:05:14 +0900 Subject: [PATCH 17/46] =?UTF-8?q?feat:=20OpenAI=20API=20=EC=8A=A4=ED=82=A4?= =?UTF-8?q?=EB=A7=88=20=EB=B3=80=EA=B2=BD=20=EB=8C=80=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/commands/discord/openai/TestGPTCommand.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/TestGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/TestGPTCommand.kt index d8ce60e..5360fc7 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/TestGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/TestGPTCommand.kt @@ -214,13 +214,13 @@ class TestGPTCommand( private fun appendRequest(builder: StringBuilder, request: OpenAIGPTRequest) { val requestMessage = request.messages.find { it.role == OpenAIGPTMessage.Role.USER }!! - builder.append("**요청:** \n${requestMessage.content.orNull()!!}") + builder.append("**요청:** \n${requestMessage.content.find { it.first == "text" }?.second}") builder.appendNewLine(2) } private fun appendResult(builder: StringBuilder, result: OpenAIGPTResponse) { val responseMessage = result.answers.last() - builder.append("**응답:** \n${responseMessage.message.content.orNull()!!}") + builder.append("**응답:** \n${responseMessage.message.content.find { it.first == "text" }?.second}") } private fun StringBuilder.appendNewLine(count: Int = 1) { From 317438758d88e07c97c9ca33842bd4b241aa67fc Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:06:21 +0900 Subject: [PATCH 18/46] =?UTF-8?q?feat:=20=EC=BD=98=ED=94=BC=EA=B7=B8=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D=20=EB=B3=80=EA=B2=BD=20=EB=8C=80=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/modules/AnthropicModule.kt | 28 ++++++ .../devain/controller/modules/DeepLModule.kt | 31 ++++--- .../devain/controller/modules/DevAinModule.kt | 10 +-- .../devain/controller/modules/OpenAIModule.kt | 86 ++++++++++++------- .../controller/modules/StabilityAIModule.kt | 6 +- 5 files changed, 108 insertions(+), 53 deletions(-) create mode 100644 src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt new file mode 100644 index 0000000..9106d3a --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt @@ -0,0 +1,28 @@ +package skywolf46.devain.controller.modules + +import org.koin.core.component.inject +import org.koin.core.context.loadKoinModules +import org.koin.dsl.module +import skywolf46.devain.controller.api.requests.anthropic.ClaudeAPICall +import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall +import skywolf46.devain.controller.commands.discord.anthropic.ClaudeCommand +import skywolf46.devain.model.data.config.APITokenElement +import skywolf46.devain.model.data.config.fetchSharedDocument +import skywolf46.devain.platform.discord.DiscordBot +import skywolf46.devain.platform.plugin.PluginModule + +class AnthropicModule : PluginModule("Anthropic Integration") { + + private val discordBot by inject() + + override fun onInitialize() { + document.fetchSharedDocument("Anthropic Integration") { config -> + loadKoinModules(module { + single { ClaudeAPICall(config.apiToken) } + }) + discordBot.registerCommands( + ClaudeCommand() + ) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/DeepLModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/DeepLModule.kt index 53d2561..7e3f154 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/DeepLModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/DeepLModule.kt @@ -5,34 +5,37 @@ import org.koin.core.context.loadKoinModules import org.koin.dsl.module import skywolf46.devain.KEY_DEEPL_PROCEED_COUNT import skywolf46.devain.KEY_DEEPL_PROCEED_TOKEN -import skywolf46.devain.controller.api.certainly +import skywolf46.devain.apicall.certainly +import skywolf46.devain.apicall.networking.GetRequest import skywolf46.devain.controller.api.requests.deepl.DeepLTranslationAPICall import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall import skywolf46.devain.controller.commands.discord.deepl.DeepLKoreanTranslationCommand import skywolf46.devain.controller.commands.discord.deepl.DeepLSimpleTranslationCommand import skywolf46.devain.controller.commands.discord.deepl.DeepLTranslationCommand import skywolf46.devain.controller.commands.discord.deepl.ModalDeepLKoreanTranslationCommand -import skywolf46.devain.model.api.openai.GetRequest +import skywolf46.devain.model.data.config.APITokenElement +import skywolf46.devain.model.data.config.fetchSharedDocument import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule -class DeepLModule(private val apiKey: String) : PluginModule("DeepL Integration") { - private val module = module { - single { DeepLTranslationAPICall(apiKey) } - } - +class DeepLModule() : PluginModule("DeepL Integration") { private val apiCall by inject() private val discordBot by inject() override fun onInitialize() { - loadKoinModules(module) - discordBot.registerCommands( - DeepLTranslationCommand(), - DeepLSimpleTranslationCommand(), - DeepLKoreanTranslationCommand(), - ModalDeepLKoreanTranslationCommand() - ) + document.fetchSharedDocument(pluginName) { config -> + loadKoinModules(module { + single { DeepLTranslationAPICall(config.apiToken) } + }) + discordBot.registerCommands( + DeepLTranslationCommand(), + DeepLSimpleTranslationCommand(), + DeepLKoreanTranslationCommand(), + ModalDeepLKoreanTranslationCommand() + ) + } + } override suspend fun getStatistics(): Map> { diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/DevAinModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/DevAinModule.kt index 647d751..7d06aed 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/DevAinModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/DevAinModule.kt @@ -3,15 +3,14 @@ package skywolf46.devain.controller.modules import io.ktor.client.* import io.ktor.client.engine.cio.* import org.json.simple.parser.JSONParser -import org.koin.core.component.inject +import org.koin.core.component.get import org.koin.core.context.loadKoinModules import org.koin.dsl.module -import skywolf46.devain.config.BotConfig import skywolf46.devain.controller.api.requests.devain.DevAinAppPropertiesAPICall import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall import skywolf46.devain.controller.api.requests.devain.DevAinUpdatePersistenceCountAPICall import skywolf46.devain.controller.commands.discord.devain.DevAinStatusCommand -import skywolf46.devain.model.store.SqliteStore +import skywolf46.devain.model.data.store.SqliteStore import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule @@ -24,7 +23,6 @@ class DevAinModule : PluginModule("DevAin Core") { } } } - single { BotConfig() } single { JSONParser() } single { SqliteStore() } // API Call Initialization @@ -33,11 +31,9 @@ class DevAinModule : PluginModule("DevAin Core") { single { DevAinUpdatePersistenceCountAPICall() } } - private val discordBot by inject() - override fun onInitialize() { loadKoinModules(devAinModule) - discordBot.registerCommands(DevAinStatusCommand()) + get().registerCommands(DevAinStatusCommand()) } override fun getVersion(): String { diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/OpenAIModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/OpenAIModule.kt index 66ed877..34a347a 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/OpenAIModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/OpenAIModule.kt @@ -4,8 +4,11 @@ import org.koin.core.component.inject import org.koin.core.context.loadKoinModules import org.koin.dsl.module import skywolf46.devain.* -import skywolf46.devain.config.BotConfig -import skywolf46.devain.controller.api.certainly +import skywolf46.devain.annotations.config.ConfigDefault +import skywolf46.devain.annotations.config.MarkConfigElement +import skywolf46.devain.apicall.certainly +import skywolf46.devain.apicall.networking.GetRequest +import skywolf46.devain.controller.api.requests.arxiv.ArxivSearchAPICall import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall import skywolf46.devain.controller.api.requests.eve.EvEOnlineStatusAPICall import skywolf46.devain.controller.api.requests.google.GoogleSearchAPICall @@ -14,27 +17,15 @@ import skywolf46.devain.controller.api.requests.openai.GPTCompletionAPICall import skywolf46.devain.controller.api.requests.openweather.OpenWeatherAPICall import skywolf46.devain.controller.api.requests.openweather.OpenWeatherForecastAPICall import skywolf46.devain.controller.commands.discord.openai.* -import skywolf46.devain.model.api.openai.GetRequest import skywolf46.devain.model.api.openai.completion.functions.* -import skywolf46.devain.model.store.OpenAIFunctionStore -import skywolf46.devain.model.store.OpenAIGPTGroupStore -import skywolf46.devain.model.store.OpenAIWorldStore +import skywolf46.devain.model.data.config.ConfigElement +import skywolf46.devain.model.data.config.fetchSharedDocument +import skywolf46.devain.model.data.store.OpenAIFunctionStore import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule import skywolf46.devain.util.TimeUtil -class OpenAIModule(private val config: BotConfig, private val apiKey: String) : PluginModule("OpenAI Integration") { - private val module = module { - single { GPTCompletionAPICall(apiKey) } - single { DallEAPICall(apiKey) } - single { OpenWeatherAPICall(config.openWeatherToken) } - single { OpenWeatherForecastAPICall(config.openWeatherToken) } - single { OpenAIFunctionStore() } - single { EvEOnlineStatusAPICall() } - single { GoogleSearchAPICall(config.googleApiToken, config.googleSearchEngineId) } - single { OpenAIGPTGroupStore() } - single { OpenAIWorldStore() } - } +class OpenAIModule : PluginModule("OpenAI Integration") { private val apiCall by inject() @@ -48,13 +39,26 @@ class OpenAIModule(private val config: BotConfig, private val apiKey: String) : GoogleSearchDeclaration(), OpenWeatherCallDeclaration(), OpenWeatherForecastDeclaration(), + ArxivSearchDeclaration(), TimeDeclaration() ) override fun onInitialize() { - loadKoinModules(module) - initFunctions() - registerCommands() + document.fetchSharedDocument(pluginName) { config -> + loadKoinModules(module { + single { GPTCompletionAPICall(config.openAIKey) } + single { DallEAPICall(config.openAIKey) } + single { OpenWeatherAPICall(config.openWeatherKey) } + single { OpenWeatherForecastAPICall(config.openWeatherKey) } + single { OpenAIFunctionStore() } + single { EvEOnlineStatusAPICall() } + single { GoogleSearchAPICall(config.googleApiKey, config.googleSearchEngineId) } + single { ArxivSearchAPICall() } + }) + + initFunctions() + registerCommands() + } } private fun initFunctions() { @@ -82,10 +86,15 @@ class OpenAIModule(private val config: BotConfig, private val apiKey: String) : "gpt-4" ), +// SimpleGPTCommand( +// "ask-fast", +// "GPT-4-0613에게 질문합니다. GPT-4는 느리지만, 조금 더 논리적인 답변을 기대할 수 있습니다.", +// "gpt-4-0613" +// ), SimpleGPTCommand( "ask-fast", - "GPT-4-0613에게 질문합니다. GPT-4는 느리지만, 조금 더 논리적인 답변을 기대할 수 있습니다.", - "gpt-4-0613" + "GPT-4-0125에게 질문합니다. GPT-4는 느리지만, 조금 더 논리적인 답변을 기대할 수 있습니다.", + "gpt-4-0125-preview" ), SimpleGPTCommand( @@ -99,8 +108,16 @@ class OpenAIModule(private val config: BotConfig, private val apiKey: String) : "ask-vision", "GPT-4-vision-preview에게 질문합니다. GPT-4는 느리지만, 조금 더 논리적인 답변을 기대할 수 있습니다.", "gpt-4-vision-preview" + ), + + ImageGPTCommand( + "ask-vision-exp", + "GPT-4-1106-vision-preview에게 질문합니다. GPT-4는 느리지만, 조금 더 논리적인 답변을 기대할 수 있습니다.", + "gpt-4-1106-vision-preview" + ), + + ) - ) } private fun registerModalCommands() { @@ -128,13 +145,9 @@ class OpenAIModule(private val config: BotConfig, private val apiKey: String) : private fun registerTestFeatureCommands() { discordBot.registerCommands( - - TestGPTCommand("test-gpt", "펑션을 사용하는 실험적인 GPT 명령입니다.", "gpt-3.5-turbo-16k"), - - GPTFunctionCommand(), + ArxivGPTCommand("arxiv-gpt", "ArXiv 검색을 사용하는 실험적인 GPT 명령입니다.", "gpt-4-turbo"), DallEGenerationCommand(), - GPTGroupCommand() ) } @@ -177,4 +190,19 @@ class OpenAIModule(private val config: BotConfig, private val apiKey: String) : override fun getVersion(): String { return "built-in" } + + data class OpenAIConfigElement( + @ConfigDefault.String("YOUR-API-TOKEN-HERE") + @MarkConfigElement("OpenAI API Key") + val openAIKey: String, + @ConfigDefault.String("YOUR-API-TOKEN-HERE") + @MarkConfigElement("OpenWeather API Key") + val openWeatherKey: String, + @ConfigDefault.String("YOUR-API-TOKEN-HERE") + @MarkConfigElement("Google API Key") + val googleApiKey: String, + @ConfigDefault.String("YOUR-API-TOKEN-HERE") + @MarkConfigElement("Google Search Engine ID") + val googleSearchEngineId: String, + ) : ConfigElement } \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/StabilityAIModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/StabilityAIModule.kt index be48413..c68f10c 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/StabilityAIModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/StabilityAIModule.kt @@ -3,13 +3,13 @@ package skywolf46.devain.controller.modules import org.koin.core.component.inject import skywolf46.devain.KEY_DALLE_PROCEED_COUNT import skywolf46.devain.KEY_DALLE_PROCEED_TIME -import skywolf46.devain.controller.api.certainly +import skywolf46.devain.apicall.certainly +import skywolf46.devain.apicall.networking.GetRequest import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall -import skywolf46.devain.model.api.openai.GetRequest import skywolf46.devain.platform.plugin.PluginModule import skywolf46.devain.util.TimeUtil -class StabilityAIModule(private val dreamStudioToken: String) : PluginModule("Stability AI Integration") { +class StabilityAIModule : PluginModule("Stability AI Integration") { private val apiCall by inject() override fun onInitialize() { From a9efce73ccbb883ba5163ea00a139d61ccef164f Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:06:54 +0900 Subject: [PATCH 19/46] =?UTF-8?q?fix:=20=EB=94=94=EC=8A=A4=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?DiscordModule=EB=A1=9C=20=EC=9D=B4=EA=B4=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/modules/DiscordModule.kt | 28 +++++++++++++++++++ .../devain/platform/discord/DiscordBot.kt | 26 ++++++++--------- 2 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 src/main/kotlin/skywolf46/devain/controller/modules/DiscordModule.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/DiscordModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/DiscordModule.kt new file mode 100644 index 0000000..3433fd1 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/modules/DiscordModule.kt @@ -0,0 +1,28 @@ +package skywolf46.devain.controller.modules + +import org.koin.core.context.loadKoinModules +import org.koin.dsl.module +import skywolf46.devain.model.data.config.APITokenElement +import skywolf46.devain.model.data.config.fetchSharedDocument +import skywolf46.devain.platform.discord.DiscordBot +import skywolf46.devain.platform.plugin.PluginModule + +class DiscordModule : PluginModule("Discord Integration") { + private val discordBot = DiscordBot() + + override fun onPreInitialize() { + loadKoinModules(module { + single { discordBot } + }) + } + + override fun onPostInitialize() { + document.fetchSharedDocument("Discord") { config -> + discordBot.finishSetup(config.apiToken) + } + } + + override fun getVersion(): String { + return "built-in" + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/platform/discord/DiscordBot.kt b/src/main/kotlin/skywolf46/devain/platform/discord/DiscordBot.kt index a5ac2cd..0a79521 100644 --- a/src/main/kotlin/skywolf46/devain/platform/discord/DiscordBot.kt +++ b/src/main/kotlin/skywolf46/devain/platform/discord/DiscordBot.kt @@ -5,11 +5,9 @@ import net.dv8tion.jda.api.JDABuilder import net.dv8tion.jda.api.OnlineStatus import net.dv8tion.jda.api.entities.Activity import net.dv8tion.jda.api.requests.GatewayIntent -import skywolf46.devain.DevAin -import skywolf46.devain.config.BotConfig import kotlin.system.exitProcess -class DiscordBot(devAin: DevAin, config: BotConfig) { +class DiscordBot { lateinit var jda: JDA private val commandAdapter by lazy { @@ -18,17 +16,6 @@ class DiscordBot(devAin: DevAin, config: BotConfig) { private val commands = mutableListOf() - init { - kotlin.runCatching { - jda = JDABuilder.create(config.botToken, GatewayIntent.values().toList()).addEventListeners() - .setStatus(OnlineStatus.IDLE).setActivity(Activity.listening("안")).build() - }.onFailure { - println("초기화 실패; 봇 초기화 중 오류가 발생하였습니다.") - it.printStackTrace() - exitProcess(-1) - } - jda.addEventListener(commandAdapter) - } fun registerCommands(vararg command: DiscordCommand): DiscordBot { commands.addAll(command) @@ -40,7 +27,16 @@ class DiscordBot(devAin: DevAin, config: BotConfig) { return this } - internal fun finishSetup() { + internal fun finishSetup(apiToken: String) { + kotlin.runCatching { + jda = JDABuilder.create(apiToken, GatewayIntent.values().toList()).addEventListeners() + .setStatus(OnlineStatus.IDLE).setActivity(Activity.listening("안")).build().awaitReady() + }.onFailure { + println("초기화 실패; 봇 초기화 중 오류가 발생하였습니다.") + it.printStackTrace() + exitProcess(-1) + } + jda.addEventListener(commandAdapter) commandAdapter.registerCommands(*commands.toTypedArray()) } } \ No newline at end of file From a136c5c8f7cf115c4071e5104e6e092f18ef7032 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:07:12 +0900 Subject: [PATCH 20/46] =?UTF-8?q?fix:=20=EB=94=94=EC=8A=A4=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?DiscordModule=EB=A1=9C=20=EC=9D=B4=EA=B4=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/skywolf46/devain/DevAin.kt | 48 ++++++++-------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/DevAin.kt b/src/main/kotlin/skywolf46/devain/DevAin.kt index c424dfb..8876f77 100644 --- a/src/main/kotlin/skywolf46/devain/DevAin.kt +++ b/src/main/kotlin/skywolf46/devain/DevAin.kt @@ -7,9 +7,11 @@ import org.koin.core.context.startKoin import org.koin.dsl.module import skywolf46.devain.config.BotConfig import skywolf46.devain.controller.modules.* +import skywolf46.devain.model.data.config.ConfigDocumentRoot import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginManager import skywolf46.devain.platform.plugin.PluginModule +import java.io.File fun main(args: Array) { @@ -17,42 +19,30 @@ fun main(args: Array) { } class DevAin : KoinComponent { - val version = "1.2.0 - Grenade Muffin" - - private val botConfig = BotConfig() - - lateinit var discordBot: DiscordBot - private set + val version = "1.3.0 - Radioactive Emmer Bread" internal fun init() { println("DevAin $version - 초기화 시작") - initializeBot() - startKoin { - loadKoinModules(module { - single { discordBot } - single { botConfig } - - single { PluginManager() } - }) - } + startKoin { } initializeBuiltInPlugins() - finalizeBot() - } - - private fun initializeBot() { - println("디스코드 봇 활성화중..") - discordBot = DiscordBot(this, botConfig) + while (true) { + Thread.sleep(Long.MAX_VALUE) + } } private fun initializeBuiltInPlugins() { println("플러그인 활성화중..") - get().apply { + PluginManager().apply { addPlugins( DevAinModule(), - OpenAIModule(botConfig, botConfig.openAIToken), - DeepLModule(botConfig.deepLToken), - StabilityAIModule(botConfig.dreamStudioToken), - CohereModule(botConfig.cohereToken), + DiscordModule(), + OpenAIModule(), + DeepLModule(), + StabilityAIModule(), + CohereModule(), + AnthropicModule(), + GroqModule(), + KModule(), object : PluginModule("Test Fatal Plugin") { override fun canBeLoaded(): Boolean { return false @@ -63,10 +53,4 @@ class DevAin : KoinComponent { } } - private fun finalizeBot() { - println("디스코드 봇 설정 마무리중..") - discordBot.finishSetup() - } - - } \ No newline at end of file From 8feb34af70a1d533e2aa7bf1b68cfd44940c8ca9 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:07:26 +0900 Subject: [PATCH 21/46] =?UTF-8?q?fix:=20=ED=94=8C=EB=9F=AC=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EB=A1=9C=EB=93=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devain/platform/plugin/PluginManager.kt | 48 +++++++++++++++---- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt index 1fe2a4d..3b69ef3 100644 --- a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt +++ b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt @@ -1,10 +1,17 @@ package skywolf46.devain.platform.plugin +import org.koin.core.component.KoinComponent +import org.koin.core.component.get +import org.koin.core.context.loadKoinModules +import org.koin.core.context.startKoin +import org.koin.dsl.module +import skywolf46.devain.model.data.config.ConfigDocumentRoot +import java.io.File import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.locks.ReentrantLock import kotlin.concurrent.withLock -class PluginManager { +class PluginManager : KoinComponent { private val plugins = mutableListOf() private val enabledPlugins = mutableListOf() @@ -13,18 +20,26 @@ class PluginManager { private val lock = ReentrantLock() + private val document = ConfigDocumentRoot(File("devain/config")) fun init() { + if (isInitialized.getAndSet(true)) { + throw IllegalStateException("PluginManager is already initialized") + } + loadKoinModules() + filterPlugins() + initializePlugin() + } + + private fun loadKoinModules() { + loadKoinModules(module { + single { this@PluginManager } + single { document } + }) + } + + private fun initializePlugin() { lock.withLock { - if (isInitialized.get()) { - throw IllegalStateException("PluginManager is already initialized") - } - enabledPlugins.addAll(plugins.filter { - runCatching { - it.canBeLoaded() - }.getOrElse { false } - }) - isInitialized.set(true) iterateEnabledPlugin { it.onPreInitialize() } @@ -34,9 +49,22 @@ class PluginManager { iterateEnabledPlugin { it.onPostInitialize() } + get().loadSharedDocument() + iterateEnabledPlugin { + it.onInitializeComplete() + } } } + private fun filterPlugins() { + enabledPlugins.addAll(plugins.filter { + runCatching { + it.canBeLoaded() + }.getOrElse { false } + }) + } + + private fun iterateEnabledPlugin(executor: (PluginModule) -> Unit) { enabledPlugins.toList().forEach { plugin -> runCatching { From eb5912473e8c05fc7c1d311ab63d818f3fa4a8c3 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:07:50 +0900 Subject: [PATCH 22/46] =?UTF-8?q?feat:=20Arxiv=20GPT=20=EB=AA=85=EB=A0=B9?= =?UTF-8?q?=EC=96=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/requests/arxiv/ArxivSearchAPICall.kt | 39 ++++ .../discord/openai/ArxivGPTCommand.kt | 213 ++++++++++++++++++ .../devain/model/api/arxiv/ArxivRequest.kt | 10 + .../devain/model/api/arxiv/ArxivResponse.kt | 8 + .../functions/ArxivSearchDeclaration.kt | 48 ++++ 5 files changed, 318 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/controller/api/requests/arxiv/ArxivSearchAPICall.kt create mode 100644 src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivRequest.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivResponse.kt create mode 100644 src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/arxiv/ArxivSearchAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/arxiv/ArxivSearchAPICall.kt new file mode 100644 index 0000000..888b090 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/arxiv/ArxivSearchAPICall.kt @@ -0,0 +1,39 @@ +package skywolf46.devain.controller.api.requests.arxiv + +import arrow.core.* +import io.ktor.client.* +import org.w3c.dom.Document +import org.w3c.dom.Node +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.XMLRESTAPICall +import skywolf46.devain.model.api.arxiv.ArxivRequest +import skywolf46.devain.model.api.arxiv.ArxivResponse + +class ArxivSearchAPICall(client: Option = None) : XMLRESTAPICall({ + "https://export.arxiv.org/api/query?search_query=all:${it.query}&sortBy=relevance&sortOrder=descending&max_results=40" +}, client) { + override suspend fun parseResult(request: ArxivRequest, response: Document): Either { + val elements = response.getElementsByTagName("entry") + val list = mutableListOf() + for (x in 0 until elements.length) { + val node = elements.item(x).asMap() + list += ArxivResponse.Article( + node["title"]!!.replace("\n ", "").replace("\n", ""), + node["summary"]!!.replace("\n ", "").replace("\n", ""), + node["id"]!!, + node["published"]!!, + node["updated"]!!, + ) + } + return ArxivResponse(list).right() + } + + private fun Node.asMap(): Map { + val map = mutableMapOf() + for (x in 0 until childNodes.length) { + val node = childNodes.item(x) + map[node.nodeName] = node.textContent + } + return map + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt new file mode 100644 index 0000000..f644095 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt @@ -0,0 +1,213 @@ +package skywolf46.devain.controller.commands.discord.openai + +import arrow.core.toOption +import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.interactions.commands.OptionType +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData +import net.dv8tion.jda.api.utils.FileUpload +import org.koin.core.component.get +import skywolf46.devain.controller.api.requests.openai.GPTCompletionAPICall +import skywolf46.devain.model.api.openai.completion.* +import java.text.DecimalFormat +import kotlin.math.round + +class ArxivGPTCommand( + command: String, + description: String, + private val model: String? = null +) : GPTCommand(command, description) { + + private val apiCall = get() + private val decimalFormat = DecimalFormat("#,###") + + override fun modifyCommandData(options: SlashCommandData) { + if (model == null) { + options.addOption(OptionType.STRING, "model", "") + } + options.addOption(OptionType.STRING, "contents", "ChatGPT-3.5에게 질문할 내용입니다.", true) + .addOption( + OptionType.NUMBER, + "temperature", + "모델의 temperature 값을 설정합니다. 값이 낮을수록 결정적이 되며, 높을수록 더 많은 무작위성이 가해집니다. (기본 1, 0-1.5내의 소수)", + false + ) + .addOption( + OptionType.NUMBER, + "top_p", + "모델의 top_p 값을 설정합니다. 값이 낮을수록 토큰의 샘플링 범위가 낮아집니다. (기본 1, 0-1.5내의 소수)", + false + ) + .addOption( + OptionType.INTEGER, + "max_token", + "최대 토큰 개수를 설정합니다.", + false + ) + .addOption( + OptionType.NUMBER, + "presence_penalty", + "모델의 중복 주제 패널티를 조정합니다. 높을수록, 새 주제(토큰)에 관해 이야기할 확률이 높아집니다. (기본 0, -2.0-2.0내의 소수)", + false + ) + .addOption( + OptionType.NUMBER, + "frequency_penalty", + "모델의 중복 빈도 패널티를 조정합니다. 높을수록, 같은 말(토큰)을 반복하지 않을 확률이 높아집니다. (기본 0, -2.0-2.0내의 소수)", + false + ) + .addOption(OptionType.INTEGER, "best_of", "모델의 최고 결과물 중 몇 개를 선택할지를 설정합니다. (기본 1, 1-10)", false) + .addOption(OptionType.BOOLEAN, "hide-prompt", "결과 창에서 프롬프트를 숨깁니다. 명령어 클릭은 숨겨지지 않습니다.", false) + .addOption(OptionType.BOOLEAN, "show-trace", "사용된 펑션 콜 스택 트레이스를 출력할지의 여부를 설정합니다.", false) + .addOption(OptionType.STRING, "base-prompt", "해당 프롬프트의 기반이 될 프롬프트입니다. AI는 해당 내용을 기반으로 답변을 시도합니다.", false) + } + + override suspend fun onCommand(event: SlashCommandInteractionEvent) { + event.defer { _, hook -> + val request = OpenAIGPTRequest( + model ?: event.getOption("model")!!.asString, + event.getOption("base-prompt")?.asString?.let { + mutableListOf( + OpenAIGPTMessage(OpenAIGPTMessage.Role.USER_PRECONDITION, it.toOption()), + OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, event.getOption("contents")!!.asString.toOption()) + ) + } ?: mutableListOf( + OpenAIGPTMessage( + OpenAIGPTMessage.Role.USER_PRECONDITION, + "모든 링크는 [LINK_DESCRIPTION](LINK_URL) 대신 [LINK_DESCRIPTION]()을 사용하십시오. 예를 들어, 구글은 다음과 같은 포맷을 따릅니다: [Google]()".toOption() + ), + OpenAIGPTMessage( + OpenAIGPTMessage.Role.USER_PRECONDITION, + "REF#N 형식의 링크는 이후에 일반 링크로 replace될 대상입니다. 링크라고 가정하여 활용하십시오.".toOption() + ), + OpenAIGPTMessage( + OpenAIGPTMessage.Role.USER, + event.getOption("contents")!!.asString.toOption() + ) + ), + 1, + event.getOption("temperature")?.asDouble.toOption(), + event.getOption("top_p")?.asDouble.toOption(), + event.getOption("best_of")?.asInt.toOption(), + event.getOption("max_token")?.asInt.toOption(), + event.getOption("presence_penalty")?.asDouble.toOption(), + event.getOption("frequency_penalty")?.asDouble.toOption(), + event.getOption("hide-prompt")?.asBoolean ?: false, + event.getOption("show-trace")?.asBoolean ?: false, + listOf( + OpenAIFunctionKey("arxiv_search", OpenAIFunctionKey.FunctionFlag.BUILT_IN), + + ).toOption() + ) + apiCall.call( + request + ).onLeft { + hook.sendMessage(it.getErrorMessage()).queue() + }.onRight { result -> + result.stackTrace.addFunction( + OpenAIFunctionCallStackTrace.TraceType.NORMAL, + OpenAIFunctionKey("gpt-finalize", OpenAIFunctionKey.FunctionFlag.BUILT_IN) + ) + if (isEmbedCompatible(request, result)) { + runCatching { + hook.sendMessageEmbeds(buildEmbedded(request, result)).queue() + }.onFailure { exception -> + exception.printStackTrace() + hook.sendMessage("${exception.javaClass.name}: ${exception.message}") + } + return@onRight + } + val text = buildReturnValue(event, request, result) + if (text.length >= 2000) { + hook.sendFiles(FileUpload.fromData(text.toByteArray(), "response.txt")).queue() + } else { + hook.sendMessage(text).queue() + } + } + } + } + + + private fun buildReturnValue( + event: SlashCommandInteractionEvent, + request: OpenAIGPTRequest, + result: OpenAIGPTResponse + ): String { + val builder = StringBuilder() + appendApiInfo(event, builder, request, result) + if (!request.hidePrompt) + appendRequest(builder, request) + appendResult(builder, result) + return builder.toString() + } + + private fun appendModel(event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest) { + builder.append("└ 모델: ${request.modelName}").appendNewLine() + appendParameter(event, builder, request) + } + + private fun appendParameter( + event: SlashCommandInteractionEvent, + builder: StringBuilder, + request: OpenAIGPTRequest + ) { + request.temperature.tap { + builder.append(" └ Temperature: $it").appendNewLine() + } + request.top_p.tap { + builder.append(" └ top_p: $it").appendNewLine() + } + request.presencePenalty.tap { + builder.append(" └ Presence Penalty: $it").appendNewLine() + } + request.frequencyPenalty.tap { + builder.append(" └ Frequency Penalty: $it").appendNewLine() + } + + request.maxTokens.tap { + builder.append(" └ Max tokens: ${decimalFormat.format(it)}").appendNewLine() + } + + if (request.hidePrompt) { + builder.append(" └ Prompt hidden").appendNewLine() + } + } + + private fun appendApiInfo( + event: SlashCommandInteractionEvent, + builder: StringBuilder, + request: OpenAIGPTRequest, + result: OpenAIGPTResponse + ) { + builder.append("**API 상세**:").appendNewLine(1) + appendModel(event, builder, request) + builder.append("└ API 소모: ${result.usage.totalToken}토큰") + builder.appendNewLine() + builder.append("└ API 응답 시간: ${decimalFormat.format(System.currentTimeMillis() - request.createdOn)}ms") + .appendNewLine(2) + } + + private fun appendRequest(builder: StringBuilder, request: OpenAIGPTRequest) { + + val requestMessage = request.messages.find { it.role == OpenAIGPTMessage.Role.USER }!! + builder.append("**요청:** \n${requestMessage.content.find { it.first == "text" }?.second}") + builder.appendNewLine(2) + } + + private fun appendResult(builder: StringBuilder, result: OpenAIGPTResponse) { + val responseMessage = result.answers.last() + builder.append("**응답:** \n${responseMessage.message.content.find { it.first == "text" }?.second}") + } + + private fun StringBuilder.appendNewLine(count: Int = 1) { + append("\n".repeat(count)) + } + + override suspend fun onAutoComplete(event: CommandAutoCompleteInteractionEvent) { + when (event.name) { + "model" -> { + + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivRequest.kt new file mode 100644 index 0000000..e437410 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivRequest.kt @@ -0,0 +1,10 @@ +package skywolf46.devain.model.api.arxiv + +import arrow.core.Either +import arrow.core.right +import skywolf46.devain.apicall.networking.Request +data class ArxivRequest(val query: String) : Request { + override fun serialize(): Either { + return "".right() + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivResponse.kt new file mode 100644 index 0000000..33274ff --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivResponse.kt @@ -0,0 +1,8 @@ +package skywolf46.devain.model.api.arxiv + +import skywolf46.devain.apicall.networking.Response + +data class ArxivResponse(val articles: List
) : Response { + + data class Article(val title: String, val summary: String, val url: String, val published: String, val updated: String) +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt new file mode 100644 index 0000000..5aa1a3b --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt @@ -0,0 +1,48 @@ +package skywolf46.devain.model.api.openai.completion.functions + +import arrow.core.getOrElse +import org.json.simple.JSONObject +import org.koin.core.component.inject +import org.koin.java.KoinJavaComponent.inject +import skywolf46.devain.apicall.networking.GenericJSONObjectResponse +import skywolf46.devain.controller.api.requests.arxiv.ArxivSearchAPICall +import skywolf46.devain.model.api.arxiv.ArxivRequest +import skywolf46.devain.model.api.openai.OpenAIParameterSchema +import skywolf46.devain.model.api.openai.completion.OpenAIFunctionDeclaration +import skywolf46.devain.model.api.openai.completion.OpenAIFunctionKey + +class ArxivSearchDeclaration : OpenAIFunctionDeclaration( + OpenAIFunctionKey("arxiv_search", OpenAIFunctionKey.FunctionFlag.BUILT_IN), + "Arxiv API를 사용해 웹에서 검색 결과를 가져옵니다. 논문 제목에는 영어만 존재한다고 가정하고, 모든 쿼리를 영어로 제공하십시오. 결과에는 논문의 제목과 초록(Abstract) 및 논문이 제출된 날짜와 수정된 날짜가 포함됩니다.", + listOf( + OpenAIParameterSchema( + "query", + "검색할 쿼리입니다. 쿼리는 가능하면 최대한 짧고, 간결해야 합니다. 또한, 쿼리에는 검색 대상 논문에 대한 정보만 있어야 하며, 시간과 같은 부가 정보는 허용되지 않습니다.", + "string", + "true" + ) + ) +) { + private val apiCall by inject() + + override suspend fun call(param: JSONObject): JSONObject { + return apiCall.call(ArxivRequest(param["query"].toString())) + .map { + JSONObject().apply { + put("result", it.articles.mapIndexed { index, item -> + JSONObject().apply { + put("title", item.title) + put("abstract", item.summary) + put("url", item.url) + } + }) + } + } + .mapLeft { + GenericJSONObjectResponse(JSONObject().apply { + put("error", it.getErrorMessage()) + }) + } + .getOrElse { it.json } + } +} \ No newline at end of file From 2f9f3618c4f10a9b18e7a237e3ea2207cc809cae Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:08:07 +0900 Subject: [PATCH 23/46] =?UTF-8?q?feat:=20=EB=88=84=EB=9D=BD=EB=90=9C=20API?= =?UTF-8?q?TokenElement=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devain/model/data/config/APITokenElement.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/model/data/config/APITokenElement.kt diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/APITokenElement.kt b/src/main/kotlin/skywolf46/devain/model/data/config/APITokenElement.kt new file mode 100644 index 0000000..35dd045 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/model/data/config/APITokenElement.kt @@ -0,0 +1,10 @@ +package skywolf46.devain.model.data.config + +import skywolf46.devain.annotations.config.ConfigDefault +import skywolf46.devain.annotations.config.MarkConfigElement + +data class APITokenElement( + @MarkConfigElement + @ConfigDefault.String("YOUR-API-TOKEN-HERE") + val apiToken: String +) : ConfigElement \ No newline at end of file From 53d5b0e997e6112b057d2c3abc11bb2f546485ec Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:08:24 +0900 Subject: [PATCH 24/46] =?UTF-8?q?chore:=20=EC=BB=A4=EB=B0=8B=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skywolf46/devain/platform/discord/DiscordCommand.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommand.kt b/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommand.kt index 70d1da0..263f995 100644 --- a/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommand.kt +++ b/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommand.kt @@ -2,8 +2,10 @@ package skywolf46.devain.platform.discord import arrow.core.Either import arrow.core.identity -import kotlinx.coroutines.* -import net.dv8tion.jda.api.EmbedBuilder +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import net.dv8tion.jda.api.entities.MessageEmbed import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent From d808d927fd5f73581440320e0746a0e71ad58473 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:08:38 +0900 Subject: [PATCH 25/46] =?UTF-8?q?feat:=20=EC=9D=BC=EA=B4=84=EC=A0=81?= =?UTF-8?q?=EC=9D=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=ED=8F=AC=EB=A7=B7?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20GenerationResultTextBuilder=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/GenerationResultTextBuilder.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/util/GenerationResultTextBuilder.kt diff --git a/src/main/kotlin/skywolf46/devain/util/GenerationResultTextBuilder.kt b/src/main/kotlin/skywolf46/devain/util/GenerationResultTextBuilder.kt new file mode 100644 index 0000000..e1f2e05 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/util/GenerationResultTextBuilder.kt @@ -0,0 +1,25 @@ +package skywolf46.devain.util + +import net.dv8tion.jda.api.EmbedBuilder +import java.awt.Color + +class GenerationResultTextBuilder(val title: String, val content: String?, val metadata: List>) { + fun asEmbed(builder: EmbedBuilder) { + builder.setTitle(title) + builder.setColor(Color(162, 103, 181)) + if (content != null) { + builder.setDescription(content) + } + for (line in metadata) { + if (line.size == 1) { + val field = line.entries.first() + builder.addField(field.key, field.value, false) + } else { + for ((k, v) in line) { + builder.addField(k, v, true) + } + } + } + } + +} \ No newline at end of file From 4e0b51f7e5151eeb685bbbb5074890f92a245e8d Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:08:52 +0900 Subject: [PATCH 26/46] =?UTF-8?q?feat:=20ImprovedDiscordCommand#sendMessag?= =?UTF-8?q?eOrEmbed=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/discord/ImprovedDiscordCommand.kt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/skywolf46/devain/platform/discord/ImprovedDiscordCommand.kt b/src/main/kotlin/skywolf46/devain/platform/discord/ImprovedDiscordCommand.kt index 4200fbb..a733f17 100644 --- a/src/main/kotlin/skywolf46/devain/platform/discord/ImprovedDiscordCommand.kt +++ b/src/main/kotlin/skywolf46/devain/platform/discord/ImprovedDiscordCommand.kt @@ -7,8 +7,10 @@ import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import net.dv8tion.jda.api.EmbedBuilder import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent +import net.dv8tion.jda.api.interactions.InteractionHook import net.dv8tion.jda.api.interactions.commands.CommandAutoCompleteInteraction import net.dv8tion.jda.api.interactions.commands.OptionType import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction @@ -16,6 +18,7 @@ import net.dv8tion.jda.api.interactions.commands.build.CommandData import net.dv8tion.jda.api.interactions.commands.build.Commands import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData import net.dv8tion.jda.api.interactions.modals.Modal +import net.dv8tion.jda.api.utils.FileUpload import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.read @@ -107,4 +110,15 @@ abstract class ImprovedDiscordCommand( return "```$prefix\n$string```" } -} \ No newline at end of file + fun InteractionHook.sendMessageOrEmbed(embedThreshold: Int, text: String, embed: (EmbedBuilder) -> Unit) { + if (text.length >= 2000) { + sendFiles(FileUpload.fromData(text.toByteArray(), "result.txt")).queue() + return + } + if (text.length >= embedThreshold) { + sendMessage(text).queue() + return + } + sendMessageEmbeds(EmbedBuilder().apply(embed).build()).queue() + } +} From 4a069eea23bed123a4b5f42723bb0bb0459248e7 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:09:21 +0900 Subject: [PATCH 27/46] =?UTF-8?q?feat:=20PluginModule#document=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20PluginModule#onInitializeComplete=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skywolf46/devain/platform/plugin/PluginModule.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginModule.kt b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginModule.kt index 293928e..47b1d71 100644 --- a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginModule.kt +++ b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginModule.kt @@ -1,6 +1,8 @@ package skywolf46.devain.platform.plugin import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import skywolf46.devain.model.data.config.ConfigDocumentRoot import java.io.File abstract class PluginModule(val pluginName: String) : KoinComponent { @@ -8,6 +10,9 @@ abstract class PluginModule(val pluginName: String) : KoinComponent { lateinit var dataDirectory: File internal set + val document by inject() + + open fun canBeLoaded(): Boolean { return true } @@ -24,6 +29,10 @@ abstract class PluginModule(val pluginName: String) : KoinComponent { // Do nothing } + open fun onInitializeComplete() { + // Do nothing + } + open suspend fun getStatistics(): Map> { return emptyMap() } @@ -33,6 +42,4 @@ abstract class PluginModule(val pluginName: String) : KoinComponent { } data class PluginStatistics(val name: String, val value: String) - - } \ No newline at end of file From 9b1e7d3bd6d7022bba34374a58c4d6c2afd3de50 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:09:57 +0900 Subject: [PATCH 28/46] =?UTF-8?q?feat:=20=EC=83=81=EC=88=98=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/skywolf46/devain/Constants.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/skywolf46/devain/Constants.kt b/src/main/kotlin/skywolf46/devain/Constants.kt index c514a1c..cfe80f3 100644 --- a/src/main/kotlin/skywolf46/devain/Constants.kt +++ b/src/main/kotlin/skywolf46/devain/Constants.kt @@ -14,11 +14,14 @@ const val KEY_DALLE_PROCEED_COUNT = "dalle_proceed_count" const val KEY_DALLE_PROCEED_TIME = "dalle_proceed_time" const val KEY_COHERE_GENERATION_PROCEED_COUNT = "cohere_proceed_count" +const val KEY_COMMAND_R_PLUS_GENERATION_PROCEED_COUNT = "command_r_plus_proceed_count" +const val KEY_GROQ_GENERATION_PROCEED_COUNT = "groq_plus_proceed_count" const val KEY_DREAM_STUDIO_SD_PROCEED_COUNT = "dreamstudio_sd_proceed_count" const val KEY_DREAM_STUDIO_SD_PROCEED_TIME = "dreamstudio_sddalle_proceed_time" - const val KEY_DEEPL_PROCEED_COUNT = "deepl_proceed_count" const val KEY_DEEPL_PROCEED_TOKEN = "deepl_proceed_token" + +const val K_CURRENCY_API_CALL = "currency_api_call" From e47036a0f644f89e93172ffbfc3cd8c7c76fb3f1 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:10:16 +0900 Subject: [PATCH 29/46] =?UTF-8?q?feat:=20Groq=20=EC=A7=80=EC=9B=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/requests/groq/GroqAPICall.kt | 48 +++++ .../discord/groq/SimpleGroqCommand.kt | 187 ++++++++++++++++++ .../devain/controller/modules/GroqModule.kt | 51 +++++ 3 files changed, 286 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/controller/api/requests/groq/GroqAPICall.kt create mode 100644 src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt create mode 100644 src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/groq/GroqAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/groq/GroqAPICall.kt new file mode 100644 index 0000000..8dbcf1f --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/groq/GroqAPICall.kt @@ -0,0 +1,48 @@ +package skywolf46.devain.controller.api.requests.groq + +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.right +import io.ktor.client.* +import io.ktor.client.statement.* +import io.ktor.http.* +import org.json.simple.JSONObject +import org.koin.core.component.inject +import skywolf46.devain.KEY_GROQ_GENERATION_PROCEED_COUNT +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall +import skywolf46.devain.controller.api.requests.devain.DevAinUpdatePersistenceCountAPICall +import skywolf46.devain.model.api.openai.UpdateRequest +import skywolf46.devain.model.api.openai.completion.OpenAIFunctionCallStackTrace +import skywolf46.devain.model.api.openai.completion.OpenAIGPTRequest +import skywolf46.devain.model.api.openai.completion.OpenAIGPTResponse + +class GroqAPICall(val apiKey: String, client: Option = None) : + RESTAPICall({ + "https://api.groq.com/openai/v1/chat/completions" + }, client, HttpMethod.Post) { + private val updateCall by inject() + + override suspend fun parseResult( + request: OpenAIGPTRequest, + response: JSONObject + ): Either { + return OpenAIGPTResponse.fromJson(response, OpenAIFunctionCallStackTrace()).apply { + updateCall.call(UpdateRequest(KEY_GROQ_GENERATION_PROCEED_COUNT, 1L)) + }.right() + } + + override fun HeadersBuilder.applyCredential() { + append("authorization", "Bearer $apiKey") + } + + override suspend fun parseHttpError( + request: OpenAIGPTRequest, + response: HttpResponse, + errorCode: Int + ): APIError { + println(response.headers) + return super.parseHttpError(request, response, errorCode) + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt new file mode 100644 index 0000000..a461557 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt @@ -0,0 +1,187 @@ +package skywolf46.devain.controller.commands.discord.groq + +import arrow.core.toOption +import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent +import net.dv8tion.jda.api.interactions.commands.OptionType +import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData +import net.dv8tion.jda.api.utils.FileUpload +import org.koin.core.component.get +import skywolf46.devain.controller.api.requests.groq.GroqAPICall +import skywolf46.devain.controller.commands.discord.openai.GPTCommand +import skywolf46.devain.model.api.openai.completion.OpenAIGPTMessage +import skywolf46.devain.model.api.openai.completion.OpenAIGPTRequest +import skywolf46.devain.model.api.openai.completion.OpenAIGPTResponse +import java.text.DecimalFormat + +class SimpleGroqCommand( + command: String, + description: String, + private val model: String, + private val modelDisplay: String +) : GPTCommand(command, description) { + private val decimalFormat = DecimalFormat("#,###") + + private val apiCall = get() + + override fun modifyCommandData(options: SlashCommandData) { + options.addOption(OptionType.STRING, "contents", "${modelDisplay}에게 질문할 내용입니다.", true) + .addOption( + OptionType.NUMBER, + "temperature", + "모델의 temperature 값을 설정합니다. 값이 낮을수록 결정적이 되며, 높을수록 더 많은 무작위성이 가해집니다. (기본 1, 0-1.5내의 소수)", + false + ) + .addOption( + OptionType.NUMBER, + "top_p", + "모델의 top_p 값을 설정합니다. 값이 낮을수록 토큰의 샘플링 범위가 낮아집니다. (기본 1, 0-1.5내의 소수)", + false + ) + .addOption( + OptionType.INTEGER, + "max_token", + "최대 토큰 개수를 설정합니다.", + false + ) + .addOption( + OptionType.NUMBER, + "presence_penalty", + "모델의 중복 주제 패널티를 조정합니다. 높을수록, 새 주제(토큰)에 관해 이야기할 확률이 높아집니다. (기본 0, -2.0-2.0내의 소수)", + false + ) + .addOption( + OptionType.NUMBER, + "frequency_penalty", + "모델의 중복 빈도 패널티를 조정합니다. 높을수록, 같은 말(토큰)을 반복하지 않을 확률이 높아집니다. (기본 0, -2.0-2.0내의 소수)", + false + ) + .addOption(OptionType.INTEGER, "best_of", "모델의 최고 결과물 중 몇 개를 선택할지를 설정합니다. (기본 1, 1-10)", false) + .addOption(OptionType.BOOLEAN, "hide-prompt", "결과 창에서 프롬프트를 숨깁니다. 명령어 클릭은 숨겨지지 않습니다.", false) + .addOption(OptionType.STRING, "base-prompt", "해당 프롬프트의 기반이 될 프롬프트입니다. AI는 해당 내용을 기반으로 답변을 시도합니다.", false) + } + + override suspend fun onCommand(event: SlashCommandInteractionEvent) { + event.defer { _, hook -> + val request = OpenAIGPTRequest( + model ?: event.getOption("model")!!.asString, + event.getOption("base-prompt")?.asString?.let { + mutableListOf( + OpenAIGPTMessage(OpenAIGPTMessage.Role.ASSISTANT, it.toOption()), + OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, event.getOption("contents")!!.asString.toOption()) + ) + } ?: mutableListOf(OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, event.getOption("contents")!!.asString.toOption())), + 1, + event.getOption("temperature")?.asDouble.toOption(), + event.getOption("top_p")?.asDouble.toOption(), + event.getOption("best_of")?.asInt.toOption(), + event.getOption("max_token")?.asInt.toOption(), + event.getOption("presence_penalty")?.asDouble.toOption(), + event.getOption("frequency_penalty")?.asDouble.toOption(), + event.getOption("hide-prompt")?.asBoolean ?: false + ) + apiCall.call( + request + ).onLeft { + hook.sendMessage(it.getErrorMessage()).queue() + }.onRight { result -> + if (isEmbedCompatible(request, result)) { + runCatching { + hook.sendMessageEmbeds(buildEmbedded(request, result)).queue() + }.onFailure { exception -> + exception.printStackTrace() + hook.sendMessage("${exception.javaClass.name}: ${exception.message}") + } + return@onRight + } + val text = buildReturnValue(event, request, result) + if (text.length >= 2000) { + hook.sendFiles(FileUpload.fromData(text.toByteArray(), "response.txt")).queue() + } else { + hook.sendMessage(text).queue() + } + } + } + } + + + private fun buildReturnValue( + event: SlashCommandInteractionEvent, + request: OpenAIGPTRequest, + result: OpenAIGPTResponse + ): String { + val builder = StringBuilder() + appendApiInfo(event, builder, request, result) + if (!request.hidePrompt) + appendRequest(builder, request) + appendResult(builder, result) + return builder.toString() + } + + private fun appendModel(event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest) { + builder.append("└ 모델: ${request.modelName}").appendNewLine() + appendParameter(event, builder, request) + } + + private fun appendParameter( + event: SlashCommandInteractionEvent, + builder: StringBuilder, + request: OpenAIGPTRequest + ) { + request.temperature.tap { + builder.append(" └ Temperature: $it").appendNewLine() + } + request.top_p.tap { + builder.append(" └ top_p: $it").appendNewLine() + } + request.presencePenalty.tap { + builder.append(" └ Presence Penalty: $it").appendNewLine() + } + request.frequencyPenalty.tap { + builder.append(" └ Frequency Penalty: $it").appendNewLine() + } + + request.maxTokens.tap { + builder.append(" └ Max tokens: ${decimalFormat.format(it)}").appendNewLine() + } + + if (request.hidePrompt) { + builder.append(" └ Prompt hidden").appendNewLine() + } + } + + private fun appendApiInfo( + event: SlashCommandInteractionEvent, + builder: StringBuilder, + request: OpenAIGPTRequest, + result: OpenAIGPTResponse + ) { + builder.append("**API 상세**:").appendNewLine(1) + appendModel(event, builder, request) + builder.append("└ API 소모: ${result.usage.totalToken}토큰") + builder.appendNewLine() + builder.append("└ API 응답 시간: ${decimalFormat.format(System.currentTimeMillis() - request.createdOn)}ms") + .appendNewLine(2) + } + + private fun appendRequest(builder: StringBuilder, request: OpenAIGPTRequest) { + builder.append("**요청:** \n${request.messages.last().content.find { it.first == "text" }?.second}") + builder.appendNewLine(2) + } + + private fun appendResult(builder: StringBuilder, result: OpenAIGPTResponse) { + builder.append("**응답:** \n${result.answers[0].message.content.find { it.first == "text" }?.second}") + } + + private fun StringBuilder.appendNewLine(count: Int = 1) { + append("\n".repeat(count)) + } + + override suspend fun onAutoComplete(event: CommandAutoCompleteInteractionEvent) { + when (event.name) { + "model" -> { + + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt new file mode 100644 index 0000000..4a7f676 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt @@ -0,0 +1,51 @@ +package skywolf46.devain.controller.modules + +import org.koin.core.component.inject +import org.koin.core.context.loadKoinModules +import org.koin.dsl.module +import skywolf46.devain.KEY_GROQ_GENERATION_PROCEED_COUNT +import skywolf46.devain.apicall.certainly +import skywolf46.devain.apicall.networking.GetRequest +import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall +import skywolf46.devain.controller.api.requests.groq.GroqAPICall +import skywolf46.devain.controller.commands.discord.groq.SimpleGroqCommand +import skywolf46.devain.model.data.config.APITokenElement +import skywolf46.devain.model.data.config.fetchSharedDocument +import skywolf46.devain.platform.discord.DiscordBot +import skywolf46.devain.platform.plugin.PluginModule + +class GroqModule : PluginModule("Groq Integration") { + private val discord by inject() + + private val apiCall by inject() + + + override fun onInitialize() { + document.fetchSharedDocument(pluginName) {config -> + loadKoinModules(module { + single { GroqAPICall(config.apiToken) } + }) + discord.registerCommands( + SimpleGroqCommand("xllama", "LLAAAAAAAAAAMAAAAAAAAA", "llama3-70b-8192", "Llama3 70B"), + SimpleGroqCommand("llama", "LLAAAAAAAAAAMAAAAAAAAA", "llama3-8b-8192", "Llama3 8B"), + SimpleGroqCommand("mixtral", "Mixtral (Groq)", "mixtral-8x7b-32768", "Mixtral 8 x 7B"), + SimpleGroqCommand("gemma", "Gemma (Groq)", "gemma-7b-it", "Gemma"), + ) + } + } + + override suspend fun getStatistics(): Map> { + return mapOf( + "Text Generation" to listOf( + PluginStatistics( + "총 생성 횟수", + "%,d".format(apiCall.certainly(GetRequest(KEY_GROQ_GENERATION_PROCEED_COUNT)).value) + ), + ) + ) + } + + override fun getVersion(): String { + return "Alpha" + } +} \ No newline at end of file From 98d81e261cc14f4a154884db418ff1782c76b789 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:10:50 +0900 Subject: [PATCH 30/46] =?UTF-8?q?feat:=20DallE=20=EB=AA=85=EB=A0=B9?= =?UTF-8?q?=EC=96=B4=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=A7=80=EC=9B=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commands/discord/openai/DallEGenerationCommand.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/DallEGenerationCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/DallEGenerationCommand.kt index a1b9ab3..d2280c8 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/DallEGenerationCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/DallEGenerationCommand.kt @@ -1,5 +1,6 @@ package skywolf46.devain.controller.commands.discord.openai +import arrow.core.Option import arrow.core.toOption import net.dv8tion.jda.api.EmbedBuilder import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent @@ -27,6 +28,9 @@ class DallEGenerationCommand : ImprovedDiscordCommand("dalle", "OpenAI DallE를 ) { DallERequest.ImageSize.values().map { it.name.lowercase() }.toList() } + options.addCompletableOption("style", "이미지의 스타일을 지정합니다.", false) { + listOf("vivid", "natural") + } } override suspend fun onCommand(event: SlashCommandInteractionEvent) { @@ -37,7 +41,8 @@ class DallEGenerationCommand : ImprovedDiscordCommand("dalle", "OpenAI DallE를 event.getOption("size")?.asString?.let { DallERequest.ImageSize.valueOf(it.uppercase()) } ?: DallERequest.ImageSize.X1024, DallERequest.ResponseType.URL, - 1 + 1, + Option.fromNullable(event.getOption("style")?.asString) )).onLeft { hook.sendMessage(it.getErrorMessage()).queue() }.onRight { From bacda090c65029c5ffcdd5b87010d86e2a3d0eab Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:11:02 +0900 Subject: [PATCH 31/46] =?UTF-8?q?feat:=20DallEImageEditAPICall=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devain/controller/api/requests/openai/DallEAPICall.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/DallEAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/DallEAPICall.kt index b30a947..145dd16 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/DallEAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/DallEAPICall.kt @@ -10,8 +10,8 @@ import org.json.simple.JSONObject import org.koin.core.component.get import skywolf46.devain.KEY_DALLE_PROCEED_COUNT import skywolf46.devain.KEY_DALLE_PROCEED_TIME -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.RESTAPICall +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall import skywolf46.devain.controller.api.requests.devain.DevAinUpdatePersistenceCountAPICall import skywolf46.devain.model.api.openai.UpdateRequest import skywolf46.devain.model.api.openai.dalle.DallERequest From 746d38026a1736c6e62dce26132b3199ecf01c80 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:11:07 +0900 Subject: [PATCH 32/46] =?UTF-8?q?feat:=20DallEImageEditAPICall=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../requests/openai/DallEImageEditAPICall.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/main/kotlin/skywolf46/devain/controller/api/requests/openai/DallEImageEditAPICall.kt diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/DallEImageEditAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/DallEImageEditAPICall.kt new file mode 100644 index 0000000..ef9c128 --- /dev/null +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/DallEImageEditAPICall.kt @@ -0,0 +1,36 @@ +package skywolf46.devain.controller.api.requests.openai + +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.right +import io.ktor.client.* +import io.ktor.http.* +import org.json.simple.JSONObject +import org.koin.core.component.get +import skywolf46.devain.KEY_DALLE_PROCEED_COUNT +import skywolf46.devain.KEY_DALLE_PROCEED_TIME +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall +import skywolf46.devain.controller.api.requests.devain.DevAinUpdatePersistenceCountAPICall +import skywolf46.devain.model.api.openai.UpdateRequest +import skywolf46.devain.model.api.openai.dalle.DallERequest +import skywolf46.devain.model.api.openai.dalle.DallEResponse + +class DallEImageEditAPICall(private val apiKey: String, client: Option = None) : + RESTAPICall({ + "https://api.openai.com/v1/images/edits" + }, client, HttpMethod.Post) { + private val updateCall = get() + + override suspend fun parseResult(request: DallERequest, response: JSONObject): Either { + return DallEResponse.fromJson(response).apply { + updateCall.call(UpdateRequest(KEY_DALLE_PROCEED_COUNT, 1L)) + updateCall.call(UpdateRequest(KEY_DALLE_PROCEED_TIME, (System.currentTimeMillis() - request.createdOn))) + }.right() + } + + override fun HeadersBuilder.applyCredential() { + append("Authorization", "Bearer $apiKey") + } +} \ No newline at end of file From b2601dbd82787bf585bd019c6e4d72147a73883e Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:11:18 +0900 Subject: [PATCH 33/46] =?UTF-8?q?feat:=20DallE=20=EB=AA=85=EB=A0=B9?= =?UTF-8?q?=EC=96=B4=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=A7=80=EC=9B=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devain/model/api/openai/dalle/DallERequest.kt | 13 +++++++++++-- .../devain/model/api/openai/dalle/DallEResponse.kt | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallERequest.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallERequest.kt index 71ea91a..a52d067 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallERequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallERequest.kt @@ -2,7 +2,7 @@ package skywolf46.devain.model.api.openai.dalle import arrow.core.* import org.json.simple.JSONObject -import skywolf46.devain.model.Request +import skywolf46.devain.apicall.networking.Request import skywolf46.devain.util.checkRangeAndFatal data class DallERequest( @@ -10,21 +10,30 @@ data class DallERequest( val imageSize: ImageSize = ImageSize.X1024, val responseType: ResponseType = ResponseType.URL, val generateCount: Int, + val style: Option = None, val createdOn: Long = System.currentTimeMillis() ) : Request { - override fun asJson(): Either { + override fun serialize(): Either { if (prompt.length > 1000) { return IllegalArgumentException("프롬프트는 1000자를 넘을 수 없습니다.").left() } generateCount.checkRangeAndFatal(1..10) { return IllegalArgumentException("생성 개수는 1개 이상 10개 이하로 설정해야 합니다.").left() } + style.tap { + if (it !in listOf("vivid", "natural")) { + return IllegalArgumentException("스타일은 vivid 또는 natural로 설정해야 합니다.").left() + } + } return JSONObject().apply { this["model"] = "dall-e-3" this["prompt"] = prompt this["n"] = generateCount this["size"] = imageSize.requestType + style.tap { + this["style"] = it + } this["response_format"] = responseType.name.lowercase() }.right() } diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallEResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallEResponse.kt index 8a9578b..6258e8f 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallEResponse.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallEResponse.kt @@ -1,7 +1,7 @@ package skywolf46.devain.model.api.openai.dalle import org.json.simple.JSONObject -import skywolf46.devain.model.Response +import skywolf46.devain.apicall.networking.Response import skywolf46.devain.model.api.openai.OpenAIImage import skywolf46.devain.util.getList From 2606066f75c2ed0c028f2bc2e54c080c2b07af58 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:12:20 +0900 Subject: [PATCH 34/46] =?UTF-8?q?feat:=20REST=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EC=99=B8=EB=B6=80=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC?= =?UTF-8?q?=EB=A6=AC=20=EB=B3=80=EA=B2=BD=20=EC=BD=94=EB=93=9C=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../requests/deepl/DeepLTranslationAPICall.kt | 6 ++-- .../devain/DevAinAppPropertiesAPICall.kt | 8 ++--- .../devain/DevAinPersistenceCountAPICall.kt | 12 ++++---- .../devain/DevAinPersistenceUserDataCall.kt | 10 +++---- .../DevAinUpdatePersistenceCountAPICall.kt | 14 ++++----- .../requests/eve/EvEOnlineStatusAPICall.kt | 8 ++--- .../requests/google/GoogleSearchAPICall.kt | 9 +++--- .../requests/openai/GPTCompletionAPICall.kt | 15 +++++----- .../openweather/OpenWeatherAPICall.kt | 8 ++--- .../openweather/OpenWeatherForecastAPICall.kt | 8 ++--- .../commands/discord/openai/GPTBaseCommand.kt | 10 +++++-- .../commands/discord/openai/GPTCommand.kt | 30 ++++++++++++------- .../discord/openai/ImageGPTCommand.kt | 23 +++++++------- .../discord/openai/ModalGPTCommand.kt | 4 +-- .../translation/DeepLTranslateRequest.kt | 4 +-- .../translation/DeepLTranslateResponse.kt | 2 +- .../model/api/google/GoogleSearchRequest.kt | 3 +- .../model/api/google/GoogleSearchResponse.kt | 2 +- .../model/api/openai/OpenAIParameterSchema.kt | 4 +-- .../devain/model/api/openai/UpdateRequest.kt | 3 +- .../completion/OpenAIFunctionDeclaration.kt | 6 ++-- .../api/openai/completion/OpenAIGPTRequest.kt | 10 +++---- .../openai/completion/OpenAIGPTResponse.kt | 2 +- .../functions/EvEOnlineStatusDeclaration.kt | 4 +-- .../functions/GoogleSearchDeclaration.kt | 2 +- .../functions/OpenWeatherCallDeclaration.kt | 2 +- .../OpenWeatherForecastDeclaration.kt | 2 +- 27 files changed, 113 insertions(+), 98 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/deepl/DeepLTranslationAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/deepl/DeepLTranslationAPICall.kt index ed9cc13..8f3c1f1 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/deepl/DeepLTranslationAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/deepl/DeepLTranslationAPICall.kt @@ -7,9 +7,9 @@ import org.json.simple.JSONObject import org.koin.core.component.get import skywolf46.devain.KEY_DEEPL_PROCEED_COUNT import skywolf46.devain.KEY_DEEPL_PROCEED_TOKEN -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.RESTAPICall -import skywolf46.devain.controller.api.error.UnexpectedError +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall +import skywolf46.devain.apicall.errors.UnexpectedError import skywolf46.devain.controller.api.requests.devain.DevAinUpdatePersistenceCountAPICall import skywolf46.devain.model.api.deepl.translation.DeepLTranslateRequest import skywolf46.devain.model.api.deepl.translation.DeepLTranslateResponse diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinAppPropertiesAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinAppPropertiesAPICall.kt index 6dde126..2f9d102 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinAppPropertiesAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinAppPropertiesAPICall.kt @@ -2,10 +2,10 @@ package skywolf46.devain.controller.api.requests.devain import arrow.core.Either import arrow.core.right -import skywolf46.devain.controller.api.APICall -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.model.EmptyRequest -import skywolf46.devain.model.GenericMapResponse +import skywolf46.devain.apicall.APICall +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.networking.EmptyRequest +import skywolf46.devain.apicall.networking.GenericMapResponse import java.util.* class DevAinAppPropertiesAPICall : APICall> { diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinPersistenceCountAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinPersistenceCountAPICall.kt index 8113817..b6a8146 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinPersistenceCountAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinPersistenceCountAPICall.kt @@ -8,12 +8,12 @@ import kotlinx.coroutines.withContext import org.koin.core.component.get import skywolf46.devain.SQLITE_PERSISTENCE import skywolf46.devain.TABLE_PERSISTENCE_COUNT -import skywolf46.devain.controller.api.APICall -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.error.UnexpectedError -import skywolf46.devain.model.api.openai.GetRequest -import skywolf46.devain.model.api.openai.GetResponse -import skywolf46.devain.model.store.SqliteStore +import skywolf46.devain.apicall.APICall +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.errors.UnexpectedError +import skywolf46.devain.apicall.networking.GetRequest +import skywolf46.devain.apicall.networking.GetResponse +import skywolf46.devain.model.data.store.SqliteStore class DevAinPersistenceCountAPICall : APICall, GetResponse> { private val store = get() diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinPersistenceUserDataCall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinPersistenceUserDataCall.kt index 2f12899..31c9d6c 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinPersistenceUserDataCall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinPersistenceUserDataCall.kt @@ -4,11 +4,11 @@ import arrow.core.Either import org.koin.core.component.get import skywolf46.devain.SQLITE_PERSISTENCE import skywolf46.devain.TABLE_PERSISTENCE_COUNT -import skywolf46.devain.controller.api.APICall -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.model.GenericListResponse -import skywolf46.devain.model.api.openai.GetRequest -import skywolf46.devain.model.store.SqliteStore +import skywolf46.devain.apicall.APICall +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.networking.GenericListResponse +import skywolf46.devain.apicall.networking.GetRequest +import skywolf46.devain.model.data.store.SqliteStore class DevAinPersistenceUserDataCall : APICall, GenericListResponse> { private val store = get() diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinUpdatePersistenceCountAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinUpdatePersistenceCountAPICall.kt index adffddd..7ce8b4a 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinUpdatePersistenceCountAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/devain/DevAinUpdatePersistenceCountAPICall.kt @@ -8,14 +8,14 @@ import kotlinx.coroutines.withContext import org.koin.core.component.get import skywolf46.devain.SQLITE_PERSISTENCE import skywolf46.devain.TABLE_PERSISTENCE_COUNT -import skywolf46.devain.controller.api.APICall -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.certainly -import skywolf46.devain.controller.api.error.UnexpectedError -import skywolf46.devain.model.EmptyResponse -import skywolf46.devain.model.api.openai.GetRequest +import skywolf46.devain.apicall.APICall +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.certainly +import skywolf46.devain.apicall.errors.UnexpectedError +import skywolf46.devain.apicall.networking.EmptyResponse +import skywolf46.devain.apicall.networking.GetRequest import skywolf46.devain.model.api.openai.UpdateRequest -import skywolf46.devain.model.store.SqliteStore +import skywolf46.devain.model.data.store.SqliteStore class DevAinUpdatePersistenceCountAPICall : APICall, EmptyResponse> { private val store = get() diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/eve/EvEOnlineStatusAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/eve/EvEOnlineStatusAPICall.kt index fa64c9e..07e1bc8 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/eve/EvEOnlineStatusAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/eve/EvEOnlineStatusAPICall.kt @@ -6,10 +6,10 @@ import arrow.core.Option import arrow.core.right import io.ktor.client.* import org.json.simple.JSONObject -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.RESTAPICall -import skywolf46.devain.model.EmptyJSONRequest -import skywolf46.devain.model.GenericJSONObjectResponse +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall +import skywolf46.devain.apicall.networking.EmptyJSONRequest +import skywolf46.devain.apicall.networking.GenericJSONObjectResponse class EvEOnlineStatusAPICall(client: Option = None) : RESTAPICall({ "https://esi.evetech.net/latest/status/" }, client) { diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/google/GoogleSearchAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/google/GoogleSearchAPICall.kt index d66dfc1..b2e099b 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/google/GoogleSearchAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/google/GoogleSearchAPICall.kt @@ -9,11 +9,10 @@ import org.json.simple.JSONObject import org.json.simple.parser.JSONParser import org.koin.core.component.get import org.koin.core.component.inject -import skywolf46.devain.controller.api.APICall -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.error.PreconditionError -import skywolf46.devain.controller.api.error.StandardRestAPIError -import skywolf46.devain.controller.api.error.UnexpectedError +import skywolf46.devain.apicall.APICall +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.errors.StandardRestAPIError +import skywolf46.devain.apicall.errors.UnexpectedError import skywolf46.devain.model.api.google.GoogleSearchRequest import skywolf46.devain.model.api.google.GoogleSearchResponse import java.net.URLEncoder diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/GPTCompletionAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/GPTCompletionAPICall.kt index 031c829..9ae717d 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/GPTCompletionAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/GPTCompletionAPICall.kt @@ -10,16 +10,15 @@ import org.json.simple.parser.JSONParser import org.koin.core.component.get import org.koin.core.component.inject import skywolf46.devain.* -import skywolf46.devain.controller.api.APICall -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.error.PreconditionError -import skywolf46.devain.controller.api.error.StandardRestAPIError -import skywolf46.devain.controller.api.error.UnexpectedError +import skywolf46.devain.apicall.APICall +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.errors.PreconditionError +import skywolf46.devain.apicall.errors.StandardRestAPIError +import skywolf46.devain.apicall.errors.UnexpectedError import skywolf46.devain.controller.api.requests.devain.DevAinUpdatePersistenceCountAPICall import skywolf46.devain.model.api.openai.UpdateRequest import skywolf46.devain.model.api.openai.completion.* -import skywolf46.devain.model.store.OpenAIFunctionStore -import skywolf46.devain.util.getMap +import skywolf46.devain.model.data.store.OpenAIFunctionStore import skywolf46.devain.util.parseMap private const val OPENAI_GPT_COMPLETION_ENDPOINT = "https://api.openai.com/v1/chat/completions" @@ -41,7 +40,7 @@ class GPTCompletionAPICall(private val apiKey: String, client: Option { return runCatching { - val prebuiltRequest = request.asJson().getOrElse { return PreconditionError(it).left() } + val prebuiltRequest = request.serialize().getOrElse { return PreconditionError(it).left() } val result = client.post(OPENAI_GPT_COMPLETION_ENDPOINT) { contentType(ContentType.Application.Json) headers { diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherAPICall.kt index 01ee6be..ad45d71 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherAPICall.kt @@ -6,10 +6,10 @@ import arrow.core.Option import arrow.core.right import io.ktor.client.* import org.json.simple.JSONObject -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.RESTAPICall -import skywolf46.devain.model.GenericJSONObjectResponse -import skywolf46.devain.model.api.openai.GetRequest +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall +import skywolf46.devain.apicall.networking.GenericJSONObjectResponse +import skywolf46.devain.apicall.networking.GetRequest class OpenWeatherAPICall(private val apiKey: String, client: Option = None) : RESTAPICall, GenericJSONObjectResponse>({ diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherForecastAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherForecastAPICall.kt index b97748b..e32efcb 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherForecastAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherForecastAPICall.kt @@ -6,10 +6,10 @@ import arrow.core.Option import arrow.core.right import io.ktor.client.* import org.json.simple.JSONObject -import skywolf46.devain.controller.api.APIError -import skywolf46.devain.controller.api.RESTAPICall -import skywolf46.devain.model.GenericJSONObjectResponse -import skywolf46.devain.model.api.openai.GetRequest +import skywolf46.devain.apicall.APIError +import skywolf46.devain.apicall.RESTAPICall +import skywolf46.devain.apicall.networking.GenericJSONObjectResponse +import skywolf46.devain.apicall.networking.GetRequest class OpenWeatherForecastAPICall(private val apiKey: String, client: Option = None) : RESTAPICall, GenericJSONObjectResponse>({ diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTBaseCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTBaseCommand.kt index 1ac8862..5a3c993 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTBaseCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTBaseCommand.kt @@ -1,6 +1,9 @@ package skywolf46.devain.controller.commands.discord.openai -import arrow.core.* +import arrow.core.None +import arrow.core.Option +import arrow.core.getOrElse +import arrow.core.toOption import net.dv8tion.jda.api.entities.MessageEmbed import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent import net.dv8tion.jda.api.interactions.commands.OptionType @@ -106,8 +109,9 @@ open class GPTBaseCommand( fun isEmbedCompatible(request: OpenAIGPTRequest, response: OpenAIGPTResponse): Boolean { val requestMessage = request.messages.find { it.role == OpenAIGPTMessage.Role.USER }!! val responseMessage = response.answers.last() - return (request.hidePrompt || requestMessage.content.orNull() - .toString().length < 4096) && (responseMessage.message.content.orNull().toString().length < 1024 - 6) + return (request.hidePrompt || requestMessage.content.find { it.first == "text" }?.second + .toString().length < 4096) && ((responseMessage.message.content.find { it.first == "text" }?.second?.length + ?: 0) < 1024 - 6) } final override fun modifyCommandData(options: SlashCommandData) { diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTCommand.kt index 2412662..225f2f7 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTCommand.kt @@ -17,7 +17,8 @@ abstract class GPTCommand(command: String, description: String) : companion object { const val DEFAULT_MODEL = "gpt-4" - private val priceInfo = mapOf("gpt-4-0613" to 0.06, "gpt-4" to 0.06, "gpt-3.5-turbo" to 0.002, "gpt-3.5-turbo-16k" to 0.002) + private val priceInfo = + mapOf("gpt-4-0613" to 0.06, "gpt-4" to 0.06, "gpt-3.5-turbo" to 0.002, "gpt-3.5-turbo-16k" to 0.002) private const val dollarToWonMultiplier = 1329.41 private val decimalFormat = DecimalFormat("#,###") } @@ -25,7 +26,7 @@ abstract class GPTCommand(command: String, description: String) : fun isEmbedCompatible(request: OpenAIGPTRequest, response: OpenAIGPTResponse): Boolean { val requestMessage = request.messages.find { it.role == OpenAIGPTMessage.Role.USER }!! val responseMessage = response.answers.last() - return (request.hidePrompt || requestMessage.content.orNull().toString().length < 4096) && (responseMessage.message.content.orNull().toString().length < 1024 - 6) + return (request.hidePrompt || requestMessage.content.find { it.first == "text" }?.second.toString().length < 4096) && (responseMessage.message.content.find { it.first == "text" }?.second.toString().length < 1024 - 6) } fun buildEmbedded(request: OpenAIGPTRequest, response: OpenAIGPTResponse): MessageEmbed { @@ -36,28 +37,35 @@ abstract class GPTCommand(command: String, description: String) : setTitle("Request complete - ${request.modelName}") setColor(Color(162, 103, 181)) if (!request.hidePrompt) { - setDescription(requestMessage.content.orNull().toString()) + setDescription(requestMessage.content.find { it.first == "text" }?.second.toString()) } else { setDescription("_프롬프트 숨겨짐_") } - addField("Response", responseMessage.message.content.orNull().toString(), false) + + addField( + "Response", + responseMessage.message.content.find { it.first == "text" }?.second.toString(), + false + ) addField( "Tokens", - box("%,d+%,d=%,d".format( - response.usage.promptToken, - response.usage.completionToken, - response.usage.totalToken - )), + box( + "%,d+%,d=%,d".format( + response.usage.promptToken, + response.usage.completionToken, + response.usage.totalToken + ) + ), true ) - if(request.modelName in priceInfo) { + if (request.modelName in priceInfo) { val token = response.usage.totalToken.toDouble() / 1000.0 val price = round(priceInfo[request.modelName]!! * token * 10000.0) / 10000.0 val won = round(dollarToWonMultiplier * price * 1000) / 1000.0 addField( "Price", box("$%.3f (%.1f원)".format(price, won)), true ) - }else { + } else { addField( "Price", box("알 수 없음"), true ) diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt index e7ebbfc..855ca0a 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt @@ -82,21 +82,24 @@ class ImageGPTCommand( event.getOption("base-prompt")?.asString?.let { mutableListOf( OpenAIGPTMessage(OpenAIGPTMessage.Role.ASSISTANT, it.toOption()), - OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, event.getOption("contents")!!.asString.toOption()), - OpenAIGPTMessage( - OpenAIGPTMessage.Role.IMAGE_URL, - event.getOption("image")!!.asAttachment.url.toOption() - ) + OpenAIGPTMessage(OpenAIGPTMessage.Role.USER,listOf( + "text" to event.getOption("contents")!!.asString, + "image_url" to event.getOption("image")!!.asAttachment.url + )) ) } ?: mutableListOf( - OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, event.getOption("contents")!!.asString.toOption()), - OpenAIGPTMessage(OpenAIGPTMessage.Role.IMAGE_URL, event.getOption("image")!!.asAttachment.url.toOption()) + OpenAIGPTMessage( + OpenAIGPTMessage.Role.USER, listOf( + "text" to event.getOption("contents")!!.asString, + "image_url" to event.getOption("image")!!.asAttachment.url + ) + ) ), 1, event.getOption("temperature")?.asDouble.toOption(), event.getOption("top_p")?.asDouble.toOption(), event.getOption("best_of")?.asInt.toOption(), - event.getOption("max_token")?.asInt.toOption(), + (event.getOption("max_token")?.asInt ?: 4096).toOption(), event.getOption("presence_penalty")?.asDouble.toOption(), event.getOption("frequency_penalty")?.asDouble.toOption(), event.getOption("hide-prompt")?.asBoolean ?: false @@ -191,12 +194,12 @@ class ImageGPTCommand( } private fun appendRequest(builder: StringBuilder, request: OpenAIGPTRequest) { - builder.append("**요청:** \n${request.messages.last().content.orNull()}") + builder.append("**요청:** \n${request.messages.last().content.find { it.first == "text" }?.second }}") builder.appendNewLine(2) } private fun appendResult(builder: StringBuilder, result: OpenAIGPTResponse) { - builder.append("**응답:** \n${result.answers[0].message.content.orNull()}") + builder.append("**응답:** \n${result.answers[0].message.content.find { it.first == "text" }?.second}") } private fun StringBuilder.appendNewLine(count: Int = 1) { diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt index 73c2283..4465f98 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt @@ -192,12 +192,12 @@ class ModalGPTCommand( } private fun appendRequest(builder: StringBuilder, request: OpenAIGPTRequest) { - builder.append("**요청:** \n${request.messages.last().content.orNull()}") + builder.append("**요청:** \n${request.messages.last().content.find { it.first == "text" }?.second}") builder.appendNewLine(2) } private fun appendResult(builder: StringBuilder, result: OpenAIGPTResponse) { - builder.append("**응답:** \n${result.answers[0].message.content.orNull()}") + builder.append("**응답:** \n${result.answers[0].message.content.find { it.first == "text" }?.second}") } private fun StringBuilder.appendNewLine(count: Int = 1) { diff --git a/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateRequest.kt index da7efbd..cdbcfca 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateRequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateRequest.kt @@ -5,7 +5,7 @@ import arrow.core.Option import arrow.core.left import arrow.core.right import org.json.simple.JSONObject -import skywolf46.devain.model.Request +import skywolf46.devain.apicall.networking.Request import skywolf46.devain.util.putArray data class DeepLTranslateRequest( @@ -51,7 +51,7 @@ data class DeepLTranslateRequest( fun getSupportedLanguage() = supportedLanguage.keys.toList() } - override fun asJson(): Either { + override fun serialize(): Either { val map = JSONObject() sourceLanguage.tap { if (!isSupported(it)) { diff --git a/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateResponse.kt index 83814e9..cff6bc9 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateResponse.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateResponse.kt @@ -1,7 +1,7 @@ package skywolf46.devain.model.api.deepl.translation import org.json.simple.JSONObject -import skywolf46.devain.model.Response +import skywolf46.devain.apicall.networking.Response data class DeepLTranslateResponse(val sourceLanguage: String, val translationResult: String) : Response { companion object { diff --git a/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchRequest.kt index 8705364..4e5c9e7 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchRequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchRequest.kt @@ -1,5 +1,6 @@ package skywolf46.devain.model.api.google -import skywolf46.devain.model.EmptyJSONRequest +import skywolf46.devain.apicall.networking.EmptyJSONRequest + class GoogleSearchRequest(val query: String, val amount: Int) : EmptyJSONRequest() \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchResponse.kt index f40a828..6de3a34 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchResponse.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchResponse.kt @@ -1,7 +1,7 @@ package skywolf46.devain.model.api.google import org.json.simple.JSONObject -import skywolf46.devain.model.Response +import skywolf46.devain.apicall.networking.Response import skywolf46.devain.util.getList class GoogleSearchResponse( diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/OpenAIParameterSchema.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/OpenAIParameterSchema.kt index d9cab7c..f913d00 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/OpenAIParameterSchema.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/OpenAIParameterSchema.kt @@ -3,7 +3,7 @@ package skywolf46.devain.model.api.openai import arrow.core.Either import arrow.core.right import org.json.simple.JSONObject -import skywolf46.devain.model.Request +import skywolf46.devain.apicall.networking.Request class OpenAIParameterSchema( val parameterName: String, @@ -11,7 +11,7 @@ class OpenAIParameterSchema( val type: String, val required: String ) : Request { - override fun asJson(): Either { + override fun serialize(): Either { return JSONObject() .apply { put("type", type) diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/UpdateRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/UpdateRequest.kt index 10c6212..8acf8ee 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/UpdateRequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/UpdateRequest.kt @@ -1,5 +1,6 @@ package skywolf46.devain.model.api.openai -import skywolf46.devain.model.EmptyRequest +import skywolf46.devain.apicall.networking.EmptyRequest + data class UpdateRequest(val key: String, val delta: DELTA) : EmptyRequest() \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIFunctionDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIFunctionDeclaration.kt index 26cf157..a30177a 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIFunctionDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIFunctionDeclaration.kt @@ -3,7 +3,7 @@ package skywolf46.devain.model.api.openai.completion import arrow.core.Either import arrow.core.right import org.json.simple.JSONObject -import skywolf46.devain.model.Request +import skywolf46.devain.apicall.networking.Request import skywolf46.devain.model.api.openai.OpenAIParameterSchema import skywolf46.devain.util.putArray import skywolf46.devain.util.putMap @@ -29,7 +29,7 @@ open class OpenAIFunctionDeclaration( return JSONObject() } - override fun asJson(): Either { + override fun serialize(): Either { return JSONObject().apply { put("name", key.functionName) put("description", description) @@ -42,7 +42,7 @@ open class OpenAIFunctionDeclaration( put("type", "object") putMap("properties", *parameterSchema.map { - it.parameterName to it.asJson().getOrNull()!! + it.parameterName to it.serialize().getOrNull()!! }.toTypedArray() ) putArray( diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTRequest.kt index b5147aa..061ea07 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTRequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTRequest.kt @@ -4,8 +4,8 @@ import arrow.core.* import org.json.simple.JSONArray import org.json.simple.JSONObject import org.koin.core.component.get -import skywolf46.devain.model.Request -import skywolf46.devain.model.store.OpenAIFunctionStore +import skywolf46.devain.apicall.networking.Request +import skywolf46.devain.model.data.store.OpenAIFunctionStore import skywolf46.devain.util.checkRangeAndFatal data class OpenAIGPTRequest( @@ -93,7 +93,7 @@ data class OpenAIGPTRequest( /** * Struct JSONObject from this request. */ - override fun asJson(): Either { + override fun serialize(): Either { val map = JSONObject() temperature.tap { it.checkRangeAndFatal(0.0..2.0) { range -> @@ -130,7 +130,7 @@ data class OpenAIGPTRequest( if (functionStore.getFunction(key).isEmpty()) return IllegalArgumentException("존재하지 않는 함수 키입니다. ($key)").left() } - map["functions"] = it.map { key -> functionStore.getFunction(key).orNull()!!.asJson().getOrNull()!! } + map["functions"] = it.map { key -> functionStore.getFunction(key).orNull()!!.serialize().getOrNull()!! } } bestOf.tap { if (it > 10) { @@ -145,7 +145,7 @@ data class OpenAIGPTRequest( // return IllegalArgumentException("마지막 메시지는 USER 혹은 FUNCTION 역할이어야 합니다.").left() // } map["messages"] = JSONArray().apply { - addAll(messages.map { it.asJson().getOrNull()!! }) + addAll(messages.map { it.serialize().getOrNull()!! }) } map["n"] = generateAmount diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTResponse.kt index 4e8dd83..e296f72 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTResponse.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTResponse.kt @@ -2,7 +2,7 @@ package skywolf46.devain.model.api.openai.completion import org.json.simple.JSONArray import org.json.simple.JSONObject -import skywolf46.devain.model.Response +import skywolf46.devain.apicall.networking.Response data class OpenAIGPTResponse( /** diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/EvEOnlineStatusDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/EvEOnlineStatusDeclaration.kt index 7b7d3f7..e08187c 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/EvEOnlineStatusDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/EvEOnlineStatusDeclaration.kt @@ -3,9 +3,9 @@ package skywolf46.devain.model.api.openai.completion.functions import arrow.core.getOrElse import org.json.simple.JSONObject import org.koin.core.component.inject +import skywolf46.devain.apicall.networking.EmptyJSONRequest +import skywolf46.devain.apicall.networking.GenericJSONObjectResponse import skywolf46.devain.controller.api.requests.eve.EvEOnlineStatusAPICall -import skywolf46.devain.model.EmptyJSONRequest -import skywolf46.devain.model.GenericJSONObjectResponse import skywolf46.devain.model.api.openai.completion.OpenAIFunctionDeclaration import skywolf46.devain.model.api.openai.completion.OpenAIFunctionKey diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/GoogleSearchDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/GoogleSearchDeclaration.kt index 1cc5cf2..62bf917 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/GoogleSearchDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/GoogleSearchDeclaration.kt @@ -3,8 +3,8 @@ package skywolf46.devain.model.api.openai.completion.functions import arrow.core.getOrElse import org.json.simple.JSONObject import org.koin.core.component.inject +import skywolf46.devain.apicall.networking.GenericJSONObjectResponse import skywolf46.devain.controller.api.requests.google.GoogleSearchAPICall -import skywolf46.devain.model.GenericJSONObjectResponse import skywolf46.devain.model.api.google.GoogleSearchRequest import skywolf46.devain.model.api.openai.OpenAIParameterSchema import skywolf46.devain.model.api.openai.completion.OpenAIFunctionDeclaration diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/OpenWeatherCallDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/OpenWeatherCallDeclaration.kt index 40ad4e8..937800f 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/OpenWeatherCallDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/OpenWeatherCallDeclaration.kt @@ -3,8 +3,8 @@ package skywolf46.devain.model.api.openai.completion.functions import arrow.core.getOrElse import org.json.simple.JSONObject import org.koin.core.component.inject +import skywolf46.devain.apicall.networking.GetRequest import skywolf46.devain.controller.api.requests.openweather.OpenWeatherAPICall -import skywolf46.devain.model.api.openai.GetRequest import skywolf46.devain.model.api.openai.OpenAIParameterSchema import skywolf46.devain.model.api.openai.completion.OpenAIFunctionDeclaration import skywolf46.devain.model.api.openai.completion.OpenAIFunctionKey diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/OpenWeatherForecastDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/OpenWeatherForecastDeclaration.kt index 6b144f8..b9b222a 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/OpenWeatherForecastDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/OpenWeatherForecastDeclaration.kt @@ -3,8 +3,8 @@ package skywolf46.devain.model.api.openai.completion.functions import arrow.core.getOrElse import org.json.simple.JSONObject import org.koin.core.component.inject +import skywolf46.devain.apicall.networking.GetRequest import skywolf46.devain.controller.api.requests.openweather.OpenWeatherForecastAPICall -import skywolf46.devain.model.api.openai.GetRequest import skywolf46.devain.model.api.openai.OpenAIParameterSchema import skywolf46.devain.model.api.openai.completion.OpenAIFunctionDeclaration import skywolf46.devain.model.api.openai.completion.OpenAIFunctionKey From b0294336e21d7a6384250077eb82acd02989d471 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:13:40 +0900 Subject: [PATCH 35/46] =?UTF-8?q?chore:=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/skywolf46/devain/DevAin.kt | 9 +-------- .../api/requests/arxiv/ArxivSearchAPICall.kt | 5 ++++- .../api/requests/google/GoogleNewsAPICall.kt | 1 + .../openweather/OpenWeatherForecastAPICall.kt | 5 ++++- .../discord/devain/DevAinStatusCommand.kt | 2 +- .../devain/controller/modules/GroqModule.kt | 2 +- .../devain/model/api/arxiv/ArxivRequest.kt | 1 + .../devain/model/api/arxiv/ArxivResponse.kt | 8 +++++++- .../devain/model/api/cohere/CohereMessage.kt | 2 +- .../devain/model/api/google/GoogleSearchItem.kt | 2 +- .../completion/OpenAIFunctionDeclaration.kt | 5 +++-- .../functions/ArxivSearchDeclaration.kt | 1 - .../functions/EvEOnlineStatusDeclaration.kt | 2 +- .../completion/functions/TimeDeclaration.kt | 2 +- .../devain/model/api/rplus/RPlusResponse.kt | 2 +- .../devain/model/data/config/ConfigAdaptor.kt | 2 +- .../discord/AnnotatedParameterDiscordCommand.kt | 16 ++++++++++++---- .../devain/platform/plugin/PluginManager.kt | 1 - .../kotlin/skywolf46/devain/util/JSONUtil.kt | 7 ++++++- .../kotlin/skywolf46/devain/util/RangeUtil.kt | 4 ++-- .../kotlin/skywolf46/devain/util/StringUtil.kt | 2 +- 21 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/DevAin.kt b/src/main/kotlin/skywolf46/devain/DevAin.kt index 8876f77..95a0ab1 100644 --- a/src/main/kotlin/skywolf46/devain/DevAin.kt +++ b/src/main/kotlin/skywolf46/devain/DevAin.kt @@ -1,17 +1,10 @@ package skywolf46.devain import org.koin.core.component.KoinComponent -import org.koin.core.component.get -import org.koin.core.context.loadKoinModules import org.koin.core.context.startKoin -import org.koin.dsl.module -import skywolf46.devain.config.BotConfig import skywolf46.devain.controller.modules.* -import skywolf46.devain.model.data.config.ConfigDocumentRoot -import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginManager import skywolf46.devain.platform.plugin.PluginModule -import java.io.File fun main(args: Array) { @@ -23,7 +16,7 @@ class DevAin : KoinComponent { internal fun init() { println("DevAin $version - 초기화 시작") - startKoin { } + startKoin { } initializeBuiltInPlugins() while (true) { Thread.sleep(Long.MAX_VALUE) diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/arxiv/ArxivSearchAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/arxiv/ArxivSearchAPICall.kt index 888b090..c59b727 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/arxiv/ArxivSearchAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/arxiv/ArxivSearchAPICall.kt @@ -1,6 +1,9 @@ package skywolf46.devain.controller.api.requests.arxiv -import arrow.core.* +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.right import io.ktor.client.* import org.w3c.dom.Document import org.w3c.dom.Node diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/google/GoogleNewsAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/google/GoogleNewsAPICall.kt index 39492b7..88e7a67 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/google/GoogleNewsAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/google/GoogleNewsAPICall.kt @@ -1,5 +1,6 @@ package skywolf46.devain.controller.api.requests.google private const val GOOGLE_NEWS_RSS_ENDPOINT = "https://news.google.com/rss/search?q=%s" + class GoogleNewsAPICall { } \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherForecastAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherForecastAPICall.kt index e32efcb..03e9f08 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherForecastAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/openweather/OpenWeatherForecastAPICall.kt @@ -16,7 +16,10 @@ class OpenWeatherForecastAPICall(private val apiKey: String, client: Option, response: JSONObject): Either { + override suspend fun parseResult( + request: GetRequest, + response: JSONObject + ): Either { return GenericJSONObjectResponse(response).right() } } \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/devain/DevAinStatusCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/devain/DevAinStatusCommand.kt index be82979..5908e71 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/devain/DevAinStatusCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/devain/DevAinStatusCommand.kt @@ -40,7 +40,7 @@ class DevAinStatusCommand : ImprovedDiscordCommand("status", "DevAin 봇의 상 (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()).toDouble() / 1024.0 / 1024.0 EmbedBuilder() // .setTitle("DevAin Standalone (${propertiesApiCall.certainly()["version"]})") - .setTitle("DevAin Standalone (1.2.0-Grenade-Muffin)") + .setTitle("DevAin Standalone (1.3.0 - Radioactive Emmer Bread)") .setColor(Color.CYAN) .addField( "업타임", diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt index 4a7f676..8fc9116 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt @@ -21,7 +21,7 @@ class GroqModule : PluginModule("Groq Integration") { override fun onInitialize() { - document.fetchSharedDocument(pluginName) {config -> + document.fetchSharedDocument(pluginName) { config -> loadKoinModules(module { single { GroqAPICall(config.apiToken) } }) diff --git a/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivRequest.kt index e437410..7d28d2d 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivRequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivRequest.kt @@ -3,6 +3,7 @@ package skywolf46.devain.model.api.arxiv import arrow.core.Either import arrow.core.right import skywolf46.devain.apicall.networking.Request + data class ArxivRequest(val query: String) : Request { override fun serialize(): Either { return "".right() diff --git a/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivResponse.kt index 33274ff..d151f8d 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivResponse.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/arxiv/ArxivResponse.kt @@ -4,5 +4,11 @@ import skywolf46.devain.apicall.networking.Response data class ArxivResponse(val articles: List
) : Response { - data class Article(val title: String, val summary: String, val url: String, val published: String, val updated: String) + data class Article( + val title: String, + val summary: String, + val url: String, + val published: String, + val updated: String + ) } \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereMessage.kt b/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereMessage.kt index c62c4dc..988785a 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereMessage.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/cohere/CohereMessage.kt @@ -4,7 +4,7 @@ import org.json.simple.JSONObject data class CohereMessage(val id: String, val text: String) { companion object { - fun fromJson(data: JSONObject) : CohereMessage { + fun fromJson(data: JSONObject): CohereMessage { return CohereMessage( data["id"] as String, data["text"] as String diff --git a/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchItem.kt b/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchItem.kt index de2dddb..6128226 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchItem.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/google/GoogleSearchItem.kt @@ -15,7 +15,7 @@ data class GoogleSearchItem( val htmlSnippet: String ) { companion object { - fun fromJson(data: JSONObject) : GoogleSearchItem { + fun fromJson(data: JSONObject): GoogleSearchItem { return GoogleSearchItem( data["kind"].toString(), data["title"].toString(), diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIFunctionDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIFunctionDeclaration.kt index a30177a..5a9d268 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIFunctionDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIFunctionDeclaration.kt @@ -25,7 +25,7 @@ open class OpenAIFunctionDeclaration( val parameterSchema: List ) : Request { - open suspend fun call(param: JSONObject) : JSONObject { + open suspend fun call(param: JSONObject): JSONObject { return JSONObject() } @@ -40,7 +40,8 @@ open class OpenAIFunctionDeclaration( private fun buildParameterJson(): JSONObject { return JSONObject().apply { put("type", "object") - putMap("properties", + putMap( + "properties", *parameterSchema.map { it.parameterName to it.serialize().getOrNull()!! }.toTypedArray() diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt index 5aa1a3b..b3773d0 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt @@ -3,7 +3,6 @@ package skywolf46.devain.model.api.openai.completion.functions import arrow.core.getOrElse import org.json.simple.JSONObject import org.koin.core.component.inject -import org.koin.java.KoinJavaComponent.inject import skywolf46.devain.apicall.networking.GenericJSONObjectResponse import skywolf46.devain.controller.api.requests.arxiv.ArxivSearchAPICall import skywolf46.devain.model.api.arxiv.ArxivRequest diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/EvEOnlineStatusDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/EvEOnlineStatusDeclaration.kt index e08187c..a17678e 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/EvEOnlineStatusDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/EvEOnlineStatusDeclaration.kt @@ -13,7 +13,7 @@ class EvEOnlineStatusDeclaration : OpenAIFunctionDeclaration( OpenAIFunctionKey("eve-status", OpenAIFunctionKey.FunctionFlag.BUILT_IN), "EvE Online(이브 온라인)의 현재 상태를 불러옵니다.", listOf() -){ +) { private val apiCall by inject() diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/TimeDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/TimeDeclaration.kt index 6915470..7e52ad8 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/TimeDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/TimeDeclaration.kt @@ -13,7 +13,7 @@ class TimeDeclaration : OpenAIFunctionDeclaration( private val timeFormat = SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초") override suspend fun call(param: JSONObject): JSONObject { - return JSONObject().apply { + return JSONObject().apply { put("time", timeFormat.format(System.currentTimeMillis())) } } diff --git a/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusResponse.kt b/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusResponse.kt index 9a292c6..c08384f 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusResponse.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/rplus/RPlusResponse.kt @@ -5,7 +5,7 @@ import skywolf46.devain.apicall.networking.Response class RPlusResponse(val text: String) : Response { companion object { - fun fromJson(jsonObject: JSONObject) : RPlusResponse { + fun fromJson(jsonObject: JSONObject): RPlusResponse { return RPlusResponse( jsonObject["text"].toString() ) diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt index 7ffe0e9..6b7e895 100644 --- a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt +++ b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt @@ -6,5 +6,5 @@ import java.io.OutputStream interface ConfigAdaptor { fun serializeTo(stream: OutputStream, data: Map) - fun serializeFrom(stream: InputStream) : Map + fun serializeFrom(stream: InputStream): Map } \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt b/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt index 7c401e0..be26b45 100644 --- a/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt +++ b/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt @@ -21,7 +21,12 @@ abstract class AnnotatedParameterDiscordCommand( override fun modifyCommandData(options: SlashCommandData) { for ((_, data) in parsed.parameters) { - options.addOption(data.type.option, data.name, data.description.replaceAllArgument(onCommandParameterDataRequested()), data.required) + options.addOption( + data.type.option, + data.name, + data.description.replaceAllArgument(onCommandParameterDataRequested()), + data.required + ) } } @@ -36,7 +41,7 @@ abstract class AnnotatedParameterDiscordCommand( abstract suspend fun onParameterCommand(event: CommandEvent, data: T) - open fun onCommandParameterDataRequested() : Map = emptyMap() + open fun onCommandParameterDataRequested(): Map = emptyMap() private class ParsedParameter(private val cls: KClass<*>) { val parameters = mutableMapOf() @@ -109,7 +114,10 @@ abstract class AnnotatedParameterDiscordCommand( }) } - data class CommandEvent(val origin: SlashCommandInteractionEvent, val executedOn: Long = System.currentTimeMillis()) { - fun elapsed() : Long = (System.currentTimeMillis() - executedOn) + data class CommandEvent( + val origin: SlashCommandInteractionEvent, + val executedOn: Long = System.currentTimeMillis() + ) { + fun elapsed(): Long = (System.currentTimeMillis() - executedOn) } } \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt index 3b69ef3..249a8a1 100644 --- a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt +++ b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt @@ -3,7 +3,6 @@ package skywolf46.devain.platform.plugin import org.koin.core.component.KoinComponent import org.koin.core.component.get import org.koin.core.context.loadKoinModules -import org.koin.core.context.startKoin import org.koin.dsl.module import skywolf46.devain.model.data.config.ConfigDocumentRoot import java.io.File diff --git a/src/main/kotlin/skywolf46/devain/util/JSONUtil.kt b/src/main/kotlin/skywolf46/devain/util/JSONUtil.kt index 39c8a06..6e8eba7 100644 --- a/src/main/kotlin/skywolf46/devain/util/JSONUtil.kt +++ b/src/main/kotlin/skywolf46/devain/util/JSONUtil.kt @@ -71,7 +71,12 @@ fun JSONObject.putNotNull(key: String, data: Any?) { } } -inline fun JSONObject.putNotNullOrFatal(key: String, data: Double?, range: ClosedRange, fatal: (ClosedRange) -> Unit) { +inline fun JSONObject.putNotNullOrFatal( + key: String, + data: Double?, + range: ClosedRange, + fatal: (ClosedRange) -> Unit +) { if (data == null) return put(key, data.checkRangeAndFatal(range, fatal)) } diff --git a/src/main/kotlin/skywolf46/devain/util/RangeUtil.kt b/src/main/kotlin/skywolf46/devain/util/RangeUtil.kt index d457c67..9d1f8a6 100644 --- a/src/main/kotlin/skywolf46/devain/util/RangeUtil.kt +++ b/src/main/kotlin/skywolf46/devain/util/RangeUtil.kt @@ -1,13 +1,13 @@ package skywolf46.devain.util -inline fun Int.checkRangeAndFatal(range: IntRange, fatal: (IntRange) -> Unit) : Int{ +inline fun Int.checkRangeAndFatal(range: IntRange, fatal: (IntRange) -> Unit): Int { if (this !in range) fatal(range) return this } -inline fun Double.checkRangeAndFatal(range: ClosedRange, fatal: (ClosedRange) -> Unit) : Double { +inline fun Double.checkRangeAndFatal(range: ClosedRange, fatal: (ClosedRange) -> Unit): Double { if (this !in range) fatal(range) return this diff --git a/src/main/kotlin/skywolf46/devain/util/StringUtil.kt b/src/main/kotlin/skywolf46/devain/util/StringUtil.kt index 13d8a68..d924e73 100644 --- a/src/main/kotlin/skywolf46/devain/util/StringUtil.kt +++ b/src/main/kotlin/skywolf46/devain/util/StringUtil.kt @@ -1,6 +1,6 @@ package skywolf46.devain.util -fun String.replaceAllArgument(args: Map) : String{ +fun String.replaceAllArgument(args: Map): String { return (listOf(this to "") + args.toList()).reduce { acc, pair -> acc.first.replace("{${pair.first}}", pair.second) to "" }.first From 4fe82a830bb4f352d7c99e8acf4975c076e017f9 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:15:35 +0900 Subject: [PATCH 36/46] =?UTF-8?q?chore:=20gitignore=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a73628 --- /dev/null +++ b/.gitignore @@ -0,0 +1,135 @@ +# Created by https://www.toptal.com/developers/gitignore/api/intellij+all,java,kotlin +# Edit at https://www.toptal.com/developers/gitignore?templates=intellij+all,java,kotlin + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +# Configuration files +*.yml +*.db + +### Kotlin ### +# Compiled class file + +# Log file + +# BlueJ files + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml + +# End of https://www.toptal.com/developers/gitignore/api/intellij+all,java,kotlin \ No newline at end of file From 48063a9a85e7530a2b2705b0bc895aee9350a40b Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 03:16:24 +0900 Subject: [PATCH 37/46] =?UTF-8?q?chore:=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commands/discord/cohere/CohereCommand.kt | 3 ++- .../discord/cohere/CommandRPlusCommand.kt | 16 +++++++++------- .../commands/discord/groq/SimpleGroqCommand.kt | 7 ++++++- .../commands/discord/openai/ArxivGPTCommand.kt | 3 +-- .../commands/discord/openai/ImageGPTCommand.kt | 12 +++++++----- .../commands/discord/openai/ModalGPTCommand.kt | 9 +++++++-- .../commands/discord/openai/SimpleGPTCommand.kt | 9 +++++++-- .../devain/controller/modules/AnthropicModule.kt | 1 - 8 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CohereCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CohereCommand.kt index 79b0720..a0b878e 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CohereCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CohereCommand.kt @@ -7,7 +7,8 @@ import skywolf46.devain.platform.discord.AnnotatedParameterDiscordCommand import skywolf46.devain.util.GenerationResultTextBuilder import skywolf46.devain.util.TimeUtil -class CohereCommand : AnnotatedParameterDiscordCommand("cohere", CohereGenerationRequest::class) { +class CohereCommand : + AnnotatedParameterDiscordCommand("cohere", CohereGenerationRequest::class) { private val apiCall by inject() override suspend fun onParameterCommand(event: CommandEvent, data: CohereGenerationRequest) { diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRPlusCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRPlusCommand.kt index 5052e8e..3f98269 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRPlusCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/cohere/CommandRPlusCommand.kt @@ -15,13 +15,15 @@ class CommandRPlusCommand : AnnotatedParameterDiscordCommand("rplu apiCall.call(data.copy(model = "command-r-plus")).fold({ hook.sendMessage("오류가 발생했습니다. ${it.getErrorMessage()}").queue() }) { - val builder = GenerationResultTextBuilder("Request Complete - Command R+", data.message, listOf( - mapOf( - "Model" to box("Command R+ (Cohere)"), - "Elapsed" to box(TimeUtil.toTimeString(event.elapsed())), - ), - mapOf("Response" to it.text) - )) + val builder = GenerationResultTextBuilder( + "Request Complete - Command R+", data.message, listOf( + mapOf( + "Model" to box("Command R+ (Cohere)"), + "Elapsed" to box(TimeUtil.toTimeString(event.elapsed())), + ), + mapOf("Response" to it.text) + ) + ) hook.sendMessageOrEmbed(1000, it.text) { embed -> builder.asEmbed(embed) } diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt index a461557..e7faddb 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt @@ -70,7 +70,12 @@ class SimpleGroqCommand( OpenAIGPTMessage(OpenAIGPTMessage.Role.ASSISTANT, it.toOption()), OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, event.getOption("contents")!!.asString.toOption()) ) - } ?: mutableListOf(OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, event.getOption("contents")!!.asString.toOption())), + } ?: mutableListOf( + OpenAIGPTMessage( + OpenAIGPTMessage.Role.USER, + event.getOption("contents")!!.asString.toOption() + ) + ), 1, event.getOption("temperature")?.asDouble.toOption(), event.getOption("top_p")?.asDouble.toOption(), diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt index f644095..868edb3 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt @@ -10,7 +10,6 @@ import org.koin.core.component.get import skywolf46.devain.controller.api.requests.openai.GPTCompletionAPICall import skywolf46.devain.model.api.openai.completion.* import java.text.DecimalFormat -import kotlin.math.round class ArxivGPTCommand( command: String, @@ -97,7 +96,7 @@ class ArxivGPTCommand( listOf( OpenAIFunctionKey("arxiv_search", OpenAIFunctionKey.FunctionFlag.BUILT_IN), - ).toOption() + ).toOption() ) apiCall.call( request diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt index 855ca0a..96a2bdd 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt @@ -82,10 +82,12 @@ class ImageGPTCommand( event.getOption("base-prompt")?.asString?.let { mutableListOf( OpenAIGPTMessage(OpenAIGPTMessage.Role.ASSISTANT, it.toOption()), - OpenAIGPTMessage(OpenAIGPTMessage.Role.USER,listOf( - "text" to event.getOption("contents")!!.asString, - "image_url" to event.getOption("image")!!.asAttachment.url - )) + OpenAIGPTMessage( + OpenAIGPTMessage.Role.USER, listOf( + "text" to event.getOption("contents")!!.asString, + "image_url" to event.getOption("image")!!.asAttachment.url + ) + ) ) } ?: mutableListOf( OpenAIGPTMessage( @@ -194,7 +196,7 @@ class ImageGPTCommand( } private fun appendRequest(builder: StringBuilder, request: OpenAIGPTRequest) { - builder.append("**요청:** \n${request.messages.last().content.find { it.first == "text" }?.second }}") + builder.append("**요청:** \n${request.messages.last().content.find { it.first == "text" }?.second}}") builder.appendNewLine(2) } diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt index 4465f98..46cc744 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt @@ -25,7 +25,7 @@ class ModalGPTCommand( ) : GPTCommand(command, description) { companion object { const val DEFAULT_MODEL = "gpt-4" - private val priceInfo = mapOf("gpt-4" to 0.06, "gpt-3.5-turbo" to 0.002,"gpt-3.5-turbo-16k" to 0.002) + private val priceInfo = mapOf("gpt-4" to 0.06, "gpt-3.5-turbo" to 0.002, "gpt-3.5-turbo-16k" to 0.002) private const val dollarToWonMultiplier = 1322.50 private val decimalFormat = DecimalFormat("#,###") } @@ -99,7 +99,12 @@ class ModalGPTCommand( if (it.interaction.getValue("prompt") == null) { return@listenModal } - requestList.add(OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, it.interaction.getValue("prompt")!!.asString.toOption())) + requestList.add( + OpenAIGPTMessage( + OpenAIGPTMessage.Role.USER, + it.interaction.getValue("prompt")!!.asString.toOption() + ) + ) it.deferReply().queue { hook -> runBlocking { apiCall.call(request).onLeft { error -> diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt index cd31a44..d4f218c 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt @@ -21,7 +21,7 @@ class SimpleGPTCommand( ) : GPTCommand(command, description) { companion object { const val DEFAULT_MODEL = "gpt-4" - private val priceInfo = mapOf("gpt-4" to 0.06, "gpt-3.5-turbo" to 0.002,"gpt-3.5-turbo-16k" to 0.002) + private val priceInfo = mapOf("gpt-4" to 0.06, "gpt-3.5-turbo" to 0.002, "gpt-3.5-turbo-16k" to 0.002) private const val dollarToWonMultiplier = 1322.50 private val decimalFormat = DecimalFormat("#,###") } @@ -77,7 +77,12 @@ class SimpleGPTCommand( OpenAIGPTMessage(OpenAIGPTMessage.Role.ASSISTANT, it.toOption()), OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, event.getOption("contents")!!.asString.toOption()) ) - } ?: mutableListOf(OpenAIGPTMessage(OpenAIGPTMessage.Role.USER, event.getOption("contents")!!.asString.toOption())), + } ?: mutableListOf( + OpenAIGPTMessage( + OpenAIGPTMessage.Role.USER, + event.getOption("contents")!!.asString.toOption() + ) + ), 1, event.getOption("temperature")?.asDouble.toOption(), event.getOption("top_p")?.asDouble.toOption(), diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt index 9106d3a..3603f80 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt @@ -4,7 +4,6 @@ import org.koin.core.component.inject import org.koin.core.context.loadKoinModules import org.koin.dsl.module import skywolf46.devain.controller.api.requests.anthropic.ClaudeAPICall -import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall import skywolf46.devain.controller.commands.discord.anthropic.ClaudeCommand import skywolf46.devain.model.data.config.APITokenElement import skywolf46.devain.model.data.config.fetchSharedDocument From adae3c489fe0b0a811e99dcd720756d9e103942a Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 19:12:56 +0900 Subject: [PATCH 38/46] =?UTF-8?q?feat:=20=EB=A9=94=EC=9D=B8=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=ED=8C=8C=EC=9D=BC=20=EC=9D=B4=EB=A6=84=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devain/model/data/config/ConfigDocumentRoot.kt | 10 +++++----- .../skywolf46/devain/platform/plugin/PluginManager.kt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt index c88635b..2e19d71 100644 --- a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt +++ b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt @@ -13,16 +13,16 @@ import kotlin.reflect.KClass import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.hasAnnotation -class ConfigDocumentRoot(private val fileRoot: File) { +class ConfigDocumentRoot(private val configRoot: File, private val configFileName: String) { private val expectedDocuments = mutableListOf() init { - if (!fileRoot.exists()) - fileRoot.mkdirs() + if (!configRoot.exists()) + configRoot.mkdirs() } fun loadSharedDocument() { - val file = fileRoot.resolve("config.yml") + val file = configRoot.resolve(configFileName) if (!file.exists()) { file.createNewFile() file.writeText(Yaml(DumperOptions().apply { @@ -42,7 +42,7 @@ class ConfigDocumentRoot(private val fileRoot: File) { } fun fetchDocument(expected: KClass, adaptor: ConfigAdaptor, key: String): T { - return fileRoot.resolve(key).inputStream().use { + return configRoot.resolve(key).inputStream().use { adaptor.serializeFrom(it) } as T } diff --git a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt index 249a8a1..efdad1e 100644 --- a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt +++ b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt @@ -19,7 +19,7 @@ class PluginManager : KoinComponent { private val lock = ReentrantLock() - private val document = ConfigDocumentRoot(File("devain/config")) + private val document = ConfigDocumentRoot(File("devain"), "config.yml") fun init() { if (isInitialized.getAndSet(true)) { From 4241f0ec88d0defe098580b7a36ac0d76e629b21 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sat, 27 Apr 2024 19:13:46 +0900 Subject: [PATCH 39/46] =?UTF-8?q?feat:=20ConfigDocumentRoot#newDocument=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skywolf46/devain/model/data/config/ConfigDocumentRoot.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt index 2e19d71..d373b0b 100644 --- a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt +++ b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt @@ -57,6 +57,10 @@ class ConfigDocumentRoot(private val configRoot: File, private val configFileNam } } + fun newDocument(fileName: String): ConfigDocumentRoot { + return ConfigDocumentRoot(configRoot.resolve(fileName), fileName) + } + class ExpectedDocument(val key: String, val cls: KClass) { private val listeners = mutableListOf<(Any) -> Unit>() From 5ec1efcef15c0f0c5fb3127fea935bc1b9f21cec Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sun, 28 Apr 2024 00:05:50 +0900 Subject: [PATCH 40/46] =?UTF-8?q?chore:=20=EB=94=94=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skywolf46/devain/model/data/config/ConfigDocumentRoot.kt | 1 - .../skywolf46/devain/platform/discord/DiscordCommandAdapter.kt | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt index d373b0b..e1f023d 100644 --- a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt +++ b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt @@ -32,7 +32,6 @@ class ConfigDocumentRoot(private val configRoot: File, private val configFileNam })) } val loaded = Yaml().load>(file.readText(StandardCharsets.UTF_8)) - println("Order: ${expectedDocuments.map { it.key }}") expectedDocuments.forEach { if (loaded[it.key] == null) return@forEach diff --git a/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommandAdapter.kt b/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommandAdapter.kt index 6f191ed..6df6b08 100644 --- a/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommandAdapter.kt +++ b/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommandAdapter.kt @@ -34,8 +34,6 @@ class DiscordCommandAdapter(private val jda: JDA) : ListenerAdapter() { } override fun onModalInteraction(event: ModalInteractionEvent) { - println("Modal! (${event.interaction.modalId})") - println(modalRegistry.keys) modalRegistry[event.interaction.modalId]?.onModal(event) } } \ No newline at end of file From dd960a004d6a304b0518ee1e35b394a6c32adc88 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sun, 28 Apr 2024 03:39:11 +0900 Subject: [PATCH 41/46] =?UTF-8?q?feat:=20=EB=94=94=ED=8E=9C=EB=8D=98?= =?UTF-8?q?=EC=8B=9C=20=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EC=99=B8=EB=B6=80?= =?UTF-8?q?=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 10 +- .../annotations/config/ConfigDefault.kt | 7 -- .../annotations/config/MarkConfigElement.kt | 5 - .../model/data/config/APITokenElement.kt | 10 -- .../devain/model/data/config/ConfigAdaptor.kt | 10 -- .../model/data/config/ConfigDocumentRoot.kt | 112 ------------------ .../devain/model/data/config/ConfigElement.kt | 3 - 7 files changed, 4 insertions(+), 153 deletions(-) delete mode 100644 src/main/kotlin/skywolf46/devain/annotations/config/ConfigDefault.kt delete mode 100644 src/main/kotlin/skywolf46/devain/annotations/config/MarkConfigElement.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/data/config/APITokenElement.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt delete mode 100644 src/main/kotlin/skywolf46/devain/model/data/config/ConfigElement.kt diff --git a/build.gradle b/build.gradle index 675f66c..d1b9b2d 100644 --- a/build.gradle +++ b/build.gradle @@ -18,12 +18,10 @@ dependencies { implementation("net.dv8tion:JDA:5.0.0-beta.5") { exclude module: 'opus-java' } - implementation("org.xerial:sqlite-jdbc:3.44.1.0") - implementation("io.insert-koin:koin-core:3.4.0") - implementation ("com.knuddels:jtokkit:0.4.0") - implementation ("org.jetbrains.kotlin:kotlin-reflect:1.8.20") - implementation ("org.yaml:snakeyaml:2.2") - implementation("skywolf46:devain-api-call:1.3.1") + implementation("com.knuddels:jtokkit:0.4.0") + implementation("skywolf46:devain-version-full:1.3.1") + implementation("skywolf46:devain-api-call:1.3.2") + implementation("skywolf46:devain-configurator-yaml:1.3.0") } test { diff --git a/src/main/kotlin/skywolf46/devain/annotations/config/ConfigDefault.kt b/src/main/kotlin/skywolf46/devain/annotations/config/ConfigDefault.kt deleted file mode 100644 index 9e810e9..0000000 --- a/src/main/kotlin/skywolf46/devain/annotations/config/ConfigDefault.kt +++ /dev/null @@ -1,7 +0,0 @@ -package skywolf46.devain.annotations.config - -class ConfigDefault { - annotation class Int(val default: kotlin.Int) - - annotation class String(val default: kotlin.String) -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/annotations/config/MarkConfigElement.kt b/src/main/kotlin/skywolf46/devain/annotations/config/MarkConfigElement.kt deleted file mode 100644 index bf1fe5a..0000000 --- a/src/main/kotlin/skywolf46/devain/annotations/config/MarkConfigElement.kt +++ /dev/null @@ -1,5 +0,0 @@ -package skywolf46.devain.annotations.config - -@Retention(AnnotationRetention.RUNTIME) -@Target(AnnotationTarget.VALUE_PARAMETER) -annotation class MarkConfigElement(val name: String = "") \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/APITokenElement.kt b/src/main/kotlin/skywolf46/devain/model/data/config/APITokenElement.kt deleted file mode 100644 index 35dd045..0000000 --- a/src/main/kotlin/skywolf46/devain/model/data/config/APITokenElement.kt +++ /dev/null @@ -1,10 +0,0 @@ -package skywolf46.devain.model.data.config - -import skywolf46.devain.annotations.config.ConfigDefault -import skywolf46.devain.annotations.config.MarkConfigElement - -data class APITokenElement( - @MarkConfigElement - @ConfigDefault.String("YOUR-API-TOKEN-HERE") - val apiToken: String -) : ConfigElement \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt deleted file mode 100644 index 6b7e895..0000000 --- a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigAdaptor.kt +++ /dev/null @@ -1,10 +0,0 @@ -package skywolf46.devain.model.data.config - -import java.io.InputStream -import java.io.OutputStream - -interface ConfigAdaptor { - fun serializeTo(stream: OutputStream, data: Map) - - fun serializeFrom(stream: InputStream): Map -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt deleted file mode 100644 index e1f023d..0000000 --- a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigDocumentRoot.kt +++ /dev/null @@ -1,112 +0,0 @@ -package skywolf46.devain.model.data.config - -import org.yaml.snakeyaml.DumperOptions -import org.yaml.snakeyaml.Yaml -import skywolf46.devain.annotations.config.ConfigDefault -import skywolf46.devain.annotations.config.MarkConfigElement -import java.io.File -import java.nio.charset.StandardCharsets -import java.util.concurrent.locks.ReentrantReadWriteLock -import kotlin.concurrent.read -import kotlin.concurrent.write -import kotlin.reflect.KClass -import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.hasAnnotation - -class ConfigDocumentRoot(private val configRoot: File, private val configFileName: String) { - private val expectedDocuments = mutableListOf() - - init { - if (!configRoot.exists()) - configRoot.mkdirs() - } - - fun loadSharedDocument() { - val file = configRoot.resolve(configFileName) - if (!file.exists()) { - file.createNewFile() - file.writeText(Yaml(DumperOptions().apply { - defaultFlowStyle = DumperOptions.FlowStyle.BLOCK - }).dump(expectedDocuments.map { it.extractDefaultValue() }.apply { - println(this) - })) - } - val loaded = Yaml().load>(file.readText(StandardCharsets.UTF_8)) - expectedDocuments.forEach { - if (loaded[it.key] == null) - return@forEach - it.callFromMap(loaded[it.key] as Map) - } - - } - - fun fetchDocument(expected: KClass, adaptor: ConfigAdaptor, key: String): T { - return configRoot.resolve(key).inputStream().use { - adaptor.serializeFrom(it) - } as T - } - - fun fetchSharedDocument(expected: KClass, key: String, unit: (T) -> Unit) { - val expectedDocument = expectedDocuments.firstOrNull { it.key == key } - ?: ExpectedDocument(key, expected).also { - expectedDocuments.add(it) - } - expectedDocument.addListener { - unit(it as T) - } - } - - fun newDocument(fileName: String): ConfigDocumentRoot { - return ConfigDocumentRoot(configRoot.resolve(fileName), fileName) - } - - class ExpectedDocument(val key: String, val cls: KClass) { - private val listeners = mutableListOf<(Any) -> Unit>() - - private val lock = ReentrantReadWriteLock() - - fun addListener(unit: (Any) -> Unit) { - lock.write { - listeners.add(unit) - } - } - - fun callListener(data: Any) { - lock.read { - listeners.forEach { - it(data) - } - } - } - - fun constructFromMap(map: Map): Any { - return cls.constructors.first().callBy( - cls.constructors.first().parameters.filter { it.hasAnnotation() }.map { - it to (map[it.findAnnotation()!!.name.ifBlank { it.name!! }] - ?: if (it.isOptional) null else throw IllegalStateException("Missing key: ${it.name}")) - }.associate { it } - ) - } - - fun callFromMap(map: Map) { - callListener(constructFromMap(map)) - } - - fun extractDefaultValue(): Map { - return cls.constructors.first().parameters.filter { it.hasAnnotation() }.map { - (it.findAnnotation()!!.name.ifBlank { it.name!! }) to (it.findAnnotation()?.default - ?: it.findAnnotation()?.default) - }.filter { it.second != null }.associate { it } - } - } -} - -inline fun ConfigDocumentRoot.fetchDocument(adaptor: ConfigAdaptor, key: String): T { - return fetchDocument(T::class, adaptor, key) -} - - -inline fun ConfigDocumentRoot.fetchSharedDocument(key: String, noinline unit: (T) -> Unit) { - fetchSharedDocument(T::class, key, unit) -} - diff --git a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigElement.kt b/src/main/kotlin/skywolf46/devain/model/data/config/ConfigElement.kt deleted file mode 100644 index 3e1f82d..0000000 --- a/src/main/kotlin/skywolf46/devain/model/data/config/ConfigElement.kt +++ /dev/null @@ -1,3 +0,0 @@ -package skywolf46.devain.model.data.config - -interface ConfigElement \ No newline at end of file From b2af28c848813fd2f5e947f56667feca79c11166 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sun, 28 Apr 2024 03:40:29 +0900 Subject: [PATCH 42/46] =?UTF-8?q?feat:=20=EB=94=94=ED=8E=9C=EB=8D=98?= =?UTF-8?q?=EC=8B=9C=20=EB=B6=84=EB=A6=AC=20=EC=98=81=ED=96=A5=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devain/controller/modules/AnthropicModule.kt | 5 +++-- .../skywolf46/devain/controller/modules/CohereModule.kt | 4 ++-- .../skywolf46/devain/controller/modules/DeepLModule.kt | 4 ++-- .../skywolf46/devain/controller/modules/DiscordModule.kt | 4 ++-- .../skywolf46/devain/controller/modules/GroqModule.kt | 4 ++-- .../skywolf46/devain/controller/modules/OpenAIModule.kt | 8 ++++---- .../skywolf46/devain/platform/plugin/PluginManager.kt | 9 ++++++--- .../skywolf46/devain/platform/plugin/PluginModule.kt | 2 +- 8 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt index 3603f80..88c1120 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/AnthropicModule.kt @@ -3,10 +3,10 @@ package skywolf46.devain.controller.modules import org.koin.core.component.inject import org.koin.core.context.loadKoinModules import org.koin.dsl.module +import skywolf46.devain.configurator.APITokenElement +import skywolf46.devain.configurator.fetchSharedDocument import skywolf46.devain.controller.api.requests.anthropic.ClaudeAPICall import skywolf46.devain.controller.commands.discord.anthropic.ClaudeCommand -import skywolf46.devain.model.data.config.APITokenElement -import skywolf46.devain.model.data.config.fetchSharedDocument import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule @@ -16,6 +16,7 @@ class AnthropicModule : PluginModule("Anthropic Integration") { override fun onInitialize() { document.fetchSharedDocument("Anthropic Integration") { config -> + loadKoinModules(module { single { ClaudeAPICall(config.apiToken) } }) diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/CohereModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/CohereModule.kt index e5c15c6..e22f7dd 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/CohereModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/CohereModule.kt @@ -6,14 +6,14 @@ import org.koin.dsl.module import skywolf46.devain.KEY_COHERE_GENERATION_PROCEED_COUNT import skywolf46.devain.apicall.certainly import skywolf46.devain.apicall.networking.GetRequest +import skywolf46.devain.configurator.APITokenElement +import skywolf46.devain.configurator.fetchSharedDocument import skywolf46.devain.controller.api.requests.cohere.CohereGenerationAPICall import skywolf46.devain.controller.api.requests.cohere.CommandRPlusAPICall import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall import skywolf46.devain.controller.commands.discord.cohere.CohereCommand import skywolf46.devain.controller.commands.discord.cohere.CommandRCommand import skywolf46.devain.controller.commands.discord.cohere.CommandRPlusCommand -import skywolf46.devain.model.data.config.APITokenElement -import skywolf46.devain.model.data.config.fetchSharedDocument import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/DeepLModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/DeepLModule.kt index 7e3f154..19af80e 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/DeepLModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/DeepLModule.kt @@ -7,14 +7,14 @@ import skywolf46.devain.KEY_DEEPL_PROCEED_COUNT import skywolf46.devain.KEY_DEEPL_PROCEED_TOKEN import skywolf46.devain.apicall.certainly import skywolf46.devain.apicall.networking.GetRequest +import skywolf46.devain.configurator.APITokenElement +import skywolf46.devain.configurator.fetchSharedDocument import skywolf46.devain.controller.api.requests.deepl.DeepLTranslationAPICall import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall import skywolf46.devain.controller.commands.discord.deepl.DeepLKoreanTranslationCommand import skywolf46.devain.controller.commands.discord.deepl.DeepLSimpleTranslationCommand import skywolf46.devain.controller.commands.discord.deepl.DeepLTranslationCommand import skywolf46.devain.controller.commands.discord.deepl.ModalDeepLKoreanTranslationCommand -import skywolf46.devain.model.data.config.APITokenElement -import skywolf46.devain.model.data.config.fetchSharedDocument import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/DiscordModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/DiscordModule.kt index 3433fd1..93837bd 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/DiscordModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/DiscordModule.kt @@ -2,8 +2,8 @@ package skywolf46.devain.controller.modules import org.koin.core.context.loadKoinModules import org.koin.dsl.module -import skywolf46.devain.model.data.config.APITokenElement -import skywolf46.devain.model.data.config.fetchSharedDocument +import skywolf46.devain.configurator.APITokenElement +import skywolf46.devain.configurator.fetchSharedDocument import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt index 8fc9116..f5b7e19 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/GroqModule.kt @@ -6,11 +6,11 @@ import org.koin.dsl.module import skywolf46.devain.KEY_GROQ_GENERATION_PROCEED_COUNT import skywolf46.devain.apicall.certainly import skywolf46.devain.apicall.networking.GetRequest +import skywolf46.devain.configurator.APITokenElement +import skywolf46.devain.configurator.fetchSharedDocument import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall import skywolf46.devain.controller.api.requests.groq.GroqAPICall import skywolf46.devain.controller.commands.discord.groq.SimpleGroqCommand -import skywolf46.devain.model.data.config.APITokenElement -import skywolf46.devain.model.data.config.fetchSharedDocument import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule diff --git a/src/main/kotlin/skywolf46/devain/controller/modules/OpenAIModule.kt b/src/main/kotlin/skywolf46/devain/controller/modules/OpenAIModule.kt index 34a347a..b0199fa 100644 --- a/src/main/kotlin/skywolf46/devain/controller/modules/OpenAIModule.kt +++ b/src/main/kotlin/skywolf46/devain/controller/modules/OpenAIModule.kt @@ -4,10 +4,12 @@ import org.koin.core.component.inject import org.koin.core.context.loadKoinModules import org.koin.dsl.module import skywolf46.devain.* -import skywolf46.devain.annotations.config.ConfigDefault -import skywolf46.devain.annotations.config.MarkConfigElement import skywolf46.devain.apicall.certainly import skywolf46.devain.apicall.networking.GetRequest +import skywolf46.devain.configurator.ConfigElement +import skywolf46.devain.configurator.annotations.ConfigDefault +import skywolf46.devain.configurator.annotations.MarkConfigElement +import skywolf46.devain.configurator.fetchSharedDocument import skywolf46.devain.controller.api.requests.arxiv.ArxivSearchAPICall import skywolf46.devain.controller.api.requests.devain.DevAinPersistenceCountAPICall import skywolf46.devain.controller.api.requests.eve.EvEOnlineStatusAPICall @@ -18,8 +20,6 @@ import skywolf46.devain.controller.api.requests.openweather.OpenWeatherAPICall import skywolf46.devain.controller.api.requests.openweather.OpenWeatherForecastAPICall import skywolf46.devain.controller.commands.discord.openai.* import skywolf46.devain.model.api.openai.completion.functions.* -import skywolf46.devain.model.data.config.ConfigElement -import skywolf46.devain.model.data.config.fetchSharedDocument import skywolf46.devain.model.data.store.OpenAIFunctionStore import skywolf46.devain.platform.discord.DiscordBot import skywolf46.devain.platform.plugin.PluginModule diff --git a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt index efdad1e..2a5af06 100644 --- a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt +++ b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginManager.kt @@ -4,7 +4,9 @@ import org.koin.core.component.KoinComponent import org.koin.core.component.get import org.koin.core.context.loadKoinModules import org.koin.dsl.module -import skywolf46.devain.model.data.config.ConfigDocumentRoot +import skywolf46.devain.configurator.ConfigAdaptor +import skywolf46.devain.configurator.ConfigDocumentRoot +import skywolf46.devain.configurator.yaml.yaml import java.io.File import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.locks.ReentrantLock @@ -19,7 +21,7 @@ class PluginManager : KoinComponent { private val lock = ReentrantLock() - private val document = ConfigDocumentRoot(File("devain"), "config.yml") + private val document = ConfigDocumentRoot(File("devain/config"), "config.yml") fun init() { if (isInitialized.getAndSet(true)) { @@ -30,6 +32,7 @@ class PluginManager : KoinComponent { initializePlugin() } + private fun loadKoinModules() { loadKoinModules(module { single { this@PluginManager } @@ -48,7 +51,7 @@ class PluginManager : KoinComponent { iterateEnabledPlugin { it.onPostInitialize() } - get().loadSharedDocument() + get().loadSharedDocument(ConfigAdaptor.yaml()) iterateEnabledPlugin { it.onInitializeComplete() } diff --git a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginModule.kt b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginModule.kt index 47b1d71..dcc6db7 100644 --- a/src/main/kotlin/skywolf46/devain/platform/plugin/PluginModule.kt +++ b/src/main/kotlin/skywolf46/devain/platform/plugin/PluginModule.kt @@ -2,7 +2,7 @@ package skywolf46.devain.platform.plugin import org.koin.core.component.KoinComponent import org.koin.core.component.inject -import skywolf46.devain.model.data.config.ConfigDocumentRoot +import skywolf46.devain.configurator.ConfigDocumentRoot import java.io.File abstract class PluginModule(val pluginName: String) : KoinComponent { From 1072aa471addfdb03339c5c5c25b0ff6e6a07bce Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sun, 28 Apr 2024 04:03:30 +0900 Subject: [PATCH 43/46] =?UTF-8?q?feat:=20=EC=BD=94=ED=8B=80=EB=A6=B0=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=201.8.22=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20=ED=8C=8C=EC=83=9D=EB=90=9C=20=EA=B6=8C=EA=B3=A0?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=9D=B4=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 9 +- .../api/requests/anthropic/ClaudeAPICall.kt | 2 +- .../requests/openai/GPTCompletionAPICall.kt | 2 +- .../discord/devain/DevAinStatusCommand.kt | 3 +- .../discord/groq/SimpleGroqCommand.kt | 15 +- .../discord/openai/ArxivGPTCommand.kt | 17 +- .../discord/openai/DallEGenerationCommand.kt | 2 +- .../commands/discord/openai/GPTBaseCommand.kt | 207 ------------------ .../commands/discord/openai/GPTCommand.kt | 10 +- .../discord/openai/ImageGPTCommand.kt | 15 +- .../discord/openai/ModalGPTCommand.kt | 13 +- .../discord/openai/SimpleGPTCommand.kt | 13 +- .../api/anthropic/ClaudeGenerationRequest.kt | 2 +- .../translation/DeepLTranslateRequest.kt | 2 +- .../api/openai/completion/OpenAIGPTMessage.kt | 6 +- .../api/openai/completion/OpenAIGPTRequest.kt | 18 +- .../functions/ArxivSearchDeclaration.kt | 2 +- .../functions/GoogleSearchDeclaration.kt | 2 +- .../model/api/openai/dalle/DallERequest.kt | 4 +- .../AnnotatedParameterDiscordCommand.kt | 2 +- .../platform/discord/DiscordCommandAdapter.kt | 2 +- .../kotlin/skywolf46/devain/util/TimeUtil.kt | 1 - 22 files changed, 68 insertions(+), 281 deletions(-) delete mode 100644 src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTBaseCommand.kt diff --git a/build.gradle b/build.gradle index d1b9b2d..cc68ef8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.jetbrains.kotlin.jvm' version '1.8.20' + id 'org.jetbrains.kotlin.jvm' version '1.8.22' id 'com.github.johnrengelman.shadow' version '7.1.2' } @@ -18,10 +18,11 @@ dependencies { implementation("net.dv8tion:JDA:5.0.0-beta.5") { exclude module: 'opus-java' } + implementation("org.jetbrains.kotlin:kotlin-stdlib") implementation("com.knuddels:jtokkit:0.4.0") - implementation("skywolf46:devain-version-full:1.3.1") - implementation("skywolf46:devain-api-call:1.3.2") - implementation("skywolf46:devain-configurator-yaml:1.3.0") + implementation("skywolf46:devain-version-full:1.3.2") + implementation("skywolf46:devain-api-call:1.3.3") + implementation("skywolf46:devain-configurator-yaml:1.3.1") } test { diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/anthropic/ClaudeAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/anthropic/ClaudeAPICall.kt index 6844a37..b4a37b3 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/anthropic/ClaudeAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/anthropic/ClaudeAPICall.kt @@ -14,7 +14,7 @@ import skywolf46.devain.model.api.anthropic.ClaudeGenerationResponse class ClaudeAPICall(private val apiKey: String, client: Option = None) : RESTAPICall( - { req -> "https://api.anthropic.com/v1/messages" }, client, HttpMethod.Post + { "https://api.anthropic.com/v1/messages" }, client, HttpMethod.Post ) { override suspend fun parseResult( request: ClaudeGenerationRequest, diff --git a/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/GPTCompletionAPICall.kt b/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/GPTCompletionAPICall.kt index 9ae717d..82bddfc 100644 --- a/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/GPTCompletionAPICall.kt +++ b/src/main/kotlin/skywolf46/devain/controller/api/requests/openai/GPTCompletionAPICall.kt @@ -72,7 +72,7 @@ class GPTCompletionAPICall(private val apiKey: String, client: Option { - val functionRequest = response.answers[0].message.functionCall.orNull()!! + val functionRequest = response.answers[0].message.functionCall.getOrNull()!! val function = functionStore.getFunctionOrEmpty( OpenAIFunctionKey( functionRequest["name"]!!.toString(), diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/devain/DevAinStatusCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/devain/DevAinStatusCommand.kt index 5908e71..e193a07 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/devain/DevAinStatusCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/devain/DevAinStatusCommand.kt @@ -80,9 +80,8 @@ class DevAinStatusCommand : ImprovedDiscordCommand("status", "DevAin 봇의 상 event.reply("이 플러그인은 통계를 제공하지 않습니다.").queue() return } - event.deferEmbed { _, hook -> + event.deferEmbed { _, _ -> EmbedBuilder() -// .setTitle("DevAin Standalone (${propertiesApiCall.certainly()["version"]})") .apply { setTitle("Plugin Statistics ($pluginName)") setColor(Color.CYAN) diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt index e7faddb..48b2f91 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/groq/SimpleGroqCommand.kt @@ -64,7 +64,7 @@ class SimpleGroqCommand( override suspend fun onCommand(event: SlashCommandInteractionEvent) { event.defer { _, hook -> val request = OpenAIGPTRequest( - model ?: event.getOption("model")!!.asString, + model, event.getOption("base-prompt")?.asString?.let { mutableListOf( OpenAIGPTMessage(OpenAIGPTMessage.Role.ASSISTANT, it.toOption()), @@ -125,28 +125,27 @@ class SimpleGroqCommand( private fun appendModel(event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest) { builder.append("└ 모델: ${request.modelName}").appendNewLine() - appendParameter(event, builder, request) + appendParameter( builder, request) } private fun appendParameter( - event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest ) { - request.temperature.tap { + request.temperature.onSome { builder.append(" └ Temperature: $it").appendNewLine() } - request.top_p.tap { + request.top_p.onSome { builder.append(" └ top_p: $it").appendNewLine() } - request.presencePenalty.tap { + request.presencePenalty.onSome { builder.append(" └ Presence Penalty: $it").appendNewLine() } - request.frequencyPenalty.tap { + request.frequencyPenalty.onSome { builder.append(" └ Frequency Penalty: $it").appendNewLine() } - request.maxTokens.tap { + request.maxTokens.onSome { builder.append(" └ Max tokens: ${decimalFormat.format(it)}").appendNewLine() } diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt index 868edb3..13490ec 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ArxivGPTCommand.kt @@ -140,30 +140,29 @@ class ArxivGPTCommand( return builder.toString() } - private fun appendModel(event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest) { + private fun appendModel(builder: StringBuilder, request: OpenAIGPTRequest) { builder.append("└ 모델: ${request.modelName}").appendNewLine() - appendParameter(event, builder, request) + appendParameter(builder, request) } private fun appendParameter( - event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest ) { - request.temperature.tap { + request.temperature.onSome { builder.append(" └ Temperature: $it").appendNewLine() } - request.top_p.tap { + request.top_p.onSome { builder.append(" └ top_p: $it").appendNewLine() } - request.presencePenalty.tap { + request.presencePenalty.onSome { builder.append(" └ Presence Penalty: $it").appendNewLine() } - request.frequencyPenalty.tap { + request.frequencyPenalty.onSome { builder.append(" └ Frequency Penalty: $it").appendNewLine() } - request.maxTokens.tap { + request.maxTokens.onSome { builder.append(" └ Max tokens: ${decimalFormat.format(it)}").appendNewLine() } @@ -179,7 +178,7 @@ class ArxivGPTCommand( result: OpenAIGPTResponse ) { builder.append("**API 상세**:").appendNewLine(1) - appendModel(event, builder, request) + appendModel(builder, request) builder.append("└ API 소모: ${result.usage.totalToken}토큰") builder.appendNewLine() builder.append("└ API 응답 시간: ${decimalFormat.format(System.currentTimeMillis() - request.createdOn)}ms") diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/DallEGenerationCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/DallEGenerationCommand.kt index d2280c8..8371c18 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/DallEGenerationCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/DallEGenerationCommand.kt @@ -51,7 +51,7 @@ class DallEGenerationCommand : ImprovedDiscordCommand("dalle", "OpenAI DallE를 .setColor(Color.GREEN) .setTitle("Reqeust complete - DallE") .setDescription(prompt) - .setImage(it.images[0].url.orNull()!!) + .setImage(it.images[0].url.getOrNull()!!) .build() ).queue() } diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTBaseCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTBaseCommand.kt deleted file mode 100644 index 5a3c993..0000000 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTBaseCommand.kt +++ /dev/null @@ -1,207 +0,0 @@ -package skywolf46.devain.controller.commands.discord.openai - -import arrow.core.None -import arrow.core.Option -import arrow.core.getOrElse -import arrow.core.toOption -import net.dv8tion.jda.api.entities.MessageEmbed -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent -import net.dv8tion.jda.api.interactions.commands.OptionType -import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData -import net.dv8tion.jda.api.interactions.components.text.TextInput -import net.dv8tion.jda.api.interactions.components.text.TextInputStyle -import net.dv8tion.jda.api.utils.FileUpload -import org.koin.core.component.inject -import skywolf46.devain.controller.api.requests.openai.GPTCompletionAPICall -import skywolf46.devain.model.api.openai.completion.OpenAIFunctionKey -import skywolf46.devain.model.api.openai.completion.OpenAIGPTMessage -import skywolf46.devain.model.api.openai.completion.OpenAIGPTRequest -import skywolf46.devain.model.api.openai.completion.OpenAIGPTResponse -import skywolf46.devain.platform.discord.ImprovedDiscordCommand - -open class GPTBaseCommand( - commandName: String, - description: String, - val supportModal: Boolean, - val supportFunctions: Boolean, - val model: Option = None -) : ImprovedDiscordCommand(commandName, description, commandName.toOption()) { - private val apiCall by inject() - - - override suspend fun onCommand(event: SlashCommandInteractionEvent) { - if (supportModal) { - requestFromModal(event) - } else { - requestFromCommand(event) - } - } - - private fun requestFromCommand(event: SlashCommandInteractionEvent) { - event.defer { _, hook -> - val request = buildRequest(event, None) - val response = apiCall.call(request).getOrElse { - hook.sendMessage(it.getErrorMessage()) - return@defer - } - if (isEmbedCompatible(request, response)) { - hook.sendMessageEmbeds(buildEmbed(request, response)).queue() - } else { - buildStringResult(request, response).apply { - if (length <= 2000) { - hook.sendMessage(this).queue() - return@defer - } - } - hook.sendFiles( - FileUpload.fromData( - StringBuilder().buildFileStringResult(request, response).toByteArray(), "result.txt" - ) - ).queue() - } - } - } - - private fun requestFromModal(event: SlashCommandInteractionEvent) { - event.listenModal(createModal("Prompt Input") { - it.addActionRow(TextInput.create("base-prompt", "사전 프롬프트", TextInputStyle.SHORT).build()) - it.addActionRow(TextInput.create("prompt", "프롬프트", TextInputStyle.PARAGRAPH).build()) - }) { modalEvent -> - val request = buildRequest(event, modalEvent.interaction.getValue("prompt")!!.asString.toOption()) - val response = apiCall.call(request).getOrElse { - modalEvent.reply(it.getErrorMessage()) - return@listenModal - } - if (isEmbedCompatible(request, response)) { - modalEvent.replyEmbeds(buildEmbed(request, response)).queue() - } else { - buildStringResult(request, response).apply { - if (length <= 2000) { - modalEvent.reply(this).queue() - return@listenModal - } - } - modalEvent.replyFiles( - FileUpload.fromData( - StringBuilder().buildFileStringResult(request, response).toByteArray(), "result.txt" - ) - ).queue() - } - - - } - } - - private fun buildEmbed(request: OpenAIGPTRequest, response: OpenAIGPTResponse): MessageEmbed { - TODO() - } - - private fun buildStringResult(request: OpenAIGPTRequest, response: OpenAIGPTResponse): String { - val builder = StringBuilder() - return builder.toString() - } - - private fun StringBuilder.buildFileStringResult(request: OpenAIGPTRequest, response: OpenAIGPTResponse): String { - val builder = StringBuilder() - return builder.toString() - } - - fun isEmbedCompatible(request: OpenAIGPTRequest, response: OpenAIGPTResponse): Boolean { - val requestMessage = request.messages.find { it.role == OpenAIGPTMessage.Role.USER }!! - val responseMessage = response.answers.last() - return (request.hidePrompt || requestMessage.content.find { it.first == "text" }?.second - .toString().length < 4096) && ((responseMessage.message.content.find { it.first == "text" }?.second?.length - ?: 0) < 1024 - 6) - } - - final override fun modifyCommandData(options: SlashCommandData) { - model.tapNone { - options.addOption(OptionType.STRING, "model", "프롬프트를 생성할 모델을 지정합니다.") - } - if (!supportModal) { - options.addOption(OptionType.STRING, "prompt", model.getOrElse { "지정된 모델" } + "에게 질문할 내용입니다.") - } - options.addOption( - OptionType.NUMBER, - "temperature", - "모델의 temperature 값을 설정합니다. 값이 낮을수록 결정적이 되며, 높을수록 더 많은 무작위성이 가해집니다. (기본 1, 0-1.5내의 소수)", - false - ) - options.addOption( - OptionType.NUMBER, - "top_p", - "모델의 top_p 값을 설정합니다. 값이 낮을수록 토큰의 샘플링 범위가 낮아집니다. (기본 1, 0-1.5내의 소수)", - false - ) - options.addOption( - OptionType.INTEGER, - "max_token", - "최대 토큰 개수를 설정합니다.", - false - ) - options.addOption( - OptionType.NUMBER, - "presence_penalty", - "모델의 중복 주제 패널티를 조정합니다. 높을수록, 새 주제(토큰)에 관해 이야기할 확률이 높아집니다. (기본 0, -2.0-2.0내의 소수)", - false - ) - options.addOption( - OptionType.NUMBER, - "frequency_penalty", - "모델의 중복 빈도 패널티를 조정합니다. 높을수록, 같은 말(토큰)을 반복하지 않을 확률이 높아집니다. (기본 0, -2.0-2.0내의 소수)", - false - ) - options.addOption(OptionType.BOOLEAN, "hide-prompt", "결과 창에서 프롬프트를 숨깁니다. 명령어 클릭은 숨겨지지 않습니다.", false) - options.addOption(OptionType.STRING, "base-prompt", "해당 프롬프트의 기반이 될 프롬프트입니다. AI는 해당 내용을 기반으로 답변을 시도합니다.", false) - if (supportFunctions) { - options.addOption(OptionType.BOOLEAN, "show-trace", "사용된 펑션 콜 스택 트레이스를 출력할지의 여부를 설정합니다.", false) - } - } - - - private fun buildRequest( - event: SlashCommandInteractionEvent, - basePrompt: Option, - prompt: Option = None - ): OpenAIGPTRequest { - val messageListBuilt = acquirePrompts(event, prompt, basePrompt = basePrompt) - return OpenAIGPTRequest( - model.getOrElse { event.getOption("model")!!.asString }, - messageListBuilt, - 1, - event.getOption("temperature")?.asDouble.toOption(), - event.getOption("top_p")?.asDouble.toOption(), - None, - event.getOption("max_token")?.asInt.toOption(), - event.getOption("presence_penalty")?.asDouble.toOption(), - event.getOption("frequency_penalty")?.asDouble.toOption(), - event.getOption("hide-prompt")?.asBoolean ?: false, - if (supportFunctions) event.getOption("show-trace")?.asBoolean ?: false else false, - acquireFunctions(event) - ) - } - - protected open fun acquirePrompts( - event: SlashCommandInteractionEvent, - prompt: Option, - basePrompt: Option = None - ): MutableList { - return mutableListOf().apply { - (basePrompt.orNull() ?: event.getOption("base-prompt")?.asString)?.let { basePrompt -> - add(OpenAIGPTMessage(OpenAIGPTMessage.Role.USER_PRECONDITION, basePrompt.toOption())) - } - add( - OpenAIGPTMessage( - OpenAIGPTMessage.Role.USER, - prompt.getOrElse { event.getOption("prompt")!!.asString }.toOption() - ) - ) - } - } - - protected open fun acquireFunctions(event: SlashCommandInteractionEvent): Option> { - if (!supportFunctions) - return None - return listOf().toOption() - } -} \ No newline at end of file diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTCommand.kt index 225f2f7..8aaa8d8 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/GPTCommand.kt @@ -73,19 +73,19 @@ abstract class GPTCommand(command: String, description: String) : addField("Process", box(TimeUtil.toTimeString(System.currentTimeMillis() - request.createdOn)), true) - request.maxTokens.tap { + request.maxTokens.onSome { addField("Max Token", box(it.toString()), true) } - request.top_p.tap { + request.top_p.onSome { addField("top_p", box(it.toString()), true) } - request.temperature.tap { + request.temperature.onSome { addField("Temperture", box(it.toString()), true) } - request.frequencyPenalty.tap { + request.frequencyPenalty.onSome { addField("Frequency Penalty", box(it.toString()), true) } - request.presencePenalty.tap { + request.presencePenalty.onSome { addField("Presence Penalty", box(it.toString()), true) } if (request.showFunctionTrace) { diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt index 96a2bdd..5d5a526 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ImageGPTCommand.kt @@ -72,7 +72,7 @@ class ImageGPTCommand( override suspend fun onCommand(event: SlashCommandInteractionEvent) { event.defer { _, hook -> - val attachment = event.getOption("image")!!.asAttachment!! + val attachment = event.getOption("image")!!.asAttachment if (!attachment.isImage) { hook.sendMessage("이미지 파일만 업로드 가능합니다.").queue() return@defer @@ -146,28 +146,27 @@ class ImageGPTCommand( private fun appendModel(event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest) { builder.append("└ 모델: ${request.modelName}").appendNewLine() - appendParameter(event, builder, request) + appendParameter( builder, request) } private fun appendParameter( - event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest ) { - request.temperature.tap { + request.temperature.onSome { builder.append(" └ Temperature: $it").appendNewLine() } - request.top_p.tap { + request.top_p.onSome { builder.append(" └ top_p: $it").appendNewLine() } - request.presencePenalty.tap { + request.presencePenalty.onSome { builder.append(" └ Presence Penalty: $it").appendNewLine() } - request.frequencyPenalty.tap { + request.frequencyPenalty.onSome { builder.append(" └ Frequency Penalty: $it").appendNewLine() } - request.maxTokens.tap { + request.maxTokens.onSome { builder.append(" └ Max tokens: ${decimalFormat.format(it)}").appendNewLine() } diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt index 46cc744..9ddea44 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/ModalGPTCommand.kt @@ -147,28 +147,27 @@ class ModalGPTCommand( private fun appendModel(event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest) { builder.append("└ 모델: ${request.modelName}").appendNewLine() - appendParameter(event, builder, request) + appendParameter( builder, request) } private fun appendParameter( - event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest ) { - request.temperature.tap { + request.temperature.onSome { builder.append(" └ Temperature: $it").appendNewLine() } - request.top_p.tap { + request.top_p.onSome { builder.append(" └ top_p: $it").appendNewLine() } - request.presencePenalty.tap { + request.presencePenalty.onSome { builder.append(" └ Presence Penalty: $it").appendNewLine() } - request.frequencyPenalty.tap { + request.frequencyPenalty.onSome { builder.append(" └ Frequency Penalty: $it").appendNewLine() } - request.maxTokens.tap { + request.maxTokens.onSome { builder.append(" └ Max tokens: ${decimalFormat.format(it)}").appendNewLine() } diff --git a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt index d4f218c..c5a9c97 100644 --- a/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt +++ b/src/main/kotlin/skywolf46/devain/controller/commands/discord/openai/SimpleGPTCommand.kt @@ -132,28 +132,27 @@ class SimpleGPTCommand( private fun appendModel(event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest) { builder.append("└ 모델: ${request.modelName}").appendNewLine() - appendParameter(event, builder, request) + appendParameter(builder, request) } private fun appendParameter( - event: SlashCommandInteractionEvent, builder: StringBuilder, request: OpenAIGPTRequest ) { - request.temperature.tap { + request.temperature.onSome { builder.append(" └ Temperature: $it").appendNewLine() } - request.top_p.tap { + request.top_p.onSome { builder.append(" └ top_p: $it").appendNewLine() } - request.presencePenalty.tap { + request.presencePenalty.onSome { builder.append(" └ Presence Penalty: $it").appendNewLine() } - request.frequencyPenalty.tap { + request.frequencyPenalty.onSome { builder.append(" └ Frequency Penalty: $it").appendNewLine() } - request.maxTokens.tap { + request.maxTokens.onSome { builder.append(" └ Max tokens: ${decimalFormat.format(it)}").appendNewLine() } diff --git a/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationRequest.kt index 762fb38..0f07922 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationRequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/anthropic/ClaudeGenerationRequest.kt @@ -14,7 +14,7 @@ class ClaudeGenerationRequest( override fun serialize(): Either { val obj = JSONObject() obj["model"] = model - obj["messages"] = messages.map { it.serialize().orNull() } + obj["messages"] = messages.map { it.serialize().getOrNull() } maxTokens.map { obj["max_tokens"] = it } return obj.right() } diff --git a/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateRequest.kt index cdbcfca..de10876 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateRequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/deepl/translation/DeepLTranslateRequest.kt @@ -53,7 +53,7 @@ data class DeepLTranslateRequest( override fun serialize(): Either { val map = JSONObject() - sourceLanguage.tap { + sourceLanguage.onSome { if (!isSupported(it)) { return IllegalArgumentException("Source language $it is not supported.").left() } diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTMessage.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTMessage.kt index d29226a..727d912 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTMessage.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTMessage.kt @@ -43,7 +43,7 @@ open class OpenAIGPTMessage( functionName: Option = None ) = OpenAIGPTMessage( role, - if (content.isEmpty()) emptyList() else listOf("text" to content.orNull()!!), + if (content.isNone()) emptyList() else listOf("text" to content.getOrNull()!!), functionCall, functionName ) @@ -62,10 +62,10 @@ open class OpenAIGPTMessage( } } } - functionCall.tap { + functionCall.onSome { this["function_call"] = it } - functionName.tap { + functionName.onSome { this["name"] = it } diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTRequest.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTRequest.kt index 061ea07..47973a5 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTRequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/OpenAIGPTRequest.kt @@ -95,44 +95,44 @@ data class OpenAIGPTRequest( */ override fun serialize(): Either { val map = JSONObject() - temperature.tap { + temperature.onSome { it.checkRangeAndFatal(0.0..2.0) { range -> return IllegalArgumentException("Temperature 값은 ${range.start} ~ ${range.endInclusive} 사이여야만 합니다.").left() } map["temperature"] = it } - top_p.tap { + top_p.onSome { it.checkRangeAndFatal(0.0..1.0) { range -> return IllegalArgumentException("top_p 값은 ${range.start} ~ ${range.endInclusive} 사이여야만 합니다.").left() } map["top_p"] = it } - maxTokens.tap { + maxTokens.onSome { it.checkRangeAndFatal(1..Int.MAX_VALUE) { range -> return IllegalArgumentException("최대 토큰 값은 ${range.start} ~ ${range.endInclusive} 사이여야만 합니다.").left() } map["max_tokens"] = it } - presencePenalty.tap { + presencePenalty.onSome { it.checkRangeAndFatal(-2.0..2.0) { range -> return IllegalArgumentException("Presence Penalty 값은 ${range.start} ~ ${range.endInclusive} 사이여야만 합니다.").left() } map["presence_penalty"] = it } - frequencyPenalty.tap { + frequencyPenalty.onSome { it.checkRangeAndFatal(-2.0..2.0) { range -> return IllegalArgumentException("Frequency Penalty 값은 ${range.start} ~ ${range.endInclusive} 사이여야만 합니다.").left() } map["frequency_penalty"] = it } - functions.tap { + functions.onSome { for (key in it) { - if (functionStore.getFunction(key).isEmpty()) + if (functionStore.getFunction(key).isNone()) return IllegalArgumentException("존재하지 않는 함수 키입니다. ($key)").left() } - map["functions"] = it.map { key -> functionStore.getFunction(key).orNull()!!.serialize().getOrNull()!! } + map["functions"] = it.map { key -> functionStore.getFunction(key).getOrNull()!!.serialize().getOrNull()!! } } - bestOf.tap { + bestOf.onSome { if (it > 10) { return IllegalArgumentException("bestOf 값은 10 이하여야 합니다.").left() } diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt index b3773d0..6437545 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/ArxivSearchDeclaration.kt @@ -28,7 +28,7 @@ class ArxivSearchDeclaration : OpenAIFunctionDeclaration( return apiCall.call(ArxivRequest(param["query"].toString())) .map { JSONObject().apply { - put("result", it.articles.mapIndexed { index, item -> + put("result", it.articles.mapIndexed { _, item -> JSONObject().apply { put("title", item.title) put("abstract", item.summary) diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/GoogleSearchDeclaration.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/GoogleSearchDeclaration.kt index 62bf917..c6a7506 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/GoogleSearchDeclaration.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/completion/functions/GoogleSearchDeclaration.kt @@ -28,7 +28,7 @@ class GoogleSearchDeclaration : OpenAIFunctionDeclaration( return apiCall.call(GoogleSearchRequest(param["query"].toString(), 6)) .map { JSONObject().apply { - put("result", it.items.mapIndexed { index, item -> + put("result", it.items.mapIndexed { _, item -> JSONObject().apply { put("title", item.title) if (item.link.length < 50) diff --git a/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallERequest.kt b/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallERequest.kt index a52d067..ad97492 100644 --- a/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallERequest.kt +++ b/src/main/kotlin/skywolf46/devain/model/api/openai/dalle/DallERequest.kt @@ -21,7 +21,7 @@ data class DallERequest( generateCount.checkRangeAndFatal(1..10) { return IllegalArgumentException("생성 개수는 1개 이상 10개 이하로 설정해야 합니다.").left() } - style.tap { + style.onSome { if (it !in listOf("vivid", "natural")) { return IllegalArgumentException("스타일은 vivid 또는 natural로 설정해야 합니다.").left() } @@ -31,7 +31,7 @@ data class DallERequest( this["prompt"] = prompt this["n"] = generateCount this["size"] = imageSize.requestType - style.tap { + style.onSome { this["style"] = it } this["response_format"] = responseType.name.lowercase() diff --git a/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt b/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt index be26b45..e266e1d 100644 --- a/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt +++ b/src/main/kotlin/skywolf46/devain/platform/discord/AnnotatedParameterDiscordCommand.kt @@ -47,7 +47,7 @@ abstract class AnnotatedParameterDiscordCommand( val parameters = mutableMapOf() init { - verify().tap { + verify().onSome { throw RuntimeException(it) } inspect() diff --git a/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommandAdapter.kt b/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommandAdapter.kt index 6df6b08..4005f2e 100644 --- a/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommandAdapter.kt +++ b/src/main/kotlin/skywolf46/devain/platform/discord/DiscordCommandAdapter.kt @@ -17,7 +17,7 @@ class DiscordCommandAdapter(private val jda: JDA) : ListenerAdapter() { commandRegistry[commandData.first] = x updateAction.addCommands(commandData.second) if (x is ImprovedDiscordCommand) { - x.modalId.tap { + x.modalId.onSome { modalRegistry[it] = x } } diff --git a/src/main/kotlin/skywolf46/devain/util/TimeUtil.kt b/src/main/kotlin/skywolf46/devain/util/TimeUtil.kt index 5e19466..e4bf25e 100644 --- a/src/main/kotlin/skywolf46/devain/util/TimeUtil.kt +++ b/src/main/kotlin/skywolf46/devain/util/TimeUtil.kt @@ -36,7 +36,6 @@ object TimeUtil { } fun parseToLong(time: String): Either { - "".toOption().and("".toOption()) return parseToLong(time, timeDelimiters) } From da9c9350598606db6b3e047d67f43e331d31dcf1 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sun, 28 Apr 2024 04:07:12 +0900 Subject: [PATCH 44/46] =?UTF-8?q?chore:=20README=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 19 ++++++++--------- docs/log/1_3_0_radioactive_emmer_bread.md | 25 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 docs/log/1_3_0_radioactive_emmer_bread.md diff --git a/README.md b/README.md index c07766d..640c144 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -### Devain Standalone - OpenAI Discord Bot +# Devain Standalone - OpenAI Discord Bot Devain은 [데비안 리눅스](https://www.debian.org/)에서 이름을 가져온 [OpenAI API](https://platform.openai.com/docs/api-reference) 기반 디스코드 봇 프로젝트입니다. @@ -21,6 +21,13 @@ Slash Command 권한 외에는 사용하지 않는 클린한 봇입니다! 최소한의 권한으로 즐겨보세요. +#### 직접 봇을 구동하고 싶지 않습니다. +봇의 개발자와 친목을 다져보세요. 개발자의 디스코드 ID는 skywolf46입니다. + +DevAin 공식 디스코드 봇은 비공개로 운영되고 있으며, 몇몇 선택된 서버에서만 사용 가능합니다. + +선택된 서버들에서의 구동 비용은 개발자가 부담하고 있습니다. + #### ChatGPT가 헛소리를 합니다. ![깡](images/breakdown.jpg)
이제 말을 들을거라고 봅니다. @@ -29,14 +36,6 @@ Slash Command 권한 외에는 사용하지 않는 클린한 봇입니다! 귀찮았습니다. 추후 업데이트를 통해 선택 가능하도록 변경될 예정입니다. -#### 왜 설정 파일로 property를..? - -귀찮았습니다. 추후 toml로 변경됩니다. - -#### 게다가 환율은 왜 하드코딩이? - -귀찮았습니다. 추후 환율 API를 사용해 실시간으로 업데이트되도록 할 예정입니다. - #### 대체 소모 비용은 왜 넣어둔겁니까? 쓰는 사람들에게 돈의 소중함을 알려주기 위해 넣어보았습니다. @@ -49,7 +48,7 @@ Slash Command 권한 외에는 사용하지 않는 클린한 봇입니다! 표면상으로는 MIT를 넣어두었지만, 사실 이 코드는 [니 마음대로 하세요](https://en.wikipedia.org/wiki/WTFPL)™ 라이선스를 따릅니다. -이 Q&A를 읽은 사람만이 MIT 라이선스에 낚이지 않고 자유롭게 코드를 수정할 수 있을겁니다. +이 Q&A를 읽은 사람만이 MIT 라이선스에 낚이지 않고 자유롭게 코드를 수정할 수 있습니다. ### 나중에 할 것 (TODO (2) - 복사본 - 복사본) diff --git a/docs/log/1_3_0_radioactive_emmer_bread.md b/docs/log/1_3_0_radioactive_emmer_bread.md new file mode 100644 index 0000000..edce078 --- /dev/null +++ b/docs/log/1_3_0_radioactive_emmer_bread.md @@ -0,0 +1,25 @@ +# DevAin StandAlone +
+ +## Radioactive Emmer Bread (1.3.0) +Radioactive Emmer Bread는 여러 기능을 추가하고, 기존의 혼잡한 코드를 외부 디펜던시로 분리한 버전입니다. + +## 설정 파일 분리 +이전 버전까지는 한 파일에 데이터 및 토큰을 사용함으로써 혼잡한 설정과 레거시가 통합되어 불편함이 많았습니다. + +1.3.0부터는, 새로운 설정 파일 솔루션을 도입하여 YAML 형태로 간편히 설정이 가능합니다. + + +## 새로운 모델 추가 +Command R+, Claude, Groq과 같은 추가적인 연동이 가능해집니다. + +## 실험적 기능 추가 +ChatGPT에 연동된 실험적 기능, Arxiv 검색이 추가됩니다. + +/arxiv-gpt [명령]으로 논문을 검색하고, ChatGPT를 통해 요약을 받아보세요. + +## 구조 개선 +기존 하드 코딩된 데이터에서 어노테이션을 통한 단순화가 이루어졌습니다. + +## 라이브러리 분리 +기존의 코드를 외부 라이브러리로 분리하여, 코드 베이스의 가독성을 높였습니다. \ No newline at end of file From 97ae06fdf07715468d4523f98d89b55ab4e23562 Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sun, 28 Apr 2024 04:15:27 +0900 Subject: [PATCH 45/46] =?UTF-8?q?feat:=20=EB=AA=85=EB=A0=B9=EC=96=B4=20?= =?UTF-8?q?=EC=84=A4=EB=AA=85=20=ED=8C=8C=EC=9D=BC=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/commands.md | 64 +++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index 1e961a6..a6783f2 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -2,47 +2,43 @@ 해당 문서에서는 DevAin Standalone 기준 명령어를 확인할 수 있습니다. -해당 문서는 DevAin Standalone 1.2.0 (Grenade Muffin)을 기준으로 작성되었습니다. +해당 문서는 DevAin Standalone 1.3.0(Radioactive Emmer Bread)을 기준으로 작성되었습니다. ##### Devain -| 명령어 | 설명 | -|-------------|---------------------------| -| /status | DevAin 봇의 상태를 확인합니다. | -| /update-log | DevAin 봇의 업데이트 로그를 확인합니다. | +| 명령어 | 설명 | +|---------|----------------------| +| /status | DevAin 봇의 상태를 확인합니다. | ##### GPT Chat -| 명령어 | 설명 | -|-----------------------------|------------------------------------------------------------------------------------------| -| /ask [Content] | ChatGPT에게 질문합니다. 해당 명령어의 기본 값은 gpt-3.5-turbo입니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | -| /ask-fast [Content] | ChatGPT에게 질문합니다. 해당 명령어의 기본 값은 gpt-4-0613입니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | -| /ask-more-fast [Content] | ChatGPT에게 질문합니다. 해당 명령어의 기본 값은 gpt-4-1106-preview입니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | -| /ask-more [Content] | ChatGPT에게 질문합니다. 해당 명령어의 기본 값은 gpt-4입니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | -| /askto [Model] [Contents] | ChatGPT의 특정 모델에게 질문합니다. | -| /edit [Instruction] [Input] | OpenAI의 InstructionGPT를 이용하여 데이터를 생성합니다. | - -##### GPT Chat Preset - -| 명령어 | 설명 | -|---------------------------------------|--------------------| -| /preset user | 자신의 프리셋 목록을 확인합니다. | -| /preset user create [Name] [Preset] | 새 유저 프리셋을 생성합니다. | -| /preset user delete [Name] | 유저 프리셋을 삭제합니다. | -| /preset server | 서버 프리셋 목록을 확인합니다. | -| /preset server create [Name] [Preset] | 새 서버 프리셋을 생성합니다. | -| /preset server delete [Name] | 서버 프리셋을 삭제합니다. | +| 명령어 | 설명 | +|-------------------------------|------------------------------------------------------------------------------------------| +| /ask [Content] | ChatGPT에게 질문합니다. 해당 명령어의 기본 값은 gpt-3.5-turbo입니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | +| /ask-fast [Content] | ChatGPT에게 질문합니다. 해당 명령어의 기본 값은 gpt-4-0613입니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | +| /ask-more-fast [Content] | ChatGPT에게 질문합니다. 해당 명령어의 기본 값은 gpt-4-1106-preview입니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | +| /ask-more [Content] | ChatGPT에게 질문합니다. 해당 명령어의 기본 값은 gpt-4입니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | +| /ask-vision [Content] [Image] | ChatGPT에게 질문합니다. 해당 명령어의 기본 값은 gpt-4-vision입니다. 이 모델은 업로드된 이미지를 읽을 수 있습니다. | -##### Dall-E Generation +##### Cohere + +| 명령어 | 설명 | +|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| /cohere [Content] | Cohere Command 모델에게 질문합니다. Cohere Command 모델은 영어 이외의 언어에 대해 출력 및 입력이 부실합니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | +| /rplus [Content] | Cohere Command R 모델에게 질문합니다. Cohere Command R 모델은 ChatGPT보다 필터가 덜하며, 한국어에 대한 출력 및 입력이 원활합니다. 환각이 심하며, 특정 지식보다는 프롬프트에 대한 해석 및 명령에 적합합니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | +| /rminus [Content] | Cohere Command R 모델에게 질문합니다. Cohere Command R+ 모델은 ChatGPT보다 필터가 덜하며, 한국어에 대한 출력 및 입력이 원활하고, 한국어에 대한 이해력이 좋습니다. 환각이 심하며, 특정 지식보다는 프롬프트에 대한 해석 및 명령에 적합합니다. 해당 명령어는 단일 세션이며, 이전 대화를 기록하지 않습니다. | -| 명령어 | 설명 | -|-----------------------------|------------------------------------------| -| /imagine [Prompt] | 프롬프트를 기준으로 Dall-E를 이용하여 이미지를 생성합니다. | -| /edit [Instruction] [Input] | OpenAI의 InstructionGPT를 이용하여 데이터를 생성합니다. | -| /dream [engine] [Prompt] | DreamStudio API를 이용해 이미지를 생성합니다. | +#### Groq -##### DreamBooth Image Generation +| 명령어 | 설명 | +|--------------------|----------------------------------------------| +| /xllama [Content] | Groq Cloud API를 통해 Llama3 70B 모델에 질의합니다. | +| /llama [Content] | Groq Cloud API를 통해 Llama3 8B 모델에 질의합니다. | +| /mixtral [Content] | Groq Cloud API를 통해 Mixtral 8 x 7B 모델에 질의합니다. | +| /gemma [Content] | Groq Cloud API를 통해 Gemma 모델에 질의합니다. | + +##### Dall-E Generation -| 명령어 | 설명 | -|-----------------------------|------------------------------------------| -| /dream [engine] [Prompt] | DreamStudio API를 이용해 이미지를 생성합니다. | \ No newline at end of file +| 명령어 | 설명 | +|-----------------|---------------------------------------| +| /dalle [Prompt] | 프롬프트를 기준으로 Dall-E 2를 이용하여 이미지를 생성합니다. | From 3cfd46aa46b3eae40418bc30b49deffdd729654b Mon Sep 17 00:00:00 2001 From: skywolf46 Date: Sun, 28 Apr 2024 04:21:41 +0900 Subject: [PATCH 46/46] =?UTF-8?q?feat:=20=EB=88=84=EB=9D=BD=EB=90=9C=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=BD=94=EB=93=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/skywolf46/devain/DevAin.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/skywolf46/devain/DevAin.kt b/src/main/kotlin/skywolf46/devain/DevAin.kt index 95a0ab1..bdb3d8c 100644 --- a/src/main/kotlin/skywolf46/devain/DevAin.kt +++ b/src/main/kotlin/skywolf46/devain/DevAin.kt @@ -35,7 +35,6 @@ class DevAin : KoinComponent { CohereModule(), AnthropicModule(), GroqModule(), - KModule(), object : PluginModule("Test Fatal Plugin") { override fun canBeLoaded(): Boolean { return false