宇树G1语音助手完整开发指南(下)——从零构建智能知识库对话系统

1. 前言回顾

在上篇文章中,我们完成了宇树G1语音助手的基础架构搭建(宇树G1语音助手完整开发指南(上)------从零构建智能知识库对话系统):

  • 系统架构设计与DDS通信机制
  • 环境配置与初始化流程
  • 状态机设计与线程安全处理
  • 语音识别消息订阅与回调

本文(下篇)将实现核心业务逻辑和生产部署方案:

  • 唤醒词检测与处理
  • TTS语音合成与回调机制
  • 用户问题处理与知识库查询
  • 超时检测与自动恢复

让我们继续完成语音助手的完整功能!

2. 核心业务逻辑实现

6. 唤醒词检测

python 复制代码
def check_wake_word(text: str) -> bool:
    """
    检查是否包含唤醒词
    支持多个唤醒词,用/分隔
    """
    # 清理文本:去除标点和空格
    text_clean = text.replace(",", "").replace(",", "").replace("。", "").replace(" ", "")
    wake_word_clean = WAKE_WORD.replace(",", "").replace(",", "")
    
    # 检查所有可能的唤醒词
    for word in wake_word_clean.split("/"):
        if word in text_clean:
            return True
    return False


def handle_wake_up():
    """处理唤醒事件"""
    print(f"\n🎉 [唤醒] 检测到唤醒词: {WAKE_WORD}")
    
    # 切换到回复状态
    set_state(RobotState.RESPONDING)
    
    # 播放唤醒回复,完成后自动进入监听状态
    speak_with_callback(
        WAKE_RESPONSE,
        lambda: set_state(RobotState.LISTENING)
    )

测试示例:

python 复制代码
check_wake_word("你好笨笨,请帮我查询")  # → True
check_wake_word("笨笨同学在吗")          # → True
check_wake_word("你好啊")                # → False

7. TTS语音合成与回调机制

这是整个系统的关键创新点------播放完成后自动切换状态

python 复制代码
def speak_with_callback(text: str, callback=None):
    """
    播放语音并在完成后执行回调
    
    参数:
        text: 要播放的文本
        callback: 播放完成后的回调函数
    """
    print(f"[播放] {text}")
    
    # 调用TTS接口
    audio_client.TtsMaker(text, 0)
    
    # 估算播放时长(中文约0.3秒/字)
    play_duration = len(text) * 0.3
    
    # 定时器在播放完成后执行回调
    def delayed_callback():
        time.sleep(play_duration)
        if callback:
            callback()
    
    timer = threading.Timer(play_duration, delayed_callback)
    timer.daemon = True  # 守护线程
    timer.start()

使用示例:

python 复制代码
# 唤醒回复后自动进入监听
speak_with_callback(
    "你好呀!",
    lambda: set_state(RobotState.LISTENING)
)

# 回答问题后继续监听
speak_with_callback(
    "G1机器人的最大速度是每秒2米。",
    lambda: set_state(RobotState.LISTENING)
)

8. 用户问题处理

python 复制代码
def handle_user_query(query: str):
    """
    处理用户查询
    
    流程:
        1. 检查是否为结束指令
        2. 调用知识库查询
        3. 播放答案并返回监听状态
    """
    print(f"\n❓ [用户问题] {query}")
    
    # ========== 1. 检查结束指令 ==========
    exit_keywords = ["再见", "拜拜", "退出", "结束", "谢谢"]
    if any(word in query for word in exit_keywords):
        set_state(RobotState.RESPONDING)
        speak_with_callback(
            "好的,再见!有问题随时叫我。",
            lambda: set_state(RobotState.IDLE)
        )
        return
    
    # ========== 2. 切换到回复状态 ==========
    set_state(RobotState.RESPONDING)
    
    # ========== 3. 查询知识库 ==========
    try:
        print(f"[查询] 正在搜索知识库...")
        answer = search_database(query)
        print(f"[结果] {answer}")
        
        if answer:
            # 找到答案
            speak_with_callback(
                answer,
                lambda: set_state(RobotState.LISTENING)
            )
        else:
            # 未找到答案
            speak_with_callback(
                "抱歉,我没有找到相关信息。",
                lambda: set_state(RobotState.LISTENING)
            )
            
    except Exception as e:
        # 查询异常
        print(f"[错误] 查询失败: {e}")
        speak_with_callback(
            "查询时出现问题,请稍后再试。",
            lambda: set_state(RobotState.LISTENING)
        )

9. 超时检测机制

防止机器人长时间占用监听状态:

python 复制代码
LISTEN_TIMEOUT = 200  # 超时时间(秒)

def check_timeout():
    """在主循环中定期检查超时"""
    global current_state, last_active_time
    
    with state_lock:
        if current_state == RobotState.LISTENING:
            elapsed = time.time() - last_active_time
            
            if elapsed > LISTEN_TIMEOUT:
                print(f"\n⏰ [超时] {LISTEN_TIMEOUT}秒无响应,回到待机")
                set_state(RobotState.RESPONDING)
                speak_with_callback(
                    "好的,有问题再叫我!",
                    lambda: set_state(RobotState.IDLE)
                )


# 主循环
while True:
    check_timeout()
    time.sleep(1)  # 每秒检查一次

10. 知识库查询接口

假设你已部署向量数据库(如Milvus、Chroma、Qdrant),接口设计如下:

python 复制代码
def search_database(query: str) -> str:
    """
    查询知识库(向量数据库)
    
    参数:
        query: 用户问题
        
    返回:
        str: 最佳答案,未找到返回空字符串
    
    实现示例(伪代码):
    """
    try:
        # 1. 文本向量化
        query_vector = embedding_model.encode(query)
        
        # 2. 向量检索
        results = vector_db.search(
            collection_name="knowledge_base",
            query_vector=query_vector,
            top_k=1,
            score_threshold=0.7  # 相似度阈值
        )
        
        # 3. 返回最佳结果
        if results and results[0].score > 0.7:
            return results[0].content
        else:
            return ""
            
    except Exception as e:
        print(f"[错误] 数据库查询异常: {e}")
        return ""

2. 使用说明

1. 基础使用

bash 复制代码
# 1. 连接机器人网线
# 2. 配置网络接口(修改代码中的NETWORK_INTERFACE)
# 3. 运行程序
python3 voice_assistant.py

2. 交互示例

复制代码
[系统] 🎤 语音助手已启动,正在监听...
[系统] 💡 请说 "你好笨笨" 唤醒我

[ASR] 你好笨笨 ✓ (置信度:0.95)
🎉 [唤醒] 检测到唤醒词: 你好笨笨
[状态] 待机中 -> 回复中
[播放] 你好呀!
[状态] 回复中 -> 监听中

[ASR] G1机器人的最大速度是多少 ✓ (置信度:0.89)
❓ [用户问题] G1机器人的最大速度是多少
[查询] 用户问题:G1机器人的最大速度是多少
[结果] 知识库查询结果:G1机器人的最大行走速度为每秒2米,奔跑速度可达每秒5米。
[状态] 监听中 -> 回复中
[播放] G1机器人的最大行走速度为每秒2米,奔跑速度可达每秒5米。
[状态] 回复中 -> 监听中

[ASR] 谢谢再见 ✓ (置信度:0.92)
❓ [用户问题] 谢谢再见
[状态] 监听中 -> 回复中
[播放] 好的,再见!有问题随时叫我。
[状态] 回复中 -> 待机中

3. 配置调优

python 复制代码
# 调整置信度阈值(降低误识别)
if not text or confidence < 0.6:  # 从0.4提高到0.6
    return

# 调整问题长度过滤(避免误触发)
elif len(text.strip()) > 8:  # 从5提高到8
    handle_user_query(text)

# 调整超时时间
LISTEN_TIMEOUT = 120  # 从200秒改为120秒

常见问题

Q1: 回调函数收不到消息?

bash 复制代码
# 检查清单:
# ✓ 网络连接是否正常?
ping 192.168.123.164

# ✓ 网卡名称是否正确?
ifconfig  # 查看实际网卡名

# ✓ DDS是否初始化?
# 确保 ChannelFactoryInitialize 在最前面

# ✓ 订阅话题是否正确?
# 应为 "rt/audio_msg"

Q2: 唤醒词识别率低?

python 复制代码
# 优化方案:
# 1. 降低置信度阈值
if not text or confidence < 0.3:  # 降低到0.3

# 2. 增加更多唤醒词
WAKE_WORD = "你好笨笨/笨笨同学/嘿笨笨/笨笨你好"

# 3. 使用模糊匹配
def check_wake_word(text: str) -> bool:
    for word in ["笨笨", "助手", "机器人"]:
        if word in text:
            return True
    return False

Q3: TTS播放时长估算不准?

python 复制代码
# 优化估算算法
def estimate_duration(text):
    # 分别计算中英文
    chinese_chars = len([c for c in text if '\u4e00' <= c <= '\u9fff'])
    english_words = len(text.split()) - chinese_chars
    
    # 中文0.35秒/字,英文0.15秒/词
    duration = chinese_chars * 0.35 + english_words * 0.15
    
    # 添加0.5秒缓冲
    return duration + 0.5

Q4: 如何调试状态机逻辑?

python 复制代码
# 添加详细日志
def set_state(new_state: RobotState):
    import traceback
    
    with state_lock:
        if current_state != new_state:
            # 打印调用栈
            stack = traceback.format_stack()[-3]
            print(f"[状态] {current_state.value} -> {new_state.value}")
            print(f"[调用] {stack}")
            
            current_state = new_state

总结

本文详细介绍了宇树G1语音助手的完整开发流程,涵盖:

  • DDS通信机制:消息订阅与回调处理
  • 状态机设计:清晰的状态转换逻辑
  • 线程安全:多线程环境下的状态保护
  • 语音识别:置信度过滤与文本处理
  • 知识库集成:向量数据库查询接口
  • 超时控制:防止长时间占用监听

完整代码随后会上传到资源库。


相关资源:

如果觉得本文有帮助,欢迎点赞、收藏、分享! 🎉

相关推荐
Katecat996632 小时前
古巽伽罗语字符识别与分类_Cascade-Mask-RCNN_RegNetX-400MF实现
人工智能·目标跟踪
说文科技2 小时前
大模型项目实战之dpo微调
人工智能·算法
周杰伦_Jay2 小时前
【Mac 上命令行安装 Claude Code】(Claude 的终端版 AI 编程助手)完整指南
人工智能·macos·claude code
一只理智恩2 小时前
AI辅助,两天实现一个IM系统?
人工智能
薛定谔的猫19822 小时前
二十、使用PyTorch和Hugging Face Transformers训练中文GPT-2模型的技术实践
人工智能·pytorch·gpt
zhangfeng11332 小时前
大模型微调主要框架 Firefly vs LLaMA Factory 全方位对比表
人工智能·语言模型·开源·llama
爱打代码的小林2 小时前
OpenCV 实现实时人脸检测
人工智能·opencv·计算机视觉
cyyt2 小时前
深度学习周报(1.26~2.1)
人工智能·深度学习
YOLO视觉与编程2 小时前
yolo26目标检测可视化界面系统源码
人工智能·目标检测·计算机视觉