Files
JChatGPT/src/main/kotlin/tools/AdjustUserFavorabilityAgent.kt

147 lines
6.7 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package top.jie65535.mirai.tools
import com.aallam.openai.api.chat.Tool
import com.aallam.openai.api.core.Parameters
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.add
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.intOrNull
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.longOrNull
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonArray
import kotlinx.serialization.json.putJsonObject
import net.mamoe.mirai.event.events.MessageEvent
import top.jie65535.mirai.JChatGPT
import top.jie65535.mirai.PluginData
import top.jie65535.mirai.FavorabilityInfo
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
class AdjustUserFavorabilityAgent : BaseAgent(
tool = Tool.function(
name = "adjustUserFavorability",
description = """
维护你对群友的认识(好感度、印象、标签、代号)。
每次和某人有实质交流后建议调用一次,可与发言工具在同一轮发出,几乎不产生额外成本。
触发场景:
- 首次有像样的对话(建立初始印象和代号)
- 对方透露身份/职业/偏好/技术栈(加 tag
- 互动产生明显情绪变化——开心/被逗/被冒犯(调 change
- 已有印象明显不准(更新 impression
change 默认为 0只更新标签/印象时不用填 reason。
tags 上限 5 个,满了须先 tags_remove 旧标签才能继续添加。
好感度范围 -100 到 100低于 0 时有概率忽略其消息,-100 则 100% 忽略。
""".trimIndent(),
parameters = Parameters.buildJsonObject {
put("type", "object")
put("properties", buildJsonObject {
put("userId", buildJsonObject {
put("type", "integer")
put("description", "用户QQ号")
})
put("change", buildJsonObject {
put("type", "integer")
put("description", "好感度变化值可正可负默认为0")
})
put("reason", buildJsonObject {
put("type", "string")
put("description", "调整原因change!=0时建议填写供溯源")
})
put("impression", buildJsonObject {
put("type", "string")
put("description", "对用户的印象描述覆盖旧值上限200字符")
})
put("name", buildJsonObject {
put("type", "string")
put("description", "Bot给此人起的代号非QQ昵称上限20字符")
})
put("tags_add", buildJsonObject {
put("type", "array")
putJsonObject("items") { put("type", "string") }
put("description", "追加标签自动去重总数超5项返错单项上限20字符")
})
put("tags_remove", buildJsonObject {
put("type", "array")
putJsonObject("items") { put("type", "string") }
put("description", "删除标签(不存在的项静默忽略)")
})
})
putJsonArray("required") {
add("userId")
}
}
)
) {
override suspend fun execute(args: JsonObject?, event: MessageEvent): String {
requireNotNull(args)
val userId = args["userId"]?.jsonPrimitive?.longOrNull
?: return "错误userId参数不能为空"
val change = args["change"]?.jsonPrimitive?.intOrNull ?: 0
val reason = args["reason"]?.jsonPrimitive?.contentOrNull
val impression = args["impression"]?.jsonPrimitive?.contentOrNull
val name = args["name"]?.jsonPrimitive?.contentOrNull
val tagsAdd = (args["tags_add"] as? JsonArray)?.mapNotNull { it.jsonPrimitive.contentOrNull }
val tagsRemove = (args["tags_remove"] as? JsonArray)?.mapNotNull { it.jsonPrimitive.contentOrNull }
// 字段长度校验
if (name != null && name.length > 20) return "错误name不能超过20字符当前${name.length}字符)"
if (impression != null && impression.length > 200) return "错误impression不能超过200字符当前${impression.length}字符)"
tagsAdd?.forEach { tag ->
if (tag.length > 20) return "错误tag「$tag」不能超过20字符"
}
val currentInfo = PluginData.userFavorability[userId] ?: FavorabilityInfo(userId)
val currentValue = currentInfo.value
val newValue = (currentValue + change).coerceIn(-100, 100)
// 只在 change != 0 时记录原因
val newReasons = if (change != 0 && reason != null) {
val timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
val newReason = "${timeFormatter.format(OffsetDateTime.now())}: $reason"
if (currentInfo.reasons.size >= 10) {
currentInfo.reasons.drop(1) + newReason
} else {
currentInfo.reasons + newReason
}
} else currentInfo.reasons
// 处理标签
val newTags = currentInfo.tags.toMutableList()
tagsRemove?.forEach { tag -> newTags.remove(tag) }
if (tagsAdd != null) {
val toAdd = tagsAdd.filter { it !in newTags }
if (newTags.size + toAdd.size > 5) {
return "错误:标签已满(当前${newTags.size}须先用tags_remove删除旧标签。当前标签[${newTags.joinToString(", ")}]"
}
newTags.addAll(toAdd)
}
val newInfo = FavorabilityInfo(
userId = userId,
value = newValue,
reasons = newReasons,
impression = impression ?: currentInfo.impression,
name = name ?: currentInfo.name,
tags = newTags
)
PluginData.userFavorability[userId] = newInfo
JChatGPT.logger.info("用户 $userId 画像已更新:好感度($currentValue -> $newValue),原因:$reason")
return buildString {
append("用户 $userId 画像已更新:好感度=$newValue")
if (newTags.isNotEmpty()) append(",标签=[${newTags.joinToString(", ")}]")
if (newInfo.name.isNotEmpty()) append(",代号=${newInfo.name}")
if (newInfo.impression.isNotEmpty()) append(",印象=${newInfo.impression}")
}
}
}