mirror of
https://github.com/Nezumi-2711/astrbot_plugin_qq_group_daily_analysis.git
synced 2026-09-22 13:38:43 +00:00
Refactor: Translate comments and logs to Chinese in application layer
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
"""
|
"""
|
||||||
Message Converter - Bridges raw platform messages to UnifiedMessage
|
消息转换器 - 连接原始平台消息和 UnifiedMessage
|
||||||
|
|
||||||
This module provides backward compatibility by converting between
|
该模块通过在原始平台消息格式和新的 UnifiedMessage 格式之间进行转换,
|
||||||
raw platform message formats and the new UnifiedMessage format.
|
提供向后兼容性。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import List, Dict, Any, Optional
|
from typing import List, Dict, Any, Optional
|
||||||
@@ -17,29 +17,29 @@ from ..domain.value_objects.unified_message import (
|
|||||||
|
|
||||||
class MessageConverter:
|
class MessageConverter:
|
||||||
"""
|
"""
|
||||||
Converts between raw platform messages and UnifiedMessage format.
|
在原始平台消息和 UnifiedMessage 格式之间进行转换。
|
||||||
|
|
||||||
This provides a migration path: existing code can continue using
|
这提供了一个迁移路径:现有代码可以继续使用原始字典,
|
||||||
raw dicts while new code uses UnifiedMessage.
|
而新代码使用 UnifiedMessage。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_onebot_message(raw_msg: dict, group_id: str) -> Optional[UnifiedMessage]:
|
def from_onebot_message(raw_msg: dict, group_id: str) -> Optional[UnifiedMessage]:
|
||||||
"""
|
"""
|
||||||
Convert OneBot v11 raw message to UnifiedMessage.
|
将 OneBot v11 原始消息转换为 UnifiedMessage。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
raw_msg: Raw message dict from OneBot API
|
raw_msg: 来自 OneBot API 的原始消息字典
|
||||||
group_id: Group ID
|
group_id: 群组 ID
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
UnifiedMessage or None if conversion fails
|
UnifiedMessage 或 None(如果转换失败)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
sender = raw_msg.get("sender", {})
|
sender = raw_msg.get("sender", {})
|
||||||
message_chain = raw_msg.get("message", [])
|
message_chain = raw_msg.get("message", [])
|
||||||
|
|
||||||
# Handle string message format
|
# 处理字符串消息格式
|
||||||
if isinstance(message_chain, str):
|
if isinstance(message_chain, str):
|
||||||
message_chain = [{"type": "text", "data": {"text": message_chain}}]
|
message_chain = [{"type": "text", "data": {"text": message_chain}}]
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ class MessageConverter:
|
|||||||
raw_data=seg
|
raw_data=seg
|
||||||
))
|
))
|
||||||
|
|
||||||
# Extract reply_to from contents
|
# 从内容中提取 reply_to
|
||||||
reply_to = None
|
reply_to = None
|
||||||
for c in contents:
|
for c in contents:
|
||||||
if c.type == MessageContentType.REPLY and c.raw_data:
|
if c.type == MessageContentType.REPLY and c.raw_data:
|
||||||
@@ -130,9 +130,9 @@ class MessageConverter:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def to_onebot_message(unified: UnifiedMessage) -> dict:
|
def to_onebot_message(unified: UnifiedMessage) -> dict:
|
||||||
"""
|
"""
|
||||||
Convert UnifiedMessage back to OneBot v11 raw format.
|
将 UnifiedMessage 转换回 OneBot v11 原始格式。
|
||||||
|
|
||||||
For backward compatibility with existing code that expects raw dicts.
|
用于与期望原始字典的现有代码向后兼容。
|
||||||
"""
|
"""
|
||||||
message_chain = []
|
message_chain = []
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ class MessageConverter:
|
|||||||
elif content.type == MessageContentType.VIDEO:
|
elif content.type == MessageContentType.VIDEO:
|
||||||
message_chain.append({"type": "video", "data": {"url": content.url}})
|
message_chain.append({"type": "video", "data": {"url": content.url}})
|
||||||
|
|
||||||
# Ensure sender fields are populated, even if missing in original
|
# 确保填充发送者字段,即使原始数据中缺失
|
||||||
sender_data = {
|
sender_data = {
|
||||||
"user_id": unified.sender_id,
|
"user_id": unified.sender_id,
|
||||||
"nickname": unified.sender_name,
|
"nickname": unified.sender_name,
|
||||||
@@ -167,14 +167,14 @@ class MessageConverter:
|
|||||||
"group_id": unified.group_id,
|
"group_id": unified.group_id,
|
||||||
"message": message_chain,
|
"message": message_chain,
|
||||||
"time": unified.timestamp,
|
"time": unified.timestamp,
|
||||||
# Add these helper fields for old analyzers that might expect them directly
|
# 添加这些辅助字段,以便旧分析器可以直接使用
|
||||||
"raw_message": unified.text_content,
|
"raw_message": unified.text_content,
|
||||||
"user_id": unified.sender_id,
|
"user_id": unified.sender_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def batch_from_onebot(raw_messages: List[dict], group_id: str) -> List[UnifiedMessage]:
|
def batch_from_onebot(raw_messages: List[dict], group_id: str) -> List[UnifiedMessage]:
|
||||||
"""Convert a batch of OneBot messages to UnifiedMessage list."""
|
"""将一批 OneBot 消息转换为 UnifiedMessage 列表。"""
|
||||||
result = []
|
result = []
|
||||||
for raw_msg in raw_messages:
|
for raw_msg in raw_messages:
|
||||||
unified = MessageConverter.from_onebot_message(raw_msg, group_id)
|
unified = MessageConverter.from_onebot_message(raw_msg, group_id)
|
||||||
@@ -184,15 +184,15 @@ class MessageConverter:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def batch_to_onebot(unified_messages: List[UnifiedMessage]) -> List[dict]:
|
def batch_to_onebot(unified_messages: List[UnifiedMessage]) -> List[dict]:
|
||||||
"""Convert a batch of UnifiedMessage to OneBot raw format."""
|
"""将一批 UnifiedMessage 转换为 OneBot 原始格式。"""
|
||||||
return [MessageConverter.to_onebot_message(msg) for msg in unified_messages]
|
return [MessageConverter.to_onebot_message(msg) for msg in unified_messages]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unified_to_analysis_text(messages: List[UnifiedMessage]) -> str:
|
def unified_to_analysis_text(messages: List[UnifiedMessage]) -> str:
|
||||||
"""
|
"""
|
||||||
Convert UnifiedMessage list to analysis text format for LLM.
|
将 UnifiedMessage 列表转换为 LLM 分析文本格式。
|
||||||
|
|
||||||
This is the format expected by the existing LLM analyzers.
|
这是现有 LLM 分析器期望的格式。
|
||||||
"""
|
"""
|
||||||
lines = []
|
lines = []
|
||||||
for msg in messages:
|
for msg in messages:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Reporting Service - Application service for generating and sending reports
|
报告服务 - 生成和发送报告的应用服务
|
||||||
|
|
||||||
This service coordinates report generation and delivery to groups.
|
该服务协调报告的生成并将其发送到群组。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -20,10 +20,10 @@ from ..infrastructure.persistence import HistoryRepository
|
|||||||
|
|
||||||
class ReportingService:
|
class ReportingService:
|
||||||
"""
|
"""
|
||||||
Application service for generating and managing reports.
|
生成和管理报告的应用服务。
|
||||||
|
|
||||||
This service coordinates between domain services and infrastructure
|
该服务协调领域服务和基础设施
|
||||||
to produce and deliver analysis reports.
|
以生成和发送分析报告。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -32,11 +32,11 @@ class ReportingService:
|
|||||||
history_repository: HistoryRepository,
|
history_repository: HistoryRepository,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Initialize the reporting service.
|
初始化报告服务。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
config: Configuration manager
|
config: 配置管理器
|
||||||
history_repository: Repository for storing reports
|
history_repository: 用于存储报告的仓库
|
||||||
"""
|
"""
|
||||||
self.config = config
|
self.config = config
|
||||||
self.history = history_repository
|
self.history = history_repository
|
||||||
@@ -52,19 +52,19 @@ class ReportingService:
|
|||||||
date_str: Optional[str] = None,
|
date_str: Optional[str] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a complete analysis report.
|
生成完整的分析报告。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
group_id: Group identifier
|
group_id: 群组标识符
|
||||||
group_name: Group display name
|
group_name: 群组显示名称
|
||||||
statistics: Group statistics
|
statistics: 群组统计
|
||||||
topics: List of discussion topics
|
topics: 讨论话题列表
|
||||||
user_titles: List of user titles
|
user_titles: 用户称号列表
|
||||||
golden_quotes: List of golden quotes
|
golden_quotes: 金句列表
|
||||||
date_str: Report date (defaults to today)
|
date_str: 报告日期(默认为今天)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Formatted report string
|
格式化的报告字符串
|
||||||
"""
|
"""
|
||||||
date_str = date_str or datetime.now().strftime("%Y-%m-%d")
|
date_str = date_str or datetime.now().strftime("%Y-%m-%d")
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ class ReportingService:
|
|||||||
date_str=date_str,
|
date_str=date_str,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate report based on configuration
|
# 根据配置生成报告
|
||||||
report = generator.generate_full_report(
|
report = generator.generate_full_report(
|
||||||
statistics=statistics,
|
statistics=statistics,
|
||||||
topics=topics if self.config.get_include_topics() else [],
|
topics=topics if self.config.get_include_topics() else [],
|
||||||
@@ -94,17 +94,17 @@ class ReportingService:
|
|||||||
date_str: Optional[str] = None,
|
date_str: Optional[str] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Generate a brief summary report.
|
生成简要摘要报告。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
group_id: Group identifier
|
group_id: 群组标识符
|
||||||
statistics: Group statistics
|
statistics: 群组统计
|
||||||
top_topic: Most significant topic
|
top_topic: 最重要的话题
|
||||||
top_quote: Best golden quote
|
top_quote: 最佳金句
|
||||||
date_str: Report date
|
date_str: 报告日期
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Brief summary string
|
简要摘要字符串
|
||||||
"""
|
"""
|
||||||
date_str = date_str or datetime.now().strftime("%Y-%m-%d")
|
date_str = date_str or datetime.now().strftime("%Y-%m-%d")
|
||||||
|
|
||||||
@@ -122,15 +122,15 @@ class ReportingService:
|
|||||||
date_str: Optional[str] = None,
|
date_str: Optional[str] = None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Save a report to history.
|
保存报告到历史记录。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
group_id: Group identifier
|
group_id: 群组标识符
|
||||||
report_data: Report data dictionary
|
report_data: 报告数据字典
|
||||||
date_str: Report date
|
date_str: 报告日期
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if saved successfully
|
如果保存成功则返回 True
|
||||||
"""
|
"""
|
||||||
date_str = date_str or datetime.now().strftime("%Y-%m-%d")
|
date_str = date_str or datetime.now().strftime("%Y-%m-%d")
|
||||||
|
|
||||||
@@ -146,14 +146,14 @@ class ReportingService:
|
|||||||
date_str: str,
|
date_str: str,
|
||||||
) -> Optional[Dict[str, Any]]:
|
) -> Optional[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Get a saved report.
|
获取已保存的报告。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
group_id: Group identifier
|
group_id: 群组标识符
|
||||||
date_str: Report date
|
date_str: 报告日期
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Report data or None
|
报告数据或 None
|
||||||
"""
|
"""
|
||||||
return self.history.get_analysis_result(group_id, date_str)
|
return self.history.get_analysis_result(group_id, date_str)
|
||||||
|
|
||||||
@@ -163,26 +163,26 @@ class ReportingService:
|
|||||||
limit: int = 7,
|
limit: int = 7,
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Get recent reports for a group.
|
获取群组的最近报告。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
group_id: Group identifier
|
group_id: 群组标识符
|
||||||
limit: Maximum number of reports
|
limit: 最大报告数
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of report data dictionaries
|
报告数据字典列表
|
||||||
"""
|
"""
|
||||||
return self.history.get_recent_results(group_id, limit)
|
return self.history.get_recent_results(group_id, limit)
|
||||||
|
|
||||||
def has_report_for_today(self, group_id: str) -> bool:
|
def has_report_for_today(self, group_id: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if a report exists for today.
|
检查今天是否已存在报告。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
group_id: Group identifier
|
group_id: 群组标识符
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if report exists
|
如果报告存在则返回 True
|
||||||
"""
|
"""
|
||||||
today = datetime.now().strftime("%Y-%m-%d")
|
today = datetime.now().strftime("%Y-%m-%d")
|
||||||
return self.history.has_analysis_for_date(group_id, today)
|
return self.history.has_analysis_for_date(group_id, today)
|
||||||
@@ -194,37 +194,37 @@ class ReportingService:
|
|||||||
format_type: Optional[str] = None,
|
format_type: Optional[str] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Format a report for a specific platform.
|
为特定平台格式化报告。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
report: Raw report text
|
report: 原始报告文本
|
||||||
platform: Target platform
|
platform: 目标平台
|
||||||
format_type: Override format type
|
format_type: 覆盖格式类型
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Platform-formatted report
|
平台格式化的报告
|
||||||
"""
|
"""
|
||||||
format_type = format_type or self.config.get_report_format()
|
format_type = format_type or self.config.get_report_format()
|
||||||
|
|
||||||
# For now, return as-is. Can be extended for platform-specific formatting
|
# 目前保持原样返回。可以扩展为平台特定的格式化
|
||||||
if format_type == "markdown":
|
if format_type == "markdown":
|
||||||
return report
|
return report
|
||||||
elif format_type == "text":
|
elif format_type == "text":
|
||||||
# Strip markdown formatting
|
# 去除 markdown 格式
|
||||||
return self._strip_markdown(report)
|
return self._strip_markdown(report)
|
||||||
else:
|
else:
|
||||||
return report
|
return report
|
||||||
|
|
||||||
def _strip_markdown(self, text: str) -> str:
|
def _strip_markdown(self, text: str) -> str:
|
||||||
"""Strip markdown formatting from text."""
|
"""从文本中去除 markdown 格式。"""
|
||||||
# Simple markdown stripping
|
# 简单的 markdown 去除
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# Remove bold
|
# 去除加粗
|
||||||
text = re.sub(r"\*\*(.*?)\*\*", r"\1", text)
|
text = re.sub(r"\*\*(.*?)\*\*", r"\1", text)
|
||||||
# Remove italic
|
# 去除斜体
|
||||||
text = re.sub(r"\*(.*?)\*", r"\1", text)
|
text = re.sub(r"\*(.*?)\*", r"\1", text)
|
||||||
# Remove headers
|
# 去除标题
|
||||||
text = re.sub(r"^#+\s*", "", text, flags=re.MULTILINE)
|
text = re.sub(r"^#+\s*", "", text, flags=re.MULTILINE)
|
||||||
|
|
||||||
return text
|
return text
|
||||||
@@ -239,18 +239,18 @@ class ReportingService:
|
|||||||
golden_quotes: List[GoldenQuote],
|
golden_quotes: List[GoldenQuote],
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Create a report data dictionary for storage.
|
创建用于存储的报告数据字典。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
group_id: Group identifier
|
group_id: 群组标识符
|
||||||
group_name: Group display name
|
group_name: 群组显示名称
|
||||||
statistics: Group statistics
|
statistics: 群组统计
|
||||||
topics: List of topics
|
topics: 话题列表
|
||||||
user_titles: List of user titles
|
user_titles: 用户称号列表
|
||||||
golden_quotes: List of golden quotes
|
golden_quotes: 金句列表
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Report data dictionary
|
报告数据字典
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
"group_id": group_id,
|
"group_id": group_id,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
"""
|
"""
|
||||||
Scheduling Service - Application service for scheduled analysis
|
调度服务 - 计划分析的应用服务
|
||||||
|
|
||||||
This service manages scheduled analysis tasks and coordinates
|
该服务管理计划的分析任务并与
|
||||||
with the analysis orchestrator.
|
分析编排器协调。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
@@ -16,13 +16,13 @@ from ..shared.constants import TASK_STATE_PENDING, TASK_STATE_RUNNING, TASK_STAT
|
|||||||
|
|
||||||
|
|
||||||
class ScheduledTask:
|
class ScheduledTask:
|
||||||
"""Represents a scheduled analysis task."""
|
"""表示一个计划的分析任务。"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
task_id: str,
|
task_id: str,
|
||||||
group_id: str,
|
group_id: str,
|
||||||
scheduled_time: str, # HH:MM format
|
scheduled_time: str, # HH:MM 格式
|
||||||
callback: Callable,
|
callback: Callable,
|
||||||
enabled: bool = True,
|
enabled: bool = True,
|
||||||
):
|
):
|
||||||
@@ -36,7 +36,7 @@ class ScheduledTask:
|
|||||||
self._calculate_next_run()
|
self._calculate_next_run()
|
||||||
|
|
||||||
def _calculate_next_run(self) -> None:
|
def _calculate_next_run(self) -> None:
|
||||||
"""Calculate the next run time."""
|
"""计算下一次运行时间。"""
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
self.next_run = None
|
self.next_run = None
|
||||||
return
|
return
|
||||||
@@ -46,50 +46,50 @@ class ScheduledTask:
|
|||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
next_run = now.replace(hour=hours, minute=minutes, second=0, microsecond=0)
|
next_run = now.replace(hour=hours, minute=minutes, second=0, microsecond=0)
|
||||||
|
|
||||||
# If the time has passed today, schedule for tomorrow
|
# 如果今天的时间已过,计划明天运行
|
||||||
if next_run <= now:
|
if next_run <= now:
|
||||||
next_run += timedelta(days=1)
|
next_run += timedelta(days=1)
|
||||||
|
|
||||||
self.next_run = next_run
|
self.next_run = next_run
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.error(f"Invalid scheduled time format: {self.scheduled_time}")
|
logger.error(f"无效的计划时间格式: {self.scheduled_time}")
|
||||||
self.next_run = None
|
self.next_run = None
|
||||||
|
|
||||||
def should_run(self) -> bool:
|
def should_run(self) -> bool:
|
||||||
"""Check if the task should run now."""
|
"""检查任务现在是否应该运行。"""
|
||||||
if not self.enabled or not self.next_run:
|
if not self.enabled or not self.next_run:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
|
|
||||||
# Check if we're within the execution window (5 minute tolerance)
|
# 检查我们是否在执行窗口内(5分钟容差)
|
||||||
if self.next_run <= now <= self.next_run + timedelta(minutes=5):
|
if self.next_run <= now <= self.next_run + timedelta(minutes=5):
|
||||||
# Check if we haven't run today
|
# 检查我们今天是否还没有运行
|
||||||
if self.last_run is None or self.last_run.date() != now.date():
|
if self.last_run is None or self.last_run.date() != now.date():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def mark_completed(self) -> None:
|
def mark_completed(self) -> None:
|
||||||
"""Mark the task as completed and schedule next run."""
|
"""将任务标记为完成并计划下一次运行。"""
|
||||||
self.last_run = datetime.now()
|
self.last_run = datetime.now()
|
||||||
self._calculate_next_run()
|
self._calculate_next_run()
|
||||||
|
|
||||||
|
|
||||||
class SchedulingService:
|
class SchedulingService:
|
||||||
"""
|
"""
|
||||||
Application service for managing scheduled analysis tasks.
|
管理计划分析任务的应用服务。
|
||||||
|
|
||||||
This service runs a background loop that checks for and
|
该服务运行一个后台循环,检查并
|
||||||
executes scheduled tasks.
|
执行计划的任务。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, config: ConfigManager):
|
def __init__(self, config: ConfigManager):
|
||||||
"""
|
"""
|
||||||
Initialize the scheduling service.
|
初始化调度服务。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
config: Configuration manager
|
config: 配置管理器
|
||||||
"""
|
"""
|
||||||
self.config = config
|
self.config = config
|
||||||
self._tasks: Dict[str, ScheduledTask] = {}
|
self._tasks: Dict[str, ScheduledTask] = {}
|
||||||
@@ -99,11 +99,11 @@ class SchedulingService:
|
|||||||
|
|
||||||
def register_callback(self, name: str, callback: Callable) -> None:
|
def register_callback(self, name: str, callback: Callable) -> None:
|
||||||
"""
|
"""
|
||||||
Register a callback for scheduled tasks.
|
为计划任务注册回调。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name: Callback name
|
name: 回调名称
|
||||||
callback: Async callback function
|
callback: 异步回调函数
|
||||||
"""
|
"""
|
||||||
self._callbacks[name] = callback
|
self._callbacks[name] = callback
|
||||||
|
|
||||||
@@ -114,22 +114,22 @@ class SchedulingService:
|
|||||||
callback_name: str = "analyze",
|
callback_name: str = "analyze",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Add a scheduled task for a group.
|
为群组添加计划任务。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
group_id: Group identifier
|
group_id: 群组标识符
|
||||||
scheduled_time: Time in HH:MM format (uses config default if not provided)
|
scheduled_time: HH:MM 格式的时间(如果未提供,则使用配置默认值)
|
||||||
callback_name: Name of registered callback to use
|
callback_name: 要使用的注册回调的名称
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Task ID
|
任务 ID
|
||||||
"""
|
"""
|
||||||
scheduled_time = scheduled_time or self.config.get_analysis_time()
|
scheduled_time = scheduled_time or self.config.get_analysis_time()
|
||||||
task_id = f"task_{group_id}"
|
task_id = f"task_{group_id}"
|
||||||
|
|
||||||
callback = self._callbacks.get(callback_name)
|
callback = self._callbacks.get(callback_name)
|
||||||
if not callback:
|
if not callback:
|
||||||
logger.warning(f"Callback '{callback_name}' not registered")
|
logger.warning(f"回调 '{callback_name}' 未注册")
|
||||||
return task_id
|
return task_id
|
||||||
|
|
||||||
task = ScheduledTask(
|
task = ScheduledTask(
|
||||||
@@ -141,28 +141,28 @@ class SchedulingService:
|
|||||||
)
|
)
|
||||||
|
|
||||||
self._tasks[task_id] = task
|
self._tasks[task_id] = task
|
||||||
logger.info(f"Added scheduled task {task_id} for {scheduled_time}")
|
logger.info(f"为 {scheduled_time} 添加了计划任务 {task_id}")
|
||||||
|
|
||||||
return task_id
|
return task_id
|
||||||
|
|
||||||
def remove_task(self, task_id: str) -> bool:
|
def remove_task(self, task_id: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Remove a scheduled task.
|
移除计划任务。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
task_id: Task identifier
|
task_id: 任务标识符
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if task was removed
|
如果任务被移除则返回 True
|
||||||
"""
|
"""
|
||||||
if task_id in self._tasks:
|
if task_id in self._tasks:
|
||||||
del self._tasks[task_id]
|
del self._tasks[task_id]
|
||||||
logger.info(f"Removed scheduled task {task_id}")
|
logger.info(f"移除了计划任务 {task_id}")
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def enable_task(self, task_id: str) -> bool:
|
def enable_task(self, task_id: str) -> bool:
|
||||||
"""Enable a scheduled task."""
|
"""启用计划任务。"""
|
||||||
if task_id in self._tasks:
|
if task_id in self._tasks:
|
||||||
self._tasks[task_id].enabled = True
|
self._tasks[task_id].enabled = True
|
||||||
self._tasks[task_id]._calculate_next_run()
|
self._tasks[task_id]._calculate_next_run()
|
||||||
@@ -170,7 +170,7 @@ class SchedulingService:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def disable_task(self, task_id: str) -> bool:
|
def disable_task(self, task_id: str) -> bool:
|
||||||
"""Disable a scheduled task."""
|
"""禁用计划任务。"""
|
||||||
if task_id in self._tasks:
|
if task_id in self._tasks:
|
||||||
self._tasks[task_id].enabled = False
|
self._tasks[task_id].enabled = False
|
||||||
self._tasks[task_id].next_run = None
|
self._tasks[task_id].next_run = None
|
||||||
@@ -179,13 +179,13 @@ class SchedulingService:
|
|||||||
|
|
||||||
def get_task_status(self, task_id: str) -> Optional[Dict[str, Any]]:
|
def get_task_status(self, task_id: str) -> Optional[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Get status of a scheduled task.
|
获取计划任务的状态。
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
task_id: Task identifier
|
task_id: 任务标识符
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Task status dictionary or None
|
任务状态字典或 None
|
||||||
"""
|
"""
|
||||||
task = self._tasks.get(task_id)
|
task = self._tasks.get(task_id)
|
||||||
if not task:
|
if not task:
|
||||||
@@ -201,20 +201,20 @@ class SchedulingService:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def list_tasks(self) -> List[Dict[str, Any]]:
|
def list_tasks(self) -> List[Dict[str, Any]]:
|
||||||
"""List all scheduled tasks."""
|
"""列出所有计划任务。"""
|
||||||
return [self.get_task_status(tid) for tid in self._tasks.keys()]
|
return [self.get_task_status(tid) for tid in self._tasks.keys()]
|
||||||
|
|
||||||
async def start(self) -> None:
|
async def start(self) -> None:
|
||||||
"""Start the scheduling service."""
|
"""启动调度服务。"""
|
||||||
if self._running:
|
if self._running:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._running = True
|
self._running = True
|
||||||
self._task = asyncio.create_task(self._run_loop())
|
self._task = asyncio.create_task(self._run_loop())
|
||||||
logger.info("Scheduling service started")
|
logger.info("调度服务已启动")
|
||||||
|
|
||||||
async def stop(self) -> None:
|
async def stop(self) -> None:
|
||||||
"""Stop the scheduling service."""
|
"""停止调度服务。"""
|
||||||
self._running = False
|
self._running = False
|
||||||
if self._task:
|
if self._task:
|
||||||
self._task.cancel()
|
self._task.cancel()
|
||||||
@@ -222,37 +222,37 @@ class SchedulingService:
|
|||||||
await self._task
|
await self._task
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
pass
|
pass
|
||||||
logger.info("Scheduling service stopped")
|
logger.info("调度服务已停止")
|
||||||
|
|
||||||
async def _run_loop(self) -> None:
|
async def _run_loop(self) -> None:
|
||||||
"""Main scheduling loop."""
|
"""主调度循环。"""
|
||||||
while self._running:
|
while self._running:
|
||||||
try:
|
try:
|
||||||
await self._check_and_run_tasks()
|
await self._check_and_run_tasks()
|
||||||
# Check every minute
|
# 每分钟检查一次
|
||||||
await asyncio.sleep(60)
|
await asyncio.sleep(60)
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error in scheduling loop: {e}")
|
logger.error(f"调度循环出错: {e}")
|
||||||
await asyncio.sleep(60)
|
await asyncio.sleep(60)
|
||||||
|
|
||||||
async def _check_and_run_tasks(self) -> None:
|
async def _check_and_run_tasks(self) -> None:
|
||||||
"""Check for and execute due tasks."""
|
"""检查并执行到期任务。"""
|
||||||
for task in list(self._tasks.values()):
|
for task in list(self._tasks.values()):
|
||||||
if task.should_run():
|
if task.should_run():
|
||||||
try:
|
try:
|
||||||
logger.info(f"Executing scheduled task {task.task_id}")
|
logger.info(f"正在执行计划任务 {task.task_id}")
|
||||||
await task.callback(task.group_id)
|
await task.callback(task.group_id)
|
||||||
task.mark_completed()
|
task.mark_completed()
|
||||||
logger.info(f"Completed scheduled task {task.task_id}")
|
logger.info(f"计划任务 {task.task_id} 已完成")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to execute task {task.task_id}: {e}")
|
logger.error(f"执行任务 {task.task_id} 失败: {e}")
|
||||||
|
|
||||||
def setup_from_config(self) -> None:
|
def setup_from_config(self) -> None:
|
||||||
"""Set up scheduled tasks from configuration."""
|
"""根据配置设置计划任务。"""
|
||||||
if not self.config.get_auto_analysis_enabled():
|
if not self.config.get_auto_analysis_enabled():
|
||||||
logger.info("Auto analysis is disabled")
|
logger.info("自动分析已禁用")
|
||||||
return
|
return
|
||||||
|
|
||||||
enabled_groups = self.config.get_enabled_groups()
|
enabled_groups = self.config.get_enabled_groups()
|
||||||
@@ -261,4 +261,4 @@ class SchedulingService:
|
|||||||
for group_id in enabled_groups:
|
for group_id in enabled_groups:
|
||||||
self.add_task(group_id, analysis_time)
|
self.add_task(group_id, analysis_time)
|
||||||
|
|
||||||
logger.info(f"Set up {len(enabled_groups)} scheduled tasks")
|
logger.info(f"设置了 {len(enabled_groups)} 个计划任务")
|
||||||
|
|||||||
Reference in New Issue
Block a user