无敌了,用Python给英语老师开发了个英语作文批改的神器(支持小学到雅思)

手撕代码八百里 2021-04-08 13:23:13
Python 英语 老师 无敌 英语老师


除了老师和家长,它也可以批改作业

最近一个家长退群的故事在某博上了热搜。故事中老师和家长的矛盾由批改作业集中爆发,至于孰是孰非,还是交给吃瓜群众去评价吧,作为一个技术工作者,我突发奇想,是否以后能让机器来辅助老师批改作业呢?这仿佛是个维护世界和平的点子!

在这里插入图片描述

经过一阵调(搜)研(索),在英语作文批改上,还真的有一些成熟的方案可以使用,而且学习成本相当之低,比如有道智云的英语作文批改服务,只需阅读文档按规则开发应用,即可得到详尽的批改结果,作文可以是图片,也可以是文字,等级可以从小学一直到雅思托福,覆盖范围极广。

怀着激动的心情,我快速地开发了一个简单的demo,下面分享一下开发过程。

调用API接口的准备工作

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

这里要特别说明一下,作文批改分为图像和文本两种形式,分别调用了不同的api,因此需要创建两个实例。

在这里插入图片描述

开发过程详细介绍

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

英语作文批改分为两个API,分别对应图像识别文本输入两种形式的作文。调用方式大同小异,都是将待批改内容和时间戳等信息生成的签名post到API接口,而后接口返回批改结果。

图像识别API输入所需参数如下表:

字段名 类型 含义 必填 备注
q text 图片的 base64。大小不超过 5MB True 图片的 base64
langType text 语言,目前仅支持英文 False en
appKey text 应用标识(应用 ID) True 可在 应用管理 查看
salt text 随机字符串 True hfa12lak56ja9gjl
sign text 签名信息:sha256(appKey+input+salt+密钥) True xxxxx
grade text 作文等级。支持列表见下面 grade 支持列表,默认不管等级,只评价句子好坏 false default
title text 作文标题 false 0
modelContent text 用户提供的范文内容 false 0
goodExpression text 用户提供的好的表达 false 0
needTypo text 是否需要 typo,(true/false),默认为 true false true
signType text 签名类型 true v3
limitedWords text 作文字数限制 false 1000

文本输入API输入参数如下表:

字段名 类型 含义 必填 备注
q text 批改的文本。文本不超过 5000 字符 True text
langType text 语言,目前仅支持英文 False en
appKey text 应用标识(应用 ID) True 可在 应用管理 查看
salt text 随机字符串 True hfa12lak56ja9gjl
sign text 签名信息:sha256(appKey+input+salt+密钥) True xxxxx
grade text 作文等级。支持列表见下面 grade 支持列表,默认不管等级,只评价句子好坏 false default
title text 作文标题 false 0
modelContent text 用户提供的范文内容 false 0
goodExpression text 用户提供的好的表达 false 0
needTypo text 是否需要 纠错,默认为 true(true/false) false true
signType text 签名类型 true v3
limitedWords text 作文字数限制 false 1000
curtime text 当前UTC时间戳(秒) true 时间戳

最好传输 limitedWords,这样评分更精确。
签名生成算法如下:

  • signType=v3,sha256(应用 ID+input+salt+curtime+密钥),推荐使用

sha256 签名计算方法为:sha256(应用 ID+input+salt+当前 UTC 时间戳+密钥)。

其中,input 的计算方式为:input=多个q拼接后前10个字符 + 多个q拼接长度 + 多个q拼接后十个字符(当多个 q 拼接后长度大于 20)或 input=多个q拼接的字符串(当多个 q 拼接后长度小于等于 20)。

在接口输入参数中,grade为以下几类:

级别 代码
不考虑级别,单纯评价句子好坏 default
小学 elementary
初中 junior
高中 high
四级 cet4
六级 cet6
考研 graduate
托福 toefl
GRE gre
雅思 ielts

Demo开发:

这个demo使用python3开发,包括maindow.py,correctclass.py,HomeworkCorrect.py 三个文件,分别为demo的界面、界面逻辑处理和英文作文批改接口调用方法的封装。

  1. 界面部分:

    UI 部分较简单,主要功能为选择待批改作文文件、选择批改结果存储路径、选择批改类型。其布局代码如下:

    root=tk.Tk()
    root.title(" youdao correct writing 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)
    # 级别选择
    label=tk.Label(frm,text='选择年级:')
    label.grid(row=3,column=0)
    combox=ttk.Combobox(frm,textvariable=tk.StringVar(),width=38)
    combox["value"]=select_type_dict
    combox.current(0)
    combox.bind("<<ComboboxSelected>>",get_grade_type)
    combox.grid(row=3,column=1)
    # 启动批改
    btn_sure=tk.Button(frm,text="批改",command=correct_files)
    btn_sure.grid(row=4,column=1)
    root.mainloop()
    

    其中启动按钮btn_sure的绑定事件correct_files()来启动批改,并在完成后打开结果存储路径:

    def correct_files():
    correct.start_correct()
    os.system('start '+correct.result_path)
    
  2. correctclass.py

    这里主要配合UI的逻辑,分析文件类型,选取合适的接口来批改作文。

    首先定义一个类Correct:

    class Correct():
    def __init__(self,file_paths,grade,result_path):
    self.file_paths=file_paths # 待批改文件路径
    self.grade =grade # 批改级别
    self.result_path=result_path # 结果路径
    

    get_correct_result()方法根据文件类型判断应调用的封装方法,并处理返回值,将批改结果存入文件系统。

     def get_correct_result(self,file_path):
    file_type=file_path.split(".")[1]
    if file_type=="txt":
    print(file_path)
    result=connect_context(file_path,self.grade)
    self.save_result(file_path,result)
    elif file_type=="png" or file_type=="jpg" or file_type=="jepg" :
    result=connect_pic(file_path,self.grade)
    self.save_result(file_path,result)
    

    save_result()方法实现了保存结果的功能:

     def save_result(self,file_path,result):
    result_file_name=os.path.basename(file_path).split('.')[0]+'_result.txt'
    f=open(self.result_path+'/'+result_file_name,'w')
    f.write(str(result))
    f.close()
    
  3. HomeworkCorrect.py

    HomeworkCorrect.py 中封装了请求两种作业批改API的方法,两个API主要区别在于URL和APP示例的不同。最核心的方法分别是connect_pic() 和 connect_context()

    connect_pic():

    def connect_pic(pic_path,grade):
    f = open(pic_path, 'rb') # 二进制方式打开图文件
    q = base64.b64encode(f.read()) # 读取文件内容,转换为base64编码
    f.close()
    data = {
    }
    curtime = str(int(time.time()))
    data['curtime'] = curtime
    salt = str(uuid.uuid1())
    #print(q)
    signStr = APP_KEY + truncate(q) + salt + curtime + APP_SECRET
    sign = encrypt(signStr)
    data['appKey'] = APP_KEY
    data['salt'] = salt
    data['q'] = q
    data['sign'] = sign
    data['grade'] = grade
    data['signType'] = 'v3'
    response = do_request(data,YOUDAO_URL_IMAGE)
    result=json.loads(str(response.content,'utf-8'))['Result']
    return result
    

    connect_context():

    def connect_context(file_path,grade):
    f=open(file_path,'rb')
    q=f.read()
    f.close()
    data = {
    }
    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['q'] = q
    data['salt'] = salt
    data['sign'] = sign
    data['signType'] = "v3"
    data['grade'] = grade
    response = do_request(data,YOUDAO_URL_TEXT)
    print(response.content)
    result = json.loads(str(response.content, 'utf-8'))['Result']
    print(result)
    return result
    

效果展示

我分别选了一段英文的图片和txt文档来进行测试:

在这里插入图片描述

响应结果说明:

{

"errorCode": "错误码",
"Result": {

"uniqueKey": "每个请求独一无二的字符串标识",
"essayLangName": "语言信息",
"rawEssay": "请求原文",
"refEssay": "参考范文""stLevel": "作文级别",
"reqSource": "请求来源",
"extraParams""额外请求参数(扩展用参数)",
"wordNum": "文章总词数"
"conjWordNum": "文章连接词数",
"AllFeatureAdvice": {
 # 作文各特征的建议
"WordNum": "词数建议,如文章字数疑似超出该考试字数要求",
"Spelling": "拼写错误建议",
"WordDiversity": "词汇丰富度建议,如词汇量积累非常少,只能给出一些零散的简单词汇,建议多积累词汇",
"Structure": "文章结构建议",
"AdvanceVocab": [
"xx", "xx", "xx" # 文中使用的高级词汇
],
"AdvanceVocabLeval": [0, 1, 2], # 对应高级词汇的级别
"lexicalSubs": [ # 词汇替换(注意:candidates中词汇可能为空,表示没有推荐替换的近义词,但word使用频率超过3次)
{
"candidates": ["xx", "xx"], "count": 频率, "word": xx 对应词}, ...
]
"Conjunction": [{

"used": ["xx", "xx", "xx"] # 已使用连词
"advice": ["xx", "xx", "xx"] # 推荐词
}],
"Topic": "主题相关性建议",
"Grammar": "语法相关建议",
"GoodExpression": ["xx", "xx", "xx"] # 好的表达
},
"AllFeatureScore": {
 # 对应上面AllFeatureAdvice各特征得分,除NeuralScore是没有Advice的,它代表神经网络作文打分结果,不是最终打分结果!
"NeuralScore": 68.64, # 范围:[0,100]
"WordNum": 10, # 范围:[0, 10] ---> 指的是词数得分
"Spelling": 10, # 范围:[0, 10]
"WordDiversity": 0, # 范围:[0, 10]
"Structure": 8, # 范围:[0, 10]
"AdvanceVocab": 7.61, # 范围:[0, 10]
"Conjunction": 6.94, # 范围:[0, 10]
"Topic": 6.03, # 范围:[0, 10]
"Grammar": 2.5 # 范围:[0, 10]
"SentComplex": 10 # 范围: [0, 10]
},
"majorScore": {
 # 是AllFeatureScore中score整合结果
"WordScore": 10, # 词汇得分:包括词数、丰富度、高级词汇等得分
"GrammarScore": 10, # 语法得分:包括拼写、语法、句子复杂度得分等
"StructureScore": 10, # 逻辑得分:包括段落和连接词得分
"topicScore": 10, # 内容(主题相关性)得分,如果没有参考范文,该部分得分会从语法和复杂度上考虑
},
"essayFeedback":{

"sentsFeedback": [
{

"sentId": "句子在全文的编号,从0开始",
"paraId": "该句所在的段落号,从0开始",
"rawSent": "原句""segSent": "原句分词后的结果""correctedSent": "原句修正后的结果",
"sentStartPos": "该句子在全文中相对于文章初始位置的偏移量",
"errorPosInfos": [
{

"type": "错误类型(包括`grammar`,`typo`,`refactor`)",
"startPos": "错误起始位置相对rawSent起始位置的偏移量",
"endPos": "错误结束位置相对rawSent起始位置的偏移量",
"orgChunk": "错误块的具体内容",
"correctChunk": "错误块修正后的具体内容",
"error_type": "(弃用) 错误的具体类别(0表示拼写错误,1表示冠词错误,2表示动词时态或者第三人称单复数错误,3表示名词单复数错误,4表示格错误,5表示介词错误,6表示其他语法错误,7表示文本格式错误,8表示正确)",
"new_error_type": "错误类别(0表示完全正确,
1表示书写格式不规范,2表示拼写错误,
3表示标点错误,4表示冠词错误,5表示动词错误,
6表示名词单复数错误,7表示代词错误,8表示介词错误,
9表示形容词错误,10表示副词错误,11表示连词错误,
20表示其他错误,21表示代指所有语法错误(兼容))"
"new_sub_error_type": "细分错误类别(0表示正确,1表示未知错误,2表示词汇缺失,3表示词汇冗余,
4表示冠词误用,5表示介词误用,6表示动词主谓一致错误,7表示动词时态错误,8表示情态动词后应接动词原形错误,
9表示被动语态错误,10表示动词不定式错误,11表示动词错误,12表示形容词比较级错误,
13表示形容词最高级错误,14表示副词比较级错误,15表示副词最高级错误,16表示名词单复数错误,
17表示名词错误,18表示人称代词主宾格混淆,19表示人称代词和物主代词混淆,20表示形容词性和名词性代词混淆,
21表示人称代词和反身代词混淆,22表示疑问/关系/连接代词混淆,23表示指示代词混淆,24表示不定代词混淆,
25表示代词错误,26表示标点符号误用,27表示拼写错误,28表示不规范错误)"
"举例说明": 如果new_error_type=5, new_sub_error_type=2,说明是动词缺失
"reason": "错误的具体原因""isValidLangChunk": "类似下面的isValidSent,判断是否为合法片段(该片段如果语言检测结果与期望不一致,则认为不合法)"
"analysis": "错误的原因的具体辨析(保留接口,暂时应该没用)"
}, ..., {
}
],
"isValidLangSent": "是否为合法句子(合法与否取决于语言检测对该句的语言信息识别结果与期望结果是否一致)"
"sentFeedback": "错误原因反馈,基于errorPosInfos中所有reason字段拼接而成",
"isContainTypoError": "返回是否含有typo错误",
"isContainGrammarError": "返回是否含有语法错误""sentScore": "句子得分(暂时没有用,即将实现)"
}
]
}
"totalScore": "文章最终得分"
"fullScore": "对应级别满分"
"essayAdvice": "文章最终评价"
"paraNum": "文章段落数"
"sentNum": "文章句子数"
}
}

总结

有道智云的英语作文批改API文档清晰,功能全面,可针对不同类型文件、不同难度的作文进行多维度批改,评价指标明确,批改结果非常具有参考价值,赞!

相信在未来,会有更多类型的作业批改服务出现吧,到那时,老师和家长们就都能得到解放了…

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

版权声明
本文为[手撕代码八百里]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_17623363/article/details/111057114

  1. Python spatial analysis | 01 using Python to calculate global Moran's index
  2. python入门教程13-05 (python语法入门之数据备份、pymysql模块)
  3. Introduction to Python 13-05 (data backup and pymysql module of introduction to Python syntax)
  4. pandas如何操作Excel?还不会的,看此一篇足矣
  5. How does panda operate excel? Not yet. This is enough
  6. 用python连接数据库模拟用户登录
  7. Using Python to connect database to simulate user login
  8. python入门教程13-04 (语法入门之记录相关操作)
  9. Introduction to Python 13-04
  10. python入门教程13-03 (python语法入门之表相关操作)
  11. Introduction to Python 13-03
  12. python的多线程的网络爬虫,待改进
  13. Python multithreaded web crawler, to be improved
  14. 常见加密算法的Python实现:
  15. Python implementation of common encryption algorithms:
  16. python刷题-核桃的数量
  17. Number of walnuts
  18. Python爬虫知乎文章,采集新闻60秒
  19. Python crawler knows articles and collects news for 60 seconds
  20. Python爬虫知乎文章,采集新闻60秒
  21. Python crawler knows articles and collects news for 60 seconds
  22. bbox_overlaps python
  23. bbox_ overlaps python
  24. 7-43 jmu-python-字符串异常处理 (20 分)
  25. 7-43 JMU Python string exception handling (20 points)
  26. n行Python代码系列:两行代码实现视频文件转成系列图片输出
  27. N-line Python code series: two lines of code to achieve video files into a series of pictures output
  28. python-阶乘计算
  29. Python factorial calculation
  30. Python实现定时发送微信消息
  31. python爬取英雄联盟所有英雄皮肤海报
  32. Sending wechat messages regularly with Python
  33. Python crawls all hero skin posters of hero League
  34. 上手Pandas,带你玩转数据(4)-- 数据清洗
  35. Hands on pandas, take you to play with data (4) -- data cleaning
  36. Python继续霸榜,上古语言Cobol重获关注,IEEE 2020编程语言榜单揭晓
  37. 教你用 Python 下载手机小视频
  38. Python continues to dominate the list, ancient language COBOL regains attention, IEEE 2020 programming language list announced
  39. How to download small video of mobile phone with Python
  40. 如何用 Python 在京东上抢口罩
  41. How to use Python to grab masks in Jingdong
  42. arcgis10.2自带的python安装第三方库
  43. 学习Python,你看这篇就够了 | 【详细】Python基础(二)
  44. ArcGIS 10.2 comes with a third-party library for installing Python
  45. Learn python, you see this is enough | [detailed] Python Foundation (2)
  46. 盘点 Django 展示可视化图表的多种方式(建议收藏)
  47. 第123天: Web 开发 Django 管理工具
  48. 盘点 Django 展示可视化图表的多种方式(建议收藏)
  49. python utc时间转北京时间
  50. 想在Python中将Excel文件转换为PDF?来看看这份Aspose.Cells指南
  51. [practice] Python nn.Transformer Mask understanding of
  52. anchors_plane python
  53. python逗号bug
  54. 第115天:Python 到底是值传递还是引用传递
  55. 第118天:Python 之对象的比较与拷贝
  56. 第119天:Python 爬取豆瓣电影 top 250
  57. 从 0 学习 Python 0 - 120 大合集总结
  58. 第124天: Web 开发 Django 模板
  59. Check various ways of displaying visual charts in Django
  60. Python自动化运维工具-Fabric部署及使用总结