1、背景
a、鵝廠近期發布了自己的人工智能 api,包括身份證ocr、名片ocr、文本分析等一堆API,因為前期項目用到圖形OCR,遂實現試用了一下,發現准確率還不錯,放出來給大家共享一下。
b、基於python3,跟python2還是有些區別。
c、特別需要提到的就是簽名生成這塊,鵝廠的api說明里寫的比較簡單,一開始在sign的生成(https://ai.qq.com/doc/auth.shtml)上卡了好幾天,后來加的官方群,咨詢之后才解決。
2、簽名算法
不夠150字,那就正好把簽名算法這塊寫一寫。
a、官網說明如下:
按URL鍵值拼接字符串T
依照算法第二步要求,將參數對列表N的參數對進行URL鍵值拼接,值使用URL編碼,URL編碼算法用大寫字母,例如%E8,而不是小寫%e8,得到字符串T如下:
b、實際上:
參數列表是指api中所有除sign之外用到的參數都要參與計算sign。
譬如:
1)文本分析接口有4個字段,拼接串為:
app_id=10000&nonce_str=20e3408a79&text=%E8%85%BE%E8%AE%AF%E5%BC%80%E6%94%BE%E5%B9%B3%E5%8F%B0&time_stamp=1493449657
參數名 | 參數值 |
---|---|
app_id | 10000 |
nonce_str | 20e3408a79 |
text | 騰訊開放平台 |
time_stamp | 1493449657 |
2)身份證ocr接口有6個字段,拼接串為:
app_id=10000&time_stamp=1511839575&nonce_str=3oxitu0qf198bh24&image=%2F9j%2F4AA************QSkZJRgA9j%2F%2F2Q%3D%3D&card_type=0&sign=2ED0122CD44DCB1FD7BC9AE1D03D64D9
參數名稱 | 是否必選 | 數據類型 | 數據約束 | 示例數據 | 描述 |
---|---|---|---|---|---|
app_id | 是 | int | 正整數 | 1000001 | 應用標識(AppId) |
time_stamp | 是 | int | 正整數 | 1493468759 | 請求時間戳(秒級) |
nonce_str | 是 | string | 非空且長度上限32字節 | fa577ce340859f9fe | 隨機字符串 |
sign | 是 | string | 非空且長度固定32字節 | B250148B284956EC5218D4B0503E7F8A | 簽名信息,詳見接口鑒權 |
image | 是 | string | 原始圖片的base64編碼數據(解碼后大小上限1MB,支持JPG、PNG、BMP格式) | ... | 待識別圖片 |
card_type | 是 | int | 整數 | 0/1 | 身份證圖片類型,0-正面,1-反面 |
注意區別:不光光是參與計算的字段變化,各字段的排序也不一樣。
3、實現代碼
在github上上傳了一下,https://github.com/jdstkxx/pyTencentAI
# -*- coding: utf-8 -*- ''' create by : joshua zou create date : 2017.11.28 Purpose: tecent ai api ''' import requests import base64 import hashlib import time import random import os,string,glob from PIL import Image from io import BytesIO from urllib.parse import urlencode from urllib import parse import json class MsgTencent(object): def __init__(self,AppID=None,AppKey=None): ''' 改成你自己的API賬號、密碼 ''' if not AppID: AppID = '1111111111' if not AppKey: AppKey = 'uuuuuuuuuu' self.app_id= AppID self.app_key= AppKey self.img_base64str=None def get_random_str(self): #隨機生成16位字符串 rule = string.ascii_lowercase + string.digits str = random.sample(rule, 16) return "".join(str) def get_time_stamp(self): return str(int(time.time())) def __get_image_base64str__(self,image): if not isinstance(image,Image):return None outputBuffer = BytesIO() bg.save(outputBuffer, format='JPEG') imgbase64 = base64.b64encode(outputBuffer.getvalue()) return imgbase64 def __get_imgfile_base64str__(self,image): if not isinstance(image, str): return None if not os.path.isfile(image): return None with open(image,'rb') as fp: imgbase64 = base64.b64encode(fp.read()) return imgbase64 def get_img_base64str(self,image): if isinstance(image, str): self.img_base64str= self.__get_imgfile_base64str__(image) elif isinstance(image,Image): self.img_base64str= self.__get_imgfile_base64str__(image) return self.img_base64str.decode() # 組裝字典,MD5加密方法 ''' ====================================== tencent獲得參數對列表N(字典升級排序) ====================================== 1\依照算法第一步要求,對參數對進行排序,得到參數對列表N如下。 參數名 參數值 app_id 10000 nonce_str 20e3408a79 text 騰訊開放平台 time_stamp 1493449657 2\按URL鍵值拼接字符串T 依照算法第二步要求,將參數對列表N的參數對進行URL鍵值拼接,值使用URL編碼,URL編碼算法用大寫字母,例如%E8,而不是小寫%e8,得到字符串T如下: app_id=10000&nonce_str=20e3408a79&text=%E8%85%BE%E8%AE%AF%E5%BC%80%E6%94%BE%E5%B9%B3%E5%8F%B0&time_stamp=1493449657 3\拼接應用密鑰,得到字符串S 依照算法第三步要求,將應用密鑰拼接到字符串T的尾末,得到字符串S如下。 app_id=10000&nonce_str=20e3408a79&text=%E8%85%BE%E8%AE%AF%E5%BC%80%E6%94%BE%E5%B9%B3%E5%8F%B0&time_stamp=1493449657&app_key=a95eceb1ac8c24ee28b70f7dbba912bf 4\計算MD5摘要,得到簽名字符串 依照算法第四步要求,對字符串S進行MD5摘要計算得到簽名字符串如。 e8f6f347d549fe514f0c9c452c95da9d 5\轉化md5簽名值大寫 對簽名字符串所有字母進行大寫轉換,得到接口請求簽名,結束算法。 E8F6F347D549FE514F0C9C452C95DA9D 6\最終請求數據 在完成簽名計算后,即可得到所有接口請求數據,進一步完成API的調用。 text 騰訊開放平台 接口請求數據,UTF-8編碼 app_id 10000 應用標識 time_stamp 1493449657 請求時間戳(秒級),用於防止請求重放 nonce_str 20e3408a79 請求隨機字符串,用於保證簽名不可預測 sign E8F6F347D549FE514F0C9C452C95DA9D 請求簽名 ''' def gen_dict_md5(self,req_dict,app_key): if not isinstance(req_dict,dict) :return None if not isinstance(app_key,str) or not app_key:return None try: #方法,先對字典排序,排序之后,寫app_key,再urlencode sort_dict= sorted(req_dict.items(), key=lambda item:item[0], reverse = False) sort_dict.append(('app_key',app_key)) sha = hashlib.md5() rawtext= urlencode(sort_dict).encode() sha.update(rawtext) md5text= sha.hexdigest().upper() #print(1) #字典可以在函數中改寫 if md5text: req_dict['sign']=md5text return md5text except Exception as e: return None #生成字典 def gen_req_dict(self, req_dict,app_id=None, app_key=None,time_stamp=None, nonce_str=None): """用MD5算法生成安全簽名""" if not req_dict.get('app_id'): if not app_id: app_id= self.app_id req_dict['app_id']= app_id #nonce_str 字典無值 if not req_dict.get('time_stamp'): if not time_stamp: time_stamp= self.get_time_stamp() req_dict['time_stamp']= time_stamp if not req_dict.get('nonce_str'): if not nonce_str: nonce_str= self.get_random_str() req_dict['nonce_str']= nonce_str #app_key 取系統參數。 if not app_key: app_key= self.app_key md5key= self.gen_dict_md5(req_dict, app_key) return md5key ''' 基本文本分析 =========== 分詞 對文本進行智能分詞識別,支持基礎詞與混排詞粒度 https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordseg text 詞性標注 對文本進行分詞,同時為每個分詞標注正確的詞性 https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordpos text 專有名詞識別 對文本進行專有名詞的分詞識別,找出文本中的專有名詞 https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordner text 同義詞識別 識別文本中存在同義詞的分詞,並返回相應的同義詞 https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordsyn text 計算機視覺--OCR識別 ==================== 通用OCR識別 識別上傳圖像上面的字段信息 https://api.ai.qq.com/fcgi-bin/ocr/ocr_generalocr image 身份證OCR識別 識別身份證圖像上面的詳細身份信息 https://api.ai.qq.com/fcgi-bin/ocr/ocr_idcardocr image,card_type(身份證,0-正面,1-反面) 名片OCR識別 識別名片圖像上面的字段信息 https://api.ai.qq.com/fcgi-bin/ocr/ocr_bcocr image 行駛證駕駛證OCR識別 識別行駛證或駕駛證圖像上面的字段信息 https://api.ai.qq.com/fcgi-bin/ocr/ocr_driverlicenseocr image,type(識別類型,0-行駛證識別,1-駕駛證識別) 營業執照OCR識別 識別營業執照上面的字段信息 https://api.ai.qq.com/fcgi-bin/ocr/ocr_bizlicenseocr image 銀行卡OCR識別 識別銀行卡上面的字段信息 https://api.ai.qq.com/fcgi-bin/ocr/ocr_creditcardocr image ''' #改成你自己的API賬號、密碼 APPID='1111111111' APPKEY='UUUUUUUUU' TencentAPI={ #基本文本分析API "nlp_wordseg": { 'APINAME':'分詞', 'APIDESC': '對文本進行智能分詞識別,支持基礎詞與混排詞粒度', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordseg', 'APIPARA': 'text' }, "nlp_wordpos": { 'APINAME':'詞性標注', 'APIDESC': '對文本進行分詞,同時為每個分詞標注正確的詞性', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordpos', 'APIPARA': 'text' }, 'nlp_wordner': { 'APINAME':'專有名詞識別', 'APIDESC': '對文本進行專有名詞的分詞識別,找出文本中的專有名詞', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordner', 'APIPARA': 'text' }, 'nlp_wordsyn': { 'APINAME':'同義詞識別', 'APIDESC': '識別文本中存在同義詞的分詞,並返回相應的同義詞', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordsyn', 'APIPARA': 'text' }, #計算機視覺--OCR識別API "ocr_generalocr": { 'APINAME':'通用OCR識別', 'APIDESC': '識別上傳圖像上面的字段信息', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_generalocr', 'APIPARA': 'image' }, "ocr_idcardocr": { 'APINAME':'身份證OCR識別', 'APIDESC': '識別身份證圖像上面的詳細身份信息', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_idcardocr', 'APIPARA': 'image,card_type' }, "ocr_bcocr": { 'APINAME':'名片OCR識別', 'APIDESC': '識別名片圖像上面的字段信息', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_bcocr', 'APIPARA': 'image' }, "ocr_driverlicenseocr":{ 'APINAME':'行駛證駕駛證OCR識別', 'APIDESC': '識別行駛證或駕駛證圖像上面的字段信息', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_driverlicenseocr', 'APIPARA': 'image,type' }, "ocr_bizlicenseocr":{ 'APINAME':'營業執照OCR識別', 'APIDESC': '識別營業執照上面的字段信息', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_bizlicenseocr', 'APIPARA': 'image' }, "ocr_creditcardocr":{ 'APINAME':'銀行卡OCR識別', 'APIDESC': '識別銀行卡上面的字段信息', 'APIURL': 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_creditcardocr', 'APIPARA': 'image' }, } def ExecTecentAPI(*arg,**kwds): if kwds.get('Apiname'): apiname= kwds.pop('Apiname') url = TencentAPI[apiname]['APIURL'] name = TencentAPI[apiname]['APINAME'] desc= TencentAPI[apiname]['APIDESC'] para= TencentAPI[apiname]['APIPARA'] tx= MsgTencent(APPID,APPKEY) Req_Dict={} for key in para.split(','): value=None print (kwds) if kwds.get(key): value = kwds.pop(key) if key=='image': #圖像獲取base64 value= tx.get_img_base64str(value) if key=='text': #文本進行GBK編碼 value= value.encode('gbk') Req_Dict[key]=value print (key,value,Req_Dict[key]) #生成請求包 sign= tx.gen_req_dict(req_dict=Req_Dict) resp = requests.post(url,data=Req_Dict,verify=False) print (name+'執行結果'+resp.text) return resp.text if __name__ == "__main__": #名片ocr file= r'名片.jpg' rest = ExecTecentAPI(Apiname='ocr_bcocr',image=file) #文本分析 rest = ExecTecentAPI(Apiname='nlp_wordseg',text='上帝保佑你')