大家好,小編來為大家解答以下問題,python作業題百度網盤,python123作業答案,今天讓我們一起來看看吧!
完整項目分享:
鏈接: https://pan.baidu.com/s/1CTMOgLYteLrWRaRnouB0SQ?pwd=12hf 提取碼: 12hf
(如果這個項目幫助到你了,麻煩點個贊,謝謝)
1.實現功能:
1.進行簡單的日常生活聊天(首先根據輸入尋找對應答案,如果未找到對應答案,就結合從百度百科上爬取下的內容進行回答)
2.關于具體電影和音樂話題的聊天(聯系上文語境、實現關鍵詞雙重查找)
附加部分:
為機器人增加了語音播報功能
實現了一個簡單的GUI,實現了交互功能
機器人對話均為中文對話
2.功能演示
日常聊天部分:
1.進行簡單的對話
點擊開始按鈕,在內部對程序進行初始化
將想要輸入的部分輸入到發送框中,然后點擊發送
2.對于特定的關鍵詞知道進行搜索
當然,如果想要的數據更精確,也可以直接行駛查詢功能
特定話題部分:
流程:
首先需要輸入“聊電影”
然后利用特定的輸入來激活到某個更具體的話題
比如輸入的“知道戀戀筆記本這部電影嗎?”,“知道陳可辛嗎?”,然后就可以就這個部分進行話題的探討
需要退出具體話題的聊天,可以直接輸入exit實現退出,返回到日常生活中的聊天。
首先是激活到對應的具體話題部分
我們先輸入“聊電影”
然后再看“激活特定話題用關鍵詞.txt”文件中的內容,選擇一個輸入
這里輸入的是“你知道陳可辛嗎?”就正式進入這個話題下的聊天了
找到對應部分后,就可以輸入對話了python簡單圖案代碼。這里利用了雙層的關鍵詞查找和聯系上下問語境
雙層關鍵詞
聯系上下文語境
前面先聊到“梁家輝”,此時的話題就記住了關鍵詞“梁家輝”,然后再問出生日期,聊天機器人就會在“梁家輝”對應的詞條下面尋找。后來又聊到了“陳可辛”,此時的語境就會切換成陳可辛,你再問機器人,機器人就會在結合陳可辛的語境進行回答。
3.實現過程:
實現所用到庫
jieba: 用于中文分詞。方便將對話輸入拆分關鍵詞,便于查找
tkinter:用于實現GUI交互界面
json:用于讀取json格式的語料庫文件
pyttsx3:用于實現機器人的語音播報
實現思路:
整體思路是結合預料庫進行正則匹配。
首先是整個字符串進行匹配,如果找到就可以直接進行輸出
然后是關鍵詞逐個匹配,在上一種情況沒有匹配的情況下,將輸入的話進行關鍵詞的拆分和組合,再進行關鍵詞的匹配。
擴展部分思路
這部分是結合語境以及關鍵詞多重匹配
結合了具體話題的語料庫的性質。
這個語料庫的關鍵詞分為三層。
第一層適用于我們激活到更加具體的話題,比如說提問“知道陳可辛嗎?”,這一整句話就是第一層關鍵詞,保證回答不會跳出這個話題。
第二層關鍵詞就適用于語境了,每次找到新回答后,這個語境關鍵詞都會被更新。
第三層關鍵詞用于查找具體的回答。
結合語境:
每次找到新回答后就會更新語境,下一次再要尋找回答時,會優先匹配之前的語境下的第三層關鍵詞,如果匹配成功了,那就直接輸出。如果沒有在之前的語境關鍵詞下匹配成功。就跳轉到使用關鍵詞的多重匹配。
關鍵詞多重匹配:
利用jieba庫對輸入的話進行關鍵詞拆分和組合,得到我們實際想知道的關鍵詞的所有可能。
先用所有的關鍵詞可能匹配第二層關鍵詞,如果匹配成功了就再匹配這個語境關鍵詞下的所有第三層關鍵詞,一旦匹配成功就可以輸出了。舉例:
輸入“梁家輝主要成就”
將關鍵詞拆分組合成“梁家輝”“梁家輝成就”,“梁家輝主要”,“梁家梁家輝成就”,“梁家梁家輝主要”,“梁家梁家輝”,“梁家成就”,“梁家主要成就”,“梁家主要”。
利用這些關鍵詞逐個匹配第二層關鍵詞,發現“梁家輝”這個關鍵詞匹配成功了
在“梁家輝”這個語境關鍵詞下,再次利用所有的關鍵詞可能匹配第三層關鍵詞,發現匹配成功了“主要成就”,就將對應結果輸出了。
實現所用函數的解釋:
query(content):
輸入:要查詢的詞條
輸出:查詢的結果
功能:爬取百度百科content的搜索內容
StrSplit(String):
輸入:要拆分的字符串
輸出:所有可能字符子串的數組
功能:將輸入的內容進行關鍵詞拆分和組合,返回形成字符串數組。
query_find(String):
輸入:要檢查的字符串
輸出:返回是否符合查找的格式,和查詢的結果
功能:檢查輸入的String是不是符合“知道xx嗎”的形式,如果是,就調用query進行查找,并且更改返回值。
MatchSiple(path, String):
輸入:語料庫的路徑,要查詢的字符串
輸出:返回是否找到結果以及結果
功能:檢查String是否在path對應的文件內容中有直接的完全符合的匹配,如果有就修改返回值
MatchHeight(path, String_lt):
輸入:語料庫的路徑,分割好后的字符串數組
輸出:是否查詢到結果,查詢的結果
功能:逐個檢查String_lt字符串數組中的字符串是否在path對應文件有完全的匹配,如有有匹配,就對應答案該返回值。
ai_movie_MatSiple(data,String oeder):
與MatchSiple(path,String)類似,只是使用的語料庫切換成了具體話題的語料庫。
ai_movie_MatchHeight(data, String_lt,order,name):同上。
ai_films_Matchname(data,String):
輸入:具體話題的語料庫,輸入的字符串
輸出:查詢的結果,是否查詢到結果,查詢到的第一個關鍵詞
功能:確定好第一個關鍵詞。
films(engine,file,string):
輸入:語音播報,打開的語料庫文件,要檢測的字符串
輸出:無返回值,直接將內容輸出到GUI上,同時進行語音播報
功能:根據前后全局變量的信息,有針對性調用前面所說的函數,找到對應的結果。
chat_bot(String):
輸入:要詢問的部分
輸出: 無返回值,直接將內容輸出到GUI上,同時進行語音播報。
功能:根據幾個全局變量的信息,有針對性的調用上述函數,找到最終的結果
send():
這個函數是被按鈕“發送”所調用的,會調用chat_bot()函數,尋找返回的字符串,同時將輸入的內容有人插入到GUI的文本框中。
begin():
對所有的信息進行初始化,這個函數是由“開始”按鈕所調用的
代碼中全局變量的解釋
global tag1:用于表示當前機器人的狀態是不是在“聊電影”這個特殊的話題上
global tag2:用于表示當前機器人的狀態是不是在“聊音樂”這個特殊的話題上
global name:用于記錄在“聊電影”和“聊音樂”上的第一個關鍵詞
global path:用于記錄日常聊天的語料庫的路徑
global engine:用于記錄語音播報
global file1:記錄“聊電影”的語料庫文件
global file2:記錄“聊音樂”的語料庫文件
global data:記錄打開的具體話題對應文件轉化成的dirt
global ord:記錄在“聊電影”或者“聊音樂”這兩個具體部分中,第一個關鍵詞對應的位置。還是方便后續的查找
##4.實驗總結:
本次實驗的主題思路是實現關鍵詞的提取和匹配,根據已經有的語料庫進行針對性的回答。
在一般的完全匹配上,增加了關鍵詞的拆分重新組合,增加了結合語境,增加了關鍵詞雙重匹配,增加了不知道結果時可以從百度百科上爬取答案。同時增加了交互界面和語音播報。
實現了可以簡單的一問一答,具體話題下的更具體的回答。
但是由于語料庫的欠缺,在實現具體話題下問答時需要用特殊的話來進行激活,這一點是有待改進。同時這次大作業,借鑒了網絡上的一些思路,表示感謝。
import tkinter
import tkinter as tk
from tkinter import scrolledtext
import jieba
import urllib.request
import urllib.parse
from lxml import etree
import json
import pyttsx3# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~全局變量~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
global tag1
global tag2
global name
global path
global engine
global file1
global file2
global data
global ord
tag1 = 0
tag2 = 0
name = None
# 標記兩個tag,一個tag表示當前的選擇是一般性回答還是film,另一個tag是在film中表示是不是第一次使用film的庫
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# ~~~~~~~~~~~~~~~~~~~~~~~~~~~日常對話部分查找~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def query(content):# 請求地址url = 'https://baike.baidu.com/item/' + urllib.parse.quote(content)# 請求頭部headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}# 利用請求地址和請求頭部構造請求對象req = urllib.request.Request(url=url, headers=headers, method='GET')# 發送請求,獲得響應response = urllib.request.urlopen(req)# 讀取響應,獲得文本text = response.read().decode('utf-8')# 構造 _Element 對象html = etree.HTML(text)# 使用 xpath 匹配數據,得到匹配字符串列表sen_list = html.xpath('//div[contains(@class,"lemma-summary") or contains(@class,"lemmaWgt-lemmaSummary")]//text()')# 過濾數據,去掉空白sen_list_after_filter = [item.strip('\n') for item in sen_list]# 將字符串列表連成字符串并返回return ''.join(sen_list_after_filter)def query_find(String):back = Nonefind = 0if '知道' in String: # 符合”知道XX嗎“的格式,直接調用query對結果進行爬蟲find = 1f1 = String.split('知道')f1 = f1[1].split('嗎')back = query(f1[0])if len(back) < 2:back = '這個小蝸也不知道哎'lt_ms = [back, find]return lt_msdef StrSplit(String):"""Decompose the string into a list # 將字符串分解為一個列表:param String: The string to be decomposed # 要分解的字符串:return: String_lt # 分解后的字符串列表"""String_lt = jieba.lcut(String, cut_all=True) # 要引入jieba庫String1 = jieba.lcut(String, cut_all=True)String2 = jieba.lcut(String, cut_all=True)String3 = jieba.lcut(String, cut_all=True)String3.append('')for Str1 in String1:String_lt.append(Str1)String2.remove(Str1)for Str2 in String2:String_lt.append(Str2) # 要添加分出來的關鍵詞try:String3.remove(Str1)except:passtry:String3.remove(Str2)except:passfor Str3 in String3:String_lt.append(Str3)String_lt.append(Str1 + Str2 + Str3) # 添加組合成的關鍵詞String_lt = sorted(String_lt, reverse=True)return String_ltdef MatchSiple(path, String):"""Matches the dictionary to a single string # 將字典匹配到單個字符串:param path: The dictionary to match # 匹配的字典:param String: The string to match # 要匹配的字符串:return: lt_ms # 匹配結果與判斷(1有/0無)的列表"""errow_matchsplit = 0back = Nonef1 = String.split(':')[0]if f1 == '查詢':errow_matchsplit = 1back = query(String.split(':')[1])lt_ms = [back, errow_matchsplit]return lt_mswith open(path, 'r', encoding='utf-8') as f: # 注意編碼while errow_matchsplit == 0:f1 = f.readline().split('\n')[0]f2 = f.readline().split('\n')[0]f3 = f.readline()if String == f1:back = f2errow_matchsplit = 1breakif f1 == '' or f2 == '':breaklt_ms = [back, errow_matchsplit]if errow_matchsplit == 0:lt_ms = query_find(String)return lt_msdef MatchHeight(path, String_lt):"""Matches the dictionary with a list of strings # 用字符串列表匹配字典:param path: The dictionary to match # 匹配的字典:param String_lt: List of strings to match # 要匹配的字符串列表:return: lt_mh # 匹配結果與判斷(1有/0無)的列表"""errow_matchheight = 0back = Nonewith open(path, 'r', encoding='utf-8') as f: # 注意編碼while errow_matchheight == 0:f1 = f.readline().split('\n')[0]f2 = f.readline().split('\n')[0]f3 = f.readline()for String in String_lt:if String == f1:back = f2errow_matchheight = 1breakif f1 == '' or f2 == '':breaklt_mh = [back, errow_matchheight]return lt_mh# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~def study(path, study_start, study_end):"""Open the dictionary and write the match statement and the match result # 打開字典并編寫匹配語句和匹配結果:param path: The dictionary to open # 要查的字典:param study_start: Dictionary matching statements # 詞典匹配語句:param study_end: The dictionary returns the result # 字典返回結果:return: None # 無返回"""with open(path, 'a', encoding='utf-8') as f: # 注意編碼f.write(study_start+'\n')f.write(study_end+'\n')f.write('\n')# ~~~~~~~~~~~~~~~~~~~~~~~~~~~具體話題查找~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def ai_movie_MatchSiple(data, String, order):errow_movie_match = 0back = Nonename = Nonef1 = String.split(':')[0]if f1 == '查詢':errow_matchsplit = 1back = query(String.split(':')[1])lt_ms = [back, errow_matchsplit,name]return lt_msfor i in range(len(data[order]['messages'])):if data[order]['messages'][i]['message'] == String:back = data[order]['messages'][i+1]['message']name = data[order]['messages'][i+1]['attrs'][0]['name']errow_movie_match = 1breaklt_ms = [back, errow_movie_match, name]return lt_msdef ai_movie_MatchHeight(data, String_lt, order, name):errow_movie_matchH = 0back = Nonefind = 0for i in range(len(data[order]['messages'])): # 優先根據結果進行檢查if errow_movie_matchH == 1:breakif len(data[order]['messages'][i]) == 2:for String in String_lt:if errow_movie_matchH == 1:break# print(String, ' ', data[order]['messages'][i]['attrs'][0]['name'])for j in range(len(data[order]['messages'][i]['attrs'])): #判斷是否普找到if String == data[order]['messages'][i]['attrs'][j]['name']:find = 1breakif find == 1:for j in range(len(data[order]['messages'][i]['attrs'])):if errow_movie_matchH == 1:breakfor String in String_lt:if String == data[order]['messages'][i]['attrs'][j]['attrname']:back = data[order]['messages'][i]['attrs'][j]['name']+','+data[order]['messages'][i]['attrs'][j]['attrname']+':'+data[order]['messages'][i]['attrs'][j]['attrvalue']name = data[order]['messages'][i]['attrs'][j]['name']errow_movie_matchH = 1breakfor i in range(len(data[order]['messages'])): # 優先根據結果進行檢查if errow_movie_matchH == 1:breakif len(data[order]['messages'][i]) == 2:for String in String_lt:#if len(data[order]['messages'][i]['attrs'][0]) == 1:#說明有不止一個attrfor j in range(len(data[order]['messages'][i]['attrs'])):if String == data[order]['messages'][i]['attrs'][j]['attrname']:if name == data[order]['messages'][i]['attrs'][j]['name']: # 首先對name 進行檢驗,不過這時候的name要換成String,進行三重檢測back = data[order]['messages'][i]['attrs'][j]['name']+','+data[order]['messages'][i]['attrs'][j]['attrname']+':'+data[order]['messages'][i]['attrs'][j]['attrvalue']errow_movie_matchH = 1breakfor i in range(len(data[order]['messages'])):if errow_movie_matchH == 1:breakif len(data[order]['messages'][i]) == 2:for String in String_lt:for j in range(len(data[order]['messages'][i]['attrs'])):if String == data[order]['messages'][i]['attrs'][j]['attrname']:back = data[order]['messages'][i]['attrs'][j]['name']+','+data[order]['messages'][i]['attrs'][j]['attrname']+':'+data[order]['messages'][i]['attrs'][j]['attrvalue']name = data[order]['messages'][i]['attrs'][j]['name']errow_movie_matchH = 1breaklt_mh = [back, errow_movie_matchH, name]return lt_mhdef ai_films_Matchname(data,String):errow_matchsplit = 0back = 0name = Nonefor i in range(149):if data[i]['messages'][0]['message'] == String:errow_matchsplit = 1name = data[i]['messages'][1]['attrs'][0]['name']back = ibreaklt_ms = [back, errow_matchsplit, name]return lt_msdef films(engine, file,String): ##聊電影對應的模塊global tag1global tag2global nameglobal dataglobal ordif tag2 == 0: ##說明剛剛進入到這個模塊當中data = json.load(file)order = ai_films_Matchname(data, String)name = order[2]ord = order[0]t.insert('end', '小蝸:'+data[order[0]]['messages'][1]['message']+'\n')engine.say(data[order[0]]['messages'][1]['message'])engine.runAndWait()tag2 = 1elif String == 'exit':tag2 = 0tag1 = 0else:a1 = ai_movie_MatchSiple(data=data, String=String, order=ord)show = a1[0]errow_matchsimple = a1[1]if errow_matchsimple == 0: # 說明沒有找到直接相匹配的,關鍵詞進行重組,查找對應的關鍵詞String_lt = StrSplit(String=String)a2 = ai_movie_MatchHeight(data=data, String_lt=String_lt, order=ord, name=name)show = a2[0]errow_matchhight = a2[1]if errow_matchhight == 0:t.insert('end', '小蝸:小蝸不知道這個細節唉😔'+'\n')engine.say("小蝸不知道這個細節唉")engine.runAndWait()else:name = a2[2]t.insert('end', '小蝸:'+ show+'\n')engine.say(show)engine.runAndWait()else:name = a1[2]t.insert('end', '小蝸:' + show + '\n')engine.say(show)engine.runAndWait()return
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# ~~~~~~~~~~~~~~~~~~~~~相當于main函數,總調度~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def chat_bot(String):global tag1global tag2global engineglobal file1global file2global pathif tag1 == 0: #標志現在是在正常的聊天當中if String == '聊電影':tag1 = 1returnelif String == '聊音樂':tag2 = 2returnelse:a1 = MatchSiple(path=path, String=String)show = a1[0]errow_matchsimple = a1[1]if errow_matchsimple == 0:String_lt = StrSplit(String=String) # 對關鍵詞全部進行重新組合a2 = MatchHeight(path=path, String_lt=String_lt)show = a2[0]errow_matchhight = a2[1]if errow_matchhight == 0:t.insert('end', '小蝸: 小蝸不知道怎么回答哎'+'\n')engine.say("小蝸不知道怎么回答哎")engine.runAndWait()else:t.insert('end', '小蝸:'+show+'\n')engine.say(show)engine.runAndWait()else:t.insert('end', '小蝸:'+show+'\n')engine.say(show)engine.runAndWait()elif tag1 == 1:films(engine=engine, file=file1, String=String)elif tag2 == 2:films(engine=engine, file=file2, String=String)return
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# ~~~~~~~~~~~~~~~~~~~~~~按鈕對應函數~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def send():val = e.get()e.delete(0, tkinter.END)t.insert('end', '主人:' + val + '\n') # 將要輸出的內容插入到文本框中chat_bot(String=val)t.see(tkinter.END)def begin(): #默認加載學習模塊global engineglobal pathglobal tag1tag1 = 0path = r'ai.txt'engine = pyttsx3.init()voices = engine.getProperty('voices') # 音色engine.setProperty('voice', "com.apple,speech.synthesis.voice.meijia")rate = engine.getProperty('rate') # 速率engine.setProperty('rate', 180)volume = engine.getProperty('volume') # 音量engine.setProperty('volume', 1.0)global file1global file2file1 = open('file.json', 'r', encoding='utf8')file2 = open('music.json', 'r', encoding='utf8')# t.insert('end', '-' * 10 + '程序開始' + '-' * 10 + '\n')t.insert('end', '小蝸: 程序開始了哦'+'\n')
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# ~~~~~~~~~~~~~~~GUI部分~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
window = tk.Tk()
window.title('小蝸機器人')
window.geometry('800x200')l1 = tk.Label(window, text='聊天', font=('Arial', 12), width=15,height=1)
l2 = tk.Label(window, text='發送框', font=('Arial', 12), width=15,height=1)
# 直接傳入部分對應輸出部分
e = tk.Entry(window, width=100)
t = scrolledtext.ScrolledText(window, height=10, width=100)be = tk.Button(window,text='開始', font=('Arial', 12), width =10,height=1, command=begin)b = tk.Button(window, text='發送', font=('Arial', 12), width=10,height=1, command=send)
# 界面布置
l1.grid(row=0, column=0)
l2.grid(row=1, column=0)
e.grid(row=1, column=1)
t.grid(row=0, column=1)
be.grid(row=2, column=0)
b.grid(row=2, column=1)
window.mainloop()
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~