Skip to content

Commit 3f064ff

Browse files
committed
语音播报功能优化
1 parent f982444 commit 3f064ff

3 files changed

Lines changed: 71 additions & 14 deletions

File tree

app/common/voice/voice.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ def stop(self) -> None:
252252
if self._play_thread and self._play_thread.is_alive():
253253
self._play_thread.join(timeout=5.0) # 添加超时保护
254254
self._clear_queue()
255+
# 重置线程状态,允许下次调用start()重新启动
256+
self._play_thread = None
257+
self._stop_flag.clear()
255258

256259
def _clear_queue(self) -> None:
257260
"""清空播放队列"""
@@ -656,12 +659,17 @@ def voice_play(
656659
if not student_names:
657660
return
658661

662+
# 停止之前的播放,清空队列
663+
self.stop()
664+
# 重新启动播放线程
665+
self.playback_system.start()
666+
659667
# 读取音频设置文件
660668
audio_settings = {}
661669
if class_name:
662670
audio_file = get_audio_path(f"{class_name}.json")
663671
if audio_file.exists():
664-
with open(audio_file, "r", encoding="utf-8") as f:
672+
with open(str(audio_file), "r", encoding="utf-8") as f:
665673
audio_settings = json.load(f)
666674

667675
# 应用TTS别名、前缀和后缀
@@ -711,6 +719,9 @@ def _handle_system_tts(
711719
) -> None:
712720
"""系统TTS处理"""
713721
with self.system_tts_lock:
722+
if self.voice_engine is None:
723+
logger.error("系统TTS引擎未初始化,无法播放语音")
724+
return
714725
for name in student_names:
715726
try:
716727
self.voice_engine.say(f"{name}")
@@ -758,8 +769,8 @@ def _prepare_and_play(
758769
self, student_names: List[str], config: Dict[str, Any], voice_name: str
759770
) -> None:
760771
"""准备并播放语音"""
761-
# 设置播放音量
762-
self.playback_system.set_volume(config["voice_volume"])
772+
# 设置播放音量,转换为0.0-1.0范围
773+
self.playback_system.set_volume(config["voice_volume"] / 100.0)
763774
# 设置播放语速
764775
self.playback_system.set_speed(config["voice_speed"])
765776

@@ -782,3 +793,11 @@ def stop(self) -> None:
782793
线程池将在对象销毁时自动关闭
783794
"""
784795
self.playback_system.stop()
796+
797+
# 系统TTS引擎也需要停止
798+
with self.system_tts_lock:
799+
if self.voice_engine is not None:
800+
try:
801+
self.voice_engine.stop()
802+
except Exception as e:
803+
logger.error(f"停止系统TTS引擎失败: {e}")

app/tools/config.py

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -391,13 +391,14 @@ def show_notification(
391391
raise ValueError(f"不支持的通知类型: {notification_type}")
392392

393393

394-
def send_system_notification(title: str, content: str) -> bool:
394+
def send_system_notification(title: str, content: str, url: str = None) -> bool:
395395
"""
396396
发送系统通知
397397
398398
Args:
399399
title: 通知标题
400400
content: 通知内容
401+
url: 点击通知后跳转的URL,默认为下载链接
401402
402403
Returns:
403404
bool: 通知发送是否成功
@@ -406,6 +407,20 @@ def send_system_notification(title: str, content: str) -> bool:
406407
# 获取软件图标路径
407408
icon_path = str(get_data_path("assets", "icon/secrandom-icon-paper.ico"))
408409

410+
# 定义点击通知的回调函数
411+
def on_notification_click():
412+
"""点击通知时执行的函数"""
413+
try:
414+
if url:
415+
import webbrowser
416+
417+
webbrowser.open(url)
418+
logger.debug(f"已打开通知链接: {url}")
419+
else:
420+
logger.warning("通知未配置URL,无法打开链接")
421+
except Exception as e:
422+
logger.error(f"打开通知链接失败: {e}")
423+
409424
if sys.platform == "win32":
410425
# Windows平台
411426
try:
@@ -414,7 +429,12 @@ def send_system_notification(title: str, content: str) -> bool:
414429

415430
toaster = ToastNotifier()
416431
toaster.show_toast(
417-
title, content, icon_path=icon_path, duration=15, threaded=True
432+
title,
433+
content,
434+
icon_path=icon_path,
435+
duration=0,
436+
threaded=True,
437+
callback_on_click=on_notification_click,
418438
)
419439
logger.debug(f"已发送Windows通知: {title}")
420440
return True
@@ -428,7 +448,7 @@ def send_system_notification(title: str, content: str) -> bool:
428448
message=content,
429449
app_name=APPLY_NAME,
430450
app_icon=icon_path,
431-
timeout=15,
451+
timeout=0,
432452
)
433453
logger.debug(f"已发送Windows通知(使用plyer): {title}")
434454
return True
@@ -441,12 +461,28 @@ def send_system_notification(title: str, content: str) -> bool:
441461
# 尝试使用notify-send命令
442462
import subprocess
443463

444-
subprocess.run(
445-
["notify-send", "--icon", icon_path, title, content],
446-
check=True,
447-
timeout=5,
448-
)
449-
logger.debug(f"已发送Linux通知: {title}")
464+
if url:
465+
subprocess.run(
466+
[
467+
"notify-send",
468+
"--icon",
469+
icon_path,
470+
"--action",
471+
f"default={url}",
472+
title,
473+
content,
474+
],
475+
check=True,
476+
timeout=0,
477+
)
478+
logger.debug(f"已发送Linux通知(包含URL): {title}")
479+
else:
480+
subprocess.run(
481+
["notify-send", "--icon", icon_path, title, content],
482+
check=True,
483+
timeout=0,
484+
)
485+
logger.debug(f"已发送Linux通知(不包含URL): {title}")
450486
return True
451487
except subprocess.CalledProcessError as e:
452488
# 如果notify-send不可用,尝试使用plyer
@@ -458,7 +494,7 @@ def send_system_notification(title: str, content: str) -> bool:
458494
message=content,
459495
app_name=APPLY_NAME,
460496
app_icon=icon_path,
461-
timeout=15,
497+
timeout=0,
462498
)
463499
logger.debug(f"已发送Linux通知(使用plyer): {title}")
464500
return True

main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,9 @@ def run(self):
447447
content = get_content_name_async(
448448
"update", "update_notification_content"
449449
).format(version=latest_version)
450-
send_system_notification(title, content)
450+
send_system_notification(
451+
title, content, url="https://secrandom.netlify.app/download"
452+
)
451453

452454
# 如果是模式2或3,自动下载更新
453455
if auto_update_mode in [2, 3]:

0 commit comments

Comments
 (0)