本篇為改進(jìn)版,之前部分代碼存在錯誤,部分網(wǎng)站api也已經(jīng)失效,現(xiàn)在更換api,并對部分代碼進(jìn)行重寫。
本次在Pycharm上測試
相關(guān)模塊如下:
baidu-aip==4.16.11
beautifulsoup4==4.12.2
chardet==5.1.0
lxml==4.9.2
PyAudio==0.2.13
pycryptodome==3.18.0
pygame==2.4.0
pyttsx3==2.90
requests==2.31.0
wxPython==4.2.1
廢話不多說,先上效果圖
功能一:人機(jī)互動
功能二:播放音樂
功能三:天氣
功能四:一句話新聞
把以下參數(shù)更換成你自己的
# 百度需要的參數(shù)
APP_ID = '000000'
API_KEY = 'xxxxxx'
SECRET_KEY = 'xxxxxx'
# 圖靈機(jī)器人需要的參數(shù)
tuling_apiKey = "xxxxxx"
tuling_userId = "000000"
# 易客云需要的參數(shù)
yikeyun_appid = '000000'
yikeyun_appsecret = 'xxxxxx'
易客云平臺(https://yikeapi.com/account)
圖靈機(jī)器人
http://www.tuling123.com/member/robot/index.jhtml
百度語音識別api 介紹請看
https://ai.baidu.com/tech/speech?_=1687103124997
控制臺:
https://console.bce.baidu.com/ai/?fromai=1#/ai/speech/overview/index
按照這些步驟一步一步創(chuàng)建自己的應(yīng)用,完成個人實(shí)名認(rèn)證可以有一定的免費(fèi)使用量,創(chuàng)建應(yīng)用完成后,從”我的應(yīng)用“ 即可看到相應(yīng)的userid, apikey 等。
import pyaudio
import wave
import win32com.client
from aip import AipSpeech
import base64
import random
from binascii import hexlify
from Crypto.Cipher import AES
import json
import time
import wx
import pyttsx3
import requests
from bs4 import BeautifulSoup
import chardet
import pygame
import win32com.client
# 百度需要的參數(shù)
APP_ID = '000000'
API_KEY = 'xxxxxx'
SECRET_KEY = 'xxxxxx'
# 圖靈機(jī)器人需要的參數(shù)
tuling_apiKey = "xxxxxx"
tuling_userId = "000000"
# 易客云需要的參數(shù)
yikeyun_appid = '000000'
yikeyun_appsecret = 'xxxxxx'
speaker = win32com.client.Dispatch("SAPI.SpVoice")
def record(file_path):
# 各路參數(shù)
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = file_path
pau = pyaudio.PyAudio()
stream = pau.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK, )
frames = []
print("開始錄音")
speaker.Speak("開始錄音")
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data)
print("錄音結(jié)束")
speaker.Speak("錄音結(jié)束")
stream.stop_stream()
stream.close()
pau.terminate()
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(pau.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
def voice2text(APP_ID, API_KEY, SECRET_KEY, file_path):
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
ret = client.asr(get_data(file_path), 'pcm', 16000, {'dev_pid': 1536}, )
return ret['result']
def get_data(file_path):
with open(file_path, 'rb') as fp:
return fp.read()
#人機(jī)互動
engine = pyttsx3.init()
# 向api發(fā)送請求
def get_response(msg):
apiUrl ='http://openapi.turingapi.com/openapi/api/v2'
data = {
"reqType": 0,
"perception": {
"inputText": {
"text": msg
},
},
"selfInfo": {
"location": {
"city": "北京",
"province": "北京",
"street": "信息路"
}
},
"userInfo": {
"apiKey": tuling_apiKey,
"userId": tuling_userId,
}
}
try:
data = json.dumps(data)
r = requests.post(apiUrl, data=data).json()
res = r['results'][0]['values']['text']
print(res)
engine.say(res)
engine.runAndWait()
except:
return
def say():
global chat_message
# 存放的文件名稱
file_path = "./data/chat-audio.wav"
# 先調(diào)用錄音函數(shù)
record(file_path)
# 語音轉(zhuǎn)成文字的內(nèi)容
chat_message = voice2text(APP_ID, API_KEY, SECRET_KEY, file_path)
print(chat_message)
def chatwithrobot():
i=0
while i<5:
say()
get_response(chat_message)
i=i+1
print("5次對話已經(jīng)結(jié)束!")
#音樂播放
class GetMusic:
def __init__(self):
self.key = GetParamsAndEncSecKey()
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36',
'Referer': 'http://music.163.com/'}
self.session = requests.Session()
self.session.headers = self.headers
self.conmment_url = 'https://music.163.com/weapi/v1/resource/comments/R_SO_4_{}?csrf_token=' # 評論
self.lyric_url = 'https://music.163.com/weapi/song/lyric?csrf_token=' # 歌詞
self.music_url = 'https://music.163.com/weapi/song/enhance/player/url?csrf_token=' # 歌曲
self.url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token=' # 搜索歌曲列表,無歌曲鏈接
def get_params_and_encSecKey(self, song=None):
'''
獲取什么就返回所需要兩個參數(shù)
1. 歌曲
2. 歌詞
3. 評論 默認(rèn)
4. 搜索的歌曲列表
:param song:
:return:
'''
if isinstance(song, int):
data = {"ids": [song], "br": 128000, "csrf_token": ""}
elif isinstance(song, str) and song.isdigit():
data = {"id": song, "lv": -1, "tv": -1, "csrf_token": ""}
elif song == None:
data = {}
else:
data = {"hlpretag": "<span class=\"s-fc7\">", "hlposttag": "</span>", "s": song, "type": "1", "offset": "0",
"total": "true", "limit": "30", "csrf_token": ""}
song = json.dumps(data)
data = self.key.get(song)
return data
def get_music_list_info(self, name):
'''
獲取歌曲詳情:歌名+歌曲id+作者
:param name:
:return:
'''
data = self.get_params_and_encSecKey(name)
res = self.session.post(self.url, data=data) # 歌曲
song_info = res.json()['result']['songs']
for song in song_info:
song_name = song['name']
song_id = song['id']
songer = song['ar'][0]['name']
print(song_name, '\t', song_id, '\t', songer)
global SongName # 定義為全局變量
global SongId # 定義為全局變量
global Songer # 定義為全局變量
SongName=song_name
SongId=song_id
Songer=songer
self.get_music_url(song_id)
self.get_music_lyric(song_id)
self.get_music_comment(song_id)
break
def get_music_url(self, id):
'''
獲取歌曲URL鏈接
:param id:
:return:
'''
global Song_url # 定義為全局變量
data = self.get_params_and_encSecKey(id)
res = self.session.post(self.music_url, data=data)
song_url = res.json()['data'][0]['url']
Song_url=song_url
#print(song_url)
def get_music_lyric(self, id_str):
'''
獲取歌詞
:param id_str:
:return:
'''
data = self.get_params_and_encSecKey(str(id_str))
res = self.session.post(self.lyric_url, data=data)
lyric = res.json()['lrc']['lyric']
#print(lyric)
def get_music_comment(self, song_id):
'''
獲取歌曲評論: 評論人+內(nèi)容+頭像
:param song_id:
:return:
'''
data = self.get_params_and_encSecKey()
comment = self.session.post(self.conmment_url.format(str(song_id)), data=data)
com_list = comment.json()['hotComments']
for com in com_list:
content = com['content']
nickname = com['user']['nickname']
user_img = com['user']['avatarUrl']
#print(nickname, '!!!!' + content + '!!!!', user_img)
class GetParamsAndEncSecKey:
def __init__(self):
self.txt = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
self.i = ''.join(random.sample(self.txt, 16)) # 16為隨機(jī)數(shù)
self.first_key = '0CoJUm6Qyw8W8jud'
def get(self, song):
'''
獲取加密的參數(shù)
params是兩次加密的
:param song:
:return:
'''
res = self.get_params(song, self.first_key)
params = self.get_params(res, self.i)
encSecKey = self.get_encSecKey()
return {
'params': params,
'encSecKey': encSecKey
}
def get_params(self, data, key):
'''
獲得params,加密字符長度要是16的倍數(shù)
:param data:
:param key:
:return:
'''
iv = '0102030405060708'
num = 16 - len(data) % 16
data = data + num * chr(num) # 補(bǔ)足
cipher = AES.new(key.encode(), AES.MODE_CBC, iv.encode())
result = cipher.encrypt(data.encode())
result_str = base64.b64encode(result).decode('utf-8')
return result_str
def get_encSecKey(self):
'''
獲取encSecKey,256個字符串
hexlify--->轉(zhuǎn)換為btyes類型
pow--->兩個參數(shù)是冪,三個參數(shù)是先冪在取余
format(rs, 'x').zfill(256)-->256位的16進(jìn)制
:return:
'''
enc_key = '010001'
modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
rs = pow(int(hexlify(self.i[::-1].encode('utf-8')), 16), int(enc_key, 16), int(modulus, 16))
return format(rs, 'x').zfill(256)
def music():
file_path="./data/music.wav"
# 先調(diào)用錄音函數(shù)
record(file_path)
# 語音轉(zhuǎn)成文字的內(nèi)容
song_message = voice2text(APP_ID, API_KEY, SECRET_KEY, file_path)
print(song_message)
song_name = song_message[0].split('播放')[1]
Msuic = GetMusic()
Msuic.get_music_list_info(song_name)
songid=str(SongId)
headers = { 'User-agent':
'Mozilla/5.0 (X11; Linux x86_64; rv:57.0)Gecko/20100101 Firefox/57.0',
}
response = requests.get("http://music.163.com/song/media/outer/url?id=" + songid + ".mp3",
headers = headers)
content = response.content
with open('./data/'+SongName+'.mp3', mode = "wb") as f:
f.write(content)
print(SongName + " " + "下載完成")
engine = pyttsx3.init()
engine.say("即將為您播放 "+Songer+' 的 '+SongName)
engine.runAndWait()
pygame.mixer.init()
filename = './data/' + SongName+'.mp3'
pygame.mixer.music.load(filename)
pygame.mixer.music.play()
#天氣播報
def weather():
# 存放的文件名稱
file_path='./data/weather-audio.wav'
# 先調(diào)用錄音函數(shù)
record(file_path)
# 語音轉(zhuǎn)成文字的內(nèi)容
weather_message =voice2text(APP_ID, API_KEY, SECRET_KEY, file_path)
print(weather_message)
#抓取中國天氣網(wǎng)指定城主天氣
#input_message=['播放杭州天氣情況']
input2=''.join(weather_message) #轉(zhuǎn)換成字符串
city_name=input2[2:4]
s1 = f'https://v0.yiketianqi.com/api?unescape=1&version=v61&appid={yikeyun_appid}&appsecret={yikeyun_appsecret}&city='
url=s1+city_name #拼接 url
r = requests.get(url)
r.encoding = 'utf-8'
# 提取相關(guān)天氣信息
date=r.json()["date"]
templow=r.json()["tem2"]
temphigh=r.json()["tem1"]
tempnow=r.json()["tem"]
week=r.json()["week"]
tip=r.json()["air_tips"]
weather=r.json()['wea_day']
add=r.json()["city"]
wind=r.json()['win']
WS=r.json()["win_speed"]
t = time.localtime() # 當(dāng)前時間的紀(jì)元值
fmt = "%H %M"
now = time.strftime(fmt, t) # 將紀(jì)元值轉(zhuǎn)化為包含時、分的字符串
now = now.split(' ') #以空格切割,將時、分放入名為now的列表中
hour = now[0]
minute = now[1]
wea='你好,今天是%s%s,現(xiàn)在北京時間%s時%s分,%s天氣 %s,氣溫%s攝氏度~%s攝氏度,現(xiàn)在為%s攝氏度,%s,風(fēng)力%s,%s'%(date,week,hour,minute,add,weather,templow,temphigh,tempnow,wind,WS,tip)
print(wea)
engine = pyttsx3.init()
engine.say('即將為您播放'+city_name+"天氣情況")
engine.say(wea)
engine.runAndWait()
#新聞播報
def news():
def get_content():
url="https://news.topurl.cn/" # 爬取一名話新聞網(wǎng)科技類新聞
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'}
rqg=requests.get(url,headers=headers) # 開始爬取,設(shè)置headers信息來偽裝成瀏覽器請求數(shù)據(jù)
rqg.encoding=chardet.detect(rqg.content)['encoding']
html=rqg.content.decode('utf-8') #換化編碼為utf-8
soup=BeautifulSoup(html,'lxml')
soup.prettify() #格式化soup對象
return soup
soup2=get_content()
target=soup2.find_all(class_='news-wrap') #取新聞標(biāo)題
Tag=[]
for tag in target:
Tag.append(tag.get_text()) #取新聞標(biāo)題文本添加到列表中
list_news = Tag[0].replace('\n', '').split('\u2003')
list_news.pop() # 刪除最后一個空項(xiàng)
engine = pyttsx3.init()
engine.say('即將為您播放新聞')
engine.runAndWait()
for news in list_news:
print(news)
engine.say(news)
engine.runAndWait()
#GUI界面
speaker = win32com.client.Dispatch("SAPI.SpVoice")
class Panel1(wx.Panel):
"""class Panel1 creates a panel with an image on it, inherits wx.Panel"""
def __init__(self, parent, id):
# create the panel
wx.Panel.__init__(self, parent,id)
try:
image_file = './image/bg.png'
bmp1 = wx.Image(image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
self.bitmap1 = wx.StaticBitmap(self, -1, bmp1, (0, 0))
except IOError:
print ("Image file is not found") % image_file
raise SystemExit
pic1 = wx.Image("./image/hudong.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap()
pic2 = wx.Image("./image/yinyue.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap()
pic3 = wx.Image("./image/tianqiqing.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap()
pic4 = wx.Image("./image/xinwen.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap()
#繪圖按鈕1,默認(rèn)風(fēng)格3D
self.button1 = wx.BitmapButton(self.bitmap1, -1, pic1, pos = (230, 420),style=0,size=(50,50))
self.Bind(wx.EVT_BUTTON, self.On1Click, self.button1)
self.button1.SetDefault()
#繪圖按鈕2,默認(rèn)風(fēng)格3D
self.button2 = wx.BitmapButton(self.bitmap1, -1, pic2, pos = (300, 420),style=0,size=(50,50))
self.Bind(wx.EVT_BUTTON, self.On2Click, self.button2)
self.button2.SetDefault()
#繪圖按鈕3,默認(rèn)風(fēng)格3D
self.button3 = wx.BitmapButton(self.bitmap1, -1, pic3, pos = (230, 480),style=0,size=(50,50))
self.Bind(wx.EVT_BUTTON, self.On3Click, self.button3)
self.button3.SetDefault()
#繪圖按鈕4,默認(rèn)風(fēng)格3D
self.button4 = wx.BitmapButton(self.bitmap1, -1, pic4, pos = (300, 480),style=0,size=(50,50))
self.Bind(wx.EVT_BUTTON, self.On4Click, self.button4)
self.button4.SetDefault()
def On1Click(self, event):
print("人機(jī)交互")
speaker.Speak("您已選擇人機(jī)交互模式 ")
chatwithrobot()
event.Skip()
def On2Click(self, event):
print("音樂播放")
speaker.Speak("您已選擇音樂播放模式 ")
music()
event.Skip()
def On3Click(self, event):
print("天氣播報")
speaker.Speak("您已選擇天氣播報模式 ")
weather()
event.Skip()
def On4Click(self, event):
print("新聞播報")
speaker.Speak("您已選擇新聞播報模式 ")
news()
event.Skip()
app = wx.App(False)
frame1 = wx.Frame(None, -1, title='Robot', size=(600, 640))
# create the class instance
panel1 = Panel1(frame1, -1)
frame1.Show(True)
app.MainLoop()
代碼及圖片地址:
https://gitee.com/ouaqq/python-voice-robot.git文章來源:http://www.zghlxwxcb.cn/news/detail-496116.html
歡迎給個小小的star文章來源地址http://www.zghlxwxcb.cn/news/detail-496116.html
到了這里,關(guān)于Python 智能語音機(jī)器人(改進(jìn)版)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!