add:支持手动按住说话

This commit is contained in:
hrz
2025-02-04 13:57:05 +08:00
parent 93acdb5861
commit 22506019a9
5 changed files with 59 additions and 34 deletions
+2 -2
View File
@@ -27,16 +27,16 @@
## 已实现
- `xiaozhi-esp32` 通信 WebSocket 协议
- 支持实时打断对话,试一下在聊天的时候说一句`你好小智`
- 支持唤醒对话、手动对话、实时打断对话
- 支持国语、粤语、英语、日语、韩语 5 种语言识别(FunASR(默认))
- 自由更换 LLM(支持ChatGLM(默认)、Dify、DeepSeek
- 自由更换 TTS(支持EdgeTTS(默认)、火山引擎豆包TTS)
## 正在实现
- 按键手动对话
- 长时间不聊天进入休眠状态
- 对话记忆
- 更换心情模式
## 本项目依赖服务
+2 -2
View File
@@ -32,16 +32,16 @@ To fully experience this project, follow these steps:
## Implemented
- `xiaozhi-esp32` WebSocket communication protocol
- Support interrupt dialogue in real time, try to say a sentence when chatting `你好小智`
- Supports wake-word initiated dialogue, manual dialogue, and real-time interruption of dialogue.
- Support for 5 languages: Mandarin, Cantonese, English, Japanese, Korean (FunASR - default)
- Flexible LLM switching (ChatGLM - default, Dify, DeepSeek)
- Flexible TTS switching (EdgeTTS - default, ByteDance Doubao TTS)
## In Progress
- Manual button-triggered dialogue
- Sleep mode after inactivity
- Dialogue memory
- Change the mood mode
## Dependencies
+4 -15
View File
@@ -12,8 +12,6 @@ from collections import deque
from core.utils.util import is_segment
from core.utils.dialogue import Message, Dialogue
from core.handle.textHandle import handleTextMessage
from core.handle.abortHandle import handleAbortMessage
from core.handle.helloHandle import handleHelloMessage
from core.utils.util import get_string_no_punctuation_or_emoji
from concurrent.futures import ThreadPoolExecutor, TimeoutError
from core.handle.audioHandle import handleAudioMessage, sendAudioMessage
@@ -29,7 +27,10 @@ class ConnectionHandler:
self.session_id = None
self.prompt = None
self.welcome_msg = None
# 客户端状态相关
self.client_abort = False
self.client_listen_mode = "auto"
# 线程任务相关
self.loop = asyncio.get_event_loop()
@@ -91,22 +92,10 @@ class ConnectionHandler:
async def _route_message(self, message):
"""消息路由"""
if isinstance(message, str):
await self._handle_text(message)
await handleTextMessage(self, message)
elif isinstance(message, bytes):
await handleAudioMessage(self, message)
async def _handle_text(self, message):
"""处理文本消息"""
self.logger.info(f"收到文本消息:{message}")
try:
msg_json = json.loads(message)
if msg_json["type"] == "hello":
await handleHelloMessage(self, "你好")
if msg_json["type"] == "abort":
await handleAbortMessage(self)
except json.JSONDecodeError:
await handleTextMessage(self, message)
def _initialize_components(self):
self.prompt = self.config["prompt"]
# 赋予LLM时间观念
+21 -15
View File
@@ -11,7 +11,10 @@ async def handleAudioMessage(conn, audio):
if not conn.asr_server_receive:
logger.debug(f"前期数据处理中,暂停接收")
return
have_voice = conn.vad.is_vad(conn, audio)
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:
@@ -26,25 +29,28 @@ async def handleAudioMessage(conn, audio):
logger.info(f"识别文本: {text}")
text_len = remove_punctuation_and_length(text)
if text_len > 0:
stt_text = get_string_no_punctuation_or_emoji(text)
await conn.websocket.send(json.dumps({
"type": "stt",
"text": stt_text,
"session_id": conn.session_id}
))
await conn.websocket.send(
json.dumps({
"type": "llm",
"text": "😊",
"emotion": "happy",
"session_id": conn.session_id}
))
conn.executor.submit(conn.chat, text)
await startToChat(conn, text)
else:
conn.asr_server_receive = True
conn.asr_audio.clear()
conn.reset_vad_states()
async def startToChat(conn, text):
stt_text = get_string_no_punctuation_or_emoji(text)
await conn.websocket.send(json.dumps({
"type": "stt",
"text": stt_text,
"session_id": conn.session_id}
))
await conn.websocket.send(
json.dumps({
"type": "llm",
"text": "😊",
"emotion": "happy",
"session_id": conn.session_id}
))
conn.executor.submit(conn.chat, text)
async def sendAudioMessage(conn, audios, duration, text):
base_delay = conn.tts_duration
+30
View File
@@ -1,7 +1,37 @@
import logging
import json
from core.handle.abortHandle import handleAbortMessage
from core.handle.helloHandle import handleHelloMessage
from core.handle.audioHandle import startToChat
logger = logging.getLogger(__name__)
async def handleTextMessage(conn, message):
"""处理文本消息"""
logger.info(f"收到文本消息:{message}")
try:
msg_json = json.loads(message)
if msg_json["type"] == "hello":
await handleHelloMessage(conn, "你好")
elif msg_json["type"] == "abort":
await handleAbortMessage(conn)
elif msg_json["type"] == "listen":
if "mode" in msg_json:
conn.client_listen_mode = msg_json["mode"]
logger.info(f"客户端拾音模式:{conn.client_listen_mode}")
if msg_json["state"] == "start":
conn.client_have_voice = True
conn.client_voice_stop = False
elif msg_json["state"] == "stop":
conn.client_have_voice = True
conn.client_voice_stop = True
elif msg_json["state"] == "detect":
conn.asr_server_receive = False
conn.client_have_voice = False
conn.asr_audio.clear()
if "text" in msg_json:
await startToChat(conn, msg_json["text"])
except json.JSONDecodeError:
await handleTextMessage(conn, message)
await conn.websocket.send(message)