mirror of
https://github.com/Nezumi-2711/astrbot_plugin_qq_group_daily_analysis.git
synced 2026-09-23 04:09:59 +00:00
feat: complete DDD Phase 2 - add domain services, infrastructure layers, and shared components
- domain/value_objects: Add Topic, UserTitle, GoldenQuote, Statistics value objects - domain/services: Add StatisticsCalculator, ReportGenerator domain services - domain/exceptions: Add comprehensive domain exception hierarchy - infrastructure/persistence: Add HistoryRepository for data storage - infrastructure/llm: Add LLMClient wrapper for AstrBot providers - infrastructure/config: Add ConfigManager for centralized configuration - infrastructure/resilience: Add CircuitBreaker, RateLimiter, retry utilities - application: Add SchedulingService, ReportingService application services - shared: Add constants and TraceContext for request tracing All imports verified in Docker container.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
Shared Module - Common utilities and constants
|
||||
"""
|
||||
|
||||
from .constants import *
|
||||
from .trace_context import TraceContext
|
||||
|
||||
__all__ = [
|
||||
"TraceContext",
|
||||
# Constants are exported via *
|
||||
]
|
||||
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
Constants - Shared constants used across the plugin
|
||||
"""
|
||||
|
||||
# Plugin metadata
|
||||
PLUGIN_NAME = "astrbot_plugin_qq_group_daily_analysis"
|
||||
PLUGIN_VERSION = "2.0.0"
|
||||
|
||||
# Platform identifiers
|
||||
PLATFORM_ONEBOT = "onebot"
|
||||
PLATFORM_TELEGRAM = "telegram"
|
||||
PLATFORM_DISCORD = "discord"
|
||||
PLATFORM_SLACK = "slack"
|
||||
PLATFORM_LARK = "lark"
|
||||
|
||||
SUPPORTED_PLATFORMS = [
|
||||
PLATFORM_ONEBOT,
|
||||
# Future platforms
|
||||
# PLATFORM_TELEGRAM,
|
||||
# PLATFORM_DISCORD,
|
||||
# PLATFORM_SLACK,
|
||||
# PLATFORM_LARK,
|
||||
]
|
||||
|
||||
# Analysis defaults
|
||||
DEFAULT_MAX_TOPICS = 5
|
||||
DEFAULT_MAX_USER_TITLES = 10
|
||||
DEFAULT_MAX_GOLDEN_QUOTES = 5
|
||||
DEFAULT_MIN_MESSAGES = 50
|
||||
DEFAULT_MAX_TOKENS = 2000
|
||||
|
||||
# Time periods
|
||||
HOUR_RANGES = {
|
||||
"morning": (6, 12),
|
||||
"afternoon": (12, 18),
|
||||
"evening": (18, 24),
|
||||
"night": (0, 6),
|
||||
}
|
||||
|
||||
# Report formats
|
||||
REPORT_FORMAT_TEXT = "text"
|
||||
REPORT_FORMAT_MARKDOWN = "markdown"
|
||||
REPORT_FORMAT_IMAGE = "image"
|
||||
REPORT_FORMAT_HTML = "html"
|
||||
|
||||
# Message content types
|
||||
CONTENT_TYPE_TEXT = "text"
|
||||
CONTENT_TYPE_IMAGE = "image"
|
||||
CONTENT_TYPE_EMOJI = "emoji"
|
||||
CONTENT_TYPE_STICKER = "sticker"
|
||||
CONTENT_TYPE_FILE = "file"
|
||||
CONTENT_TYPE_AUDIO = "audio"
|
||||
CONTENT_TYPE_VIDEO = "video"
|
||||
CONTENT_TYPE_REPLY = "reply"
|
||||
CONTENT_TYPE_AT = "at"
|
||||
CONTENT_TYPE_UNKNOWN = "unknown"
|
||||
|
||||
# Analysis task states
|
||||
TASK_STATE_PENDING = "pending"
|
||||
TASK_STATE_RUNNING = "running"
|
||||
TASK_STATE_COMPLETED = "completed"
|
||||
TASK_STATE_FAILED = "failed"
|
||||
TASK_STATE_CANCELLED = "cancelled"
|
||||
|
||||
# Error codes
|
||||
ERROR_INSUFFICIENT_DATA = "INSUFFICIENT_DATA"
|
||||
ERROR_LLM_FAILED = "LLM_FAILED"
|
||||
ERROR_PLATFORM_ERROR = "PLATFORM_ERROR"
|
||||
ERROR_CONFIG_ERROR = "CONFIG_ERROR"
|
||||
ERROR_TIMEOUT = "TIMEOUT"
|
||||
|
||||
# Cache TTL (in seconds)
|
||||
CACHE_TTL_SHORT = 60 # 1 minute
|
||||
CACHE_TTL_MEDIUM = 300 # 5 minutes
|
||||
CACHE_TTL_LONG = 3600 # 1 hour
|
||||
CACHE_TTL_DAY = 86400 # 24 hours
|
||||
|
||||
# Rate limiting defaults
|
||||
RATE_LIMIT_LLM_CALLS = 10 # calls per minute
|
||||
RATE_LIMIT_API_CALLS = 60 # calls per minute
|
||||
RATE_LIMIT_BURST = 5 # burst size
|
||||
|
||||
# Retry defaults
|
||||
RETRY_MAX_ATTEMPTS = 3
|
||||
RETRY_BASE_DELAY = 1.0
|
||||
RETRY_MAX_DELAY = 30.0
|
||||
|
||||
# File paths
|
||||
HISTORY_DIR = "history"
|
||||
CACHE_DIR = "cache"
|
||||
TEMP_DIR = "temp"
|
||||
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
Trace Context - Request tracing and correlation
|
||||
|
||||
Provides context for tracking requests across the plugin.
|
||||
"""
|
||||
|
||||
import uuid
|
||||
from contextvars import ContextVar
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
# Context variable for current trace
|
||||
_current_trace: ContextVar[Optional["TraceContext"]] = ContextVar(
|
||||
"current_trace", default=None
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TraceContext:
|
||||
"""
|
||||
Context for tracing requests through the plugin.
|
||||
|
||||
Provides correlation IDs and timing information for debugging
|
||||
and monitoring.
|
||||
"""
|
||||
|
||||
trace_id: str = field(default_factory=lambda: str(uuid.uuid4())[:8])
|
||||
group_id: str = ""
|
||||
platform: str = ""
|
||||
operation: str = ""
|
||||
start_time: datetime = field(default_factory=datetime.now)
|
||||
metadata: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
# Timing data
|
||||
_checkpoints: Dict[str, datetime] = field(default_factory=dict, init=False)
|
||||
|
||||
def checkpoint(self, name: str) -> None:
|
||||
"""
|
||||
Record a timing checkpoint.
|
||||
|
||||
Args:
|
||||
name: Checkpoint name
|
||||
"""
|
||||
self._checkpoints[name] = datetime.now()
|
||||
|
||||
def elapsed_ms(self, from_checkpoint: Optional[str] = None) -> float:
|
||||
"""
|
||||
Get elapsed time in milliseconds.
|
||||
|
||||
Args:
|
||||
from_checkpoint: Optional checkpoint to measure from
|
||||
|
||||
Returns:
|
||||
Elapsed time in milliseconds
|
||||
"""
|
||||
start = self.start_time
|
||||
if from_checkpoint and from_checkpoint in self._checkpoints:
|
||||
start = self._checkpoints[from_checkpoint]
|
||||
|
||||
delta = datetime.now() - start
|
||||
return delta.total_seconds() * 1000
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Convert trace context to dictionary."""
|
||||
return {
|
||||
"trace_id": self.trace_id,
|
||||
"group_id": self.group_id,
|
||||
"platform": self.platform,
|
||||
"operation": self.operation,
|
||||
"start_time": self.start_time.isoformat(),
|
||||
"elapsed_ms": self.elapsed_ms(),
|
||||
"metadata": self.metadata,
|
||||
"checkpoints": {k: v.isoformat() for k, v in self._checkpoints.items()},
|
||||
}
|
||||
|
||||
def __enter__(self) -> "TraceContext":
|
||||
"""Enter context manager."""
|
||||
_current_trace.set(self)
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
||||
"""Exit context manager."""
|
||||
_current_trace.set(None)
|
||||
|
||||
@classmethod
|
||||
def current(cls) -> Optional["TraceContext"]:
|
||||
"""Get the current trace context."""
|
||||
return _current_trace.get()
|
||||
|
||||
@classmethod
|
||||
def get_or_create(
|
||||
cls,
|
||||
group_id: str = "",
|
||||
platform: str = "",
|
||||
operation: str = "",
|
||||
) -> "TraceContext":
|
||||
"""
|
||||
Get current trace or create a new one.
|
||||
|
||||
Args:
|
||||
group_id: Group identifier
|
||||
platform: Platform name
|
||||
operation: Operation name
|
||||
|
||||
Returns:
|
||||
TraceContext instance
|
||||
"""
|
||||
current = cls.current()
|
||||
if current:
|
||||
return current
|
||||
|
||||
return cls(
|
||||
group_id=group_id,
|
||||
platform=platform,
|
||||
operation=operation,
|
||||
)
|
||||
|
||||
|
||||
def get_trace_id() -> str:
|
||||
"""
|
||||
Get current trace ID or generate a new one.
|
||||
|
||||
Returns:
|
||||
Trace ID string
|
||||
"""
|
||||
trace = TraceContext.current()
|
||||
if trace:
|
||||
return trace.trace_id
|
||||
return str(uuid.uuid4())[:8]
|
||||
|
||||
|
||||
def with_trace(
|
||||
group_id: str = "",
|
||||
platform: str = "",
|
||||
operation: str = "",
|
||||
):
|
||||
"""
|
||||
Decorator to add trace context to a function.
|
||||
|
||||
Args:
|
||||
group_id: Group identifier
|
||||
platform: Platform name
|
||||
operation: Operation name
|
||||
|
||||
Returns:
|
||||
Decorated function
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
async def wrapper(*args, **kwargs):
|
||||
with TraceContext(
|
||||
group_id=group_id,
|
||||
platform=platform,
|
||||
operation=operation or func.__name__,
|
||||
):
|
||||
return await func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
Reference in New Issue
Block a user