3232
3333# --------- 项目内部 ---------
3434from app .tools .path_utils import ensure_dir , get_audio_path
35+ from app .tools .settings_access import readme_settings_async
36+ from app .tools .config import restore_volume
3537
3638
3739# 权限检查装饰器
@@ -175,13 +177,13 @@ def _safe_play(self, data: np.ndarray, fs: int) -> None:
175177
176178 with self ._is_playing_lock :
177179 self ._is_playing = True # 开始播放
178- logger .debug ("开始播放音频" )
180+ logger .info ("开始播放音频" )
179181
180182 # 分块写入避免卡顿
181183 chunk_size : int = 4096
182184 for i in range (0 , len (data ), chunk_size ):
183185 if self ._stop_flag .is_set ():
184- logger .debug ("收到停止信号,中断播放" )
186+ logger .info ("收到停止信号,中断播放" )
185187 break
186188
187189 chunk = data [i : i + chunk_size ]
@@ -193,7 +195,7 @@ def _safe_play(self, data: np.ndarray, fs: int) -> None:
193195 # 写入音频流
194196 stream .write (chunk )
195197
196- logger .debug ("音频播放完毕" )
198+ logger .info ("音频播放完毕" )
197199 with self ._is_playing_lock :
198200 self ._is_playing = False # 播放结束
199201
@@ -303,7 +305,7 @@ def get_voice(self, text: str, voice: str) -> Tuple[np.ndarray, int]:
303305 logger .error (f"无效的语音名称: { voice } " )
304306 raise ValueError ("语音名称不能为空" )
305307
306- logger .debug (f"获取语音: text='{ text [: 50 ] } ... ', voice='{ voice } '" )
308+ logger .info (f"获取语音: text='{ text } ', voice='{ voice } '" )
307309
308310 # 检查并执行缓存清理
309311 self ._check_and_cleanup ()
@@ -349,7 +351,7 @@ def get_voice(self, text: str, voice: str) -> Tuple[np.ndarray, int]:
349351 async def _generate_voice (self , text : str , voice : str ) -> Tuple [np .ndarray , int ]:
350352 """生成语音核心方法"""
351353 # 限制文本长度,防止生成过大的音频
352- max_text_length = 1000
354+ max_text_length = 500
353355 if len (text ) > max_text_length :
354356 text = text [:max_text_length ]
355357 logger .warning (f"文本长度超过限制{ max_text_length } ,已截断" )
@@ -464,32 +466,33 @@ class LoadBalancer:
464466
465467 # 基础队列大小设置
466468 BASE_QUEUE_SIZE : int = 3 # 基础队列大小(最低3人)
467-
468- # CPU负载阈值与对应的队列大小增量
469- CPU_THRESHOLDS : list [tuple [float , int ]] = [
470- (90 , 0 ), # CPU > 90%: 不增加
471- (80 , 2 ), # 80% < CPU ≤ 90%: 增加2人
472- (70 , 4 ), # 70% < CPU ≤ 80%: 增加4人
473- (60 , 6 ), # 60% < CPU ≤ 70%: 增加6人
474- (50 , 8 ), # 50% < CPU ≤ 60%: 增加8人
475- (40 , 10 ), # 40% < CPU ≤ 50%: 增加10人
476- (30 , 12 ), # 30% < CPU ≤ 40%: 增加12人
477- (20 , 14 ), # 20% < CPU ≤ 30%: 增加14人
478- (10 , 16 ), # 10% < CPU ≤ 20%: 增加16人
479- (0 , 20 ), # CPU ≤ 10%: 增加20人
469+ MAX_QUEUE_SIZE : int = 100 # 最大队列大小,防止无限增长
470+
471+ # CPU负载阈值与对应的队列大小系数(按CPU使用率从低到高排序)
472+ CPU_THRESHOLDS : list [tuple [float , float ]] = [
473+ (0 , 1.0 ), # CPU ≤ 10%: 正常系数
474+ (10 , 0.9 ), # 10% < CPU ≤ 20%: 略降系数
475+ (20 , 0.8 ), # 20% < CPU ≤ 30%: 降低系数
476+ (30 , 0.7 ), # 30% < CPU ≤ 40%: 进一步降低
477+ (40 , 0.6 ), # 40% < CPU ≤ 50%: 继续降低
478+ (50 , 0.5 ), # 50% < CPU ≤ 60%: 中等负载
479+ (60 , 0.4 ), # 60% < CPU ≤ 70%: 较高负载
480+ (70 , 0.3 ), # 70% < CPU ≤ 80%: 高负载
481+ (80 , 0.2 ), # 80% < CPU ≤ 90%: 很高负载
482+ (90 , 0.1 ), # CPU > 90%: 极高负载
480483 ]
481484
482- # 内存负载阈值与对应的队列大小增量
483- MEMORY_THRESHOLDS : list [tuple [float , int ]] = [
484- (0.5 , 0 ), # 内存 < 0.5GB: 不增加
485- (1 , 5 ), # 0.5GB ≤ 内存 < 1GB: 增加5人
486- (2 , 10 ), # 1GB ≤ 内存 < 2GB: 增加10人
487- (4 , 20 ), # 2GB ≤ 内存 < 4GB: 增加20人
488- (8 , 30 ), # 4GB ≤ 内存 < 8GB: 增加30人
489- (16 , 40 ), # 8GB ≤ 内存 < 16GB: 增加40人
490- (32 , 50 ), # 16GB ≤ 内存 < 32GB: 增加50人
491- (64 , 60 ), # 32GB ≤ 内存 < 64GB: 增加60人
492- (float ( "inf" ), 70 ), # 内存 ≥ 64GB: 增加70人
485+ # 内存负载阈值与对应的队列大小系数(按可用内存从低到高排序)
486+ MEMORY_THRESHOLDS : list [tuple [float , float ]] = [
487+ (0 , 0.2 ), # 内存 < 0.5GB: 极低内存,大幅降低队列
488+ (0.5 , 0.3 ), # 0.5GB ≤ 内存 < 1GB: 低内存,降低队列
489+ (1 , 0.5 ), # 1GB ≤ 内存 < 2GB: 中等偏低内存,适当降低
490+ (2 , 0.7 ), # 2GB ≤ 内存 < 4GB: 中等内存,略微降低
491+ (4 , 0.8 ), # 4GB ≤ 内存 < 8GB: 较充足内存,小幅降低
492+ (8 , 0.9 ), # 8GB ≤ 内存 < 16GB: 充足内存,略降
493+ (16 , 0.95 ), # 16GB ≤ 内存 < 32GB: 很充足内存,微调
494+ (32 , 1.0 ), # 32GB ≤ 内存 < 64GB: 充足内存,正常系数
495+ (64 , 1.0 ), # 内存 ≥ 64GB: 非常充足内存,正常系数
493496 ]
494497
495498 def get_optimal_queue_size (self ) -> int :
@@ -500,6 +503,7 @@ def get_optimal_queue_size(self) -> int:
500503 mem_available : float = psutil .virtual_memory ().available / (
501504 1024 ** 3
502505 ) # GB(可用内存)
506+ mem_percent : float = psutil .virtual_memory ().percent # 内存使用率%
503507
504508 # 参数有效性检查
505509 if (
@@ -514,25 +518,40 @@ def get_optimal_queue_size(self) -> int:
514518 logger .error ("内存信息异常,使用基础队列大小" )
515519 return self .BASE_QUEUE_SIZE
516520
517- # 根据CPU使用率确定增量
518- cpu_bonus : int = 0
519- for threshold , bonus in self .CPU_THRESHOLDS :
520- if cpu_percent >= threshold :
521- cpu_bonus = bonus
521+ # 计算基于CPU的队列大小调整系数
522+ cpu_factor : float = 1.0
523+ for threshold , factor in self .CPU_THRESHOLDS :
524+ if cpu_percent > threshold :
525+ cpu_factor = factor
526+ else :
522527 break
523528
524- # 根据可用内存确定增量
525- mem_bonus : int = 0
526- for threshold , bonus in self .MEMORY_THRESHOLDS :
527- if mem_available <= threshold :
528- mem_bonus = bonus
529+ # 计算基于内存的队列大小调整系数
530+ mem_factor : float = 1.0
531+ for threshold , factor in self .MEMORY_THRESHOLDS :
532+ if mem_available > threshold :
533+ mem_factor = factor
534+ else :
529535 break
530536
531- # 计算最终队列大小
532- queue_size : int = self .BASE_QUEUE_SIZE + cpu_bonus + mem_bonus
537+ # 计算动态队列基础值(根据系统资源情况)
538+ # 可用内存越多,动态基础值越大
539+ dynamic_base = self .BASE_QUEUE_SIZE + int (
540+ mem_available * 5
541+ ) # 每GB内存增加5个队列位置
542+
543+ # 结合CPU和内存负载,计算最终队列大小
544+ # 使用几何平均计算综合系数,更合理地平衡CPU和内存负载
545+ combined_factor = (cpu_factor * mem_factor ) ** 0.5
546+ queue_size : int = int (dynamic_base * combined_factor )
547+
548+ # 确保队列大小在合理范围内
549+ queue_size = max (self .BASE_QUEUE_SIZE , min (queue_size , self .MAX_QUEUE_SIZE ))
533550
534551 logger .debug (
535- f"系统负载 (CPU:{ cpu_percent } %, 内存:{ mem_available :.2f} GB),队列大小设为{ queue_size } "
552+ f"系统负载 (CPU:{ cpu_percent } %, 内存使用率:{ mem_percent } %, 可用内存:{ mem_available :.2f} GB) "
553+ f"→ CPU系数:{ cpu_factor } , 内存系数:{ mem_factor } , 综合系数:{ combined_factor :.2f} "
554+ f"→ 队列大小设为{ queue_size } "
536555 )
537556 return queue_size
538557 except Exception as e :
@@ -718,6 +737,23 @@ def _handle_system_tts(
718737 self , student_names : List [str ], config : Dict [str , Any ]
719738 ) -> None :
720739 """系统TTS处理"""
740+ # 检查是否开启系统音量控制(增强错误处理,防止崩溃)
741+ try :
742+ system_volume_control = readme_settings_async (
743+ "basic_voice_settings" , "system_volume_control"
744+ )
745+ if system_volume_control :
746+ # 获取系统音量大小并设置
747+ system_volume_size = readme_settings_async (
748+ "basic_voice_settings" , "system_volume_size"
749+ )
750+ # 确保音量值是整数
751+ if isinstance (system_volume_size , (int , str )):
752+ restore_volume (int (system_volume_size ))
753+ except Exception as e :
754+ logger .error (f"系统音量控制处理失败: { e } " )
755+ # 继续执行,不影响语音播报
756+
721757 with self .system_tts_lock :
722758 if self .voice_engine is None :
723759 logger .error ("系统TTS引擎未初始化,无法播放语音" )
@@ -769,6 +805,23 @@ def _prepare_and_play(
769805 self , student_names : List [str ], config : Dict [str , Any ], voice_name : str
770806 ) -> None :
771807 """准备并播放语音"""
808+ # 检查是否开启系统音量控制(增强错误处理,防止崩溃)
809+ try :
810+ system_volume_control = readme_settings_async (
811+ "basic_voice_settings" , "system_volume_control"
812+ )
813+ if system_volume_control :
814+ # 获取系统音量大小并设置
815+ system_volume_size = readme_settings_async (
816+ "basic_voice_settings" , "system_volume_size"
817+ )
818+ # 确保音量值是整数
819+ if isinstance (system_volume_size , (int , str )):
820+ restore_volume (int (system_volume_size ))
821+ except Exception as e :
822+ logger .error (f"系统音量控制处理失败: { e } " )
823+ # 继续执行,不影响语音播报
824+
772825 # 设置播放音量,转换为0.0-1.0范围
773826 self .playback_system .set_volume (config ["voice_volume" ] / 100.0 )
774827 # 设置播放语速
0 commit comments