mirror of
https://github.com/Nezumi-2711/astrbot_plugin_qq_group_daily_analysis.git
synced 2026-09-22 13:38:43 +00:00
feat(分析功能): 添加人格设定的配置选项,并更新相关提示词构建逻辑
feat(persona): 自动检测当前群聊激活的对话所绑定的性格
This commit is contained in:
@@ -220,6 +220,12 @@
|
|||||||
"description": "最大金句数量",
|
"description": "最大金句数量",
|
||||||
"default": 5,
|
"default": 5,
|
||||||
"hint": "分析报告中显示的最大金句数量,依赖于 LLM 输出的格式化信息质量,模型越好结果越好,可能出现数量不匹配。"
|
"hint": "分析报告中显示的最大金句数量,依赖于 LLM 输出的格式化信息质量,模型越好结果越好,可能出现数量不匹配。"
|
||||||
|
},
|
||||||
|
"keep_original_persona": {
|
||||||
|
"description": "是否保持原始人格设定参与回复",
|
||||||
|
"type": "bool",
|
||||||
|
"default": false,
|
||||||
|
"hint": "开启后,若当前会话存在人格设定,将尝试读取其 Prompt 融入系统提示词。尽量保持分析报告的说话倾向与会话人设一致。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from ..utils.llm_utils import (
|
|||||||
class BaseAnalyzer(ABC):
|
class BaseAnalyzer(ABC):
|
||||||
"""
|
"""
|
||||||
基础分析器抽象类
|
基础分析器抽象类
|
||||||
定义所有分析器的通用接口和流程
|
定义所有分析器的通用接口 and 流程
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, context, config_manager):
|
def __init__(self, context, config_manager):
|
||||||
@@ -172,10 +172,6 @@ class BaseAnalyzer(ABC):
|
|||||||
|
|
||||||
# 保存调试数据
|
# 保存调试数据
|
||||||
debug_mode = self.config_manager.get_debug_mode()
|
debug_mode = self.config_manager.get_debug_mode()
|
||||||
logger.info(
|
|
||||||
f"[Debug] debug_mode={debug_mode}, session_id={session_id}, prompt_len={len(prompt) if prompt else 0}"
|
|
||||||
) # Added log
|
|
||||||
|
|
||||||
if debug_mode and session_id and prompt:
|
if debug_mode and session_id and prompt:
|
||||||
self._save_debug_data(prompt, session_id)
|
self._save_debug_data(prompt, session_id)
|
||||||
elif debug_mode and not session_id:
|
elif debug_mode and not session_id:
|
||||||
@@ -193,14 +189,37 @@ class BaseAnalyzer(ABC):
|
|||||||
temperature = self.get_temperature()
|
temperature = self.get_temperature()
|
||||||
provider_id_key = self.get_provider_id_key()
|
provider_id_key = self.get_provider_id_key()
|
||||||
|
|
||||||
|
# 获取人格设定
|
||||||
|
system_prompt = await self._build_system_prompt(umo)
|
||||||
|
|
||||||
|
# 如果开启了人格设定且成功获取到 Prompt,我们将其注入到主提示词中,以确保最佳效果
|
||||||
|
if system_prompt:
|
||||||
|
logger.info(f"[{self.get_data_type()}分析] 已启用人格设定")
|
||||||
|
# 在主提示词前添加人格说明,并要求 LLM 保持风格
|
||||||
|
prompt = (
|
||||||
|
f"你可以扮演以下人格:\n{system_prompt}\n\n"
|
||||||
|
f"请在接下来的分析工作中,保持上述人格的角色定位和说话风格。\n"
|
||||||
|
"--- 任务开始 ---\n"
|
||||||
|
f"{prompt}"
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(f"[{self.get_data_type()}分析] 开始发起 LLM 请求, umo: {umo}")
|
||||||
|
|
||||||
|
# [Debug] 记录调试信息
|
||||||
|
if debug_mode:
|
||||||
|
logger.debug(
|
||||||
|
f"[Debug] debug_mode={debug_mode}, umo={umo}, session_id={session_id}, prompt_len={len(prompt) if prompt else 0}"
|
||||||
|
)
|
||||||
|
|
||||||
response = await call_provider_with_retry(
|
response = await call_provider_with_retry(
|
||||||
self.context,
|
self.context,
|
||||||
self.config_manager,
|
self.config_manager,
|
||||||
prompt,
|
prompt=prompt,
|
||||||
max_tokens,
|
max_tokens=max_tokens,
|
||||||
temperature,
|
temperature=temperature,
|
||||||
umo,
|
umo=umo,
|
||||||
provider_id_key,
|
provider_id_key=provider_id_key,
|
||||||
|
system_prompt=system_prompt,
|
||||||
)
|
)
|
||||||
|
|
||||||
if response is None:
|
if response is None:
|
||||||
@@ -274,3 +293,88 @@ class BaseAnalyzer(ABC):
|
|||||||
温度参数
|
温度参数
|
||||||
"""
|
"""
|
||||||
return 0.6
|
return 0.6
|
||||||
|
|
||||||
|
async def _build_system_prompt(self, umo: str | None) -> str | None:
|
||||||
|
"""
|
||||||
|
构建带有会话人格的系统提示词
|
||||||
|
"""
|
||||||
|
keep = self.config_manager.get_keep_original_persona()
|
||||||
|
if not keep or not umo:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 获取人格管理器
|
||||||
|
persona_mgr = getattr(self.context, "persona_manager", None)
|
||||||
|
if persona_mgr is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
persona_prompt = None
|
||||||
|
try:
|
||||||
|
# 1. 尝试从 SharedPreferences 获取当前会话选中的人格 ID (类似 /persona 设置的)
|
||||||
|
from astrbot.api import sp
|
||||||
|
|
||||||
|
# resolve_selected_persona 的简化逻辑
|
||||||
|
session_service_config = await sp.get_async(
|
||||||
|
scope="umo", scope_id=str(umo), key="session_service_config", default={}
|
||||||
|
)
|
||||||
|
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. 如果没有选定人格,尝试获取当前对话的人格 ID (Dialogue Persona)
|
||||||
|
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)
|
||||||
|
if (
|
||||||
|
conv_obj
|
||||||
|
and conv_obj.persona_id
|
||||||
|
and conv_obj.persona_id != "[%None]"
|
||||||
|
):
|
||||||
|
persona_obj = await persona_mgr.get_persona(
|
||||||
|
conv_obj.persona_id
|
||||||
|
)
|
||||||
|
persona_prompt = (
|
||||||
|
persona_obj.system_prompt
|
||||||
|
if hasattr(persona_obj, "system_prompt")
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
if persona_prompt:
|
||||||
|
logger.debug(
|
||||||
|
f"找到对话设定的人格: {conv_obj.persona_id} (conv_id: {curr_conv_id})"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. 如果还是没有,回退到 UMO 默认人格
|
||||||
|
if not persona_prompt:
|
||||||
|
personality = await persona_mgr.get_default_persona_v3(umo)
|
||||||
|
if isinstance(personality, dict):
|
||||||
|
persona_prompt = personality.get("prompt")
|
||||||
|
else:
|
||||||
|
persona_prompt = getattr(personality, "prompt", None)
|
||||||
|
if persona_prompt:
|
||||||
|
logger.debug("使用 UMO 默认人格设定")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"获取人格设定失败 (umo: {umo}): {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not isinstance(persona_prompt, str) or not persona_prompt.strip():
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 构建系统提示词,要求 LLM 保持人格设定
|
||||||
|
system_prompt = persona_prompt.strip()
|
||||||
|
return system_prompt
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ async def call_provider_with_retry(
|
|||||||
temperature: float,
|
temperature: float,
|
||||||
umo: str | None = None,
|
umo: str | None = None,
|
||||||
provider_id_key: str | None = None,
|
provider_id_key: str | None = None,
|
||||||
|
system_prompt: str | None = None,
|
||||||
) -> Any | None:
|
) -> Any | None:
|
||||||
"""
|
"""
|
||||||
调用LLM提供者,带超时、重试与退避。支持自定义服务商和配置化 Provider 选择。
|
调用LLM提供者,带超时、重试与退避。支持自定义服务商和配置化 Provider 选择。
|
||||||
@@ -200,6 +201,7 @@ async def call_provider_with_retry(
|
|||||||
temperature: 采样温度
|
temperature: 采样温度
|
||||||
umo: 指定使用的模型唯一标识符
|
umo: 指定使用的模型唯一标识符
|
||||||
provider_id_key: 配置中的 provider_id 键名(如 'topic_provider_id'),用于选择特定的 Provider
|
provider_id_key: 配置中的 provider_id 键名(如 'topic_provider_id'),用于选择特定的 Provider
|
||||||
|
system_prompt: 系统提示词
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
LLM生成的结果,失败时返回None
|
LLM生成的结果,失败时返回None
|
||||||
@@ -231,6 +233,11 @@ async def call_provider_with_retry(
|
|||||||
f"[LLM 调用] Prompt 前100字符: {prompt[:100] if prompt else 'None'}..."
|
f"[LLM 调用] Prompt 前100字符: {prompt[:100] if prompt else 'None'}..."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if system_prompt:
|
||||||
|
logger.debug(
|
||||||
|
f"[LLM 调用] System Prompt 前100字符: {system_prompt[:100]}..."
|
||||||
|
)
|
||||||
|
|
||||||
# 检查 prompt 是否为空
|
# 检查 prompt 是否为空
|
||||||
if not prompt or not prompt.strip():
|
if not prompt or not prompt.strip():
|
||||||
logger.error(
|
logger.error(
|
||||||
@@ -253,6 +260,7 @@ async def call_provider_with_retry(
|
|||||||
prompt=prompt,
|
prompt=prompt,
|
||||||
max_tokens=max_tokens,
|
max_tokens=max_tokens,
|
||||||
temperature=temperature,
|
temperature=temperature,
|
||||||
|
system_prompt=system_prompt,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 成功记录
|
# 成功记录
|
||||||
|
|||||||
@@ -220,6 +220,10 @@ class ConfigManager:
|
|||||||
"""获取金句分析专用 Provider ID"""
|
"""获取金句分析专用 Provider ID"""
|
||||||
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:
|
||||||
|
"""获取是否保持原始人格设定"""
|
||||||
|
return self._get_group("analysis_features").get("keep_original_persona", False)
|
||||||
|
|
||||||
def get_pdf_output_dir(self) -> str:
|
def get_pdf_output_dir(self) -> str:
|
||||||
"""获取PDF输出目录"""
|
"""获取PDF输出目录"""
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1237,7 +1237,9 @@ class OneBotAdapter(PlatformAdapter):
|
|||||||
f"[群分析相册] Base64 接口 2 (upload_group_album) 失败: {e3}"
|
f"[群分析相册] Base64 接口 2 (upload_group_album) 失败: {e3}"
|
||||||
)
|
)
|
||||||
await self.bot.call_action("upload_qun_album", **params)
|
await self.bot.call_action("upload_qun_album", **params)
|
||||||
logger.info("[群分析相册] Base64 模式 (upload_qun_album) 上传成功")
|
logger.info(
|
||||||
|
"[群分析相册] Base64 模式 (upload_qun_album) 上传成功"
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -1294,7 +1296,9 @@ class OneBotAdapter(PlatformAdapter):
|
|||||||
|
|
||||||
for action in actions:
|
for action in actions:
|
||||||
try:
|
try:
|
||||||
logger.debug(f"[群分析相册] 正在通过 {action} 获取列表 (群: {group_id})...")
|
logger.debug(
|
||||||
|
f"[群分析相册] 正在通过 {action} 获取列表 (群: {group_id})..."
|
||||||
|
)
|
||||||
result = await self.bot.call_action(
|
result = await self.bot.call_action(
|
||||||
action,
|
action,
|
||||||
group_id=int(group_id), # 确保传整型,对齐 NapCat 等实现
|
group_id=int(group_id), # 确保传整型,对齐 NapCat 等实现
|
||||||
@@ -1329,7 +1333,9 @@ class OneBotAdapter(PlatformAdapter):
|
|||||||
if not album_name:
|
if not album_name:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
logger.debug(f"[群分析相册] 正在群 {group_id} 中查找名为 '{album_name}' 的相册...")
|
logger.debug(
|
||||||
|
f"[群分析相册] 正在群 {group_id} 中查找名为 '{album_name}' 的相册..."
|
||||||
|
)
|
||||||
albums = await self.get_group_album_list(group_id)
|
albums = await self.get_group_album_list(group_id)
|
||||||
for album in albums:
|
for album in albums:
|
||||||
name = album.get("name") or album.get("album_name", "")
|
name = album.get("name") or album.get("album_name", "")
|
||||||
|
|||||||
Reference in New Issue
Block a user