mirror of
https://github.com/Nezumi-2711/astrbot_plugin_qq_group_daily_analysis.git
synced 2026-09-22 13:38:43 +00:00
feat(persona): 人格设定功能增强,支持插件指定和会话继承的人格分析
This commit is contained in:
@@ -306,6 +306,19 @@ _✨ 一个基于 AstrBot 的智能群聊分析插件,支持 **QQ (OneBot)**
|
|||||||
- 机器人根据文件名和 `html_base_url` 拼接成完整链接发送到群里。
|
- 机器人根据文件名和 `html_base_url` 拼接成完整链接发送到群里。
|
||||||
- **注意**:本插件**不提供** Web 服务器功能,你需要自行使用 Nginx 或 AstrBot 所在的服务器环境来实现静态文件的公网访问。
|
- **注意**:本插件**不提供** Web 服务器功能,你需要自行使用 Nginx 或 AstrBot 所在的服务器环境来实现静态文件的公网访问。
|
||||||
|
|
||||||
|
|
||||||
|
## 人格设定 (Persona)
|
||||||
|
|
||||||
|
插件支持深度的“人格化”分析,让 AI 能够以特定的人设风格(口吻、偏好、语气)来产出摘要和锐评。
|
||||||
|
|
||||||
|
### 人格识别优先级
|
||||||
|
插件在构建分析任务时,会按以下顺序确定最终使用的“人设状态”:
|
||||||
|
|
||||||
|
1. **强制插件人格 (优先级最高)**:在配置中开启 `强制使用插件指定人格` 并选择 ID。此时 **全平台、所有群聊** 都会统一使用这一种人设,忽略群聊本身的设置。
|
||||||
|
2. **继承会话人设 (优先级次之)**:在配置中开启 `继承会话人设风格`。插件会尝试识别当前群聊在 AstrBot 中设置的人格(如通过 `/persona` 指令设置的人设)。如果该群已有人设,分析报告将尽量模拟其说话倾向。
|
||||||
|
3. **系统默认人设**:若上述开关均关闭,或未识别到有效人设,则回退到当前默认设定。
|
||||||
|
|
||||||
|
|
||||||
## 常见问题 (FAQ)
|
## 常见问题 (FAQ)
|
||||||
|
|
||||||
### 获取不到带记录的引用消息
|
### 获取不到带记录的引用消息
|
||||||
|
|||||||
+15
-2
@@ -238,10 +238,23 @@
|
|||||||
"hint": "分析报告中显示的最大金句数量,依赖于 LLM 输出的格式化信息质量,模型越好结果越好,可能出现数量不匹配。"
|
"hint": "分析报告中显示的最大金句数量,依赖于 LLM 输出的格式化信息质量,模型越好结果越好,可能出现数量不匹配。"
|
||||||
},
|
},
|
||||||
"keep_original_persona": {
|
"keep_original_persona": {
|
||||||
"description": "是否保持原始人格设定参与回复",
|
"description": "继承会话人设风格",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"default": false,
|
"default": false,
|
||||||
"hint": "开启后,若当前会话存在人格设定,将尝试读取其 Prompt 融入系统提示词。尽量保持分析报告的说话倾向与会话人设一致。"
|
"hint": "【优先级2】开启后将自动尝试识别当前群聊会话(或对话)的人格设定。若该群已设置人设,则分析报告会尽量模拟该人设的口吻进行回复。注意:此开关在“强制使用插件指定人格”关闭时才会生效。"
|
||||||
|
},
|
||||||
|
"use_plugin_specific_persona": {
|
||||||
|
"description": "强制使用插件指定人格",
|
||||||
|
"type": "bool",
|
||||||
|
"default": false,
|
||||||
|
"hint": "【优先级1:核心开关】若开启,将完全忽略当前群聊的人格设定,统一强制使用下方选择的“插件指定人格 ID”进行分析。适用于希望全群分析保持某种统一固定风格(如特定的“记录员”人设)的情况。"
|
||||||
|
},
|
||||||
|
"plugin_specific_persona_id": {
|
||||||
|
"description": "插件指定人格 ID",
|
||||||
|
"type": "string",
|
||||||
|
"_special": "select_persona",
|
||||||
|
"default": "",
|
||||||
|
"hint": "当“强制使用插件指定人格”开启时,在此处选择系统中已定义的人设。若此处未选择,则仍会尝试识别全局默认人格。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -474,85 +474,115 @@ class BaseAnalyzer(ABC, Generic[TDataObject]):
|
|||||||
|
|
||||||
async def _build_system_prompt(self, umo: str | None) -> str | None:
|
async def _build_system_prompt(self, umo: str | None) -> str | None:
|
||||||
"""
|
"""
|
||||||
构建带有会话人格的系统提示词
|
构建带有会话人格的系统提示词,优先级如下:
|
||||||
"""
|
1. 插件指定的全局人格 (若核心开关开启)
|
||||||
keep = self.config_manager.get_keep_original_persona()
|
2. 会话/对话选定的人格 (若开启了继承开关)
|
||||||
if not keep or not umo:
|
3. 当前 UMO 的默认人格 (若开启了继承开关)
|
||||||
return None
|
|
||||||
|
|
||||||
# 获取人格管理器
|
Args:
|
||||||
|
umo: 用户模型对象标识,用于定位会话上下文
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
最终生成的 System Prompt 字符串,若无则返回 None
|
||||||
|
"""
|
||||||
|
# 获取配置
|
||||||
|
use_specific = self.config_manager.get_use_plugin_specific_persona()
|
||||||
|
specific_id = self.config_manager.get_plugin_specific_persona_id()
|
||||||
|
keep_original = self.config_manager.get_keep_original_persona()
|
||||||
|
|
||||||
|
# 获取 AstrBot 核心的人格管理器
|
||||||
persona_mgr = getattr(self.context, "persona_manager", None)
|
persona_mgr = getattr(self.context, "persona_manager", None)
|
||||||
if persona_mgr is None:
|
if persona_mgr is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
persona_prompt = None
|
persona_prompt = None
|
||||||
try:
|
|
||||||
# 1. 尝试从 SharedPreferences 获取当前会话选中的人格 ID (类似 /persona 设置的)
|
|
||||||
from astrbot.api import sp
|
|
||||||
|
|
||||||
# resolve_selected_persona 的简化逻辑
|
# --- 优先级 1: 插件指定的全局固定人格 ---
|
||||||
session_service_config = await sp.get_async(
|
# 适用于希望所有分析报告都呈现同一种风格的情况
|
||||||
scope="umo", scope_id=str(umo), key="session_service_config", default={}
|
if use_specific and specific_id:
|
||||||
)
|
try:
|
||||||
persona_id = (
|
persona_obj = await persona_mgr.get_persona(specific_id)
|
||||||
session_service_config.get("persona_id")
|
|
||||||
if session_service_config
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
if persona_id and persona_id != "[%None]":
|
|
||||||
# 获取指定人格
|
|
||||||
persona_obj = await persona_mgr.get_persona(persona_id)
|
|
||||||
persona_prompt = (
|
persona_prompt = (
|
||||||
persona_obj.system_prompt
|
persona_obj.system_prompt
|
||||||
if hasattr(persona_obj, "system_prompt")
|
if hasattr(persona_obj, "system_prompt")
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
if persona_prompt:
|
if persona_prompt:
|
||||||
logger.debug(f"找到会话选定的人格: {persona_id}")
|
logger.debug(f"已应用插件指定的全局强制人格设定: {specific_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"获取插件指定人格失败 (ID: {specific_id}): {e}")
|
||||||
|
|
||||||
# 2. 如果没有选定人格,尝试获取当前对话的人格 ID (Dialogue Persona)
|
# --- 优先级 2: 继承当前会话/群聊的原始人格 ---
|
||||||
if not persona_prompt:
|
# 只有在未开启“强制人格”且开启了“继承设定”时生效
|
||||||
conv_mgr = getattr(self.context, "conversation_manager", None)
|
if not persona_prompt and keep_original and umo:
|
||||||
if conv_mgr:
|
try:
|
||||||
curr_conv_id = await conv_mgr.get_curr_conversation_id(umo)
|
# 2.1 尝试获取 SharedPreferences 中会话绑定的 Persona ID (通常是 /persona 命令设置的)
|
||||||
if curr_conv_id:
|
from astrbot.api import sp
|
||||||
conv_obj = await conv_mgr.get_conversation(umo, curr_conv_id)
|
|
||||||
if (
|
session_service_config = await sp.get_async(
|
||||||
conv_obj
|
scope="umo",
|
||||||
and conv_obj.persona_id
|
scope_id=str(umo),
|
||||||
and conv_obj.persona_id != "[%None]"
|
key="session_service_config",
|
||||||
):
|
default={},
|
||||||
persona_obj = await persona_mgr.get_persona(
|
)
|
||||||
conv_obj.persona_id
|
persona_id = (
|
||||||
|
session_service_config.get("persona_id")
|
||||||
|
if session_service_config
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
if persona_id and persona_id != "[%None]":
|
||||||
|
persona_obj = await persona_mgr.get_persona(persona_id)
|
||||||
|
persona_prompt = (
|
||||||
|
persona_obj.system_prompt
|
||||||
|
if hasattr(persona_obj, "system_prompt")
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
if persona_prompt:
|
||||||
|
logger.debug(f"继承到会话选定人格: {persona_id}")
|
||||||
|
|
||||||
|
# 2.2 若无会话绑定,尝试获取当前对话(Dialogue)级别的人格
|
||||||
|
if not persona_prompt:
|
||||||
|
conv_mgr = getattr(self.context, "conversation_manager", None)
|
||||||
|
if conv_mgr:
|
||||||
|
curr_conv_id = await conv_mgr.get_curr_conversation_id(umo)
|
||||||
|
if curr_conv_id:
|
||||||
|
conv_obj = await conv_mgr.get_conversation(
|
||||||
|
umo, curr_conv_id
|
||||||
)
|
)
|
||||||
persona_prompt = (
|
if (
|
||||||
persona_obj.system_prompt
|
conv_obj
|
||||||
if hasattr(persona_obj, "system_prompt")
|
and conv_obj.persona_id
|
||||||
else None
|
and conv_obj.persona_id != "[%None]"
|
||||||
)
|
):
|
||||||
if persona_prompt:
|
persona_obj = await persona_mgr.get_persona(
|
||||||
logger.debug(
|
conv_obj.persona_id
|
||||||
f"找到对话设定的人格: {conv_obj.persona_id} (conv_id: {curr_conv_id})"
|
|
||||||
)
|
)
|
||||||
|
persona_prompt = (
|
||||||
|
persona_obj.system_prompt
|
||||||
|
if hasattr(persona_obj, "system_prompt")
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
if persona_prompt:
|
||||||
|
logger.debug(
|
||||||
|
f"继承到对话(Dialogue)设定人格: {conv_obj.persona_id}"
|
||||||
|
)
|
||||||
|
|
||||||
# 3. 如果还是没有,回退到 UMO 默认人格
|
# 2.3 若仍无结果,尝试获取 UMO 设定的默认人格
|
||||||
if not persona_prompt:
|
if not persona_prompt:
|
||||||
personality = await persona_mgr.get_default_persona_v3(umo)
|
personality = await persona_mgr.get_default_persona_v3(umo)
|
||||||
if isinstance(personality, dict):
|
if isinstance(personality, dict):
|
||||||
persona_prompt = personality.get("prompt")
|
persona_prompt = personality.get("prompt")
|
||||||
else:
|
else:
|
||||||
persona_prompt = getattr(personality, "prompt", None)
|
persona_prompt = getattr(personality, "prompt", None)
|
||||||
if persona_prompt:
|
if persona_prompt:
|
||||||
logger.debug("使用 UMO 默认人格设定")
|
logger.debug("继承到 UMO 默认人格设定")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"获取人格设定失败 (umo: {umo}): {e}")
|
logger.warning(f"分析人格回溯识别失败 (umo: {umo}): {e}")
|
||||||
return None
|
|
||||||
|
|
||||||
|
# 检查生成结果
|
||||||
if not isinstance(persona_prompt, str) or not persona_prompt.strip():
|
if not isinstance(persona_prompt, str) or not persona_prompt.strip():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 构建系统提示词,要求 LLM 保持人格设定
|
return persona_prompt.strip()
|
||||||
system_prompt = persona_prompt.strip()
|
|
||||||
return system_prompt
|
|
||||||
|
|||||||
@@ -225,9 +225,21 @@ class ConfigManager:
|
|||||||
return self._get_group("llm").get("golden_quote_provider_id", "")
|
return self._get_group("llm").get("golden_quote_provider_id", "")
|
||||||
|
|
||||||
def get_keep_original_persona(self) -> bool:
|
def get_keep_original_persona(self) -> bool:
|
||||||
"""获取是否保持原始人格设定"""
|
"""获取是否继承会话原始人格设定"""
|
||||||
return self._get_group("analysis_features").get("keep_original_persona", False)
|
return self._get_group("analysis_features").get("keep_original_persona", False)
|
||||||
|
|
||||||
|
def get_use_plugin_specific_persona(self) -> bool:
|
||||||
|
"""获取是否强制使用插件指定的人格设定"""
|
||||||
|
return self._get_group("analysis_features").get(
|
||||||
|
"use_plugin_specific_persona", False
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_plugin_specific_persona_id(self) -> str:
|
||||||
|
"""获取插件指定的全局人格 ID (通过 select_persona 接口选择)"""
|
||||||
|
return self._get_group("analysis_features").get(
|
||||||
|
"plugin_specific_persona_id", ""
|
||||||
|
)
|
||||||
|
|
||||||
def get_pdf_output_dir(self) -> str:
|
def get_pdf_output_dir(self) -> str:
|
||||||
"""获取PDF输出目录"""
|
"""获取PDF输出目录"""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|||||||
Reference in New Issue
Block a user