?文章的目的為了記錄AI應用學習的經歷,降低AI的入門難度。同時記錄開發流程和要點有些記憶模糊,防止忘記。也希望可以給看到文章的朋友帶來一些收獲。
相關鏈接:
AI 應用 圖文 解說 (一) -- 百度智能云 實現 語音 聊天-CSDN博客
AI 應用 圖文 解說 (二) -- 百度智能云 ASR LIM TTS 語音AI助手程序 -CSDN博客
推薦鏈接:
開源 python 應用 開發(一)python、pip、pyAutogui、python opencv安裝-CSDN博客
開源 python 應用 開發(二)基于pyautogui、open cv 視覺識別的工具自動化-CSDN博客
開源 python 應用 開發(三)python語法介紹-CSDN博客
開源 python 應用 開發(四)python文件和系統綜合應用-CSDN博客
開源 python 應用 開發(五)python opencv之目標檢測-CSDN博客
開源 python 應用 開發(六)網絡爬蟲-CSDN博客
開源 python 應用 開發(七)數據可視化-CSDN博客
開源 python 應用 開發(八)圖片比對-CSDN博客
開源 python 應用 開發(九)目標跟蹤-CSDN博客
開源 python 應用 開發(十)音頻壓縮-CSDN博客
開源 python 應用 開發(十一)AI應用--百度智能云ASR短語音轉文本-CSDN博客
開源 python 應用 開發(十二)AI應用--百度智能云Agent聊天-CSDN博客
開源 python 應用 開發(十三)AI應用--百度智能云TTS語音合成-CSDN博客
開源 python 應用 開發(十四)python快速建設網站-CSDN博客
?推薦鏈接:
開源 Arkts 鴻蒙應用 開發(一)工程文件分析-CSDN博客
開源 Arkts 鴻蒙應用 開發(二)封裝庫.har制作和應用-CSDN博客
開源 Arkts 鴻蒙應用 開發(三)Arkts的介紹-CSDN博客
開源 Arkts 鴻蒙應用 開發(四)布局和常用控件-CSDN博客
開源 Arkts 鴻蒙應用 開發(五)控件組成和復雜控件-CSDN博客
?推薦鏈接:
開源 java android app 開發(一)開發環境的搭建-CSDN博客
開源 java android app 開發(二)工程文件結構-CSDN博客
開源 java android app 開發(三)GUI界面布局和常用組件-CSDN博客
開源 java android app 開發(四)GUI界面重要組件-CSDN博客
開源 java android app 開發(五)文件和數據庫存儲-CSDN博客
開源 java android app 開發(六)多媒體使用-CSDN博客
開源 java android app 開發(七)通訊之Tcp和Http-CSDN博客
開源 java android app 開發(八)通訊之Mqtt和Ble-CSDN博客
開源 java android app 開發(九)后臺之線程和服務-CSDN博客
開源 java android app 開發(十)廣播機制-CSDN博客
開源 java android app 開發(十一)調試、發布-CSDN博客
開源 java android app 開發(十二)封庫.aar-CSDN博客
推薦鏈接:
開源C# .net mvc 開發(一)WEB搭建_c#部署web程序-CSDN博客
開源 C# .net mvc 開發(二)網站快速搭建_c#網站開發-CSDN博客
開源 C# .net mvc 開發(三)WEB內外網訪問(VS發布、IIS配置網站、花生殼外網穿刺訪問)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客
開源 C# .net mvc 開發(四)工程結構、頁面提交以及顯示_c#工程結構-CSDN博客
??????開源 C# .net mvc 開發(五)常用代碼快速開發_c# mvc開發-CSDN博客
主要內容:一個完整的語音AI助手程序,使用Python實現錄音、語音識別、AI對話和語音合成的功能。
目錄:
1.主要功能
2.源碼分析
3.所有源碼
4.顯示效果
一、主要功能
音頻錄制:使用sounddevice庫錄制16kHz單聲道音頻
語音識別:通過百度語音識別API將音頻轉換為文本
AI對話:使用AppBuilder AI模型進行智能對話
語音合成:通過百度語音合成API將文本轉換為語音
音頻播放:使用多種方式播放生成的語音回復
二、源碼分析
2.1??類定義和初始化 (VoiceAIAssistant)
初始化錄音配置參數(采樣率、聲道數等)
設置API密鑰和認證信息
初始化各個組件(pygame音頻、AppBuilder客戶端)
2.2? 音頻處理功能
start_recording(): 開始錄制音頻
stop_recording(): 停止錄制并保存
audio_callback(): 音頻流回調函數,收集音頻數據
save_to_wav(): 使用wave模塊保存WAV文件
2.3? API調用功能
get_access_token(): 獲取百度API訪問令牌
speech_to_text(): 調用百度語音識別API
text_to_speech(): 調用百度語音合成API
call_ai_model(): 調用AppBuilder AI模型
2.4? 輔助功能
play_audio(): 使用多種方式播放音頻文件
process_audio(): 完整的音頻處理流程
keyboard_listener(): 鍵盤監聽主循環
5. 工具函數
check_dependencies(): 檢查所需Python庫是否已安裝
main(): 程序主函數
三、所有源碼
import sounddevice as sd
import numpy as np
import wave
import keyboard
import time
import os
import base64
import urllib
import requests
import json
import pygame
import tempfile
import threading
import subprocess
from pydub import AudioSegment
import appbuilderclass VoiceAIAssistant:def __init__(self):# 錄音配置self.is_recording = Falseself.frames = []self.sample_rate = 16000self.channels = 1self.audio_filename = "test.wav"self.response_filename = "response.wav"# API配置 - 請替換為您的實際密鑰self.api_key = ""self.secret_key = ""self.app_token = ""self.app_id = ""# 設置環境變量os.environ["APPBUILDER_TOKEN"] = self.app_token# 初始化組件self.init_components()def init_components(self):"""初始化各個組件"""try:# 初始化pygame音頻pygame.mixer.init()print("? Pygame音頻初始化成功")except Exception as e:print(f"? Pygame初始化失敗: {e}")try:# 初始化AppBuilder客戶端self.app_builder_client = appbuilder.AppBuilderClient(self.app_id)self.conversation_id = self.app_builder_client.create_conversation()print("? AppBuilder客戶端初始化成功")except Exception as e:print(f"? AppBuilder初始化失敗: {e}")self.app_builder_client = Nonedef start_recording(self):"""開始錄制音頻"""if self.is_recording:print("已經在錄制中...")returnself.is_recording = Trueself.frames = []print("開始錄制16K音頻... (按空格鍵停止并保存)")try:# 直接使用16K采樣率錄制self.stream = sd.InputStream(samplerate=self.sample_rate,channels=self.channels,callback=self.audio_callback,dtype='int16')self.stream.start()return Trueexcept Exception as e:print(f"開始錄制失敗: {e}")self.is_recording = Falsereturn Falsedef stop_recording(self):"""停止錄制并保存"""if not self.is_recording:print("當前沒有在錄制")return Falseself.is_recording = Falseprint("停止錄制,正在保存16K WAV文件...")try:self.stream.stop()self.stream.close()return self.save_to_wav()except Exception as e:print(f"停止錄制失敗: {e}")return Falsedef audio_callback(self, indata, frames, time, status):"""音頻回調函數"""if status:print(f"音頻流狀態: {status}")if self.is_recording:self.frames.append(indata.copy())def save_to_wav(self):"""使用wave模塊保存WAV文件"""if not self.frames:print("沒有音頻數據可保存")return Falsetry:# 合并所有音頻幀audio_data = np.concatenate(self.frames, axis=0)audio_data = audio_data.flatten()# 確保數據在16位范圍內audio_data = np.clip(audio_data, -32768, 32767)audio_data = audio_data.astype(np.int16)# 使用wave模塊保存with wave.open(self.audio_filename, 'wb') as wav_file:wav_file.setnchannels(self.channels)wav_file.setsampwidth(2) # 16位 = 2字節wav_file.setframerate(self.sample_rate)wav_file.writeframes(audio_data.tobytes())print(f"? 成功保存16K WAV文件: {self.audio_filename}")return Trueexcept Exception as e:print(f"保存文件時出錯: {e}")return Falsedef get_file_content_as_base64(self, path, urlencoded=False):"""獲取文件base64編碼"""try:with open(path, "rb") as f:content = base64.b64encode(f.read()).decode("utf8")if urlencoded:content = urllib.parse.quote_plus(content)return contentexcept Exception as e:print(f"讀取文件錯誤: {e}")return Nonedef get_access_token(self):"""獲取百度API訪問令牌"""try:url = "https://aip.baidubce.com/oauth/2.0/token"params = {"grant_type": "client_credentials", "client_id": self.api_key, "client_secret": self.secret_key}response = requests.post(url, params=params)response.raise_for_status()result = response.json()access_token = result.get("access_token")if access_token:print("? 成功獲取access_token")return access_tokenelse:print(f"獲取access_token失敗: {result}")return Noneexcept Exception as e:print(f"獲取access_token錯誤: {e}")return Nonedef speech_to_text(self):"""語音識別:將音頻轉換為文本"""try:if not os.path.exists(self.audio_filename):print(f"錯誤:文件不存在 - {self.audio_filename}")return Nonefile_size = os.path.getsize(self.audio_filename)url = "https://vop.baidu.com/server_api"access_token = self.get_access_token()if not access_token:return Nonepayload = json.dumps({"format": "wav","rate": 16000,"channel": 1,"cuid": "voice_assistant_cuid","token": access_token,"speech": self.get_file_content_as_base64(self.audio_filename, False),"len": file_size}, ensure_ascii=False)headers = {'Content-Type': 'application/json','Accept': 'application/json'}response = requests.post(url, headers=headers, data=payload.encode("utf-8"))if response.status_code == 200:result = response.json()if result.get("err_no") == 0:text = result.get("result", [""])[0]print(f"? 識別結果: {text}")return textelse:print(f"語音識別失敗: {result.get('err_msg')}")return Noneelse:print(f"請求失敗,狀態碼: {response.status_code}")return Noneexcept Exception as e:print(f"語音識別錯誤: {e}")return Nonedef text_to_speech(self, text):"""文本轉語音:將文本轉換為音頻"""try:url = "https://tsn.baidu.com/text2audio"access_token = self.get_access_token()if not access_token:return Noneencoded_text = urllib.parse.quote(text)params = {'tex': encoded_text,'tok': access_token,'cuid': 'voice_assistant_cuid','ctp': 1,'lan': 'zh','spd': 5,'pit': 5,'vol': 5,'per': 0,'aue': 6 # WAV格式}headers = {'Content-Type': 'application/x-www-form-urlencoded','Accept': 'audio/wav'}response = requests.post(url, data=params, headers=headers)if response.status_code == 200:# 保存音頻文件with open(self.response_filename, 'wb') as f:f.write(response.content)print(f"? 語音合成完成,保存為: {self.response_filename}")return self.response_filenameelse:print(f"語音合成失敗,狀態碼: {response.status_code}")return Noneexcept Exception as e:print(f"語音合成錯誤: {e}")return Nonedef call_ai_model(self, text):"""調用AI大模型處理文本"""if not self.app_builder_client:print("? AppBuilder客戶端未初始化")return "抱歉,AI服務暫時不可用。"try:print(f"🤖 向AI模型提問: {text}")resp = self.app_builder_client.run(self.conversation_id, text)answer = resp.content.answerprint(f"🤖 AI回復: {answer}")return answerexcept Exception as e:print(f"調用AI模型錯誤: {e}")return "抱歉,我暫時無法處理您的請求。"def play_audio(self, audio_file):"""播放音頻文件"""if not os.path.exists(audio_file):print(f"錯誤:音頻文件不存在 - {audio_file}")return Falsetry:# 方法1: 使用winsound播放(最簡單)import winsoundprint("🔊 正在播放音頻...")winsound.PlaySound(audio_file, winsound.SND_FILENAME)print("? 播放完成")return Trueexcept Exception as e:print(f"winsound播放失敗: {e}")try:# 方法2: 使用pygame播放pygame.mixer.music.load(audio_file)pygame.mixer.music.play()print("🔊 正在播放音頻...")# 等待播放完成while pygame.mixer.music.get_busy():pygame.time.wait(100)print("? 播放完成")return Trueexcept Exception as e:print(f"pygame播放失敗: {e}")try:# 方法3: 使用系統命令播放if os.name == 'nt': # Windowsos.startfile(audio_file)else: # Linux/Macsubprocess.run(['aplay', audio_file])print("? 使用系統播放器播放")return Trueexcept Exception as e:print(f"系統播放失敗: {e}")return Falsedef process_audio(self):"""完整處理流程:錄音->識別->AI->語音合成->播放"""print("=" * 60)print("開始處理音頻...")print("=" * 60)# 1. 語音識別print("🎤 正在識別語音...")recognized_text = self.speech_to_text()if not recognized_text:print("? 語音識別失敗")return False# 2. 調用AI模型print("🧠 正在調用AI模型...")ai_response = self.call_ai_model(recognized_text)# 3. 語音合成print("🔊 正在合成語音...")audio_file = self.text_to_speech(ai_response)if not audio_file:print("? 語音合成失敗")return False# 4. 播放音頻print("?? 正在播放回復...")return self.play_audio(audio_file)def keyboard_listener(self):"""鍵盤監聽主循環"""print("=" * 60)print("語音AI助手已啟動")print("按空格鍵開始/停止錄制")print("按ESC鍵退出程序")print("=" * 60)recording_started = Falsewhile True:# 檢測空格鍵if keyboard.is_pressed('space'):if not recording_started:if not self.is_recording:# 開始錄制if self.start_recording():print("?? 錄制中... (再次按空格停止)")else:# 停止錄制并處理if self.stop_recording():# 在新線程中處理音頻,避免阻塞鍵盤監聽processing_thread = threading.Thread(target=self.process_audio)processing_thread.daemon = Trueprocessing_thread.start()recording_started = Truetime.sleep(0.5) # 防抖else:recording_started = False# 檢測ESC鍵退出if keyboard.is_pressed('esc'):if self.is_recording:self.stop_recording()print("👋 程序退出")breaktime.sleep(0.1)def check_dependencies():"""檢查所需依賴"""required_libs = ['sounddevice', 'numpy', 'keyboard', 'requests', 'pygame', 'pydub', 'appbuilder']missing_libs = []for lib in required_libs:try:if lib == 'appbuilder':import appbuilderelif lib == 'pydub':from pydub import AudioSegmentelse:__import__(lib)print(f"? {lib} 已安裝")except ImportError:print(f"? {lib} 未安裝")missing_libs.append(lib)if missing_libs:print(f"\n請安裝缺失的庫: pip install {' '.join(missing_libs)}")return Falsereturn Truedef main():"""主函數"""# 檢查依賴if not check_dependencies():return# 創建語音助手實例try:assistant = VoiceAIAssistant()# 啟動鍵盤監聽assistant.keyboard_listener()except KeyboardInterrupt:print("\n👋 程序被用戶中斷")except Exception as e:print(f"? 程序運行錯誤: {e}")if __name__ == "__main__":main()
四、使用效果
使用python IDE 運行或雙擊.py文件,代碼會檢查所需要的庫,如果沒有安裝,使用pip安裝就行。
如果報錯 Appbuilder問題,可以進行升級。
pip install --upgrade appbuilder-sdk -i https://mirrors.aliyun.com/pypi/simple/
程序不再報錯后,按下空格開始錄音,會音頻提交到智能云,與AI對話,最后返回合成的語音。音頻文件為.wav存放在桌面。