树莓派Linux实现ChatGPT语音交互(语音识别,TTS)

[复制链接]
发表于 2026-10-3 13:48:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

树莓派上做一个会听会说的语音助手

思路其实很朴素:麦克风录音 → 语音识别成文字 → 调大模型 API 得到回答 → TTS 合成语音 → 播放器播出。四段各用一个库搞定,串起来就是一个能对话的树莓派音箱。整个方案在树莓派 4B 上就能跑,成本不到两百块。

一、准备 API 密钥

先在对应平台申请密钥并保存好:

  • 大模型侧:进 OpenAI 的 API Keys 页面创建一个 key(模型可以换成国内可用的替代,代码差异很小)。
  • TTS 侧:阿里云百炼 dashscope 申请 api key,它有 SamBERT 系列中文语音合成,延迟低、听感自然,国内网络下速度优势明显。

两个 key 都要写进环境变量或配置文件,别硬编码进脚本里提交到 git。免费额度有限(大模型侧常见 5 美元起步额度),日常自测基本用不完。

二、装依赖

pip3 install openai
pip3 install SpeechRecognition
pip3 install dashscope
pip3 install pygame

几个包各司其职:SpeechRecognition 做 ASR,dashscope 提供 SamBERT 的 TTS,pygame 的 mixer 是实测里延迟最低、最稳的 Python 音频播放方式。

三、先验证大模型 API

先用一段最小代码确认 key 和模型都通:

# -*- coding: utf-8 -*-
import openai

openai.api_key = 'sk-xxxxxxxx'      # 换成你自己的 key

conversation_history = [
    {'role': 'system', 'content': 'You are a helpful assistant.'}
]

while True:
    user_input = input("User: ")
    conversation_history.append({'role': 'user', 'content': user_input})

    response = openai.ChatCompletion.create(
        model='gpt-3.5-turbo',
        messages=conversation_history,
        max_tokens=100,
        n=1,
        stop=None,
        temperature=0.7
    )

    assistant_reply = response['choices'][0]['message']['content']
    print("Assistant:", assistant_reply)
    conversation_history.append({'role': 'assistant', 'content': assistant_reply})

    if user_input.lower() == 'exit':
        break

能问答就说明 API 段通了。把 conversation_history 带着一起传是关键——多轮对话靠这个历史列表,不传就只能一问一答、模型没有记忆。

四、语音识别(ASR)

硬件上一台免驱 USB 麦克风就够(树莓派原生的 3.5mm 口录不了,别走那个坑)。插上先确认系统认得:

arecord -l
# 能看到 card 就说明音频输入设备就绪
import speech_recognition as sr

r = sr.Recognizer()

with sr.Microphone() as source:
    print("请说话:")
    audio = r.listen(source)

try:
    text = r.recognize_google(audio, language='zh-CN')
    print("你说的是:" + text)
except sr.UnknownValueError:
    print("无法识别你的语音")
except sr.RequestError as e:
    print("无法连接识别服务,错误原因:" + str(e))

几点实战体会:

  • 安静环境识别率高,嘈杂环境基本废——先用 r.adjust_for_ambient_noise(source) 做一次环境噪声校准。
  • recognize_google 需要能访问 Google 的服务,网络不通就换国内 ASR(百度、讯飞、阿里 Paraformer),接口换成对应 SDK 即可,形状一样:audio → text。
  • 识别结果存在 text 变量里,下一步直接塞给大模型就行。

五、TTS 合成语音

# coding=utf-8
import dashscope
from dashscope.audio.tts import SpeechSynthesizer

dashscope.api_key = 'your-dashscope-api-key'

result = SpeechSynthesizer.call(
    model='sambert-zhichu-v1',      # 可换成 sambert-zhimiao-emo-v1 等带情绪的版本
    text='今天天气怎么样',
    sample_rate=48000,
    format='wav'
)

if result.get_audio_data() is not None:
    with open('output.wav', 'wb') as f:
        f.write(result.get_audio_data())
    print('get response: %s' % (result.get_response()))

跑完目录里会多一个 output.wav(这里存的是模型回答的音频)。

六、播放音频

pip3 install pygame
import pygame
from pygame import mixer

mixer.init()
mixer.music.load('output.wav')
mixer.music.play()

while mixer.music.get_busy():        # 播完再往下走,别急着退出
    pass

七、整合成一个语音对话循环

# -*- coding: utf-8 -*-
import openai
import time
import pygame
from pygame import mixer
import dashscope
from dashscope.audio.tts import SpeechSynthesizer
import speech_recognition as sr

r = sr.Recognizer()
mixer.init()

openai.api_key = 'sk-xxxx'
dashscope.api_key = 'sk-xxxx'

conversation_history = [
    {'role': 'system', 'content': 'You are a helpful assistant.'}
]

while True:
    with sr.Microphone() as source:
        print("请开始说话...")
        audio = r.listen(source)

    try:
        text = r.recognize_google(audio, language='zh-CN')
        print("识别结果:", text)
    except sr.UnknownValueError:
        print("无法识别音频")
        continue
    except sr.RequestError as e:
        print("请求出错:", e)
        continue

    conversation_history.append({'role': 'user', 'content': text})

    response = openai.ChatCompletion.create(
        model='gpt-3.5-turbo',
        messages=conversation_history,
        max_tokens=100,
        n=1,
        stop=None,
        temperature=0.7
    )

    assistant_reply = response['choices'][0]['message']['content']

    result = SpeechSynthesizer.call(
        model='sambert-zhimiao-emo-v1',
        text=assistant_reply,
        sample_rate=48000,
        format='wav'
    )

    print("Assistant:", assistant_reply)
    if result.get_audio_data() is not None:
        with open('output.wav', 'wb') as f:
            f.write(result.get_audio_data())
        mixer.music.load('output.wav')
        mixer.music.play()

    conversation_history.append({'role': 'assistant', 'content': assistant_reply})
    time.sleep(1)
    while pygame.mixer.music.get_busy():
        pass

两处原代码的小 bug 顺手修了:一是 recognize_google 异常后 text 可能未定义就往下走,会抛 UnboundLocalError,这里加了 continue;二是 pygame 用了 pygame.mixer 但只 import 了 mixer,get_busy 调用要统一。

八、性能与排错

  • 延时主要花在两端:ASR 和 TTS 都是联网请求,本地只做编解码。整个来回几秒是正常的,别指望秒回。
  • 识别率差:先 r.adjust_for_ambient_noise(source) 校准,再把麦克风离嘴 10–20 cm,噪音大就换指向性麦克风。
  • 没声音:先 paplay output.wav 或 aplay output.wav 用命令行播一次,确认功放/耳机接对了再怪 pygame。
  • 树莓派 CPU 吃紧:ARM 上跑 Python 事件循环没压力,但 TTS 的 48 kHz wav 下载占带宽,sample_rate 降到 16000 明显更轻。
  • 想换模型:ASR 换国内引擎、大模型换任何 OpenAI 兼容接口,都是替换 xxx.create(...) 那一处,整体结构不用动。

小结

整套方案拆开就四步:Recognizer 拿音频转文字 → 带 history 调大模型 → SamBERT 把回答合成 wav → pygame mixer 播完再进下一轮。跑通之后把它挂成 systemd 服务、开机自启,就是一个摆在家里随时能用的语音助手。真正耗时间的地方从来不是代码,而是麦克风硬件选型和网络连通性——这两样搞定,剩下都是拼装。

qidao123.com企服评测-应用市场 编辑提示

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表