""" 工具类模块 提供语音控制插件所需的实用工具函数 """ import time import math import os import json import threading from typing import Dict, Any, List, Optional, Union import hashlib class VoiceUtils: """ 语音工具类 提供语音控制插件所需的实用工具函数 """ def __init__(self, plugin): """ 初始化语音工具类 Args: plugin: 语音控制插件实例 """ self.plugin = plugin self.enabled = False self.initialized = False # 性能监控 self.performance_metrics = { "update_times": [], "processing_times": [], "memory_usage": 0, "cpu_usage": 0 } # 日志配置 self.log_config = { "enable_logging": True, "log_level": "INFO", "log_file": "/home/hello/EG/plugins/user/voice_control/logs/voice.log", "max_log_size": 10 * 1024 * 1024, # 10MB "log_format": "[{timestamp}] {level}: {message}" } # 数据转换配置 self.conversion_config = { "audio_level_curve": "linear", # linear, exponential, logarithmic "confidence_mapping": "linear", "duration_scaling": "linear" } # 数学工具 self.math_utils = MathUtils() # 缓存管理 self.cache_manager = CacheManager() # 调试工具 self.debug_tools = DebugTools() # 文件管理 self.file_manager = FileManager() # 统计信息 self.stats = { "functions_called": 0, "data_processed": 0, "cache_hits": 0, "cache_misses": 0, "files_processed": 0 } # 线程锁 self.utils_lock = threading.RLock() print("✓ 语音工具类已创建") def initialize(self) -> bool: """ 初始化语音工具类 Returns: 是否初始化成功 """ try: # 创建日志目录 log_dir = "/home/hello/EG/plugins/user/voice_control/logs" if not os.path.exists(log_dir): os.makedirs(log_dir) # 初始化子工具 self.math_utils.initialize() self.cache_manager.initialize() self.debug_tools.initialize() self.file_manager.initialize() self.initialized = True print("✓ 语音工具类初始化完成") return True except Exception as e: print(f"✗ 语音工具类初始化失败: {e}") import traceback traceback.print_exc() return False def enable(self) -> bool: """ 启用语音工具类 Returns: 是否启用成功 """ try: if not self.initialized: print("✗ 语音工具类未初始化") return False self.enabled = True # 启用子工具 self.math_utils.enable() self.cache_manager.enable() self.debug_tools.enable() self.file_manager.enable() print("✓ 语音工具类已启用") return True except Exception as e: print(f"✗ 语音工具类启用失败: {e}") import traceback traceback.print_exc() return False def disable(self): """禁用语音工具类""" try: self.enabled = False # 禁用子工具 self.math_utils.disable() self.cache_manager.disable() self.debug_tools.disable() self.file_manager.disable() print("✓ 语音工具类已禁用") except Exception as e: print(f"✗ 语音工具类禁用失败: {e}") import traceback traceback.print_exc() def finalize(self): """清理语音工具类资源""" try: self.disable() self.performance_metrics.clear() self.cache_manager.clear() self.debug_tools.clear() self.file_manager.clear() self.initialized = False print("✓ 语音工具类资源已清理") except Exception as e: print(f"✗ 语音工具类资源清理失败: {e}") import traceback traceback.print_exc() def update(self, dt: float): """ 更新语音工具类状态 Args: dt: 时间增量 """ try: if not self.enabled: return # 更新性能指标 self._update_performance_metrics(dt) # 更新子工具 self.cache_manager.update(dt) self.debug_tools.update(dt) self.file_manager.update(dt) except Exception as e: print(f"✗ 语音工具类更新失败: {e}") import traceback traceback.print_exc() def _update_performance_metrics(self, dt: float): """更新性能指标""" try: # 记录更新时间 self.performance_metrics["update_times"].append(dt) # 保持历史记录大小 if len(self.performance_metrics["update_times"]) > 1000: self.performance_metrics["update_times"] = self.performance_metrics["update_times"][-1000:] except Exception as e: print(f"✗ 性能指标更新失败: {e}") def log_message(self, message: str, level: str = "INFO"): """ 记录日志消息 Args: message: 日志消息 level: 日志级别 (DEBUG, INFO, WARNING, ERROR) """ try: if not self.log_config["enable_logging"]: return # 检查日志级别 level_priority = {"DEBUG": 0, "INFO": 1, "WARNING": 2, "ERROR": 3} config_level = self.log_config["log_level"] if level_priority.get(level, 1) < level_priority.get(config_level, 1): return # 格式化日志消息 timestamp = time.strftime("%Y-%m-%d %H:%M:%S") formatted_message = self.log_config["log_format"].format( timestamp=timestamp, level=level, message=message ) # 输出到控制台 print(formatted_message) # 写入日志文件 try: with self.utils_lock: # 检查文件大小 if os.path.exists(self.log_config["log_file"]): if os.path.getsize(self.log_config["log_file"]) > self.log_config["max_log_size"]: # 重命名旧日志文件 backup_file = self.log_config["log_file"] + ".old" if os.path.exists(backup_file): os.remove(backup_file) os.rename(self.log_config["log_file"], backup_file) with open(self.log_config["log_file"], "a", encoding="utf-8") as f: f.write(formatted_message + "\n") except Exception as e: pass # 忽略文件写入错误 except Exception as e: pass # 忽略日志记录错误 def measure_performance(self, func: callable, *args, **kwargs) -> tuple: """ 测量函数性能 Args: func: 要测量的函数 *args: 函数参数 **kwargs: 函数关键字参数 Returns: (结果, 执行时间) """ try: start_time = time.perf_counter() result = func(*args, **kwargs) end_time = time.perf_counter() execution_time = end_time - start_time # 记录到性能指标 metric_name = f"{func.__name__}_times" if metric_name not in self.performance_metrics: self.performance_metrics[metric_name] = [] self.performance_metrics[metric_name].append(execution_time) # 保持历史记录大小 if len(self.performance_metrics[metric_name]) > 1000: self.performance_metrics[metric_name] = self.performance_metrics[metric_name][-1000:] self.stats["functions_called"] += 1 return (result, execution_time) except Exception as e: self.log_message(f"性能测量失败: {e}", "ERROR") raise def convert_audio_level(self, level: float, curve: str = None) -> float: """ 转换音频级别值 Args: level: 原始级别值 (0.0-1.0) curve: 转换曲线类型 Returns: 转换后的级别值 """ try: curve_type = curve or self.conversion_config["audio_level_curve"] level = max(0.0, min(1.0, level)) if curve_type == "exponential": # 指数曲线 return math.pow(level, 2) elif curve_type == "logarithmic": # 对数曲线 return math.log(level + 1) / math.log(2) else: # 线性曲线 return level except Exception as e: self.log_message(f"音频级别转换失败: {e}", "ERROR") return level def convert_confidence(self, confidence: float, mapping: str = None) -> float: """ 转换置信度值 Args: confidence: 原始置信度值 (0.0-1.0) mapping: 映射类型 Returns: 转换后的置信度值 """ try: mapping_type = mapping or self.conversion_config["confidence_mapping"] confidence = max(0.0, min(1.0, confidence)) if mapping_type == "exponential": # 指数映射 return math.pow(confidence, 2) elif mapping_type == "logarithmic": # 对数映射 return math.log(confidence * 9 + 1) / math.log(10) else: # 线性映射 return confidence except Exception as e: self.log_message(f"置信度转换失败: {e}", "ERROR") return confidence def scale_duration(self, duration: float, scale_factor: float = 1.0, scaling_type: str = None) -> float: """ 缩放持续时间 Args: duration: 原始持续时间 scale_factor: 缩放因子 scaling_type: 缩放类型 Returns: 缩放后的持续时间 """ try: scaling = scaling_type or self.conversion_config["duration_scaling"] duration = max(0.0, duration) scale_factor = max(0.0, scale_factor) if scaling == "exponential": return duration * math.pow(scale_factor, 2) elif scaling == "logarithmic": return duration * math.log(scale_factor + 1) else: return duration * scale_factor except Exception as e: self.log_message(f"持续时间缩放失败: {e}", "ERROR") return duration def interpolate_values(self, start_value: float, end_value: float, progress: float, interpolation_type: str = "linear") -> float: """ 插值计算 Args: start_value: 起始值 end_value: 结束值 progress: 进度 (0.0-1.0) interpolation_type: 插值类型 Returns: 插值结果 """ try: progress = max(0.0, min(1.0, progress)) if interpolation_type == "ease_in": progress = math.pow(progress, 2) elif interpolation_type == "ease_out": progress = 1.0 - math.pow(1.0 - progress, 2) elif interpolation_type == "ease_in_out": progress = 0.5 * (1 - math.cos(progress * math.pi)) # linear 为默认情况,无需特殊处理 return start_value + (end_value - start_value) * progress except Exception as e: self.log_message(f"插值计算失败: {e}", "ERROR") return start_value def calculate_similarity(self, text1: str, text2: str) -> float: """ 计算文本相似度 Args: text1: 文本1 text2: 文本2 Returns: 相似度值 (0.0-1.0) """ try: # 使用简单的字符级相似度计算 set1 = set(text1) set2 = set(text2) intersection = len(set1.intersection(set2)) union = len(set1.union(set2)) if union == 0: return 1.0 if text1 == text2 else 0.0 return intersection / union except Exception as e: self.log_message(f"相似度计算失败: {e}", "ERROR") return 0.0 def normalize_text(self, text: str, language: str = "zh-CN") -> str: """ 标准化文本 Args: text: 原始文本 language: 语言代码 Returns: 标准化后的文本 """ try: # 移除多余空格 text = " ".join(text.split()) # 转换为小写(仅适用于英文) if language == "en-US": text = text.lower() # 移除特殊字符(保留字母、数字和基本标点) import re if language == "zh-CN": text = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9\s\.,!?;:]", "", text) else: text = re.sub(r"[^a-zA-Z0-9\s\.,!?;:]", "", text) return text.strip() except Exception as e: self.log_message(f"文本标准化失败: {e}", "ERROR") return text def generate_hash(self, data: Union[str, bytes]) -> str: """ 生成数据哈希值 Args: data: 要哈希的数据 Returns: 哈希值字符串 """ try: if isinstance(data, str): data = data.encode("utf-8") return hashlib.md5(data).hexdigest() except Exception as e: self.log_message(f"哈希生成失败: {e}", "ERROR") return "" def format_time(self, seconds: float) -> str: """ 格式化时间显示 Args: seconds: 秒数 Returns: 格式化的时间字符串 """ try: if seconds < 60: return f"{seconds:.1f}秒" elif seconds < 3600: minutes = int(seconds // 60) secs = seconds % 60 return f"{minutes}分{secs:.1f}秒" else: hours = int(seconds // 3600) minutes = int((seconds % 3600) // 60) secs = seconds % 60 return f"{hours}时{minutes}分{secs:.1f}秒" except Exception as e: self.log_message(f"时间格式化失败: {e}", "ERROR") return f"{seconds:.1f}秒" def get_performance_stats(self) -> Dict[str, Any]: """ 获取性能统计信息 Returns: 性能统计字典 """ try: stats = {} for key, times in self.performance_metrics.items(): if times: stats[key] = { "count": len(times), "average": sum(times) / len(times), "min": min(times), "max": max(times), "total": sum(times) } return stats except Exception as e: self.log_message(f"性能统计获取失败: {e}", "ERROR") return {} def get_system_info(self) -> Dict[str, Any]: """ 获取系统信息 Returns: 系统信息字典 """ try: import platform import psutil return { "platform": platform.system(), "platform_version": platform.version(), "processor": platform.processor(), "cpu_count": psutil.cpu_count(), "memory_total": psutil.virtual_memory().total, "memory_available": psutil.virtual_memory().available, "plugin_version": getattr(self.plugin, "version", "unknown") } except Exception as e: self.log_message(f"系统信息获取失败: {e}", "ERROR") return {} def get_stats(self) -> Dict[str, int]: """ 获取统计信息 Returns: 统计信息字典 """ return self.stats.copy() def reset_stats(self): """重置统计信息""" try: self.stats = { "functions_called": 0, "data_processed": 0, "cache_hits": 0, "cache_misses": 0, "files_processed": 0 } print("✓ 工具类统计信息已重置") except Exception as e: self.log_message(f"统计信息重置失败: {e}", "ERROR") def set_log_config(self, config: Dict[str, Any]) -> bool: """ 设置日志配置 Args: config: 日志配置字典 Returns: 是否设置成功 """ try: self.log_config.update(config) self.log_message(f"日志配置已更新: {self.log_config}", "INFO") return True except Exception as e: self.log_message(f"日志配置设置失败: {e}", "ERROR") return False def set_conversion_config(self, config: Dict[str, Any]) -> bool: """ 设置转换配置 Args: config: 转换配置字典 Returns: 是否设置成功 """ try: self.conversion_config.update(config) self.log_message(f"转换配置已更新: {self.conversion_config}", "INFO") return True except Exception as e: self.log_message(f"转换配置设置失败: {e}", "ERROR") return False def get_cache_manager(self): """ 获取缓存管理器 Returns: 缓存管理器实例 """ return self.cache_manager def get_debug_tools(self): """ 获取调试工具 Returns: 调试工具实例 """ return self.debug_tools def get_file_manager(self): """ 获取文件管理器 Returns: 文件管理器实例 """ return self.file_manager class MathUtils: """数学工具类""" def __init__(self): self.enabled = False self.initialized = False def initialize(self): """初始化数学工具""" self.initialized = True def enable(self): """启用数学工具""" self.enabled = True def disable(self): """禁用数学工具""" self.enabled = False @staticmethod def clamp(value: float, min_value: float, max_value: float) -> float: """限制值在指定范围内""" return max(min_value, min(max_value, value)) @staticmethod def lerp(start: float, end: float, t: float) -> float: """线性插值""" return start + (end - start) * t @staticmethod def smoothstep(edge0: float, edge1: float, x: float) -> float: """平滑插值""" t = MathUtils.clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0) return t * t * (3.0 - 2.0 * t) @staticmethod def distance(pos1: tuple, pos2: tuple) -> float: """计算两点间距离""" try: dx = pos2[0] - pos1[0] dy = pos2[1] - pos1[1] dz = pos2[2] - pos1[2] if len(pos1) > 2 and len(pos2) > 2 else 0 return math.sqrt(dx*dx + dy*dy + dz*dz) except Exception: return 0.0 class CacheManager: """缓存管理器""" def __init__(self): self.enabled = False self.initialized = False self.cache = {} self.access_times = {} self.max_size = 1000 def initialize(self): """初始化缓存管理器""" self.initialized = True def enable(self): """启用缓存管理器""" self.enabled = True def disable(self): """禁用缓存管理器""" self.enabled = False def update(self, dt: float): """更新缓存管理器""" if self.enabled: self._cleanup() def get(self, key: str) -> Optional[Any]: """获取缓存值""" if key in self.cache: self.access_times[key] = time.time() return self.cache[key] return None def set(self, key: str, value: Any, ttl: float = 300.0): """设置缓存值""" self.cache[key] = value self.access_times[key] = time.time() # 检查缓存大小 if len(self.cache) > self.max_size: self._cleanup() def _cleanup(self): """清理过期缓存""" current_time = time.time() expired_keys = [ key for key, access_time in self.access_times.items() if current_time - access_time > 300.0 ] for key in expired_keys: del self.cache[key] del self.access_times[key] def clear(self): """清空缓存""" self.cache.clear() self.access_times.clear() class DebugTools: """调试工具类""" def __init__(self): self.enabled = False self.initialized = False self.debug_enabled = False self.debug_data = {} def initialize(self): """初始化调试工具""" self.initialized = True def enable(self): """启用调试工具""" self.enabled = True def disable(self): """禁用调试工具""" self.enabled = False def update(self, dt: float): """更新调试工具""" pass def enable_debug(self): """启用调试模式""" self.debug_enabled = True def disable_debug(self): """禁用调试模式""" self.debug_enabled = False def log_debug_data(self, key: str, data: Any): """记录调试数据""" if self.debug_enabled: self.debug_data[key] = data def get_debug_data(self, key: str = None) -> Union[Dict[str, Any], Any]: """获取调试数据""" if key: return self.debug_data.get(key) return self.debug_data.copy() def clear_debug_data(self): """清空调试数据""" self.debug_data.clear() def clear(self): """清理调试工具""" self.debug_data.clear() class FileManager: """文件管理器""" def __init__(self): self.enabled = False self.initialized = False self.watched_files = {} def initialize(self): """初始化文件管理器""" self.initialized = True def enable(self): """启用文件管理器""" self.enabled = True def disable(self): """禁用文件管理器""" self.enabled = False def update(self, dt: float): """更新文件管理器""" if self.enabled: self._check_file_changes() def _check_file_changes(self): """检查文件变化""" try: for file_path, last_modified in list(self.watched_files.items()): if os.path.exists(file_path): current_modified = os.path.getmtime(file_path) if current_modified > last_modified: self.watched_files[file_path] = current_modified # 触发文件变化事件 except Exception as e: pass def watch_file(self, file_path: str): """监视文件变化""" try: if os.path.exists(file_path): self.watched_files[file_path] = os.path.getmtime(file_path) except Exception as e: pass def unwatch_file(self, file_path: str): """取消监视文件""" if file_path in self.watched_files: del self.watched_files[file_path] def read_json_file(self, file_path: str) -> Optional[Dict[str, Any]]: """读取JSON文件""" try: with open(file_path, "r", encoding="utf-8") as f: return json.load(f) except Exception as e: return None def write_json_file(self, file_path: str, data: Dict[str, Any]) -> bool: """写入JSON文件""" try: with open(file_path, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) return True except Exception as e: return False def clear(self): """清理文件管理器""" self.watched_files.clear()