refactor: 完成 0.4.0 版本更新
完成 0.4.0 版本更新, 为了消除此前提交消息风格不一致与错误提交超大文件的问题, 维持代码统计数据的准确性和提交消息风格的一致性, 重新初始化仓库; 旧的提交历史在 HeurAMS-legacy 仓库(https://gitea.imwangzhiyu.xyz/ajax/HeurAMS-legacy)
This commit is contained in:
2
src/heurams/services/README.md
Normal file
2
src/heurams/services/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# Services - 服务
|
||||
基础服务相关代码
|
||||
12
src/heurams/services/audio_service.py
Normal file
12
src/heurams/services/audio_service.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# 音频服务
|
||||
from heurams.context import config_var
|
||||
from heurams.providers.audio import providers as prov
|
||||
from typing import Callable
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
play_by_path: Callable = prov[config_var.get()["services"]["audio"]].play_by_path
|
||||
logger.debug(
|
||||
"音频服务初始化完成, 使用 provider: %s", config_var.get()["services"]["audio"]
|
||||
)
|
||||
55
src/heurams/services/config.py
Normal file
55
src/heurams/services/config.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# 配置文件服务
|
||||
import pathlib
|
||||
import toml
|
||||
import typing
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
|
||||
class ConfigFile:
|
||||
def __init__(self, path: pathlib.Path):
|
||||
self.logger = get_logger(__name__)
|
||||
self.path = path
|
||||
if not self.path.exists():
|
||||
self.path.touch()
|
||||
self.logger.debug("创建配置文件: %s", self.path)
|
||||
self.data = dict()
|
||||
self._load()
|
||||
|
||||
def _load(self):
|
||||
"""从文件加载配置数据"""
|
||||
with open(self.path, "r") as f:
|
||||
try:
|
||||
self.data = toml.load(f)
|
||||
self.logger.debug("配置文件加载成功: %s", self.path)
|
||||
except toml.TomlDecodeError as e:
|
||||
print(f"{e}")
|
||||
self.logger.error("TOML解析错误: %s", e)
|
||||
self.data = {}
|
||||
|
||||
def modify(self, key: str, value: typing.Any):
|
||||
"""修改配置值并保存"""
|
||||
self.data[key] = value
|
||||
self.logger.debug("修改配置项: %s = %s", key, value)
|
||||
self.save()
|
||||
|
||||
def save(self, path: typing.Union[str, pathlib.Path] = ""):
|
||||
"""保存配置到文件"""
|
||||
save_path = pathlib.Path(path) if path else self.path
|
||||
with open(save_path, "w") as f:
|
||||
toml.dump(self.data, f)
|
||||
self.logger.debug("配置文件已保存: %s", save_path)
|
||||
|
||||
def get(self, key: str, default: typing.Any = None) -> typing.Any:
|
||||
"""获取配置值, 如果不存在返回默认值"""
|
||||
return self.data.get(key, default)
|
||||
|
||||
def __getitem__(self, key: str) -> typing.Any:
|
||||
return self.data[key]
|
||||
|
||||
def __setitem__(self, key: str, value: typing.Any):
|
||||
self.data[key] = value
|
||||
self.save()
|
||||
|
||||
def __contains__(self, key: str) -> bool:
|
||||
"""支持 in 语法"""
|
||||
return key in self.data
|
||||
19
src/heurams/services/hasher.py
Normal file
19
src/heurams/services/hasher.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# 哈希服务
|
||||
import hashlib
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_md5(text):
|
||||
logger.debug(f"计算哈希, 输入`{text}`")
|
||||
result = hashlib.md5(text.encode("utf-8")).hexdigest()
|
||||
logger.debug("哈希结果: %s...", result[:8])
|
||||
return result
|
||||
|
||||
|
||||
def hash(text):
|
||||
logger.debug(f"计算哈希, 输入`{text}`")
|
||||
result = hashlib.md5(text.encode("utf-8")).hexdigest()
|
||||
logger.debug("哈希结果: %s...", result[:8])
|
||||
return result
|
||||
155
src/heurams/services/logger.py
Normal file
155
src/heurams/services/logger.py
Normal file
@@ -0,0 +1,155 @@
|
||||
"""
|
||||
HeurAMS 日志服务模块
|
||||
基于Python标准logging库, 提供统一的日志记录功能
|
||||
"""
|
||||
|
||||
import logging
|
||||
import logging.handlers
|
||||
import pathlib
|
||||
import sys
|
||||
from typing import Optional, Union
|
||||
|
||||
# 默认配置
|
||||
DEFAULT_LOG_LEVEL = logging.DEBUG
|
||||
DEFAULT_LOG_FILE = pathlib.Path("heurams.log")
|
||||
DEFAULT_LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
DEFAULT_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
# 全局logger缓存
|
||||
_loggers = {}
|
||||
|
||||
|
||||
def setup_logging(
|
||||
log_file: Union[str, pathlib.Path] = DEFAULT_LOG_FILE,
|
||||
log_level: int = DEFAULT_LOG_LEVEL,
|
||||
log_format: str = DEFAULT_LOG_FORMAT,
|
||||
date_format: str = DEFAULT_DATE_FORMAT,
|
||||
max_bytes: int = 10 * 1024 * 1024, # 10MB
|
||||
backup_count: int = 5,
|
||||
) -> None:
|
||||
"""
|
||||
配置全局日志系统
|
||||
|
||||
Args:
|
||||
log_file: 日志文件路径
|
||||
log_level: 日志级别 (logging.DEBUG, logging.INFO等)
|
||||
log_format: 日志格式字符串
|
||||
date_format: 日期时间格式
|
||||
max_bytes: 单个日志文件最大字节数
|
||||
backup_count: 备份文件数量
|
||||
"""
|
||||
# 确保日志目录存在
|
||||
log_path = pathlib.Path(log_file)
|
||||
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 创建formatter
|
||||
formatter = logging.Formatter(log_format, date_format)
|
||||
|
||||
# 创建文件handler(使用RotatingFileHandler防止日志过大)
|
||||
file_handler = logging.handlers.RotatingFileHandler(
|
||||
filename=log_path,
|
||||
maxBytes=max_bytes,
|
||||
backupCount=backup_count,
|
||||
encoding="utf-8",
|
||||
)
|
||||
file_handler.setFormatter(formatter)
|
||||
file_handler.setLevel(log_level)
|
||||
|
||||
# 配置root logger - 设置为 WARNING 级别(只记录重要信息)
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(logging.WARNING) # 这里改为 WARNING
|
||||
|
||||
# 移除所有现有handler
|
||||
for handler in root_logger.handlers[:]:
|
||||
root_logger.removeHandler(handler)
|
||||
|
||||
# 创建自己的应用logger(单独设置DEBUG级别)
|
||||
app_logger = logging.getLogger("heurams")
|
||||
app_logger.setLevel(log_level) # 保持DEBUG级别
|
||||
app_logger.addHandler(file_handler)
|
||||
|
||||
# 禁止传播到root logger, 避免双重记录
|
||||
app_logger.propagate = False
|
||||
|
||||
# 设置第三方库的日志级别为WARNING, 避免调试信息干扰
|
||||
third_party_loggers = [
|
||||
"markdown_it",
|
||||
"markdown_it.rules_block",
|
||||
"markdown_it.rules_core",
|
||||
"markdown_it.rules_inline",
|
||||
"asyncio",
|
||||
]
|
||||
|
||||
for logger_name in third_party_loggers:
|
||||
logging.getLogger(logger_name).setLevel(logging.WARNING)
|
||||
|
||||
# 记录日志系统初始化
|
||||
app_logger.info("日志系统已初始化, 日志文件: %s", log_path)
|
||||
|
||||
|
||||
def get_logger(name: Optional[str] = None) -> logging.Logger:
|
||||
"""
|
||||
获取指定名称的logger
|
||||
|
||||
Args:
|
||||
name: logger名称, 通常使用模块名(__name__)
|
||||
如果为None, 返回root logger
|
||||
|
||||
Returns:
|
||||
logging.Logger实例
|
||||
"""
|
||||
if name is None:
|
||||
return logging.getLogger()
|
||||
|
||||
# 确保使用 heurams 作为前缀, 继承应用logger的配置
|
||||
if not name.startswith("heurams") and name != "":
|
||||
logger_name = f"heurams.{name}"
|
||||
else:
|
||||
logger_name = name
|
||||
|
||||
# 缓存logger以提高性能
|
||||
if logger_name not in _loggers:
|
||||
logger = logging.getLogger(logger_name)
|
||||
_loggers[logger_name] = logger
|
||||
|
||||
return _loggers[logger_name]
|
||||
|
||||
|
||||
# 便捷函数
|
||||
def debug(msg: str, *args, **kwargs) -> None:
|
||||
"""DEBUG级别日志"""
|
||||
get_logger().debug(msg, *args, **kwargs)
|
||||
|
||||
|
||||
def info(msg: str, *args, **kwargs) -> None:
|
||||
"""INFO级别日志"""
|
||||
get_logger().info(msg, *args, **kwargs)
|
||||
|
||||
|
||||
def warning(msg: str, *args, **kwargs) -> None:
|
||||
"""WARNING级别日志"""
|
||||
get_logger().warning(msg, *args, **kwargs)
|
||||
|
||||
|
||||
def error(msg: str, *args, **kwargs) -> None:
|
||||
"""ERROR级别日志"""
|
||||
get_logger().error(msg, *args, **kwargs)
|
||||
|
||||
|
||||
def critical(msg: str, *args, **kwargs) -> None:
|
||||
"""CRITICAL级别日志"""
|
||||
get_logger().critical(msg, *args, **kwargs)
|
||||
|
||||
|
||||
def exception(msg: str, *args, **kwargs) -> None:
|
||||
"""记录异常信息 (ERROR级别)"""
|
||||
get_logger().exception(msg, *args, **kwargs)
|
||||
|
||||
|
||||
# 初始化日志系统(硬编码配置)
|
||||
setup_logging()
|
||||
|
||||
|
||||
# 模块级别的logger实例
|
||||
logger = get_logger(__name__)
|
||||
logger.info("HeurAMS日志服务模块已加载")
|
||||
31
src/heurams/services/timer.py
Normal file
31
src/heurams/services/timer.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# 时间服务
|
||||
from heurams.context import config_var
|
||||
import time
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_daystamp() -> int:
|
||||
"""获取当前日戳(以天为单位的整数时间戳)"""
|
||||
time_override = config_var.get().get("daystamp_override", -1)
|
||||
if time_override != -1:
|
||||
logger.debug("使用覆盖的日戳: %d", time_override)
|
||||
return int(time_override)
|
||||
|
||||
result = int((time.time() + config_var.get().get("timezone_offset")) // (24 * 3600))
|
||||
logger.debug("计算日戳: %d", result)
|
||||
return result
|
||||
|
||||
|
||||
def get_timestamp() -> float:
|
||||
"""获取 UNIX 时间戳"""
|
||||
# 搞这个类的原因是要支持可复现操作
|
||||
time_override = config_var.get().get("timestamp_override", -1)
|
||||
if time_override != -1:
|
||||
logger.debug("使用覆盖的时间戳: %f", time_override)
|
||||
return float(time_override)
|
||||
|
||||
result = time.time()
|
||||
logger.debug("获取当前时间戳: %f", result)
|
||||
return result
|
||||
12
src/heurams/services/tts_service.py
Normal file
12
src/heurams/services/tts_service.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# 文本转语音服务
|
||||
from heurams.context import config_var
|
||||
from heurams.providers.tts import TTSs
|
||||
from typing import Callable
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
convert: Callable = TTSs[config_var.get().get("tts_provider")]
|
||||
logger.debug(
|
||||
"TTS服务初始化完成, 使用 provider: %s", config_var.get().get("tts_provider")
|
||||
)
|
||||
10
src/heurams/services/version.py
Normal file
10
src/heurams/services/version.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# 版本控制集成服务
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
ver = "0.4.0"
|
||||
stage = "prototype"
|
||||
codename = "fledge" # 雏鸟, 0.4.x 版本
|
||||
|
||||
logger.info("HeurAMS 版本: %s (%s), 阶段: %s", ver, codename, stage)
|
||||
Reference in New Issue
Block a user