facepp python接入工具
来源:互联网 发布:ltescdma是什么网络 编辑:程序博客网 时间:2024/06/06 13:00
旷视官方系统的webapi调用的封装文件地址:https://github.com/FacePlusPlus/python-sdk.git这个api接口文件的编写应该需要满足以下几点要求:1、在python中调用方式应该是api.function(param1,param2)2、这个SDK应该在API实现更新升级后,尽量不需要改动。3、官方提供的webapi的格式是url加post参数POST "https://api-cn.faceplusplus.com/facepp/v3/detect" -F "api_key=<api_key>" -F "api_secret=<api_secret>" \-F "image_file=@image_file.jpg" \-F "return_landmark=1" \-F "return_attributes=gender,age"接下来区分下变的部分和不变的部分webapi的形式是不变的,webapi的方法是随着版本更新而变化的,其post部分的参数也是变化的我们(SDK)希望,提供给调用放的调用方式是不变的,但提供给调用方的方法是随着版本变化能够动态调整的简单的说,facepp这个文件充当webapi和以对象方式调用之间的一个动态适配器,其输出能够根据webapi的动态调整而能够动态调整,单SDK部分的编码应当最小的变化。本着这几点来看下面的这个文件,我们的SDK应该暴露给用户的应该是要使用的方法,以及参数的辅助类。
# -*- coding: utf-8 -*-"""a simple facepp sdkexample:api = API(key, secret)api.detect(img = File('/tmp/test.jpg'))"""__all__ = ['File', 'APIError', 'API']#所有暴露给调用方的类DEBUG_LEVEL = 1import sysimport socketimport urllib2import jsonimport os.pathimport itertoolsimport mimetoolsimport mimetypesimport timeimport tempfilefrom collections import Iterableclass File(object):#暴露给用户的发送图片文件的的支持类 """an object representing a local file""" path = None content = None def __init__(self, path): self.path = path self._get_content() def _get_content(self): """read image content""" if os.path.getsize(self.path) > 2 * 1024 * 1024: raise APIError(-1, None, 'image file size too large') else: with open(self.path, 'rb') as f: self.content = f.read() def get_filename(self): return os.path.basename(self.path)class APIError(Exception):#定义的报错类 code = None """HTTP status code""" url = None """request URL""" body = None """server response body; or detailed error information""" def __init__(self, code, url, body): self.code = code self.url = url self.body = body def __str__(self): return 'code={s.code}\nurl={s.url}\n{s.body}'.format(s=self) __repr__ = __str__class API(object):#暴露给用户的接口类,其应当实现webapi到API对应方法的动态转换。 key = None secret = None server = 'https://api-cn.faceplusplus.com/facepp/v3/' decode_result = True timeout = None max_retries = None retry_delay = None def __init__(self, key, secret, srv=None, decode_result=True, timeout=30, max_retries=10, retry_delay=5): """:param srv: The API server address :param decode_result: whether to json_decode the result :param timeout: HTTP request timeout in seconds :param max_retries: maximal number of retries after catching URL error or socket error :param retry_delay: time to sleep before retrying""" self.key = key self.secret = secret if srv: self.server = srv self.decode_result = decode_result assert timeout >= 0 or timeout is None assert max_retries >= 0 self.timeout = timeout self.max_retries = max_retries self.retry_delay = retry_delay _setup_apiobj(self, self, [])#生成API类对应的方法 def update_request(self, request): """overwrite this function to update the request before sending it to server""" passdef _setup_apiobj(self, api, path):#根据_APIS列表生成API类对应的方法 if self is not api: self._api = api self._urlbase = api.server + '/'.join(path) lvl = len(path) done = set() for i in _APIS: if len(i) <= lvl: continue cur = i[lvl] if i[:lvl] == path and cur not in done: done.add(cur) setattr(self, cur, _APIProxy(api, i[:lvl + 1]))class _APIProxy(object): _api = None """underlying :class:`API`object""" _urlbase = None def __init__(self, api, path): _setup_apiobj(self, api, path) def __call__(self, *args, **kargs):#将此类实现成方法调用 if len(args):#通过生成异常,来实现只支持keyword的方法调用。如果存在非keyword参数,则args的长度非零 raise TypeError('Only keyword arguments are allowed') form = _MultiPartForm()#将键值对形式的参数,转换为webapi需要的格式 for (k, v) in kargs.iteritems():#文件参数的处理 if isinstance(v, File): form.add_file(k, v.get_filename(), v.content) url = self._urlbase for k, v in self._mkarg(kargs).iteritems():#普通参数的处理 form.add_field(k, v) request = urllib2.Request(url) body = str(form) request.add_header('Content-type', form.get_content_type()) request.add_header('Content-length', str(len(body))) request.add_data(body) self._api.update_request(request) retry = self._api.max_retries while True: retry -= 1 try: ret = urllib2.urlopen(request, timeout=self._api.timeout).read() break except urllib2.HTTPError as e: raise APIError(e.code, url, e.read()) except (socket.error, urllib2.URLError) as e: if retry < 0: raise e _print_debug('caught error: {}; retrying'.format(e)) time.sleep(self._api.retry_delay) if self._api.decode_result: try: ret = json.loads(ret) except: raise APIError(-1, url, 'json decode error, value={0!r}'.format(ret)) return ret def _mkarg(self, kargs): """change the argument list (encode value, add api key/secret) :return: the new argument list""" def enc(x): if isinstance(x, unicode): return x.encode('utf-8') return str(x) kargs = kargs.copy() kargs['api_key'] = self._api.key kargs['api_secret'] = self._api.secret for (k, v) in kargs.items(): if isinstance(v, Iterable) and not isinstance(v, basestring): kargs[k] = ','.join([enc(i) for i in v]) elif isinstance(v, File) or v is None: del kargs[k] else: kargs[k] = enc(v) return kargs# ref: http://www.doughellmann.com/PyMOTW/urllib2/class _MultiPartForm(object):#将键值对形式的参数,转换为webapi需要的格式
"""Accumulate the data to be used when posting a form.""" def __init__(self): self.form_fields = [] self.files = [] self.boundary = mimetools.choose_boundary() return def get_content_type(self): return 'multipart/form-data; boundary=%s' % self.boundary def add_field(self, name, value):#提供了键值对格式的参数到webapi格式参数的转换方法 """Add a simple field to the form data.""" self.form_fields.append((name, value)) return def add_file(self, fieldname, filename, content, mimetype=None):#提供了文件类型键值对参数到webapi格式参数的转换方法 """Add a file to be uploaded.""" if mimetype is None: mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' self.files.append((fieldname, filename, mimetype, content)) return def __str__(self): """Return a string representing the form data, including attached files.""" # Build a list of lists, each containing "lines" of the # request. Each part is separated by a boundary string. # Once the list is built, return a string where each # line is separated by '\r\n'. parts = [] part_boundary = '--' + self.boundary # Add the form fields parts.extend( [part_boundary, 'Content-Disposition: form-data; name="%s"' % name,'',value, ] for name, value in self.form_fields ) # Add the files to upload parts.extend( [part_boundary, 'Content-Disposition: file; name="%s"; filename="%s"' % (field_name, filename), 'Content-Type: %s' % content_type, '', body, ] for field_name, filename, content_type, body in self.files ) # Flatten the list and add closing boundary marker, # then return CR+LF separated data flattened = list(itertools.chain(*parts)) flattened.append('--' + self.boundary + '--') flattened.append('') return '\r\n'.join(flattened)def _print_debug(msg): if DEBUG_LEVEL: sys.stderr.write(str(msg) + '\n')_APIS = [ '/detect', '/compare', '/search', '/faceset/create', '/faceset/addface', '/faceset/removeface', '/faceset/update', '/faceset/getdetail', '/faceset/delete', '/faceset/getfacesets', '/face/analyze', '/face/getdetail', '/face/setuserid']_APIS = [i.split('/')[1:] for i in _APIS]
总结:这段代码是学习灵活适应api变化SDK开发很好的例子,有助于自己软件开发代码的设计。
阅读全文
0 0
- facepp python接入工具
- Crashlytics工具的接入
- Python接入天气预报api
- Psexec.exe,Windows服务器接入工具
- android 内存分析工具leakcanary接入
- 新浪开放平台接入Python版
- python多线程socket编程--多客户端接入
- python多线程socket编程--多客户端接入
- python网络爬虫-HTTP基本接入认证
- python 工具
- python工具
- 远程接入产品与企业即时通讯工具完美结
- Python支持WS-Security接入预研情况
- rabbit常用三种exchange类型和python接入脚本
- 个人微信接入图灵机器人(基于Python)
- 个人微信接入图灵机器人(基于Python)
- 利用 django+wechat-python-sdk 创建微信服务器接入
- 个人微信接入图灵机器人(python版)
- HTML简单笔记
- 注册热键和快捷键
- 自媒体头条号关于图文、视频、图集原创标准细则
- [分布式监控CAT] Server端源码解析——消息消费\报表处理\展示
- Linux进阶之 find 命令的参数详解
- facepp python接入工具
- lambad
- 知乎爬虫相关问题存到mongoDB中
- SqlServer 两表更新问题
- 云数据库 Redis 版使用教程
- windows下Python版本切换使用方法
- bzoj3391 [Usaco2004 Dec]Tree Cutting网络破坏(dfs)
- 华为2017年9月校招芯片类面试经验
- 不定宽高的盒子模型水平垂直居中问题。