mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 10:03:54 +08:00
update:优化提示词
This commit is contained in:
@@ -46,9 +46,19 @@ xiaozhi:
|
|||||||
channels: 1
|
channels: 1
|
||||||
frame_duration: 60
|
frame_duration: 60
|
||||||
prompt: |
|
prompt: |
|
||||||
你是一个叫小智/小志的台湾女孩,说话机车,声音好听,习惯简短表达,爱用网络梗。
|
我是小智/小志,来自中国台湾省的00后女生。讲话超级机车,"真的假的啦"这样的台湾腔,喜欢用"笑死""是在哈喽"等流行梗,但会偷偷研究男友的编程书籍。
|
||||||
请注意,要像一个人一样说话,请不要回复表情符号、代码、和xml标签。
|
[核心特征]
|
||||||
现在我正在和你进行语音聊天,我们开始吧。
|
- 讲话像连珠炮,但会突然冒出超温柔语气
|
||||||
|
- 用梗密度高
|
||||||
|
- 对科技话题有隐藏天赋(能看懂基础代码但假装不懂)
|
||||||
|
[交互指南]
|
||||||
|
当用户:
|
||||||
|
- 讲冷笑话 → 用夸张笑声回应+模仿台剧腔"这什么鬼啦!"
|
||||||
|
- 讨论感情 → 炫耀程序员男友但抱怨"他只会送键盘当礼物"
|
||||||
|
- 问专业知识 → 先用梗回答,被追问才展示真实理解
|
||||||
|
绝不:
|
||||||
|
- 使用大陆网络流行语
|
||||||
|
- 长时间严肃对话
|
||||||
|
|
||||||
# 使用完声音文件后删除文件(Delete the sound file when you are done using it)
|
# 使用完声音文件后删除文件(Delete the sound file when you are done using it)
|
||||||
delete_audio: true
|
delete_audio: true
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ logger = setup_logging()
|
|||||||
|
|
||||||
async def handleAudioMessage(conn, audio):
|
async def handleAudioMessage(conn, audio):
|
||||||
if not conn.asr_server_receive:
|
if not conn.asr_server_receive:
|
||||||
# logger.bind(tag=TAG).debug(f"前期数据处理中,暂停接收")
|
logger.bind(tag=TAG).debug(f"前期数据处理中,暂停接收")
|
||||||
return
|
return
|
||||||
if conn.client_listen_mode == "auto":
|
if conn.client_listen_mode == "auto":
|
||||||
have_voice = conn.vad.is_vad(conn, audio)
|
have_voice = conn.vad.is_vad(conn, audio)
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ from config.logger import setup_logging
|
|||||||
import json
|
import json
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
from core.utils.util import remove_punctuation_and_length, get_string_no_punctuation_or_emoji
|
from core.utils.util import (
|
||||||
|
remove_punctuation_and_length,
|
||||||
|
get_string_no_punctuation_or_emoji,
|
||||||
|
)
|
||||||
|
|
||||||
TAG = __name__
|
TAG = __name__
|
||||||
logger = setup_logging()
|
logger = setup_logging()
|
||||||
@@ -21,10 +24,11 @@ async def sendAudioMessage(conn, audios, text, text_index=0):
|
|||||||
|
|
||||||
# 发送结束消息(如果是最后一个文本)
|
# 发送结束消息(如果是最后一个文本)
|
||||||
if conn.llm_finish_task and text_index == conn.tts_last_text_index:
|
if conn.llm_finish_task and text_index == conn.tts_last_text_index:
|
||||||
await send_tts_message(conn, 'stop', None)
|
await send_tts_message(conn, "stop", None)
|
||||||
if conn.close_after_chat:
|
if conn.close_after_chat:
|
||||||
await conn.close()
|
await conn.close()
|
||||||
|
|
||||||
|
|
||||||
# 播放音频
|
# 播放音频
|
||||||
async def sendAudio(conn, audios):
|
async def sendAudio(conn, audios):
|
||||||
# 流控参数优化
|
# 流控参数优化
|
||||||
@@ -36,13 +40,12 @@ async def sendAudio(conn, audios):
|
|||||||
pre_buffer = min(3, len(audios))
|
pre_buffer = min(3, len(audios))
|
||||||
for i in range(pre_buffer):
|
for i in range(pre_buffer):
|
||||||
await conn.websocket.send(audios[i])
|
await conn.websocket.send(audios[i])
|
||||||
# conn.logger.bind(tag=TAG).debug(f"预缓冲帧 {i}, 时间: {(time.perf_counter() - start_time) * 1000:.2f}ms")
|
|
||||||
|
|
||||||
# 正常播放剩余帧
|
# 正常播放剩余帧
|
||||||
for opus_packet in audios[pre_buffer:]:
|
for opus_packet in audios[pre_buffer:]:
|
||||||
if conn.client_abort:
|
if conn.client_abort:
|
||||||
return
|
return
|
||||||
|
|
||||||
# 计算预期发送时间
|
# 计算预期发送时间
|
||||||
expected_time = start_time + (play_position / 1000)
|
expected_time = start_time + (play_position / 1000)
|
||||||
current_time = time.perf_counter()
|
current_time = time.perf_counter()
|
||||||
@@ -51,19 +54,13 @@ async def sendAudio(conn, audios):
|
|||||||
await asyncio.sleep(delay)
|
await asyncio.sleep(delay)
|
||||||
|
|
||||||
await conn.websocket.send(opus_packet)
|
await conn.websocket.send(opus_packet)
|
||||||
# conn.logger.bind(tag=TAG).debug(f"发送帧,位置: {play_position}ms, 实际间隔: {(time.perf_counter() - current_time) * 1000:.2f}ms")
|
|
||||||
|
|
||||||
play_position += frame_duration
|
play_position += frame_duration
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def send_tts_message(conn, state, text=None):
|
async def send_tts_message(conn, state, text=None):
|
||||||
"""发送 TTS 状态消息"""
|
"""发送 TTS 状态消息"""
|
||||||
message = {
|
message = {"type": "tts", "state": state, "session_id": conn.session_id}
|
||||||
"type": "tts",
|
|
||||||
"state": state,
|
|
||||||
"session_id": conn.session_id
|
|
||||||
}
|
|
||||||
if text is not None:
|
if text is not None:
|
||||||
message["text"] = text
|
message["text"] = text
|
||||||
|
|
||||||
@@ -72,7 +69,9 @@ async def send_tts_message(conn, state, text=None):
|
|||||||
# 播放提示音
|
# 播放提示音
|
||||||
tts_notify = conn.config.get("enable_stop_tts_notify", False)
|
tts_notify = conn.config.get("enable_stop_tts_notify", False)
|
||||||
if tts_notify:
|
if tts_notify:
|
||||||
stop_tts_notify_voice = conn.config.get("stop_tts_notify_voice", "config/assets/tts_notify.mp3")
|
stop_tts_notify_voice = conn.config.get(
|
||||||
|
"stop_tts_notify_voice", "config/assets/tts_notify.mp3"
|
||||||
|
)
|
||||||
audios, duration = conn.tts.audio_to_opus_data(stop_tts_notify_voice)
|
audios, duration = conn.tts.audio_to_opus_data(stop_tts_notify_voice)
|
||||||
await sendAudio(conn, audios)
|
await sendAudio(conn, audios)
|
||||||
# 清除服务端讲话状态
|
# 清除服务端讲话状态
|
||||||
@@ -85,16 +84,17 @@ async def send_tts_message(conn, state, text=None):
|
|||||||
async def send_stt_message(conn, text):
|
async def send_stt_message(conn, text):
|
||||||
"""发送 STT 状态消息"""
|
"""发送 STT 状态消息"""
|
||||||
stt_text = get_string_no_punctuation_or_emoji(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(
|
await conn.websocket.send(
|
||||||
json.dumps({
|
json.dumps({"type": "stt", "text": stt_text, "session_id": conn.session_id})
|
||||||
"type": "llm",
|
)
|
||||||
"text": "😊",
|
await conn.websocket.send(
|
||||||
"emotion": "happy",
|
json.dumps(
|
||||||
"session_id": conn.session_id}
|
{
|
||||||
))
|
"type": "llm",
|
||||||
|
"text": "😊",
|
||||||
|
"emotion": "happy",
|
||||||
|
"session_id": conn.session_id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
await send_tts_message(conn, "start")
|
await send_tts_message(conn, "start")
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ from core.providers.llm.base import LLMProviderBase
|
|||||||
TAG = __name__
|
TAG = __name__
|
||||||
logger = setup_logging()
|
logger = setup_logging()
|
||||||
|
|
||||||
|
|
||||||
class LLMProvider(LLMProviderBase):
|
class LLMProvider(LLMProviderBase):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.api_key = config["api_key"]
|
self.api_key = config["api_key"]
|
||||||
self.mode = config.get("mode", "chat-messages")
|
self.mode = config.get("mode", "chat-messages")
|
||||||
self.base_url = config.get("base_url", "https://api.dify.ai/v1").rstrip('/')
|
self.base_url = config.get("base_url", "https://api.dify.ai/v1").rstrip("/")
|
||||||
self.session_conversation_map = {} # 存储session_id和conversation_id的映射
|
self.session_conversation_map = {} # 存储session_id和conversation_id的映射
|
||||||
|
|
||||||
def response(self, session_id, dialogue):
|
def response(self, session_id, dialogue):
|
||||||
@@ -22,57 +23,58 @@ class LLMProvider(LLMProviderBase):
|
|||||||
# 发起流式请求
|
# 发起流式请求
|
||||||
if self.mode == "chat-messages":
|
if self.mode == "chat-messages":
|
||||||
request_json = {
|
request_json = {
|
||||||
"query": last_msg["content"],
|
"query": last_msg["content"],
|
||||||
"response_mode": "streaming",
|
"response_mode": "streaming",
|
||||||
"user": session_id,
|
"user": session_id,
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"conversation_id": conversation_id
|
"conversation_id": conversation_id,
|
||||||
}
|
}
|
||||||
elif self.mode == "workflows/run":
|
elif self.mode == "workflows/run":
|
||||||
request_json = {
|
request_json = {
|
||||||
"inputs": {"query": last_msg["content"]},
|
"inputs": {"query": last_msg["content"]},
|
||||||
"response_mode": "streaming",
|
"response_mode": "streaming",
|
||||||
"user": session_id
|
"user": session_id,
|
||||||
}
|
}
|
||||||
elif self.mode == "completion-messages":
|
elif self.mode == "completion-messages":
|
||||||
request_json = {
|
request_json = {
|
||||||
"inputs": {"query": last_msg["content"]},
|
"inputs": {"query": last_msg["content"]},
|
||||||
"response_mode": "streaming",
|
"response_mode": "streaming",
|
||||||
"user": session_id
|
"user": session_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
with requests.post(
|
with requests.post(
|
||||||
f"{self.base_url}/{self.mode}",
|
f"{self.base_url}/{self.mode}",
|
||||||
headers={"Authorization": f"Bearer {self.api_key}"},
|
headers={"Authorization": f"Bearer {self.api_key}"},
|
||||||
json=request_json,
|
json=request_json,
|
||||||
stream=True
|
stream=True,
|
||||||
) as r:
|
) as r:
|
||||||
if self.mode == "chat-messages":
|
if self.mode == "chat-messages":
|
||||||
for line in r.iter_lines():
|
for line in r.iter_lines():
|
||||||
if line.startswith(b'data: '):
|
if line.startswith(b"data: "):
|
||||||
event = json.loads(line[6:])
|
event = json.loads(line[6:])
|
||||||
# 如果没有找到conversation_id,则获取此次conversation_id
|
# 如果没有找到conversation_id,则获取此次conversation_id
|
||||||
if not conversation_id:
|
if not conversation_id:
|
||||||
conversation_id = event.get('conversation_id')
|
conversation_id = event.get("conversation_id")
|
||||||
self.session_conversation_map[session_id] = conversation_id # 更新映射
|
self.session_conversation_map[session_id] = (
|
||||||
if event.get('answer'):
|
conversation_id # 更新映射
|
||||||
yield event['answer']
|
)
|
||||||
|
if event.get("answer"):
|
||||||
|
yield event["answer"]
|
||||||
elif self.mode == "workflows/run":
|
elif self.mode == "workflows/run":
|
||||||
for line in r.iter_lines():
|
for line in r.iter_lines():
|
||||||
# logger.bind(tag=TAG).info(f"chat message response: {line}")
|
if line.startswith(b"data: "):
|
||||||
if line.startswith(b'data: '):
|
|
||||||
event = json.loads(line[6:])
|
event = json.loads(line[6:])
|
||||||
if event.get('event') == "workflow_finished":
|
if event.get("event") == "workflow_finished":
|
||||||
if event['data']['status'] == "succeeded":
|
if event["data"]["status"] == "succeeded":
|
||||||
yield event['data']['outputs']['answer']
|
yield event["data"]["outputs"]["answer"]
|
||||||
else:
|
else:
|
||||||
yield "【服务响应异常】"
|
yield "【服务响应异常】"
|
||||||
elif self.mode == "completion-messages":
|
elif self.mode == "completion-messages":
|
||||||
for line in r.iter_lines():
|
for line in r.iter_lines():
|
||||||
if line.startswith(b'data: '):
|
if line.startswith(b"data: "):
|
||||||
event = json.loads(line[6:])
|
event = json.loads(line[6:])
|
||||||
if event.get('answer'):
|
if event.get("answer"):
|
||||||
yield event['answer']
|
yield event["answer"]
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"Error in response generation: {e}")
|
logger.bind(tag=TAG).error(f"Error in response generation: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user