在这篇文章中,我将向您展示如何使用Python构建自己的答案查找系统。 基本上,这种自动化可以从图片中找到多项选择题的答案。
一件事很清楚,在考试期间不可能在互联网上搜索问题,但是当考官转过头来时,我可以快速拍照。 那是算法的第一部分。 我不知何故需要从图片中提取问题。
似乎有很多服务可以提供文本提取工具,但是我需要某种API来解决此问题。 最后,Google的Vision API是我正在寻找的确切工具。 很棒的是,每月前1000个API调用是免费的,这足以让我测试和使用该API。
视觉人工智能
首先,创建Google Cloud帐户,然后在服务中搜索Vision AI 。 使用Vision AI,您可以执行诸如为图像分配标签以组织图像,获取推荐的裁切顶点,检测出著名的风景或地方,提取文本等工作。
查看文档以启用和设置API。 配置后,您必须创建JSON文件,其中包含您的密钥下载到计算机上。
运行以下命令以安装客户端库:
pip install google-cloud-vision
然后,通过设置环境变量GOOGLE_APPLICATION_CREDENTIALS为您的应用程序代码提供身份验证凭据。
import os, io
from google.cloud import vision
from google.cloud.vision import types
# JSON file that contains your key
os.environ[ 'GOOGLE_APPLICATION_CREDENTIALS' ] = 'your_private_key.json'
# Instantiates a client
client = vision.ImageAnnotatorClient()
FILE_NAME = 'your_image_file.jpg'
# Loads the image into memory
with io.open(os.path.join(FILE_NAME), 'rb' ) as image_file:
content = image_file.read()
image = vision.types.Image(content=content)
# Performs text detection on the image file
response = client.text_detection(image=image)
print(response)
# Extract description
texts = response.text_annotations[ 0 ]
print(texts.description)
运行代码时,您将看到JSON格式的响应,其中包括检测到的文本的规范。 但是我们只需要纯描述,因此我从响应中提取了这部分。
在Google上搜索问题
下一步是在Google上搜索问题部分以获取一些信息。 我使用正则表达式库从描述中提取问题部分(响应)。 然后,我们必须对提取的问题部分进行批处理才能进行搜索。
import re
import urllib
# If ending with question mark
if '?' in texts.description:
question = re.search( '([^?]+)' , texts.description).group( 1 )
# If ending with colon
elif ':' in texts.description:
question = re.search( '([^:]+)' , texts.description).group( 1 )
# If ending with newline
elif '\n' in texts.description:
question = re.search( '([^\n]+)' , texts.description).group( 1 )
# Slugify the match
slugify_keyword = urllib.parse.quote_plus(question)
print(slugify_keyword)
检索信息
我们将使用BeautifulSoup抓取前3个结果以获取有关该问题的一些信息,因为答案可能位于其中一个中。
此外,如果您要从Google的搜索列表中抓取特定数据,请不要使用inspect元素来查找元素的属性,而应打印整个页面以查看属性,因为它与实际页面有所不同。
我们需要对搜索结果中的前3个链接进行爬网,但是这些链接确实被弄乱了,因此获取用于爬网的干净链接很重要。
/url?q=https: //en.wikipedia.org/wiki/IAU_definition_of_planet&sa=U&ved=2ahUKEwiSmtrEsaTnAhXtwsQBHduCCO4QFjAAegQIBBAB&usg=AOvVaw0HzMKrBxdHZj5u1Yq1t0en
如您所见,实际链接位于q =和&sa之间。 通过使用Regex,我们可以获得此特定字段或有效的URL。
result_urls = []
def crawl_result_urls () :
req = Request( 'https://google.com/search?q=' + slugify_keyword, headers={ 'User-Agent' : 'Mozilla/5.0' })
html = urlopen(req).read()
bs = BeautifulSoup(html, 'html.parser' )
results = bs.find_all( 'div' , class_= 'ZINbbc' )
try :
for result in results:
link = result.find( 'a' )[ 'href' ]
# Checking if it is url (in case)
if 'url' in link:
result_urls.append(re.search( 'q=(.*)&sa' , link).group( 1 ))
except (AttributeError, IndexError) as e:
pass
在我们抓取这些URL的内容之前,让我向您展示使用Python的问答系统。
问答系统
那是算法的主要部分。 从前3个结果中检索信息后,程序应通过迭代文档来检测答案。 首先,我认为最好使用相似性算法来检测与问题最相似的文档,但是我不知道如何实现。
经过数小时的研究,我在Medium中找到了一篇文章,解释了使用Python的问答系统。 它易于使用的python软件包可对您自己的私有数据实施质量检查系统。 您可以从此处检查更多说明
首先安装该软件包:
pip install cdqa
我正在使用下面的示例代码块中包含的下载功能来手动下载经过预训练的模型和数据:
import pandas as pd
from ast import literal_eval
from cdqa.utils.filters import filter_paragraphs
from cdqa.utils.download import download_model, download_bnpp_data
from cdqa.pipeline.cdqa_sklearn import QAPipeline
# Download data and models
download_bnpp_data(dir= './data/bnpp_newsroom_v1.1/' )
download_model(model= 'bert-squad_1.1' , dir= './models' )
# Loading data and filtering / preprocessing the documents
df = pd.read_csv( 'data/bnpp_newsroom_v1.1/bnpp_newsroom-v1.1.csv' , converters={ 'paragraphs' : literal_eval})
df = filter_paragraphs(df)
# Loading QAPipeline with CPU version of BERT Reader pretrained on SQuAD 1.1
cdqa_pipeline = QAPipeline(reader= 'models/bert_qa.joblib' )
# Fitting the retriever to the list of documents in the dataframe
cdqa_pipeline.fit_retriever(df)
# Sending a question to the pipeline and getting prediction
query = 'Since when does the Excellence Program of BNP Paribas exist?'
prediction = cdqa_pipeline.predict(query)
print( 'query: {}\n' .format(query))
print( 'answer: {}\n' .format(prediction[ 0 ]))
print( 'title: {}\n' .format(prediction[ 1 ]))
print( 'paragraph: {}\n' .format(prediction[ 2 ]))
他的输出应如下所示:
它打印确切的答案和包含答案的段落。
基本上,当从图片中提取问题并将其发送到系统时,检索器将从已爬网数据中选择最有可能包含答案的文档列表。 如前所述,它计算问题与爬网数据中每个文档之间的余弦相似度。
选择最有可能的文档后,系统将每个文档分为几段,并将其与问题一起发送给读者,
这基本上是一种预先训练的深度学习模型。 使用的模型是著名的NLP模型BERT的Pytorch版本。
然后,阅读器输出在每个段落中可以找到的最可能的答案。 在阅读器之后,系统中的最后一层通过使用内部得分函数比较答案,并根据得分输出最有可能的答案,这将成为我们的答案。
题。
这是系统机制的架构。
您必须以特定的结构设置数据帧(CSV),以便可以将其发送到cdQA管道。
但是实际上我使用PDF转换器从
PDF文件目录。 因此,我将为每个结果将所有已爬网的数据保存在pdf文件中。 希望我们总共有3个pdf文件(也可以是1个或2个)。 此外,我们需要命名这些pdf文件,这就是为什么我抓取每个页面的标题的原因。
def get_result_details (url) :
try :
req = Request(url, headers={ 'User-Agent' : 'Mozilla/5.0' })
html = urlopen(req).read()
bs = BeautifulSoup(html, 'html.parser' )
try :
# Crawl any heading in result to name pdf file
title = bs.find(re.compile( '^h[1-6]$' )).get_text().strip().replace( '?' , '' ).lower()
# Naming the pdf file
filename = "/home/coderasha/autoans/pdfs/" + title + ".pdf"
if not os.path.exists(os.path.dirname(filename)):
try :
os.makedirs(os.path.dirname(filename))
except OSError as exc: # Guard against race condition
if exc.errno != errno.EEXIST:
raise
with open(filename, 'w' ) as f:
# Crawl first 5 paragraphs
for line in bs.find_all( 'p' )[: 5 ]:
f.write(line.text + '\n' )
except AttributeError:
pass
except urllib.error.HTTPError:
pass
def find_answer () :
df = pdf_converter(directory_path= '/home/coderasha/autoans/pdfs' )
cdqa_pipeline = QAPipeline(reader= 'models/bert_qa.joblib' )
cdqa_pipeline.fit_retriever(df)
query = question + '?'
prediction = cdqa_pipeline.predict(query)
print( 'query: {}\n' .format(query))
print( 'answer: {}\n' .format(prediction[ 0 ]))
print( 'title: {}\n' .format(prediction[ 1 ]))
print( 'paragraph: {}\n' .format(prediction[ 2 ]))
return prediction[ 0 ]
好吧,如果我总结一下算法,它将提取图片中的问题,在google上搜索,首先抓取3个结果,从抓取的数据中创建3个pdf文件,最后使用问题回答系统找到答案。
如果您想查看它的工作方式,请检查一下我制作的机器人,该机器人可以解决图片中的考试问题
这是完整代码:
import os, io
import errno
import urllib
import urllib.request
import hashlib
import re
import requests
from time import sleep
from google.cloud import vision
from google.cloud.vision import types
from urllib.request import urlopen, Request
from bs4 import BeautifulSoup
import pandas as pd
from ast import literal_eval
from cdqa.utils.filters import filter_paragraphs
from cdqa.utils.download import download_model, download_bnpp_data
from cdqa.pipeline.cdqa_sklearn import QAPipeline
from cdqa.utils.converters import pdf_converter
result_urls = []
os.environ[ 'GOOGLE_APPLICATION_CREDENTIALS' ] = 'your_private_key.json'
client = vision.ImageAnnotatorClient()
FILE_NAME = 'your_image_file.jpg'
with io.open(os.path.join(FILE_NAME), 'rb' ) as image_file:
content = image_file.read()
image = vision.types.Image(content=content)
response = client.text_detection(image=image)
texts = response.text_annotations[ 0 ]
# print(texts.description)
if '?' in texts.description:
question = re.search( '([^?]+)' , texts.description).group( 1 )
elif ':' in texts.description:
question = re.search( '([^:]+)' , texts.description).group( 1 )
elif '\n' in texts.description:
question = re.search( '([^\n]+)' , texts.description).group( 1 )
slugify_keyword = urllib.parse.quote_plus(question)
# print(slugify_keyword)
def crawl_result_urls () :
req = Request( 'https://google.com/search?q=' + slugify_keyword, headers={ 'User-Agent' : 'Mozilla/5.0' })
html = urlopen(req).read()
bs = BeautifulSoup(html, 'html.parser' )
results = bs.find_all( 'div' , class_= 'ZINbbc' )
try :
for result in results:
link = result.find( 'a' )[ 'href' ]
print(link)
if 'url' in link:
result_urls.append(re.search( 'q=(.*)&sa' , link).group( 1 ))
except (AttributeError, IndexError) as e:
pass
def get_result_details (url) :
try :
req = Request(url, headers={ 'User-Agent' : 'Mozilla/5.0' })
html = urlopen(req).read()
bs = BeautifulSoup(html, 'html.parser' )
try :
title = bs.find(re.compile( '^h[1-6]$' )).get_text().strip().replace( '?' , '' ).lower()
# Set your path to pdf directory
filename = "/path/to/pdf_folder/" + title + ".pdf"
if not os.path.exists(os.path.dirname(filename)):
try :
os.makedirs(os.path.dirname(filename))
except OSError as exc:
if exc.errno != errno.EEXIST:
raise
with open(filename, 'w' ) as f:
for line in bs.find_all( 'p' )[: 5 ]:
f.write(line.text + '\n' )
except AttributeError:
pass
except urllib.error.HTTPError:
pass
def find_answer () :
# Set your path to pdf directory
df = pdf_converter(directory_path= '/path/to/pdf_folder/' )
cdqa_pipeline = QAPipeline(reader= 'models/bert_qa.joblib' )
cdqa_pipeline.fit_retriever(df)
query = question + '?'
prediction = cdqa_pipeline.predict(query)
# print('query: {}\n'.format(query))
# print('answer: {}\n'.format(prediction[0]))
# print('title: {}\n'.format(prediction[1]))
# print('paragraph: {}\n'.format(prediction[2]))
return prediction[ 0 ]
crawl_result_urls()
for url in result_urls[: 3 ]:
get_result_details(url)
sleep( 5 )
answer = find_answer()
print( 'Answer: ' + answer)
有时可能会造成混淆,但我认为通常是可以的。 至少我可以通过60%的正确答案通过考试:D
好了,开发人员! 请在评论中告诉我您对此有何看法? 实际上,最好一次遍历所有问题,所以我不需要为每个问题拍照。 但是不幸的是我没有足够的时间来做,所以最好下次保留它。
检查反向Python 以获得更酷的内容。
参考文献:
如何使用python轻松创建自己的问答系统
保持联系!