mirror of
https://github.com/Nezumi-2711/astrbot_plugin_qq_group_daily_analysis.git
synced 2026-09-22 20:01:04 +00:00
feat(增量分析): 添加增量LLM并发分析方法和分析器最大数量覆盖机制
This commit is contained in:
@@ -32,6 +32,8 @@ class BaseAnalyzer(ABC):
|
||||
"""
|
||||
self.context = context
|
||||
self.config_manager = config_manager
|
||||
# 增量分析模式下的最大数量覆盖值,为 None 时使用配置默认值
|
||||
self._incremental_max_count: int | None = None
|
||||
|
||||
def get_provider_id_key(self) -> str:
|
||||
"""
|
||||
|
||||
@@ -27,7 +27,9 @@ class GoldenQuoteAnalyzer(BaseAnalyzer):
|
||||
return "金句"
|
||||
|
||||
def get_max_count(self) -> int:
|
||||
"""获取最大金句数量"""
|
||||
"""获取最大金句数量,增量模式下使用覆盖值"""
|
||||
if self._incremental_max_count is not None:
|
||||
return self._incremental_max_count
|
||||
return self.config_manager.get_max_golden_quotes()
|
||||
|
||||
def get_max_tokens(self) -> int:
|
||||
|
||||
@@ -28,7 +28,9 @@ class TopicAnalyzer(BaseAnalyzer):
|
||||
return "话题"
|
||||
|
||||
def get_max_count(self) -> int:
|
||||
"""获取最大话题数量"""
|
||||
"""获取最大话题数量,增量模式下使用覆盖值"""
|
||||
if self._incremental_max_count is not None:
|
||||
return self._incremental_max_count
|
||||
return self.config_manager.get_max_topics()
|
||||
|
||||
def get_max_tokens(self) -> int:
|
||||
|
||||
@@ -191,28 +191,7 @@ class LLMAnalyzer:
|
||||
|
||||
# 保存原始消息数据 (Debug Mode)
|
||||
if self.config_manager.get_debug_mode():
|
||||
# ... (保持原有的调试保存代码)
|
||||
try:
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from astrbot.core.utils.astrbot_path import (
|
||||
get_astrbot_plugin_data_path,
|
||||
)
|
||||
|
||||
plugin_name = "astrbot_plugin_qq_group_daily_analysis"
|
||||
base_data_path = get_astrbot_plugin_data_path()
|
||||
if isinstance(base_data_path, str):
|
||||
base_data_path = Path(base_data_path)
|
||||
|
||||
debug_dir = base_data_path / plugin_name / "debug_data"
|
||||
debug_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
msg_file_path = debug_dir / f"{session_id}_messages.json"
|
||||
with open(msg_file_path, "w", encoding="utf-8") as f:
|
||||
json.dump(messages, f, ensure_ascii=False, indent=2)
|
||||
except Exception:
|
||||
pass
|
||||
self._save_debug_messages(messages, session_id)
|
||||
|
||||
# 构建并发任务列表
|
||||
tasks = []
|
||||
@@ -285,6 +264,130 @@ class LLMAnalyzer:
|
||||
logger.error(f"并发分析失败: {e}")
|
||||
return [], [], [], TokenUsage()
|
||||
|
||||
async def analyze_incremental_concurrent(
|
||||
self,
|
||||
messages: list[dict],
|
||||
umo: str = None,
|
||||
topics_per_batch: int = 3,
|
||||
quotes_per_batch: int = 3,
|
||||
) -> tuple[list[SummaryTopic], list[GoldenQuote], TokenUsage]:
|
||||
"""
|
||||
增量分析模式的并发执行方法。
|
||||
仅执行话题分析和金句分析(用户称号分析在最终报告时执行),
|
||||
使用较小的批次数量以控制单次分析的输出规模。
|
||||
|
||||
Args:
|
||||
messages: 本次增量分析的群聊消息列表
|
||||
umo: 模型唯一标识符
|
||||
topics_per_batch: 本次批次最大话题数量
|
||||
quotes_per_batch: 本次批次最大金句数量
|
||||
|
||||
Returns:
|
||||
(话题列表, 金句列表, 总Token使用统计)
|
||||
"""
|
||||
try:
|
||||
from datetime import datetime
|
||||
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
if umo:
|
||||
safe_umo = umo.replace(":", "_")
|
||||
session_id = f"incr_{timestamp}_{safe_umo}"
|
||||
else:
|
||||
session_id = f"incr_{timestamp}"
|
||||
|
||||
logger.info(
|
||||
f"开始增量并发分析 (话题上限:{topics_per_batch}, 金句上限:{quotes_per_batch}),"
|
||||
f"消息数量: {len(messages)},会话ID: {session_id}"
|
||||
)
|
||||
|
||||
# 保存原始消息数据 (Debug Mode)
|
||||
if self.config_manager.get_debug_mode():
|
||||
self._save_debug_messages(messages, session_id)
|
||||
|
||||
# 设置增量模式的最大数量覆盖值
|
||||
self.topic_analyzer._incremental_max_count = topics_per_batch
|
||||
self.golden_quote_analyzer._incremental_max_count = quotes_per_batch
|
||||
|
||||
try:
|
||||
# 构建并发任务列表(仅话题和金句,不包含用户称号)
|
||||
tasks = [
|
||||
self.topic_analyzer.analyze_topics(messages, umo, session_id),
|
||||
self.golden_quote_analyzer.analyze_golden_quotes(
|
||||
messages, umo, session_id
|
||||
),
|
||||
]
|
||||
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
# 处理结果
|
||||
topics, topic_usage = [], TokenUsage()
|
||||
golden_quotes, quote_usage = [], TokenUsage()
|
||||
|
||||
# 话题分析结果
|
||||
if isinstance(results[0], Exception):
|
||||
logger.error(f"增量话题分析失败: {results[0]}")
|
||||
else:
|
||||
topics, topic_usage = results[0]
|
||||
|
||||
# 金句分析结果
|
||||
if isinstance(results[1], Exception):
|
||||
logger.error(f"增量金句分析失败: {results[1]}")
|
||||
else:
|
||||
golden_quotes, quote_usage = results[1]
|
||||
|
||||
# 合并Token使用统计
|
||||
total_usage = TokenUsage(
|
||||
prompt_tokens=topic_usage.prompt_tokens + quote_usage.prompt_tokens,
|
||||
completion_tokens=topic_usage.completion_tokens
|
||||
+ quote_usage.completion_tokens,
|
||||
total_tokens=topic_usage.total_tokens + quote_usage.total_tokens,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"增量并发分析完成 - 话题: {len(topics)}, 金句: {len(golden_quotes)}, "
|
||||
f"Token消耗: {total_usage.total_tokens}"
|
||||
)
|
||||
return topics, golden_quotes, total_usage
|
||||
|
||||
finally:
|
||||
# 无论成功或失败,都要恢复原始的最大数量设置
|
||||
self.topic_analyzer._incremental_max_count = None
|
||||
self.golden_quote_analyzer._incremental_max_count = None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"增量并发分析失败: {e}", exc_info=True)
|
||||
return [], [], TokenUsage()
|
||||
|
||||
def _save_debug_messages(self, messages: list[dict], session_id: str):
|
||||
"""
|
||||
保存调试消息数据到文件(Debug Mode 专用)
|
||||
|
||||
Args:
|
||||
messages: 群聊消息列表
|
||||
session_id: 会话ID
|
||||
"""
|
||||
try:
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from astrbot.core.utils.astrbot_path import (
|
||||
get_astrbot_plugin_data_path,
|
||||
)
|
||||
|
||||
plugin_name = "astrbot_plugin_qq_group_daily_analysis"
|
||||
base_data_path = get_astrbot_plugin_data_path()
|
||||
if isinstance(base_data_path, str):
|
||||
base_data_path = Path(base_data_path)
|
||||
|
||||
debug_dir = base_data_path / plugin_name / "debug_data"
|
||||
debug_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
msg_file_path = debug_dir / f"{session_id}_messages.json"
|
||||
with open(msg_file_path, "w", encoding="utf-8") as f:
|
||||
json.dump(messages, f, ensure_ascii=False, indent=2)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 向后兼容的方法,保持原有调用方式
|
||||
async def _call_provider_with_retry(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user