基于Whisper与ChatGPT构建本地智能语音助手:从原理到Home Assistant集成实战
语音识别(STT)与自然语言处理(NLP)是构建智能交互系统的两大核心技术。语音识别负责将音频信号转化为文本,其核心原理涉及声学模型与语言模型的协同工作,以应对不同口音和噪声环境的挑战。自然语言处理则致力于让机器理解人类语言的意图,其技术价值在于将非结构化的文本指令转化为计算机可执行的、结构化的命令,从而实现从“听懂”到“理解”的跨越。这一技术组合在智能家居、语音助手、无障碍交互等场景中具有广泛应
1. 项目概述与核心价值
最近在折腾智能家居和语音交互,发现市面上的方案要么太“重”,需要一整套生态;要么太“傻”,识别不准还反应慢。直到我看到了GitHub上这个名为“SheikhAminul/ChatGPT-voice-control”的项目,眼前顿时一亮。这本质上是一个利用OpenAI的Whisper语音识别模型和ChatGPT大语言模型,将本地语音指令转化为智能响应的Python脚本。它最吸引我的地方在于其“轻量”和“智能”的结合——你不需要昂贵的智能音箱硬件,只需要一台能跑Python的电脑(甚至树莓派),就能获得一个理解力超强、能处理复杂指令的私人语音助手。
这个项目解决了几个核心痛点。首先,它实现了高质量的离线或在线语音转文本(STT)。Whisper模型在识别准确率,尤其是对中文的识别上,表现远超许多开源方案。其次,它接入了ChatGPT,这意味着你的语音指令不再局限于“开灯”、“关空调”这种预设的关键词匹配。你可以用更自然、更复杂的方式下达指令,比如“把客厅的灯光调到适合看电影的亮度,顺便把空调设为26度”,ChatGPT能够理解这句话的意图,并将其解析成具体的、可执行的动作命令。最后,整个流程是模块化的,你可以轻松地将ChatGPT生成的文本响应,通过自定义的逻辑,去控制家里的智能设备、执行系统命令,或者进行任何你想要的自动化操作。
简单来说,这个项目为你提供了一个强大的“大脑”(ChatGPT)和“耳朵”(Whisper),你需要做的,就是为它配上“手”和“脚”(即执行具体动作的代码)。无论是资深开发者想打造高度定制化的智能中控,还是编程爱好者想体验一把AI语音交互的魅力,这个项目都是一个极佳的起点。接下来,我将从环境搭建到核心代码解析,再到实战扩展,带你完整复现并深度定制这个项目。
2. 环境准备与依赖部署
工欲善其事,必先利其器。这个项目的运行依赖于一个稳定的Python环境以及几个关键的库。我强烈建议使用 conda 或 venv 创建一个独立的虚拟环境,避免与系统其他Python项目产生依赖冲突。
2.1 创建与激活虚拟环境
如果你使用 conda (我个人更推荐,尤其在处理不同版本的Python和库时更省心),可以这样操作:
# 创建一个名为`chatgpt-voice`的Python3.9环境
conda create -n chatgpt-voice python=3.9
# 激活环境
conda activate chatgpt-voice
如果使用 venv :
# 在项目目录下创建虚拟环境
python -m venv venv
# 激活环境 (Linux/macOS)
source venv/bin/activate
# 激活环境 (Windows)
venv\Scripts\activate
2.2 安装核心依赖
项目原作者可能提供了 requirements.txt ,但根据其核心功能,我们必须确保以下几个库的版本是兼容的。我根据实测,整理了一份更稳定的依赖列表:
pip install openai==0.28.1 # OpenAI API客户端
pip install whisper-openai # 这是OpenAI官方维护的Whisper Python包,比`whisper`更推荐
pip install sounddevice # 用于录制音频
pip install numpy # 音频数据处理
pip install scipy # 可能用于音频处理
pip install pydub # 音频格式转换(如果需要处理mp3等)
pip install python-dotenv # 管理环境变量,保护你的API Key
注意 :
whisper模型本身在首次运行时会自动下载模型文件(如base,small,medium)。small模型在精度和速度上取得了很好的平衡,适合大多数场景。如果你追求极致的准确率且机器性能足够(最好有GPU),可以考虑medium甚至large模型。
2.3 获取并配置OpenAI API密钥
这是项目的关键一步。你需要一个有效的OpenAI API密钥来调用ChatGPT和Whisper的API服务(如果你选择使用API而非本地Whisper模型)。
- 访问 OpenAI平台 并登录。
- 点击右上角个人头像,选择“View API keys”。
- 点击“Create new secret key”来生成一个新的密钥。 请立即复制并妥善保存这个密钥,关闭页面后将无法再次查看完整密钥。
为了安全地使用这个密钥,我们采用环境变量管理,而不是硬编码在脚本里。在项目根目录下创建一个名为 .env 的文件,内容如下:
OPENAI_API_KEY=你的实际API密钥
然后在你的Python脚本中,通过 python-dotenv 来加载:
from dotenv import load_dotenv
import os
load_dotenv() # 加载.env文件中的环境变量
api_key = os.getenv("OPENAI_API_KEY")
2.4 音频输入设备检查
项目使用 sounddevice 库进行录音。在编写代码前,最好先确认你的麦克风能被正确识别。你可以运行一个简单的测试脚本:
import sounddevice as sd
print(sd.query_devices()) # 打印所有音频设备
# 通常,默认输入设备是我们要用的。记录下它的设备ID(通常是0)。
如果输出列表为空或找不到麦克风,你需要检查系统的音频设置,确保麦克风权限已授予给你的Python环境或终端。
3. 核心代码模块深度解析
原项目代码结构清晰,我们可以将其拆解为三个核心模块: 语音录制 、 语音转文本(STT) 、 文本交互与意图解析(ChatGPT) 。我将逐一解析,并补充关键细节和优化点。
3.1 语音录制模块:稳定获取音频流
录音的质量直接影响到Whisper识别的准确率。我们需要录制一段音频,并将其保存为Whisper支持的格式(如WAV)。这里的关键参数是采样率( samplerate )和录音时长。
import sounddevice as sd
import numpy as np
from scipy.io.wavfile import write
import tempfile
import os
def record_audio(duration=5, samplerate=16000, device=None):
"""
录制指定时长的音频。
Args:
duration: 录音时长(秒)
samplerate: 采样率,Whisper推荐16000 Hz
device: 输入设备ID,None为默认设备
Returns:
audio_numpy: 录音的numpy数组
temp_file_path: 临时WAV文件路径
"""
print(f"开始录音,请说话...(最长{duration}秒)")
# 录制音频,返回的是numpy数组
audio_data = sd.rec(int(duration * samplerate),
samplerate=samplerate,
channels=1, # 单声道足以满足语音识别
dtype='float32',
device=device)
sd.wait() # 等待录音完成
print("录音结束。")
# 将float32的音频数据转换为int16,这是WAV文件常用的格式
audio_int16 = (audio_data * 32767).astype(np.int16)
# 创建临时文件保存音频
with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as tmpfile:
temp_file_path = tmpfile.name
write(temp_file_path, samplerate, audio_int16)
return audio_data, temp_file_path
实操心得 :
duration不宜设置过短,否则用户话没说完就结束了;也不宜过长,否则会一直录音占用资源。一个折中的方案是 实现一个“静音检测”(VAD)功能 ,当检测到用户停止说话一段时间后自动结束录音。这能极大提升体验。你可以使用webrtcvad这样的库来实现,虽然会增加一些复杂度,但对于追求产品化的项目来说是值得的。
3.2 语音转文本模块:Whisper的本地与云端抉择
这是项目的“耳朵”。你有两种选择:使用本地Whisper模型,或调用OpenAI的Whisper API。
方案一:本地Whisper模型(离线、免费,但消耗计算资源)
import whisper
def transcribe_local(audio_file_path, model_name="small"):
"""
使用本地Whisper模型进行语音识别。
Args:
audio_file_path: 音频文件路径
model_name: 模型大小,可选"tiny", "base", "small", "medium", "large"
Returns:
text: 识别出的文本
"""
# 加载模型(首次运行会下载)
model = whisper.load_model(model_name)
# 执行识别
result = model.transcribe(audio_file_path, language="zh") # 指定中文,提升准确率
return result["text"]
优势 :完全离线,无需网络,没有API调用费用,隐私性好。 劣势 :首次下载模型慢(小模型约500MB),转录速度取决于CPU/GPU性能,大模型对内存要求高。
方案二:OpenAI Whisper API(在线、准确率高、需付费)
from openai import OpenAI
import os
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def transcribe_api(audio_file_path):
"""
调用OpenAI的Whisper API进行语音识别。
Args:
audio_file_path: 音频文件路径
Returns:
text: 识别出的文本
"""
with open(audio_file_path, "rb") as audio_file:
transcript = client.audio.transcriptions.create(
model="whisper-1",
file=audio_file,
language="zh" # 同样建议指定语言
)
return transcript.text
优势 :识别准确率通常是最高的一档,速度快,不消耗本地算力。 劣势 :需要网络,按使用量付费(目前价格是$0.006 /分钟),音频数据会上传至OpenAI。
注意事项 :对于个人或低频使用,API方案的成本极低(识别100分钟才0.6美元),且体验最好。对于高频使用或对隐私、网络有严格要求的场景,本地模型是必选项。我建议在开发调试阶段使用API,部署时根据实际情况选择。
3.3 智能交互与意图解析模块:赋予ChatGPT“思考”能力
这是项目的“大脑”。我们将用户语音识别出的文本(即指令)发送给ChatGPT,并引导它将其解析为结构化的、可执行的命令。这里的关键在于 系统提示词(System Prompt) 的设计。
from openai import OpenAI
import os
import json
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def ask_chatgpt(user_query):
"""
向ChatGPT发送用户查询,并期望返回一个可解析的JSON指令。
Args:
user_query: 用户的语音指令文本
Returns:
dict: 解析后的指令字典,如果解析失败返回None
"""
# 精心设计的系统提示词,决定了ChatGPT的输出格式和行为
system_prompt = """
你是一个智能家居控制助手。用户会向你发出自然语言指令。
你的任务是将指令解析为以下JSON格式:
{
"action": "动作名称,如:turn_on, turn_off, adjust, query, custom",
"target": "操作目标,如:living_room_light, air_conditioner, all_lights",
"parameters": {
// 动作参数,例如:
// "brightness": 80, // 亮度百分比
// "temperature": 26, // 温度值
// "color": "warm_white" // 颜色
},
"response": "给用户的自然语言回复,确认操作或告知结果"
}
规则:
1. 如果指令不明确或无法识别,`action`设为`unknown`,`target`和`parameters`可为空,`response`中友好地请求用户澄清。
2. 对于查询类指令(如“客厅温度多少?”),`action`设为`query`。
3. 对于复杂指令(如“先开灯再开空调”),可以返回一个包含多个指令对象的列表(用JSON数组表示)。
4. `response`字段必须用中文回复。
"""
try:
response = client.chat.completions.create(
model="gpt-3.5-turbo-1106", # 或 "gpt-4",支持JSON模式
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_query}
],
temperature=0.1, # 低温度值使输出更确定,减少随机性
response_format={"type": "json_object"} # 强制返回JSON,这是gpt-3.5-turbo-1106及以后模型的新特性
)
# 解析返回的JSON
result_text = response.choices[0].message.content
instruction = json.loads(result_text)
return instruction
except json.JSONDecodeError as e:
print(f"ChatGPT返回的不是有效JSON: {result_text}")
return None
except Exception as e:
print(f"调用ChatGPT API出错: {e}")
return None
系统提示词设计解析 :
- 角色定义 :明确告诉AI“你是一个智能家居控制助手”,限定其回答范围。
- 输出格式 :强制要求返回一个特定的JSON结构。这是实现 结构化输出 的关键,使得后续代码可以稳定地解析
action,target,parameters等字段。 - 规则细化 :处理边界情况,如未知指令、查询指令、复合指令。这能大大提高系统的鲁棒性。
- 语言指定 :要求
response用中文,保证给用户的语音反馈是母语。
模型选择与参数 :
gpt-3.5-turbo-1106是性价比之选,响应快,成本低,并且支持response_format参数来强制JSON输出,这比让模型自己“尽量输出JSON”要可靠得多。temperature=0.1使得输出非常稳定,对于控制指令这种需要确定性的场景非常合适。
4. 主循环与执行器整合
现在我们将三个模块串联起来,形成一个完整的语音控制循环,并添加一个简单的“执行器”来模拟设备控制。
import time
import os
def execute_instruction(instruction):
"""
根据解析后的指令执行具体操作(这里是模拟)。
在实际应用中,这里会调用具体的硬件API(如Home Assistant, MQTT, 或厂商SDK)。
Args:
instruction: 从ChatGPT返回的指令字典
"""
if not instruction:
print("无效指令,跳过执行。")
return
# 处理可能是列表的指令(复合指令)
instructions_list = instruction if isinstance(instruction, list) else [instruction]
for instr in instructions_list:
action = instr.get("action")
target = instr.get("target")
params = instr.get("parameters", {})
response = instr.get("response", "操作完成")
print(f"[执行] 动作: {action}, 目标: {target}, 参数: {params}")
print(f"[助手回复] {response}")
# 这里是实际控制逻辑的占位符
if action == "turn_on":
# 调用打开目标设备的函数,例如:homeassistant.turn_on(target)
print(f"模拟:打开 {target}")
elif action == "turn_off":
print(f"模拟:关闭 {target}")
elif action == "adjust":
if "brightness" in params:
print(f"模拟:将 {target} 亮度调整为 {params['brightness']}%")
if "temperature" in params:
print(f"模拟:将 {target} 温度设置为 {params['temperature']}°C")
elif action == "query":
print(f"模拟:查询 {target} 的状态...")
# 这里可以真实查询设备状态并更新response
elif action == "unknown":
print(f"指令不明确: {response}")
else:
print(f"未定义的动作: {action}")
time.sleep(0.5) # 模拟操作间隔
def main_loop():
"""主循环:录音->识别->解析->执行"""
print("语音控制助手已启动。按下 Ctrl+C 退出。")
try:
while True:
input("按回车键开始录音...") # 简单的触发方式,可替换为热词检测
# 1. 录音
audio_data, audio_path = record_audio(duration=7) # 录音7秒
# 2. 语音转文本
print("正在识别语音...")
# 选择一种转录方式
# user_text = transcribe_local(audio_path, model_name="small") # 本地
user_text = transcribe_api(audio_path) # API
print(f"识别结果: {user_text}")
# 3. 发送给ChatGPT解析
print("正在解析指令...")
instruction = ask_chatgpt(user_text)
# 4. 执行指令
if instruction:
execute_instruction(instruction)
else:
print("指令解析失败,请重试。")
# 清理临时音频文件
os.unlink(audio_path)
print("-" * 40)
except KeyboardInterrupt:
print("\n程序退出。")
if __name__ == "__main__":
main_loop()
这个 main_loop 实现了一个基本的交互流程。它使用“按回车键”作为触发方式,在实际应用中,你可以将其替换为:
- 全局快捷键触发 :使用
pynput等库监听某个快捷键。 - 物理按钮触发 :配合树莓派GPIO,连接一个实体按钮。
- 语音热词唤醒 :集成
Porcupine或Snowboy等离线热词检测库,实现真正的“嘿,Siri”式唤醒。
5. 实战扩展:连接真实智能家居平台
上面的 execute_instruction 函数只是打印模拟信息。要让项目真正发挥作用,必须将其与真实的智能家居平台或设备连接。这里以目前最流行的开源家庭自动化平台 Home Assistant 为例,展示如何实现真实控制。
5.1 Home Assistant 集成准备
假设你的Home Assistant已经安装并运行在本地网络(例如 http://192.168.1.100:8123 ),并且你已经创建了一个长期访问令牌(Long-Lived Access Token)。
-
在Home Assistant中,点击你的用户名 -> 滚动到底部 -> “创建令牌”。为你的语音助手创建一个令牌并复制保存。
-
在Python项目中安装Home Assistant的官方REST客户端:
pip install homeassistant-api或者使用更通用的
requests库。
5.2 实现真实的执行器
我们修改 execute_instruction 函数,使其能通过Home Assistant的API控制实体。
import requests
import os
from dotenv import load_dotenv
load_dotenv()
# 从环境变量读取Home Assistant配置
HA_BASE_URL = os.getenv("HA_BASE_URL", "http://192.168.1.100:8123")
HA_ACCESS_TOKEN = os.getenv("HA_ACCESS_TOKEN") # 你的长期访问令牌
HEADERS = {
"Authorization": f"Bearer {HA_ACCESS_TOKEN}",
"Content-Type": "application/json",
}
def execute_instruction_ha(instruction):
"""
通过Home Assistant API执行指令。
"""
if not instruction or not HA_ACCESS_TOKEN:
print("HA配置缺失或指令无效。")
return
instructions_list = instruction if isinstance(instruction, list) else [instruction]
for instr in instructions_list:
action = instr.get("action")
target = instr.get("target") # 这里target应该是HA中的entity_id,如 `light.living_room`
params = instr.get("parameters", {})
response = instr.get("response", "操作完成")
print(f"[HA执行] 动作: {action}, 目标: {target}")
# 将ChatGPT的通用动作映射到HA的服务调用
service_data = {"entity_id": target}
service_data.update(params) # 合并额外参数
try:
if action in ["turn_on", "turn_off"]:
# 调用 homeassistant.turn_on/turn_off 服务
service = f"homeassistant.{action}"
ha_response = requests.post(
f"{HA_BASE_URL}/api/services/homeassistant/{action}",
headers=HEADERS,
json={"entity_id": target}
)
elif action == "adjust":
# 调整操作需要调用具体域的服务,例如 light.turn_on 并带参数
# 我们需要根据target的域来判断,例如 light.living_room -> 域是 light
domain = target.split('.')[0] if '.' in target else 'homeassistant'
if domain == 'light':
# 调用 light.turn_on 服务来调整亮度、颜色等
service_data = {"entity_id": target}
if "brightness" in params:
# HA亮度范围是0-255
service_data["brightness"] = int(params["brightness"] * 255 / 100)
if "color" in params:
# 这里需要将颜色名称映射为RGB或色温值,简化处理
pass
ha_response = requests.post(
f"{HA_BASE_URL}/api/services/light/turn_on",
headers=HEADERS,
json=service_data
)
elif domain == 'climate':
# 控制空调温度
if "temperature" in params:
service_data = {"entity_id": target, "temperature": params["temperature"]}
ha_response = requests.post(
f"{HA_BASE_URL}/api/services/climate/set_temperature",
headers=HEADERS,
json=service_data
)
elif action == "query":
# 查询实体状态
ha_response = requests.get(
f"{HA_BASE_URL}/api/states/{target}",
headers=HEADERS
)
if ha_response.status_code == 200:
state_info = ha_response.json()
print(f"[状态查询] {target} 的状态是: {state_info.get('state')}")
# 可以更新instr['response'],用于后续语音反馈
instr['response'] = f"{target} 当前状态是 {state_info.get('state')}。"
# 检查HA API响应
if 'ha_response' in locals() and ha_response.status_code not in [200, 201]:
print(f"HA API调用失败: {ha_response.status_code}, {ha_response.text}")
instr['response'] = "操作似乎没有成功,请检查设备。"
else:
print(f"[HA执行成功]")
except requests.exceptions.ConnectionError:
print("无法连接到Home Assistant,请检查网络和地址。")
instr['response'] = "无法连接到智能家居系统。"
except Exception as e:
print(f"执行过程中发生未知错误: {e}")
instr['response'] = "操作执行出错。"
# 播放或显示助手回复
print(f"[助手回复] {instr.get('response')}")
# 这里可以接入一个TTS引擎,将回复文本转为语音播放出来
关键点解析 :
- 实体ID映射 :这是最核心的一步。你需要将ChatGPT解析出的通用
target(如living_room_light)映射到Home Assistant中具体的entity_id(如light.yeelight_living_room)。一个更智能的做法是,在系统提示词中让ChatGPT直接输出entity_id,但这需要你预先给ChatGPT“灌输”一份你的设备清单。更实用的方法是在本地维护一个映射字典。 - 服务调用 :Home Assistant通过“服务”来控制设备。不同设备域(
light,climate,switch等)有各自的服务和参数。上述代码提供了基本框架,实际应用中需要根据你的设备类型进行扩展。 - 错误处理 :网络错误、实体不存在、服务调用失败等情况都必须考虑,并给出友好的用户反馈(通过
response字段)。
5.3 添加文本转语音(TTS)反馈
一个完整的语音交互系统,除了“听”,还应该能“说”。我们可以利用操作系统的TTS引擎或第三方API来实现。
使用pyttsx3(离线,跨平台) :
pip install pyttsx3
import pyttsx3
def speak_text(text):
"""使用系统T引擎朗读文本"""
try:
engine = pyttsx3.init()
engine.say(text)
engine.runAndWait()
except Exception as e:
print(f"TTS出错: {e}")
# 在execute_instruction_ha函数最后,调用 speak_text(instr.get('response'))
使用Edge-TTS(在线,声音自然) :
pip install edge-tts
import asyncio
import edge_tts
async def speak_text_edge(text, voice="zh-CN-XiaoxiaoNeural"):
"""使用Edge TTS朗读文本(需要网络)"""
communicate = edge_tts.Communicate(text, voice)
await communicate.save("temp_feedback.mp3")
# 使用playsound或pydub播放temp_feedback.mp3
os.system("afplay temp_feedback.mp3") # macOS
# os.system("start temp_feedback.mp3") # Windows
os.unlink("temp_feedback.mp3")
# 注意:调用异步函数需要在异步环境中,或使用 asyncio.run(speak_text_edge(...))
将TTS集成后,你的助手就能在每次执行指令后,用语音回复“已打开客厅灯”或“当前室内温度是25度”,体验瞬间提升一个档次。
6. 性能优化与常见问题排查
在实际部署中,你可能会遇到延迟、识别不准、资源占用高等问题。这里分享一些优化和排查经验。
6.1 降低端到端延迟
延迟是影响体验的首要因素。整个流程的延迟主要来自:录音时长、Whisper识别时间、ChatGPT API响应时间、网络延迟。
优化策略 :
- 实现流式语音识别(VAD + 流式Whisper) :不要等用户说完固定的7秒再识别。使用
webrtcvad检测到语音开始和结束,一旦检测到说话间隙(例如静音超过500毫秒),立即将已录制的音频片段发送给Whisper进行 流式识别 。OpenAI的Whisper API支持response_format=verbose_json并设置timestamp,但真正的流式需要更复杂的处理。一个折中方案是使用更短的固定录音间隔(如2秒)并连续识别。 - 缓存与预热 :如果是本地Whisper模型,首次加载很慢。可以在程序启动时预先加载模型(
whisper.load_model)。对于ChatGPT,可以考虑对常见指令(如“开灯”、“关灯”)的解析结果进行缓存,避免重复调用API。 - 模型选型 :在准确率和速度间权衡。Whisper模型选
tiny或base速度最快;ChatGPT模型选gpt-3.5-turbo-instruct(补全模型)可能比聊天模型响应稍快,但指令解析能力可能稍弱。 - 并行处理 :当录音还在进行最后一段时,就可以开始将前面已录好的部分发送给Whisper,实现流水线操作。
6.2 提升语音识别准确率
识别不准会导致后续所有环节出错。
排查与改进 :
- 检查音频质量 :确保麦克风正常工作,没有过多环境噪音。可以尝试增加录音时的
gain(增益),或使用noise库进行简单的降噪预处理。 - 明确语言上下文 :在调用Whisper时,始终指定
language=”zh”。对于中英混合场景,可以尝试不指定语言或使用language=”zh”并设置task=”transcribe”。 - 使用更准确的模型 :如果本地
small模型不准,果断换用medium或调用Whisper API。API的准确率在绝大多数环境下都是最好的。 - 提示词工程 :在将文本发送给ChatGPT前,可以对识别结果进行简单的后处理。例如,如果识别结果包含明显的无意义音节或重复词,可以用规则进行过滤。更高级的做法是,将识别文本和可能的候选列表(如果Whisper提供了的话)一起送给ChatGPT,让它来选择最合理的那个。
6.3 处理复杂指令与上下文
最初的系统提示词只能处理单轮指令。如何实现多轮对话和上下文记忆?
实现思路 :
- 维护对话历史 :在
ask_chatgpt函数中,不再只发送当前用户指令,而是发送一个包含历史对话的messages列表。conversation_history = [] # 全局或会话级变量 def ask_chatgpt_with_history(user_query): global conversation_history # 将历史记录和最新查询组合 messages = [ {"role": "system", "content": system_prompt}, *conversation_history[-6:], # 只保留最近3轮对话(6条消息),防止token超限 {"role": "user", "content": user_query} ] response = client.chat.completions.create(...) assistant_reply = response.choices[0].message.content # 更新历史 conversation_history.append({"role": "user", "content": user_query}) conversation_history.append({"role": "assistant", "content": assistant_reply}) return json.loads(assistant_reply) - 在提示词中明确上下文 :在
system_prompt中加入关于上下文的说明,例如“请参考之前的对话历史来理解指代,比如‘把它关掉’中的‘它’可能指代上一句提到的设备。”
6.4 资源占用与部署建议
- CPU/GPU占用 :本地运行Whisper
small模型,推理时单核CPU占用可能接近100%。如果部署在树莓派4B上,可能会比较卡顿,建议使用tiny或base模型,或者使用API方案。 - 内存占用 :加载Whisper模型会占用数百MB内存。确保你的部署设备有足够的内存。
- 长期运行 :将主脚本作为系统服务(如使用
systemd)运行,并配置看门狗,确保程序崩溃后能自动重启。 - 隐私与安全 :如果使用API,你的音频和指令文本会经过OpenAI的服务器。如果涉及非常私密的对话或指令,请务必使用本地模型方案,并确保网络传输安全(HTTPS)。
7. 项目总结与未来展望
通过一步步拆解和实现,我们不仅复现了“SheikhAminul/ChatGPT-voice-control”项目的核心,还对其进行了深度的扩展和优化。这个项目的精髓在于其 架构的优雅 :前端(语音采集与识别)与后端(意图解析与执行)通过一个结构化的JSON协议解耦。这意味着,你可以随时替换其中的任何一个模块。
例如,你可以把Whisper换成其他STT引擎(如阿里云、腾讯云的语音识别服务);可以把ChatGPT换成 Claude、Gemini 或其他本地大语言模型(如通过Ollama部署的Llama 3);可以把Home Assistant换成米家、Apple HomeKit或直接控制MQTT设备。这种模块化设计赋予了项目极强的生命力和适应性。
从我个人的实战经验来看,将这个系统部署到一台旧笔记本或树莓派上,让它7x24小时运行,作为家庭智能中枢的“语音交互层”,是一个非常酷且实用的选择。它弥补了现有商业语音助手在 复杂指令理解 和 本地化深度控制 上的不足。你可以用它实现这样的场景:“把我书房的电脑、显示器、台灯和空调都打开,并把空调调到除湿模式”——只需一句话,ChatGPT会帮你拆解成多个有序的指令,并逐一执行。
当然,目前这还是一个需要主动触发(按回车或说热词)的“半自动”方案。未来的优化方向可以朝着 全双工连续对话 和 更强的本地化 迈进,比如集成本地LLM完全离线运行,但这需要更强的硬件支持。无论如何,这个项目已经为我们打开了一扇门,展示了利用当今最先进的AI模型构建个性化、智能化工具的无限可能。剩下的,就交给你的想象力和动手能力去发挥了。
更多推荐



所有评论(0)