-
Notifications
You must be signed in to change notification settings - Fork 415
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Update util.py解决返回元组报错 (#103) 解决返回元组报错 * 增加播放本地音乐功能 (#105) * Please enter the commit message for your changes. Lines starting with '#' will be ignored, and an empty message aborts the commit. On branch Music-playback Your branch is up to date with 'origin/Music-playback'. Changes to be committed: modified: core/handle/audioHandle.py new file: "music/\346\234\210\344\272\256\344\273\243\350\241\250\346\210\221\347\232\204\345\277\203_\351\202\223\344\270\275\345\220\233.mp3" new file: "music/\350\270\217\345\261\261\346\262\263.mp3" * Please enter the commit message for your changes. Lines starting with '#' will be ignored, and an empty message aborts the commit. On branch Music-playback Your branch is up to date with 'origin/Music-playback'. Changes to be committed: modified: config.yaml modified: core/connection.py modified: core/handle/abortHandle.py modified: core/handle/audioHandle.py new file: core/handle/musicHandler.py modified: core/handle/textHandle.py modified: core/websocket_server.py new file: "music/\344\270\200\345\277\265\345\215\203\345\271\264_\345\233\275\351\243\216\347\211\210.mp3" new file: "music/\344\270\255\347\247\213\346\234\210.mp3" deleted: "music/\346\234\210\344\272\256\344\273\243\350\241\250\346\210\221\347\232\204\345\277\203_\351\202\223\344\270\275\345\220\233.mp3" deleted: "music/\350\270\217\345\261\261\346\262\263.mp3" * 增加播放本地音乐功能 * 增加播放本地音乐功能 * 让音乐配置变的优雅 On branch Music-playback Your branch is up to date with 'origin/Music-playback'. Changes to be committed: modified: config.yaml modified: core/handle/musicHandler.py renamed: "music/\344\270\200\345\277\265\345\215\203\345\271\264_\345\233\275\351\243\216\347\211\210.mp3" -> "music/mp3/\344\270\200\345\277\265\345\215\203\345\271\264_\345\233\275\351\243\216\347\211\210.mp3" renamed: "music/\344\270\255\347\247\213\346\234\210.mp3" -> "music/mp3/\344\270\255\347\247\213\346\234\210.mp3" renamed: "music/\345\273\211\346\263\242\350\200\201\347\237\243\357\274\214\345\260\232\350\203\275\351\245\255\345\220\246.mp3" -> "music/mp3/\345\273\211\346\263\242\350\200\201\347\237\243\357\274\214\345\260\232\350\203\275\351\245\255\345\220\246.mp3" new file: music/music_config.yaml --------- Co-authored-by: 欣南科技 <[email protected]> * update:优化代码 * update:流控调试 * update:优化音乐播放 * update:优化音乐配置初始化 --------- Co-authored-by: linqingping <[email protected]> Co-authored-by: Chris <[email protected]> Co-authored-by: hrz <[email protected]>
- Loading branch information
1 parent
73803f4
commit 87cb0b4
Showing
11 changed files
with
242 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
from config.logger import setup_logging | ||
import os | ||
import random | ||
import difflib | ||
import re | ||
import traceback | ||
from core.handle.sendAudioHandle import sendAudioMessage, send_stt_message | ||
|
||
TAG = __name__ | ||
logger = setup_logging() | ||
|
||
|
||
def _extract_song_name(text): | ||
"""从用户输入中提取歌名""" | ||
for keyword in ["听", "播放", "放", "唱"]: | ||
if keyword in text: | ||
parts = text.split(keyword) | ||
if len(parts) > 1: | ||
return parts[1].strip() | ||
return None | ||
|
||
|
||
def _find_best_match(potential_song, music_files): | ||
"""查找最匹配的歌曲""" | ||
best_match = None | ||
highest_ratio = 0 | ||
|
||
for music_file in music_files: | ||
song_name = os.path.splitext(music_file)[0] | ||
ratio = difflib.SequenceMatcher(None, potential_song, song_name).ratio() | ||
if ratio > highest_ratio and ratio > 0.4: | ||
highest_ratio = ratio | ||
best_match = music_file | ||
return best_match | ||
|
||
|
||
class MusicHandler: | ||
def __init__(self, config): | ||
self.config = config | ||
self.music_related_keywords = [] | ||
|
||
if "music" in self.config: | ||
self.music_config = self.config["music"] | ||
self.music_dir = os.path.abspath( | ||
self.music_config.get("music_dir", "./music") # 默认路径修改 | ||
) | ||
self.music_related_keywords = self.music_config.get("music_commands", []) | ||
else: | ||
self.music_dir = os.path.abspath("./music") | ||
self.music_related_keywords = ["来一首歌", "唱一首歌", "播放音乐", "来点音乐", "背景音乐", "放首歌", | ||
"播放歌曲", "来点背景音乐", "我想听歌", "我要听歌", "放点音乐"] | ||
|
||
async def handle_music_command(self, conn, text): | ||
"""处理音乐播放指令""" | ||
clean_text = re.sub(r'[^\w\s]', '', text).strip() | ||
logger.bind(tag=TAG).debug(f"检查是否是音乐命令: {clean_text}") | ||
|
||
# 尝试匹配具体歌名 | ||
if os.path.exists(self.music_dir): | ||
music_files = [f for f in os.listdir(self.music_dir) if f.endswith('.mp3')] | ||
logger.bind(tag=TAG).debug(f"找到的音乐文件: {music_files}") | ||
|
||
potential_song = _extract_song_name(clean_text) | ||
if potential_song: | ||
best_match = _find_best_match(potential_song, music_files) | ||
if best_match: | ||
logger.bind(tag=TAG).info(f"找到最匹配的歌曲: {best_match}") | ||
await self.play_local_music(conn, specific_file=best_match) | ||
return True | ||
|
||
# 检查是否是通用播放音乐命令 | ||
if any(cmd in clean_text for cmd in self.music_related_keywords): | ||
await self.play_local_music(conn) | ||
return True | ||
|
||
return False | ||
|
||
async def play_local_music(self, conn, specific_file=None): | ||
"""播放本地音乐文件""" | ||
try: | ||
if not os.path.exists(self.music_dir): | ||
logger.bind(tag=TAG).error(f"音乐目录不存在: {self.music_dir}") | ||
return | ||
|
||
# 确保路径正确性 | ||
if specific_file: | ||
music_path = os.path.join(self.music_dir, specific_file) | ||
if not os.path.exists(music_path): | ||
logger.bind(tag=TAG).error(f"指定的音乐文件不存在: {music_path}") | ||
return | ||
selected_music = specific_file | ||
else: | ||
music_files = [f for f in os.listdir(self.music_dir) if f.endswith('.mp3')] | ||
if not music_files: | ||
logger.bind(tag=TAG).error("未找到MP3音乐文件") | ||
return | ||
selected_music = random.choice(music_files) | ||
music_path = os.path.join(self.music_dir, selected_music) | ||
text = f"正在播放{selected_music}" | ||
await send_stt_message(conn, text) | ||
conn.tts_first_text = selected_music | ||
conn.tts_last_text = selected_music | ||
conn.llm_finish_task = True | ||
opus_packets, duration = conn.tts.wav_to_opus_data(music_path) | ||
await sendAudioMessage(conn, opus_packets, duration, selected_music) | ||
|
||
except Exception as e: | ||
logger.bind(tag=TAG).error(f"播放音乐失败: {str(e)}") | ||
logger.bind(tag=TAG).error(f"详细错误: {traceback.format_exc()}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from config.logger import setup_logging | ||
import asyncio | ||
import time | ||
from core.utils.util import remove_punctuation_and_length | ||
from core.handle.sendAudioHandle import schedule_with_interrupt, send_stt_message | ||
|
||
TAG = __name__ | ||
logger = setup_logging() | ||
|
||
|
||
async def handleAudioMessage(conn, audio): | ||
if not conn.asr_server_receive: | ||
logger.bind(tag=TAG).debug(f"前期数据处理中,暂停接收") | ||
return | ||
if conn.client_listen_mode == "auto": | ||
have_voice = conn.vad.is_vad(conn, audio) | ||
else: | ||
have_voice = conn.client_have_voice | ||
|
||
# 如果本次没有声音,本段也没声音,就把声音丢弃了 | ||
if have_voice == False and conn.client_have_voice == False: | ||
await no_voice_close_connect(conn) | ||
conn.asr_audio.clear() | ||
return | ||
conn.client_no_voice_last_time = 0.0 | ||
conn.asr_audio.append(audio) | ||
# 如果本段有声音,且已经停止了 | ||
if conn.client_voice_stop: | ||
conn.client_abort = False | ||
conn.asr_server_receive = False | ||
# 音频太短了,无法识别 | ||
if len(conn.asr_audio) < 3: | ||
conn.asr_server_receive = True | ||
else: | ||
text, file_path = await conn.asr.speech_to_text(conn.asr_audio, conn.session_id) | ||
logger.bind(tag=TAG).info(f"识别文本: {text}") | ||
text_len, text_without_punctuation = remove_punctuation_and_length(text) | ||
if await conn.music_handler.handle_music_command(conn, text_without_punctuation): | ||
conn.asr_server_receive = True | ||
conn.asr_audio.clear() | ||
return | ||
if text_len <= conn.max_cmd_length and await handleCMDMessage(conn, text_without_punctuation): | ||
return | ||
if text_len > 0: | ||
await startToChat(conn, text) | ||
else: | ||
conn.asr_server_receive = True | ||
conn.asr_audio.clear() | ||
conn.reset_vad_states() | ||
|
||
|
||
async def handleCMDMessage(conn, text): | ||
cmd_exit = conn.cmd_exit | ||
for cmd in cmd_exit: | ||
if text == cmd: | ||
logger.bind(tag=TAG).info("识别到明确的退出命令".format(text)) | ||
await conn.close() | ||
return True | ||
return False | ||
|
||
|
||
async def startToChat(conn, text): | ||
# 异步发送 stt 信息 | ||
stt_task = asyncio.create_task( | ||
schedule_with_interrupt(0, send_stt_message(conn, text)) | ||
) | ||
conn.scheduled_tasks.append(stt_task) | ||
conn.executor.submit(conn.chat, text) | ||
|
||
|
||
async def no_voice_close_connect(conn): | ||
if conn.client_no_voice_last_time == 0.0: | ||
conn.client_no_voice_last_time = time.time() * 1000 | ||
else: | ||
no_voice_time = time.time() * 1000 - conn.client_no_voice_last_time | ||
close_connection_no_voice_time = conn.config.get("close_connection_no_voice_time", 120) | ||
if no_voice_time > 1000 * close_connection_no_voice_time: | ||
conn.client_abort = False | ||
conn.asr_server_receive = False | ||
prompt = "时间过得真快,我都好久没说话了。请你用十个字左右话跟我告别,以“再见”或“拜拜”为结尾" | ||
await startToChat(conn, prompt) |
Oops, something went wrong.