first commit

This commit is contained in:
编码猿
2024-09-27 01:20:28 +08:00
commit ddc91bf4e2
137 changed files with 4017 additions and 0 deletions

320
app/lib/face/facepp.py Executable file
View File

@@ -0,0 +1,320 @@
# -*- coding: utf-8 -*-
"""a simple facepp sdk
usage:
api = API(key, secret)
api.detect(img = File('/tmp/test.jpg'))
"""
import sys
import socket
import json
import os.path
import itertools
import mimetypes
import time
from collections.abc import Iterable
from app.lib.face.structures import ObjectDict
from app.lib.face.compat import (basestring, str, numeric_types, enc, choose_boundary,
Request, urlopen, HTTPError, URLError)
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
__all__ = ['File', 'APIError', 'API']
DEBUG_LEVEL = 1
# 添加API Key API Secret
API_KEY = "xfXREfL_pXgnqK2GedOunNPN2MFYSsPR"
API_SECRET = "x0PGyvHoVSjX19KlkjH1Ct7Md5wxz8aV"
class 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):
key = None
secret = None
server = 'https://api-cn.faceplusplus.com'
decode_result = True
timeout = None
max_retries = None
retry_delay = None
def __init__(self):
"""
: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
"""
if len(API_KEY)==0 or len(API_SECRET)==0:
print('\n'+'请在'+os.path.realpath(__file__)+'文件中填写正确的API_KEY和API_SECRET'+'\n')
exit(1)
self.key = API_KEY
self.secret = API_SECRET
srv = None
decode_result = True
timeout = 30
max_retries = 10
retry_delay = 5
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, '', [])
def update_request(self, request):
"""overwrite this function to update the request before sending it to
server"""
pass
def _setup_apiobj(self, api, prefix, path):
if self is not api:
self._api = api
self._urlbase = '{server}/{prefix}/{path}'.format(server=api.server, prefix=prefix, path='/'.join(path))
lvl = len(path)
done = set()
for prefix, paths in _APIS:
for i in paths:
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, prefix, i[:lvl + 1]))
class _APIProxy(object):
_api = None
"""underlying :class:`API` object"""
_urlbase = None
def __init__(self, api, prefix, path):
_setup_apiobj(self, api, prefix, path)
def __call__(self, *args, **kargs):
if len(args):
raise TypeError('Only keyword arguments are allowed')
form = _MultiPartForm()
for (k, v) in kargs.items():
if isinstance(v, File):
form.add_file(k, v.get_filename(), v.content)
url = self._urlbase
for k, v in self._mkarg(kargs).items():
form.add_field(k, v)
body = form.bytes
request = Request(url, data=body)
request.add_header('Content-type', form.get_content_type())
request.add_header('Content-length', str(len(body)))
self._api.update_request(request)
retry = self._api.max_retries
while True:
retry -= 1
try:
ret = urlopen(request, timeout=self._api.timeout).read()
break
except HTTPError as e:
raise APIError(e.code, url, e.read())
except (socket.error, 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, object_hook=ObjectDict)
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"""
kargs = kargs.copy()
kargs['api_key'] = self._api.key
kargs['api_secret'] = self._api.secret
for k, v in list(kargs.items()):
if isinstance(v, Iterable) and not isinstance(v, basestring):
kargs[k] = ','.join(v)
elif isinstance(v, File) or v is None:
del kargs[k]
elif isinstance(v, numeric_types):
kargs[k] = str(v)
else:
kargs[k] = v
return kargs
class _MultiPartForm(object):
"""Accumulate the data to be used when posting a form."""
def __init__(self):
self.form_fields = []
self.files = []
self.boundary = choose_boundary()
def get_content_type(self):
return 'multipart/form-data; boundary={}'.format(self.boundary)
def add_field(self, name, value):
"""Add a simple field to the form data."""
self.form_fields.append((name, value))
def add_file(self, fieldname, filename, content, mimetype=None):
"""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))
@property
def bytes(self):
"""Return a string(2.x) or bytes(3.x) 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="{}"'.format(name), '', value]
for name, value in self.form_fields
)
# Add the files to upload
parts.extend(
[part_boundary,
'Content-Disposition: form-data; name="{}"; filename="{}"'.format(field_name, filename),
'Content-Type: {}'.format(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(part_boundary + '--')
flattened.append('')
return b'\r\n'.join(enc(x) for x in flattened)
def _print_debug(msg):
if DEBUG_LEVEL:
sys.stderr.write(str(msg) + '\n')
_APIS = [
{
'prefix': 'facepp/v3',
'paths': [
'/detect',
'/compare',
'/search',
'/faceset/create',
'/faceset/addface',
'/faceset/removeface',
'/faceset/update',
'/faceset/getdetail',
'/faceset/delete',
'/faceset/getfacesets',
'/face/analyze',
'/face/getdetail',
'/face/setuserid',
],
},
{
'prefix': 'humanbodypp/v1',
'paths': [
'/detect',
'/segment',
]
},
{
'prefix': 'cardpp/v1',
'paths': [
'/ocridcard',
'/ocrdriverlicense',
'/ocrvehiclelicense',
'/ocrbankcard',
]
},
{
'prefix': 'imagepp/v1',
'paths': [
'/licenseplate',
'/recognizetext',
'/mergeface'
]
}
]
_APIS = [(i['prefix'], [p.split('/')[1:] for p in i['paths']]) for i in _APIS]