mirror of
https://github.com/jie65535/JChatGPT.git
synced 2026-06-23 00:49:31 +08:00
147 lines
6.7 KiB
Kotlin
147 lines
6.7 KiB
Kotlin
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}")
|
||
}
|
||
}
|
||
}
|