Files
xiaozhi-esp32-server/main/xiaozhi-server/core/handle/intentHandler.py
T

131 lines
4.7 KiB
Python
Raw Normal View History

2025-03-09 21:33:45 +08:00
from config.logger import setup_logging
import json
2025-03-17 02:13:10 +08:00
import uuid
2025-03-09 21:33:45 +08:00
from core.handle.sendAudioHandle import send_stt_message
2025-03-23 22:02:13 +08:00
from core.handle.helloHandle import checkWakeupWords
2025-03-13 00:54:01 +08:00
from core.utils.util import remove_punctuation_and_length
2025-03-28 14:13:54 +08:00
from core.utils.dialogue import Message
2025-03-25 14:28:59 +08:00
from loguru import logger
2025-03-09 21:33:45 +08:00
TAG = __name__
logger = setup_logging()
async def handle_user_intent(conn, text):
# 检查是否有明确的退出命令
if await check_direct_exit(conn, text):
return True
2025-03-23 22:02:13 +08:00
# 检查是否是唤醒词
if await checkWakeupWords(conn, text):
return True
2025-03-09 21:33:45 +08:00
if conn.use_function_call_mode:
# 使用支持function calling的聊天方法,不再进行意图分析
return False
# 使用LLM进行意图分析
2025-03-25 14:28:59 +08:00
intent_result = await analyze_intent_with_llm(conn, text)
if not intent_result:
2025-03-09 21:33:45 +08:00
return False
# 处理各种意图
2025-03-25 14:28:59 +08:00
return await process_intent_result(conn, intent_result, text)
2025-03-09 21:33:45 +08:00
async def check_direct_exit(conn, text):
"""检查是否有明确的退出命令"""
2025-03-13 00:54:01 +08:00
_, text = remove_punctuation_and_length(text)
2025-03-09 21:33:45 +08:00
cmd_exit = conn.cmd_exit
for cmd in cmd_exit:
if text == cmd:
logger.bind(tag=TAG).info(f"识别到明确的退出命令: {text}")
await send_stt_message(conn, text)
2025-03-09 21:33:45 +08:00
await conn.close()
return True
return False
async def analyze_intent_with_llm(conn, text):
"""使用LLM分析用户意图"""
if not hasattr(conn, 'intent') or not conn.intent:
logger.bind(tag=TAG).warning("意图识别服务未初始化")
return None
2025-03-11 00:25:33 +08:00
# 对话历史记录
2025-03-09 21:33:45 +08:00
dialogue = conn.dialogue
try:
2025-03-13 00:54:01 +08:00
intent_result = await conn.intent.detect_intent(conn, dialogue.dialogue, text)
2025-03-25 14:28:59 +08:00
return intent_result
2025-03-09 21:33:45 +08:00
except Exception as e:
logger.bind(tag=TAG).error(f"意图识别失败: {str(e)}")
return None
2025-03-25 14:28:59 +08:00
async def process_intent_result(conn, intent_result, original_text):
2025-03-09 21:33:45 +08:00
"""处理意图识别结果"""
2025-03-25 14:28:59 +08:00
try:
# 尝试将结果解析为JSON
intent_data = json.loads(intent_result)
2025-03-28 14:13:54 +08:00
2025-03-25 14:28:59 +08:00
# 检查是否有function_call
if "function_call" in intent_data:
# 直接从意图识别获取了function_call
logger.bind(tag=TAG).info(f"检测到function_call格式的意图结果: {intent_data['function_call']['name']}")
function_name = intent_data["function_call"]["name"]
2025-03-28 14:13:54 +08:00
if function_name == "continue_chat":
return False
function_args = None
if "arguments" in intent_data["function_call"]:
function_args = intent_data["function_call"]["arguments"]
2025-03-25 14:28:59 +08:00
# 确保参数是字符串格式的JSON
if isinstance(function_args, dict):
function_args = json.dumps(function_args)
2025-03-28 14:13:54 +08:00
2025-03-25 14:28:59 +08:00
function_call_data = {
"name": function_name,
"id": str(uuid.uuid4().hex),
"arguments": function_args
}
2025-03-09 21:33:45 +08:00
2025-03-25 14:28:59 +08:00
await send_stt_message(conn, original_text)
2025-03-28 14:13:54 +08:00
2025-03-25 14:28:59 +08:00
# 使用executor执行函数调用和结果处理
2025-03-28 14:13:54 +08:00
def process_function_call():
conn.dialogue.put(Message(role="user", content=original_text))
2025-03-25 14:28:59 +08:00
result = conn.func_handler.handle_llm_function_call(conn, function_call_data)
if result and function_name != 'play_music':
2025-03-25 14:28:59 +08:00
# 获取当前最新的文本索引
text = result.response
if text is None:
text = result.result
if text is not None:
text_index = conn.tts_last_text_index + 1 if hasattr(conn, 'tts_last_text_index') else 0
conn.recode_first_last_text(text, text_index)
future = conn.executor.submit(conn.speak_and_play, text, text_index)
conn.llm_finish_task = True
conn.tts_queue.put(future)
conn.dialogue.put(Message(role="assistant", content=text))
2025-03-28 14:13:54 +08:00
2025-03-25 14:28:59 +08:00
# 将函数执行放在线程池中
2025-03-28 14:13:54 +08:00
conn.executor.submit(process_function_call)
2025-03-25 14:28:59 +08:00
return True
2025-03-28 14:13:54 +08:00
return False
except json.JSONDecodeError as e:
2025-03-25 14:28:59 +08:00
logger.bind(tag=TAG).error(f"处理意图结果时出错: {e}")
2025-03-28 14:13:54 +08:00
return False
2025-03-17 02:13:10 +08:00
def extract_text_in_brackets(s):
"""
从字符串中提取中括号内的文字
:param s: 输入字符串
:return: 中括号内的文字,如果不存在则返回空字符串
"""
left_bracket_index = s.find('[')
right_bracket_index = s.find(']')
if left_bracket_index != -1 and right_bracket_index != -1 and left_bracket_index < right_bracket_index:
return s[left_bracket_index + 1:right_bracket_index]
else:
2025-03-25 14:28:59 +08:00
return ""