除了老師和家長,它也可以批改作業
最近一個家長退群的故事在某博上了熱搜。故事中老師和家長的矛盾由批改作業集中爆發,至於孰是孰非,還是交給吃瓜群眾去評價吧,作為一個技術工作者,我突發奇想,是否以后能讓機器來輔助老師批改作業呢?這仿佛是個維護世界和平的點子!
經過一陣調(搜)研(索),在英語作文批改上,還真的有一些成熟的方案可以使用,而且學習成本相當之低,比如有道智雲的英語作文批改服務,只需閱讀文檔按規則開發應用,即可得到詳盡的批改結果,作文可以是圖片,也可以是文字,等級可以從小學一直到雅思托福,覆蓋范圍極廣。
懷着激動的心情,我快速地開發了一個簡單的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的界面、界面邏輯處理和英文作文批改接口調用方法的封裝。
-
界面部分:
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) -
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() -
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 resultconnect_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文檔清晰,功能全面,可針對不同類型文件、不同難度的作文進行多維度批改,評價指標明確,批改結果非常具有參考價值,贊!
相信在未來,會有更多類型的作業批改服務出現吧,到那時,老師和家長們就都能得到解放了...
