引言
隨著以ChatGLM2-6B為代表的開源大型語(yǔ)言模型的興起,人工智能革命正席卷全球……
ChatGLM2-6B這一代表性的開源大型模型,以其易于部署、適度的參數(shù)量和強(qiáng)大的中文處理能力,為個(gè)人用戶提供了在個(gè)人顯卡上部署大型模型的便捷途徑。
然而,在大型語(yǔ)言模型領(lǐng)域,人機(jī)交互仍然主要以傳統(tǒng)的文字輸入為主,這種方式難以滿足人們對(duì)實(shí)時(shí)性和高效率的需求。在許多情景下,人們更期望能夠直接與一個(gè)語(yǔ)音交互的智能助手互動(dòng)。
本文將結(jié)合STT(自動(dòng)語(yǔ)音識(shí)別)、大型模型和TTS(文本到語(yǔ)音合成)等人工智能技術(shù),創(chuàng)建一個(gè)具備語(yǔ)音交互功能的智能機(jī)器人演示。
環(huán)境準(zhǔn)備
- 在開始之前,我們需要準(zhǔn)備好開發(fā)環(huán)境。本文的代碼主要采用Python語(yǔ)言編寫,建議使用Python版本3.9以上。作者在Windows10操作系統(tǒng)上使用Python 3.9進(jìn)行了測(cè)試。
- 請(qǐng)安裝一些python庫(kù),主要有:
- 錄音庫(kù):Pyaudio,及相關(guān)音頻處理庫(kù)wave。
- TTS庫(kù):edge-tte,一款免費(fèi)的TTS庫(kù)。
- 音頻播放庫(kù):pygame,實(shí)現(xiàn)代碼播放音頻文件。
- openai:調(diào)用大語(yǔ)言模型API需要用到。
- uuid:用于生成唯一的文件名。
? ? ? 請(qǐng)參考以下Python庫(kù)的導(dǎo)入列表,并根據(jù)需要使用pip進(jìn)行安裝。
import pyaudio
import wave
import requests
import json
import base64
import os
import edge_tts
import asyncio
import pygame
import openai
import uuid # 用于生成唯一的文件名
????????3. 在百度AI開發(fā)平臺(tái)開通短語(yǔ)識(shí)別標(biāo)準(zhǔn)版服務(wù),可以領(lǐng)取免費(fèi)額度,贈(zèng)送15萬(wàn)次調(diào)用,很香。
短語(yǔ)音識(shí)別標(biāo)準(zhǔn)版_短語(yǔ)音識(shí)別-百度AI開放平臺(tái) (baidu.com)
? ? ? ? ? 按照官網(wǎng)給出的操作指引一步一步來(lái)就OK了。
? ? ? ? ? 提醒:調(diào)用百度語(yǔ)音識(shí)別API之前一定要先創(chuàng)建應(yīng)用。
? ? ? ? 4. 一臺(tái)可以跑ChatGLM2-6B的服務(wù)器或個(gè)人電腦。模型的下載、部署這里不做贅述,可以參考網(wǎng)絡(luò)上的教程。命令行運(yùn)行ChatGLM2-6B-main目錄下面的openai_api.py。
python openai_api.py
?運(yùn)行成功會(huì)給出一串地址,后面需要在調(diào)用方的主機(jī)上ssh這個(gè)地址。
具體操作是:
Win+R 打開cmd
輸入命令:
ssh -L 8000:0.0.0.0:8000 <你的服務(wù)器用戶名>@<你的服務(wù)器的IP地址>
回車
輸入密碼:
<你的服務(wù)器密碼>
?核心代碼
1.錄音模塊
我們首先使用PyAudio庫(kù)來(lái)錄制音頻,將其保存為.wav文件。這個(gè)步驟包括設(shè)置音頻參數(shù),如采樣頻率、數(shù)據(jù)流塊等。錄制完成后,音頻文件將被保存在當(dāng)前目錄下。代碼內(nèi)有詳細(xì)注釋,請(qǐng)結(jié)合注釋進(jìn)一步理解代碼。
?
#1.錄音
#用Pyaudio錄制音頻(生成wav文件)
def audio_record(rec_time,filename):
"""
:param rec_time : 音頻錄制時(shí)間
:param filename : 輸出音頻文件
:返回值:在當(dāng)前目錄輸出一個(gè)音頻文件
"""
CHUNK=1024 #定義數(shù)據(jù)流塊
FORMAT = pyaudio.paInt16 #16bit編碼格式
CHANNELS = 1 #單聲道
RATE = 16000 #16000采樣頻率
#創(chuàng)建一個(gè)音頻對(duì)象
p = pyaudio.PyAudio()
#創(chuàng)建音頻數(shù)據(jù)流
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
print('Start recording...')
frames=list() #空列表用于保存錄制的音頻流
#錄制音頻數(shù)據(jù)
for i in range(0,int(RATE/CHUNK*rec_time)):
data=stream.read(CHUNK)
frames.append(data)
#錄制完成
# print(frames)
#停止數(shù)據(jù)流
stream.stop_stream()
stream.close()
#關(guān)閉pyaudio
p.terminate()
print('recording done...')
#保存音頻文件
with wave.open(filename,'wb') as f:
f.setnchannels(CHANNELS) #設(shè)置音頻聲道數(shù)
f.setsampwidth(p.get_sample_size(FORMAT)) #以字節(jié)為樣本返回樣本寬度
f.setframerate(RATE) #設(shè)置采樣頻率
f.writeframes(b''.join(frames))
f.close()
?2.獲取百度ASR access token
為了進(jìn)行語(yǔ)音識(shí)別,我們需要獲取百度語(yǔ)音識(shí)別的Access Token。這個(gè)Token用于訪問(wèn)百度的語(yǔ)音識(shí)別API。您需要提供API_KEY和SECRET_KEY,然后使用這些密鑰生成Access Token。
如何查看自己的API_KEY和SECRET_KEY?登錄百度AI開放平臺(tái),選擇應(yīng)用列表即可查看。
?
?此函數(shù)向百度服務(wù)器發(fā)送API_KEY和SECRET_KEY,返回access token,用于識(shí)別對(duì)應(yīng)的服務(wù)和用戶。?
API_KEY = "XXX" # 這里請(qǐng)?zhí)鎿Q為你的API_KEY
SECRET_KEY = "XXX" # 這里請(qǐng)?zhí)鎿Q為你的SECRET_KEY
def get_access_token():
"""
使用 AK,SK 生成鑒權(quán)簽名(Access Token)
:return: access_token,或是None(如果錯(cuò)誤)
"""
url = "https://aip.baidubce.com/oauth/2.0/token"
params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
return str(requests.post(url, params=params).json().get("access_token"))
?3.調(diào)用百度ASR API,上傳錄音文件,獲得轉(zhuǎn)換后的文本。
使用獲取的Access Token,我們將錄音文件上傳到百度語(yǔ)音識(shí)別API,以將音頻轉(zhuǎn)換為文本。這里需要設(shè)置一些參數(shù),如采樣頻率、格式等。最終,我們將獲得從錄音中識(shí)別出的文本。
# 3.上傳錄音文件
def BaiduYuYin(file_url,token):
"""
:param file_url: 錄音文件路徑
:param token: 獲取的access token
:return: 錄音識(shí)別出來(lái)的文本
"""
try:
RATE='16000'
FORMAT='wav'
CUID='rvs7K414cquxm4f62jtasIRi6iNRNXR6'
DEV_PID='1536' # 普通話,支持簡(jiǎn)單的英文識(shí)別
file_url=file_url
token=token
#以字節(jié)格式讀取文件之后進(jìn)行編碼
with open(file_url,'rb') as f:
speech=base64.b64encode(f.read()).decode('utf-8')
size = os.path.getsize(file_url)# 語(yǔ)音文件的字節(jié)數(shù)
headers={'Content-Type':'application/json',
'Accept':'application/json'} # json格式post上傳本地文件
url='https://vop.baidu.com/server_api'
data={
"format":FORMAT,#格式
"rate":RATE,#取樣頻率,固定值16000
"dev_pid":DEV_PID,#語(yǔ)音識(shí)別類型
"speech":speech,#本地語(yǔ)音文件的二進(jìn)制數(shù)據(jù),需要進(jìn)行base64編碼
"cuid":CUID,#用戶唯一標(biāo)識(shí),用來(lái)區(qū)分用戶 建議填寫能區(qū)分用戶的機(jī)器MAC地址或IMEI碼,長(zhǎng)度為60字符以內(nèi)。
"len":size,#語(yǔ)音文件的字節(jié)數(shù)
"channel":1,#聲道數(shù),僅支持單聲道,固定值為1
"token":token,
}
req=requests.request("POST",url,data=json.dumps(data),headers=headers) #request.post 改為requests.request("POST"……)
data_dict=json.loads(req.text)
# print(data_dict['result'][0])
return data_dict['result'][0] # 返回文本
except:
return '識(shí)別不清楚'
?4.調(diào)用大語(yǔ)言模型的API,實(shí)現(xiàn)問(wèn)答。
我們使用ChatGLM2-6B大語(yǔ)言模型來(lái)生成回復(fù)文本。在這一步中,我們向模型提供之前識(shí)別的文本,然后等待模型生成回復(fù)。
# 4.接入大語(yǔ)言模型
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
os.environ['OPENAI_API_KEY'] = 'EMPTY'
os.environ['OPENAI_API_BASE'] = 'http://localhost:8000/v1'
openai.api_key = 'none'
openai.api_base = 'http://localhost:8000/v1'
def get_completion(prompt, model="gpt-3.5-turbo"):
"""
:param prompt:輸入提示詞
:param model:模型名稱(使用默認(rèn)參數(shù)即可)
:return: 大模型的回復(fù)文本
"""
messages = [{"role": "user", "content": prompt}]
response = openai.ChatCompletion.create(
model=model,
messages=messages,
temperature=0,
)
return response.choices[0].message["content"]
5. 文本轉(zhuǎn)語(yǔ)音TTS
將生成的文本轉(zhuǎn)換為語(yǔ)音,我們使用edge_tts庫(kù)。這個(gè)庫(kù)可以將文本轉(zhuǎn)換為語(yǔ)音文件(.mp3格式)??梢赃x擇不同的語(yǔ)音和參數(shù),以獲得不同風(fēng)格的語(yǔ)音。
# 5.文本轉(zhuǎn)語(yǔ)音TTS:edge-tts
async def generate_audio_from_text(text,file_url):
"""
:param text:需要進(jìn)行轉(zhuǎn)換的文本
:file_url:轉(zhuǎn)換后輸出的音頻文件地址
:return:無(wú)
"""
voice = 'zh-CN-YunxiNeural'
output = file_url
rate='-4%'
volume = '+0%'
tts = edge_tts.Communicate(text=text,voice=voice,rate=rate,volume=volume)
await tts.save(output)
注意,調(diào)用此函數(shù)時(shí),要使用asyncio.run:
#調(diào)用示例
asyncio.run(generate_audio_from_text(model_response,filename))
6.播放音頻文件
最后,我們使用pygame庫(kù)來(lái)播放生成的語(yǔ)音文件。這使得大模型的回復(fù)能夠以聲音的方式呈現(xiàn)給用戶。
# 6.播放音頻文件:pygame
def play_mp3(mp3_file):
"""
:param mp3_file:需要播放的錄音文件地址
:return:無(wú)
"""
pygame.init() # 初始化pygame
pygame.mixer.init() # 初始化音頻混合器
pygame.mixer.music.load(mp3_file) # 加載指定MP3文件
pygame.mixer.music.play() # 播放
clock = pygame.time.Clock()
while pygame.mixer.music.get_busy(): # 使用一個(gè)循環(huán)來(lái)等待音頻播放完畢,保證程序不會(huì)在播放結(jié)束前退出
clock.tick(3)
?7.整體的函數(shù)調(diào)度順序
如何運(yùn)行?
要運(yùn)行這個(gè)語(yǔ)音交互demo,只需運(yùn)行main()函數(shù)。等待您的發(fā)言,然后進(jìn)行錄音、語(yǔ)音識(shí)別、文本生成、語(yǔ)音合成和播放,最后詢問(wèn)是否繼續(xù)對(duì)話或退出。
def main():
while True:
# 1. 提示用戶發(fā)言
print('請(qǐng)發(fā)言,謝謝!')
# 2. 錄制音頻
audio_record(5, 'user_audio.wav')
print('Audio recording complete.')
# 3. 獲取百度語(yǔ)音識(shí)別的access token
baidu_token = get_access_token()
print('Baidu access token obtained.')
# 4. 上傳錄音文件并進(jìn)行語(yǔ)音識(shí)別
baidu_result = BaiduYuYin('user_audio.wav', baidu_token)
print('Baidu speech recognition result:', baidu_result)
# 5. 調(diào)用大語(yǔ)言模型進(jìn)行文本生成
model_response = get_completion(baidu_result)
print('Model response:', model_response)
# 6. 將文本轉(zhuǎn)換為語(yǔ)音,保存到唯一的文件名
unique_audio_filename = str(uuid.uuid4()) + '.mp3' # 保存為不同的文件名以避免訪問(wèn)沖突
asyncio.run(generate_audio_from_text(model_response,unique_audio_filename))
# 7. 播放生成的語(yǔ)音
play_mp3(unique_audio_filename)
# 8. 提示用戶繼續(xù)對(duì)話或退出
user_input = input('繼續(xù)對(duì)話或輸入"退出"退出: ')
if user_input == '退出':
break
注意,為了避免多輪對(duì)話產(chǎn)生的文件訪問(wèn)沖突,請(qǐng)為TTS轉(zhuǎn)換后的音頻文件設(shè)置不同的文件名,這里使用了uuid庫(kù)為每個(gè)音頻文件生成唯一的文件名。
?運(yùn)行結(jié)果:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-754451.html
?完整代碼:
import pyaudio
import wave
import requests
import json
import base64
import os
import edge_tts
import asyncio
import pygame
import openai
import uuid # 用于生成唯一的文件名
#1.錄音
#用Pyaudio錄制音頻(生成wav文件)
def audio_record(rec_time,filename):
"""
:param rec_time : 音頻錄制時(shí)間
:param filename : 輸出音頻文件
:返回值:在當(dāng)前目錄輸出一個(gè)音頻文件
"""
CHUNK=1024 #定義數(shù)據(jù)流塊
FORMAT = pyaudio.paInt16 #16bit編碼格式
CHANNELS = 1 #單聲道
RATE = 16000 #16000采樣頻率
#創(chuàng)建一個(gè)音頻對(duì)象
p = pyaudio.PyAudio()
#創(chuàng)建音頻數(shù)據(jù)流
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
print('Start recording...')
frames=list() #空列表用于保存錄制的音頻流
#錄制音頻數(shù)據(jù)
for i in range(0,int(RATE/CHUNK*rec_time)):
data=stream.read(CHUNK)
frames.append(data)
#錄制完成
# print(frames)
#停止數(shù)據(jù)流
stream.stop_stream()
stream.close()
#關(guān)閉pyaudio
p.terminate()
print('recording done...')
#保存音頻文件
with wave.open(filename,'wb') as f:
f.setnchannels(CHANNELS) #設(shè)置音頻聲道數(shù)
f.setsampwidth(p.get_sample_size(FORMAT)) #以字節(jié)為樣本返回樣本寬度
f.setframerate(RATE) #設(shè)置采樣頻率
f.writeframes(b''.join(frames))
f.close()
#2 獲取token
API_KEY = "XXX" # 這里請(qǐng)?zhí)鎿Q為你的API_KEY
SECRET_KEY = "XXX" # 這里請(qǐng)?zhí)鎿Q為你的SECRET_KEY
def get_access_token():
"""
使用 AK,SK 生成鑒權(quán)簽名(Access Token)
:return: access_token,或是None(如果錯(cuò)誤)
"""
url = "https://aip.baidubce.com/oauth/2.0/token"
params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
return str(requests.post(url, params=params).json().get("access_token"))
# 3.上傳錄音文件
def BaiduYuYin(file_url,token):
"""
:param file_url: 錄音文件路徑
:param token: 獲取的access token
:return: 錄音識(shí)別出來(lái)的文本
"""
try:
RATE='16000'
FORMAT='wav'
CUID='rvs7K414cquxm4f62jtasIRi6iNRNXR6'
DEV_PID='1536' # 普通話,支持簡(jiǎn)單的英文識(shí)別
file_url=file_url
token=token
#以字節(jié)格式讀取文件之后進(jìn)行編碼
with open(file_url,'rb') as f:
speech=base64.b64encode(f.read()).decode('utf-8')
size = os.path.getsize(file_url)# 語(yǔ)音文件的字節(jié)數(shù)
headers={'Content-Type':'application/json',
'Accept':'application/json'} # json格式post上傳本地文件
url='https://vop.baidu.com/server_api'
data={
"format":FORMAT,#格式
"rate":RATE,#取樣頻率,固定值16000
"dev_pid":DEV_PID,#語(yǔ)音識(shí)別類型
"speech":speech,#本地語(yǔ)音文件的二進(jìn)制數(shù)據(jù),需要進(jìn)行base64編碼
"cuid":CUID,#用戶唯一標(biāo)識(shí),用來(lái)區(qū)分用戶 建議填寫能區(qū)分用戶的機(jī)器MAC地址或IMEI碼,長(zhǎng)度為60字符以內(nèi)。
"len":size,#語(yǔ)音文件的字節(jié)數(shù)
"channel":1,#聲道數(shù),僅支持單聲道,固定值為1
"token":token,
}
req=requests.request("POST",url,data=json.dumps(data),headers=headers) #request.post 改為requests.request("POST"……)
data_dict=json.loads(req.text)
# print(data_dict['result'][0])
return data_dict['result'][0] # 返回文本
except:
return '識(shí)別不清楚'
# 4.接入大語(yǔ)言模型
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
os.environ['OPENAI_API_KEY'] = 'EMPTY'
os.environ['OPENAI_API_BASE'] = 'http://localhost:8000/v1'
openai.api_key = 'none'
openai.api_base = 'http://localhost:8000/v1'
def get_completion(prompt, model="gpt-3.5-turbo"):
"""
:param prompt:輸入提示詞
:param model:模型名稱(使用默認(rèn)參數(shù)即可)
:return: 大模型的回復(fù)文本
"""
messages = [{"role": "user", "content": prompt}]
response = openai.ChatCompletion.create(
model=model,
messages=messages,
temperature=0,
)
return response.choices[0].message["content"]
# 5.文本轉(zhuǎn)語(yǔ)音TTS:edge-tts
async def generate_audio_from_text(text,file_url):
"""
:param text:需要進(jìn)行轉(zhuǎn)換的文本
:file_url:轉(zhuǎn)換后輸出的音頻文件地址
:return:無(wú)
"""
voice = 'zh-CN-YunxiNeural'
output = file_url
rate='-4%'
volume = '+0%'
tts = edge_tts.Communicate(text=text,voice=voice,rate=rate,volume=volume)
await tts.save(output)
# 6.播放音頻文件:pygame
def play_mp3(mp3_file):
"""
:param mp3_file:需要播放的錄音文件地址
:return:無(wú)
"""
pygame.init() # 初始化pygame
pygame.mixer.init() # 初始化音頻混合器
pygame.mixer.music.load(mp3_file) # 加載指定MP3文件
pygame.mixer.music.play() # 播放
clock = pygame.time.Clock()
while pygame.mixer.music.get_busy(): # 使用一個(gè)循環(huán)來(lái)等待音頻播放完畢,保證程序不會(huì)在播放結(jié)束前退出
clock.tick(3)
def main():
while True:
# 1. 提示用戶發(fā)言
print('請(qǐng)發(fā)言,謝謝!')
# 2. 錄制音頻
audio_record(5, 'user_audio.wav')
print('Audio recording complete.')
# 3. 獲取百度語(yǔ)音識(shí)別的access token
baidu_token = get_access_token()
print('Baidu access token obtained.')
# 4. 上傳錄音文件并進(jìn)行語(yǔ)音識(shí)別
baidu_result = BaiduYuYin('user_audio.wav', baidu_token)
print('Baidu speech recognition result:', baidu_result)
# 5. 調(diào)用大語(yǔ)言模型進(jìn)行文本生成
model_response = get_completion(baidu_result)
print('Model response:', model_response)
# 6. 將文本轉(zhuǎn)換為語(yǔ)音,保存到唯一的文件名
unique_audio_filename = str(uuid.uuid4()) + '.mp3' # 保存為不同的文件名以避免訪問(wèn)沖突
asyncio.run(generate_audio_from_text(model_response,unique_audio_filename))
# 7. 播放生成的語(yǔ)音
play_mp3(unique_audio_filename)
# 8. 提示用戶繼續(xù)對(duì)話或退出
user_input = input('繼續(xù)對(duì)話或輸入"退出"退出: ')
if user_input == '退出':
break
if __name__ == "__main__":
main()
?局限性
- ChatGLM2-6B的api存在局限性,調(diào)用此api只能一問(wèn)一答,沒(méi)有記憶性。
- api不能部署到公網(wǎng)上,只能本地訪問(wèn)。運(yùn)行上面的代碼之前,一定要先ssh到運(yùn)行大模型的服務(wù)器上。
結(jié)語(yǔ)
看到了這里,你一定是個(gè)熱愛學(xué)習(xí)編程的極客,令人欽佩。在這個(gè)知識(shí)無(wú)邊界的時(shí)代,你的點(diǎn)贊和收藏是我創(chuàng)作的最大動(dòng)力。讓我們攜手前行,探索更多的學(xué)習(xí)和創(chuàng)新,為共同的熱愛努力,因?yàn)樵谥R(shí)的海洋里,我們永不止步,共同譜寫著學(xué)習(xí)的精彩篇章。感謝你的支持!點(diǎn)贊、收藏! ????文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-754451.html
到了這里,關(guān)于以大語(yǔ)言模型ChatGLM2-6B為后臺(tái),打造個(gè)人語(yǔ)音交互機(jī)器人Demo的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!