哈哈,我用Python开发了一个搜题神奇

专业搜题,家长好帮手

很早之前曾经做过一个图片识别的项目,当时有一项功能是整题识别,即传入数学题的截图,可通过ocr技术识别出图片内容,但当时只限于识别文字,并未作更深一步的处理,现在想来实用性并不强,毕竟大家更需要的是解题思路,而不是让AI读出题干(题干的文字,我都认识,连起来我就不知道怎么下手去做了 = = ),最近刚好有时间,于是尝试来为有娃的朋友做一个搜题神器。

鉴于之前整题识别的开发使用有道智云的良好体验,我再次打开其官方文档,果然找到了拍照搜题服务的开放API,轻车熟路地做了一个简单的批量搜题demo, 下面分享一下开发过程。

调用API接口的准备工作

首先,是需要在有道智云的个人页面上创建实例、创建应用、绑定应用和实例,获取到应用的id和密钥。具体个人注册的过程和应用创建过程详见文章

在这里插入图片描述

开发过程详细介绍

下面介绍具体的代码开发过程。

API接收的参数较为简单:

字段名类型含义必填备注
qtext要识别的图片,需要Base64编码True必须是Base64编码(baes64前边不要加上data:image/png;base64)
appKeytext应用IDTrue可在应用管理查看
salttextUUIDTrueuuid
curtimetext当前UTC时间戳(秒)trueTimeStamp
signtext签名 sha256(应用ID+input+salt+curtime+应用密钥);input的生成规则见表下的备注Truesha256(应用ID+input+salt+curtime+应用密钥)
signTypetext签名类型truev2
typetext上传类型, 仅支持base64上传,请填写固定值1True1
searchTypetext搜索类型,img为图片搜题,text为文本搜题falseimg

签名sign生成方法如下:
signType=v2;
sign=sha256(应用ID+input+salt+curtime+应用密钥)。
其中,input的计算方式为:input=q前10个字符 + q长度 + q后10个字符(当q长度大于20)或 input=q字符串(当q长度小于等于20)。

需要注意的是,API对题目图片有如下要求:

规则描述
传输方式HTTPS
请求方式POST
字符编码统一使用UTF-8编码
请求格式表单
响应格式JSON
图片格式jpg/png/bmp
图片大小1MB以下
文字长度50个字符以下

Demo开发:

这个demo使用python3开发,包括maindow.py,QuestionClass.py,OcrQuestion.py 三个文件,分别为demo的界面、界面逻辑处理和ocr搜题方法的封装。

  1. 界面部分:

    UI 部分较简单,主要功能为选择待题目图片、选择批改结果存储路径。其布局代码如下:

    root=tk.Tk()
    root.title(" youdao ocr question test")
    frm = tk.Frame(root)
    frm.grid(padx='50', pady='50')
    
    # 选题和结果保存按钮
    btn_get_file = tk.Button(frm, text='选择题目图片', command=get_files)
    btn_get_file.grid(row=0, column=0, ipadx='3', ipady='3', padx='10', pady='20')
    text1 = tk.Text(frm, width='40', height='10')
    text1.grid(row=0, column=1)
    btn_get_result_path=tk.Button(frm,text='选择搜索结果路径',command=set_result_path)
    btn_get_result_path.grid(row=1,column=0)
    text2=tk.Text(frm,width='40', height='2')
    text2.grid(row=1,column=1)
    
    
    # 搜题按钮
    btn_sure=tk.Button(frm,text="搜题",command=search_question_files)
    btn_sure.grid(row=4,column=1)
    
    root.mainloop()
    

    其中启动按钮btn_sure的绑定事件search_question_files()来根据题目照片搜题,并在完成后打开结果存储路径:

    def search_question_files():
        question.start_ocr()
        os.system('start '+question.result_path)
    
  2. QuestionClass.py

    这里主要配合UI的逻辑,调用搜题方法。

    首先定义一个类Question:

    class Question():
        def __init__(self,file_paths,result_path):	
            self.file_paths=file_paths		# 题目照片存储路径
            self.result_path=result_path	# 结果路径
    

    start_ocr()方法调用connect()方法依次搜题并保存结果。

    def start_ocr(self):
        for file_path in self.file_paths:
            result=connect(file_path)
            print(file_path)
           self.save_result_format(file_path,result)
    

    从OcrQuestion.py的connect方法获取的结果是json格式,save_result_format()方法,解析从接口取得的接口,格式整理,保存结果到html:

        def save_result_format(self,file_path,result):
            result_file_name=os.path.basename(file_path).split('.')[0]+'_result.html'
            f=open(self.result_path+'/'+result_file_name,'w',encoding='utf-8')
            result_json= json.loads(result)
            if result_json['errorCode'] == '0':
                data=result_json['data']
                questions=data["questions"]
                text=data["text"]
                f.write("题目识别:<br/>"+text)
                i=0
                for answers in questions:
                    i=i+1
                    subject="科目:"+answers["subject"]+"<br>"
                    answer="答案:" +answers["answer"]+"<br>"
                    analysis="分析:"+answers["analysis"]+"<br>"
                    knowledge="知识点:"+answers["knowledge"]+"<br>"
                    print(subject+answer+analysis+knowledge)
                    result_each="<h3>搜题结果"+str(i)+"<br></h3>"
                    result_each=result_each+subject+answer+analysis+knowledge+"<br>=================这是一条分隔符============<br>"
                    f.write(result_each)
            else:
                f.write("result error code:"+result_json['errorCode'])
    
  3. OcrQuestion.py

    OcrQuestion.py 中封装请求ocr搜题API的方法,其中最主要的方法是connect():

    def connect(pic_path):
        f = open(pic_path, 'rb')  # 二进制方式打开图文件
        q = base64.b64encode(f.read()).decode('utf-8')  # 读取文件内容,转换为base64编码
        f.close()
    
        data = {}
        data['q'] = q
        data['signType'] = 'v2'
        curtime = str(int(time.time()))
        data['curtime'] = curtime
        salt = str(uuid.uuid1())
        signStr = APP_KEY + truncate(q) + salt + curtime + APP_SECRET
        sign = encrypt(signStr)
        data['appKey'] = APP_KEY
        data['salt'] = salt
        data['sign'] = sign
    
        response = do_request(data)
        result=response.content.decode('utf-8')
        print(result)
        return result
    
    API响应结果示例
    {
        "data":{
            "questions":[
                {
                    "score":0.9875,
                    "answer":"D",
                    "subject":"历史",
                    "id":"a9db8f1252778836c99204e5cf9d7738",
                    "analysis":"",
                    "type":"",
                    "content":"xxx",
                    "knowledge":""
                }
            ],
            "text":"xxx"
        },
        "errorCode":"0"
    }
    

    响应结果是以json形式输出,包含字段如下表所示:

字段含义
errorCode识别结果错误码,一定存在。 详细信息可参见 错误代码列表
data数据
-text图片题目OCR结果
-questions相关题目
–id答案
–content题目内容
–answer答案
–analysis解析
–knowledge知识点

效果展示

demo操作演示

在这里插入图片描述

来看看结果吧:

数学题搜索结果展示:

在这里插入图片描述

总结

有道智云的整体搜索API文档清晰,题目范围极广而且可以自动判断学科,搜索结果可谓“举一反三”,会返回几个可能的相近题目,很具有参考价值,值得推荐!数学解答题会返回相关图片、公式等,用在web项目中效果灰常不错。

项目地址:https://github.com/LemonQH/OcrQuestion

手撕代码八百里 CSDN认证博客专家 Linux 分布式 Java
原名:TrueDei,现:手撕代码八百里

不荒废现在,不畏惧未来!我认为把知识给别人讲会,讲明白,自己才彻底明白。努力把文章写好,写明白每一篇文章,分享给更多人。
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 程序猿惹谁了 设计师:白松林 返回首页
实付 49.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值