Merge pull request #4 from Nezumi-2711/docs/vietnamese-shared-module

docs: Việt hóa tài liệu module shared
This commit is contained in:
2026-07-22 22:59:04 +07:00
committed by GitHub
3 changed files with 101 additions and 87 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
"""
共享模块 - 通用工具和常量
Mô-đun chia sẻ - Công cụ dùng chung và hằng số.
"""
from .constants import ContentType, Platform, ReportFormat, TaskStatus
+27 -25
View File
@@ -1,5 +1,5 @@
"""
常量 - 插件中使用的共享常量
Hằng số - Các hằng số dùng chung trong plugin.
"""
from enum import Enum
@@ -7,9 +7,9 @@ from enum import Enum
class Platform(str, Enum):
"""
支持的聊天平台枚举
Liệt kê các nền tảng trò chuyện được hỗ trợ.
定义了插件适配的所有基础通讯平台标识。
Định nghĩa mã định danh của các nền tảng giao tiếp cơ bản mà plugin hỗ trợ.
"""
ONEBOT = "onebot"
@@ -22,9 +22,10 @@ class Platform(str, Enum):
class TaskStatus(str, Enum):
"""
分析任务执行状态枚举
Liệt kê các trạng thái thực thi của tác vụ phân tích.
用于在异步处理流水线中标记分析任务的生命阶段。
Dùng để đánh dấu giai đoạn trong vòng đời của tác vụ phân tích
thuộc quy trình xử lý bất đồng bộ.
"""
PENDING = "pending"
@@ -36,9 +37,10 @@ class TaskStatus(str, Enum):
class ContentType(str, Enum):
"""
统一消息内容类型枚举
Liệt kê các loại nội dung tin nhắn hợp nhất.
将不同平台(OneBot, Discord 等)的消息片段抽象为统一的类型体系。
Trừu tượng hóa các thành phần tin nhắn từ nhiều nền tảng
(OneBot, Discord, v.v.) thành một hệ thống kiểu thống nhất.
"""
TEXT = "text"
@@ -55,9 +57,9 @@ class ContentType(str, Enum):
class ReportFormat(str, Enum):
"""
分析报告导出格式枚举
Liệt kê các định dạng xuất báo cáo phân tích.
控制最终呈现给用户的报告呈现形式。
Kiểm soát hình thức trình bày báo cáo cuối cùng cho người dùng.
"""
TEXT = "text"
@@ -66,25 +68,25 @@ class ReportFormat(str, Enum):
HTML = "html"
# 插件元数据
# Siêu dữ liệu của plugin
PLUGIN_NAME = "astrbot_plugin_qq_group_daily_analysis"
PLUGIN_VERSION = "2.0.0"
# 平台标识符
# Mã định danh nền tảng
SUPPORTED_PLATFORMS = [
Platform.ONEBOT.value,
Platform.TELEGRAM.value,
Platform.DISCORD.value,
]
# 分析默认值
# Giá trị phân tích mặc định
DEFAULT_MAX_TOPICS = 5
DEFAULT_MAX_USER_TITLES = 10
DEFAULT_MAX_GOLDEN_QUOTES = 5
DEFAULT_MIN_MESSAGES = 50
DEFAULT_MAX_TOKENS = 2000
# 时间段
# Các khoảng thời gian
HOUR_RANGES = {
"morning": (6, 12),
"afternoon": (12, 18),
@@ -92,30 +94,30 @@ HOUR_RANGES = {
"night": (0, 6),
}
# 错误代码
# Mã lỗi
ERROR_INSUFFICIENT_DATA = "INSUFFICIENT_DATA"
ERROR_LLM_FAILED = "LLM_FAILED"
ERROR_PLATFORM_ERROR = "PLATFORM_ERROR"
ERROR_CONFIG_ERROR = "CONFIG_ERROR"
ERROR_TIMEOUT = "TIMEOUT"
# 缓存 TTL(秒)
CACHE_TTL_SHORT = 60 # 1 分钟
CACHE_TTL_MEDIUM = 300 # 5 分钟
CACHE_TTL_LONG = 3600 # 1 小时
CACHE_TTL_DAY = 86400 # 24 小时
# Thời gian tồn tại của bộ nhớ đệm (giây)
CACHE_TTL_SHORT = 60 # 1 phút
CACHE_TTL_MEDIUM = 300 # 5 phút
CACHE_TTL_LONG = 3600 # 1 giờ
CACHE_TTL_DAY = 86400 # 24 giờ
# 速率限制默认值
RATE_LIMIT_LLM_CALLS = 10 # 每分钟调用次数
RATE_LIMIT_API_CALLS = 60 # 每分钟调用次数
RATE_LIMIT_BURST = 5 # 突发大小
# Giá trị giới hạn tốc độ mặc định
RATE_LIMIT_LLM_CALLS = 10 # Số lượt gọi mỗi phút
RATE_LIMIT_API_CALLS = 60 # Số lượt gọi mỗi phút
RATE_LIMIT_BURST = 5 # Quy mô gọi đột biến
# 重试默认值
# Giá trị thử lại mặc định
RETRY_MAX_ATTEMPTS = 3
RETRY_BASE_DELAY = 1.0
RETRY_MAX_DELAY = 30.0
# 文件路径
# Đường dẫn tệp
HISTORY_DIR = "history"
CACHE_DIR = "cache"
TEMP_DIR = "temp"
+73 -61
View File
@@ -1,7 +1,7 @@
"""
追踪上下文 - 请求追踪和关联
Ngữ cảnh truy vết - Theo dõi và liên kết yêu cầu.
提供用于在插件中跟踪请求的上下文。
Cung cấp ngữ cảnh dùng để theo dõi yêu cầu trong plugin.
"""
import functools
@@ -13,14 +13,14 @@ from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Optional
# Trace ID 中群名的最大长度(平衡可读性和日志宽度)
# Độ dài tối đa của tên nhóm trong Trace ID (cân bằng khả năng đọc và độ rộng nhật ký)
_MAX_GROUP_NAME_LEN = 10
# 用于匹配报告 Caption 中去重 Token 的正则模式
# 格式: "| MM-DD HH:MM:SS"
# Mẫu biểu thức chính quy dùng để khớp token khử trùng lặp trong Caption báo cáo
# Định dạng: "| MM-DD HH:MM:SS"
REPORT_CAPTION_PATTERN = re.compile(r"\| (\d{2}-\d{2} \d{2}:\d{2}:\d{2})")
# 当前追踪的上下文变量
# Biến ngữ cảnh đang được truy vết
_current_trace: ContextVar[Optional["TraceContext"]] = ContextVar(
"current_trace", default=None
)
@@ -29,18 +29,20 @@ _current_trace: ContextVar[Optional["TraceContext"]] = ContextVar(
@dataclass
class TraceContext:
"""
核心组件:全链路追踪上下文 (Tracing Context)
Thành phần cốt lõi: ngữ cảnh truy vết toàn bộ chuỗi (Tracing Context).
该组件用于在复杂的异步分析流程中关联日志、耗时统计及元数据。
它不仅提供了 TraceId 的生成与传递,还集成了毫秒级的性能打点(Checkpoint)功能。
Thành phần này liên kết nhật ký, thống kê thời gian thực thi và siêu dữ liệu
trong các quy trình phân tích bất đồng bộ phức tạp.
Ngoài khả năng tạo và truyền Trace ID, thành phần còn tích hợp chức năng
ghi nhận hiệu năng ở độ chính xác mili giây (Checkpoint).
Attributes:
trace_id (str): 链路唯一标识码,默认为 UUID 前 8 位
group_id (str): 当前关联的群组 ID
platform (str): 当前消息所属平台
operation (str): 当前执行的操作名称 (如 'DAILY_ANALYSIS')
start_time (datetime): 追踪开始的具体时刻
metadata (dict[str, Any]): 随链路传递的额外上下文数据
trace_id (str): Mã định danh duy nhất của chuỗi, mặc định là 8 ký tự đầu của UUID.
group_id (str): ID của nhóm đang được liên kết.
platform (str): Nền tảng của tin nhắn hiện tại.
operation (str): Tên thao tác đang thực hiện, ví dụ: 'DAILY_ANALYSIS'.
start_time (datetime): Thời điểm cụ thể bắt đầu truy vết.
metadata (dict[str, Any]): Dữ liệu ngữ cảnh bổ sung được truyền theo chuỗi.
"""
trace_id: str = field(default_factory=lambda: str(uuid.uuid4())[:8])
@@ -50,27 +52,28 @@ class TraceContext:
start_time: datetime = field(default_factory=datetime.now)
metadata: dict[str, Any] = field(default_factory=dict)
# 内部计时器,用于多阶段耗时分析
# Bộ hẹn giờ nội bộ, dùng để phân tích thời gian thực thi qua nhiều giai đoạn
_checkpoints: dict[str, datetime] = field(default_factory=dict, init=False)
def checkpoint(self, name: str) -> None:
"""
在当前时间轴上设置一个命名锚点(打点)。
Đặt một mốc có tên trên trục thời gian hiện tại.
Args:
name (str): 锚点标识符,如 'LLM_REPLY_RECEIVED'
name (str): Mã định danh của mốc, ví dụ: 'LLM_REPLY_RECEIVED'.
"""
self._checkpoints[name] = datetime.now()
def elapsed_ms(self, from_checkpoint: str | None = None) -> float:
"""
计算从开始或指定锚点到当前时刻经过的毫秒数。
Tính số mili giây đã trôi qua từ lúc bắt đầu hoặc từ một mốc chỉ định đến hiện tại.
Args:
from_checkpoint (str, optional): 起始锚点名称。若为 None 则从链路启动时算起。
from_checkpoint (str, optional): Tên mốc bắt đầu. Nếu là None,
tính từ thời điểm chuỗi được khởi tạo.
Returns:
float: 经过的毫秒数
float: Số mili giây đã trôi qua.
"""
start = self.start_time
if from_checkpoint and from_checkpoint in self._checkpoints:
@@ -81,10 +84,11 @@ class TraceContext:
def to_dict(self) -> dict[str, Any]:
"""
将链路快照序列化为字典格式,便于持久化或 JSON 日志输出。
Tuần tự hóa ảnh chụp trạng thái của chuỗi thành dạng từ điển,
thuận tiện cho việc lưu trữ hoặc xuất nhật ký JSON.
Returns:
dict[str, Any]: 序列化后的追踪状态
dict[str, Any]: Trạng thái truy vết sau khi tuần tự hóa.
"""
return {
"trace_id": self.trace_id,
@@ -100,12 +104,12 @@ class TraceContext:
_token: Token | None = field(default=None, init=False, repr=False)
def __enter__(self) -> "TraceContext":
"""进入上下文管理器,将当前实例绑定到当前协程上下文。"""
"""Bước vào trình quản lý ngữ cảnh và liên kết instance hiện tại với ngữ cảnh coroutine."""
self._token = _current_trace.set(self)
return self
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
"""退出上下文管理器,清理绑定状态。"""
"""Thoát khỏi trình quản lý ngữ cảnh và dọn dẹp trạng thái liên kết."""
if self._token:
_current_trace.reset(self._token)
self._token = None
@@ -113,10 +117,11 @@ class TraceContext:
@classmethod
def current(cls) -> Optional["TraceContext"]:
"""
静态获取当前协程活跃的追踪上下文。
Lấy ngữ cảnh truy vết đang hoạt động trong coroutine hiện tại.
Returns:
Optional[TraceContext]: 若当前处于追踪链路中则返回实例,否则返回 None
Optional[TraceContext]: Instance nếu hiện tại đang ở trong chuỗi truy vết,
ngược lại trả về None.
"""
return _current_trace.get()
@@ -129,16 +134,17 @@ class TraceContext:
auto_bind: bool = False,
) -> "TraceContext":
"""
尝试获取现有链路,若不存在则按需创建一个。
Thử lấy chuỗi hiện có; nếu không tồn tại thì tạo một chuỗi mới khi cần.
Args:
group_id (str): 群组 ID
platform (str): 平台名称
operation (str): 操作描述
auto_bind (bool): 若新建,是否自动绑定到当前上下文(仅在 non-with 场景有用,谨慎使用)
group_id (str): ID nhóm.
platform (str): Tên nền tảng.
operation (str): Mô tả thao tác.
auto_bind (bool): Nếu tạo mới, có tự động liên kết với ngữ cảnh hiện tại
hay không (chỉ hữu ích trong trường hợp không dùng with, hãy thận trọng).
Returns:
TraceContext: 活跃或新生成的实例
TraceContext: Instance đang hoạt động hoặc vừa được tạo.
"""
current = cls.current()
if current:
@@ -156,20 +162,21 @@ class TraceContext:
@staticmethod
def generate(prefix: str = "", group_name: str = "") -> str:
"""
生成语义化、易读的追踪 ID。
Tạo Trace ID có ngữ nghĩa và dễ đọc.
格式: {来源}_{群名}_{时间点}
示例: manual_系统交流群_1733
Định dạng: {nguồn}_{tên_nhóm}_{thời_điểm}
Ví dụ: manual_Nhóm_hệ_thống_1733
由于插件存在任务锁 (DuplicateGroupTaskError),确保了一个群同一时间只有一个分析任务,
因此 时间点 (HHmm) 已足够提供唯一性,无需 UUID 缀。
Do plugin có khóa tác vụ (DuplicateGroupTaskError), bảo đảm mỗi nhóm
chỉ có một tác vụ phân tích tại một thời điểm. Vì vậy, thời điểm (HHmm)
đã đủ để tạo tính duy nhất và không cần thêm UUID.
Args:
prefix (str): 来源标识,如 'manual', 'group', 'incr', 'report'
group_name (str): 可选群名,用于日志中快速识别
prefix (str): Mã nguồn, ví dụ: 'manual', 'group', 'incr', 'report'.
group_name (str): Tên nhóm tùy chọn, dùng để nhận diện nhanh trong nhật ký.
Returns:
str: 语义化 TraceID 字符串
str: Chuỗi Trace ID có ngữ nghĩa.
"""
timestamp = datetime.now().strftime("%H%M")
@@ -177,7 +184,7 @@ class TraceContext:
if prefix:
parts.append(prefix)
if group_name:
# 清理:移除空白符和文件系统不安全字符
# Làm sạch: loại bỏ khoảng trắng và các ký tự không an toàn cho hệ thống tệp
safe_name = re.sub(r'[\s\n\r\t/\\:*?"<>|\[\]{}]', "", group_name)
safe_name = safe_name[:_MAX_GROUP_NAME_LEN]
if safe_name:
@@ -189,13 +196,15 @@ class TraceContext:
@staticmethod
def make_report_caption() -> str:
"""
生成整洁的、面向用户的报告 Caption,包含用于去重的隐式时间戳。
Tạo Caption báo cáo gọn gàng hướng đến người dùng,
có chứa dấu thời gian ẩn dùng để khử trùng lặp.
该时间戳用作图片去重检查的 Token。
格式: "📊 每日群聊分析报告已生成 | MM-DD HH:MM:SS"
Dấu thời gian này được dùng làm token kiểm tra trùng lặp hình ảnh.
Định dạng gồm biểu tượng báo cáo, nội dung Caption hiện tại và dấu thời gian
theo mẫu ``MM-DD HH:MM:SS``.
Returns:
str: 报告 Caption 字符串
str: Chuỗi Caption của báo cáo.
"""
ts = datetime.now().strftime("%m-%d %H:%M:%S")
return f"📊 每日群聊分析报告已生成 | {ts}"
@@ -203,29 +212,30 @@ class TraceContext:
@classmethod
def set(cls, trace_id: str) -> None:
"""
[兼容性接口] 直接设置当前上下文的 TraceID
这会创建一个新的 TraceContext 实例并将其推入 ContextVar
[Giao diện tương thích] Đặt trực tiếp Trace ID của ngữ cảnh hiện tại.
Thao tác này tạo một instance TraceContext mới và đưa vào ContextVar.
Args:
trace_id (str): 要设置的追踪 ID 字符串
trace_id (str): Chuỗi Trace ID cần đặt.
"""
ctx = cls(trace_id=trace_id)
# 注意:此处不手动存储 Token,依靠异步任务结束时 ContextVar 的自动清理。
# Lưu ý: không lưu Token thủ công ở đây; dựa vào việc ContextVar tự dọn dẹp
# khi tác vụ bất đồng bộ kết thúc.
_current_trace.set(ctx)
@classmethod
def get(cls) -> str:
"""
[兼容性接口] 获取当前活跃的追踪 ID 字符串。
[Giao diện tương thích] Lấy chuỗi Trace ID đang hoạt động hiện tại.
"""
return get_trace_id()
class TraceLogFilter(logging.Filter):
"""
日志过滤器:自动将当前的 TraceID 注入每一条日志记录中。
Bộ lọc nhật ký: tự động chèn Trace ID hiện tại vào mỗi bản ghi nhật ký.
配合日志格式化字符串 `[%(trace_id)s]` 使用。
Được sử dụng cùng chuỗi định dạng nhật ký `[%(trace_id)s]`.
"""
def filter(self, record: logging.LogRecord) -> bool:
@@ -235,10 +245,11 @@ class TraceLogFilter(logging.Filter):
def get_trace_id() -> str:
"""
便捷接口:快速获取当前活跃的 TraceID 或零时生成一个临时 ID。
Giao diện tiện ích: nhanh chóng lấy Trace ID đang hoạt động,
hoặc tạm thời tạo một ID mới nếu chưa có.
Returns:
str: 8 位十六进制追踪 ID
str: Trace ID hệ thập lục phân gồm 8 ký tự.
"""
trace = TraceContext.current()
if trace:
@@ -252,21 +263,22 @@ def with_trace(
operation: str = "",
):
"""
装饰器:自动为异步函数包裹追踪上下文。
Decorator: tự động bao bọc hàm bất đồng bộ bằng ngữ cảnh truy vết.
Args:
group_id (str): 设置追踪的群组
platform (str): 设置追踪的平台
operation (str): 操作名称,默认为函数名
group_id (str): Nhóm cần truy vết.
platform (str): Nền tảng cần truy vết.
operation (str): Tên thao tác, mặc định là tên hàm.
Returns:
Callable: 装饰后的函数
Callable: Hàm sau khi được trang trí.
"""
def decorator(func):
@functools.wraps(func)
async def wrapper(*args, **kwargs):
# 优先使用装饰器声明的 operation,否则取函数原始名称
# Ưu tiên operation được khai báo trong decorator; nếu không có,
# sử dụng tên gốc của hàm.
op_name = operation or func.__name__
with TraceContext(
group_id=group_id,