From d2205b21c688ee07808560f70d96398ebae003bf Mon Sep 17 00:00:00 2001 From: Sebastian Noack Date: Sat, 17 Dec 2011 17:34:31 +0100 Subject: [PATCH 01/25] Added support for file-like objects to faces_detect() and faces_recognize(). --- face_client/face_client.py | 52 ++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/face_client/face_client.py b/face_client/face_client.py index edaf4e4..9fa45f9 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -9,8 +9,6 @@ # Author: Tomaž Muraus (http://www.tomaz.me) # License: BSD -from __future__ import with_statement - import urllib import urllib2 import os.path @@ -80,21 +78,22 @@ def faces_detect(self, urls=None, file=None, aggressive=False): if not urls and not file: raise AttributeError('Missing URLs/filename argument') + data = {'attributes': 'all'} + files = [] + if file: # Check if the file exists - if not os.path.exists(file): + if not hasattr(file, 'read') and not os.path.exists(file): raise IOError('File %s does not exist' % (file)) - data = {'file': file} + files.append(file) else: - data = {'urls': urls} + data['urls'] = urls if aggressive: data['detector'] = 'Aggressive' - data['attributes'] = 'all' - - response = self.send_request('faces/detect', data) + response = self.send_request('faces/detect', data, files) return response def faces_status(self, uids=None, namespace=None): @@ -135,13 +134,14 @@ def faces_recognize(self, uids=None, urls=None, file=None, train=None, self.__check_user_auth_credentials(uids) data = {'uids': uids, 'attributes': 'all'} + files = [] if file: # Check if the file exists - if not os.path.exists(file): + if not hasattr(file, 'read') and not os.path.exists(file): raise IOError('File %s does not exist' % (file)) - data.update({'file': file}) + files.append(file) else: data.update({'urls': urls}) @@ -149,7 +149,7 @@ def faces_recognize(self, uids=None, urls=None, file=None, train=None, self.__append_optional_arguments(data, train=train, namespace=namespace) - response = self.send_request('faces/recognize', data) + response = self.send_request('faces/recognize', data, files) return response def faces_train(self, uids=None, namespace=None): @@ -324,7 +324,7 @@ def __append_optional_arguments(self, data, **kwargs): if value: data.update({key: value}) - def send_request(self, method=None, parameters=None): + def send_request(self, method=None, parameters=None, files=None): if USE_SSL: protocol = 'https://' else: @@ -340,18 +340,32 @@ def send_request(self, method=None, parameters=None): data.update(parameters) # Local file is provided, use multi-part form - if parameters and 'file' in parameters: + if files: from multipart import Multipart form = Multipart() for key, value in data.iteritems(): - - if key == 'file': - with open(value, 'r') as file: - form.file(os.path.basename(key), os.path.basename(key), - file.read()) + form.field(key, value) + + for key, value in files: + if hasattr(value, 'read'): + if hasattr(value, 'name'): + name = os.path.basename(value.name) + else: + import tempfile + name = tempfile.mktemp(prefix='', dir='') + close_file = False + file = value else: - form.field(key, value) + name = os.path.basename(value) + close_file = True + file = open(value, 'r') + + try: + form.file(name, name, file.read()) + finally: + if close_file: + file.close() (content_type, post_data) = form.get() headers = {'Content-Type': content_type} From 2aecae1faea0f9055f393817933b66f8307a89bd Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Sat, 17 Dec 2011 14:42:00 -0800 Subject: [PATCH 02/25] 'files' is a list of string values not a dictionary or a list of tuples. Also use a get_random_string function instead of tempfile. --- face_client/face_client.py | 8 +++++--- face_client/utils.py | 7 +++++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 face_client/utils.py diff --git a/face_client/face_client.py b/face_client/face_client.py index 9fa45f9..3f4b5d2 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -9,11 +9,14 @@ # Author: Tomaž Muraus (http://www.tomaz.me) # License: BSD +import os import urllib import urllib2 import os.path import warnings +from utils import get_random_string + try: import json except ImportError: @@ -347,13 +350,12 @@ def send_request(self, method=None, parameters=None, files=None): for key, value in data.iteritems(): form.field(key, value) - for key, value in files: + for value in files: if hasattr(value, 'read'): if hasattr(value, 'name'): name = os.path.basename(value.name) else: - import tempfile - name = tempfile.mktemp(prefix='', dir='') + name = get_random_string(10) close_file = False file = value else: diff --git a/face_client/utils.py b/face_client/utils.py new file mode 100644 index 0000000..64fecca --- /dev/null +++ b/face_client/utils.py @@ -0,0 +1,7 @@ +import random +import string + +def get_random_string(length): + value = ''.join(random.choice(string.letters + string.digits) for i in + xrange(length)) + return value From c1aa360c6e0bb075cbef14671906cc58b2a06233 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Sat, 17 Dec 2011 14:43:54 -0800 Subject: [PATCH 03/25] Update changes. --- CHANGES | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES b/CHANGES index f46ded8..e145281 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +1.3 - in development: + + - Allow user to pass file-like object for the 'file' argument to the + faces_detect and faces_recognize function. + [Sebastian Noack] + 1.2 - 25.09.2011: - Remove deprecated Twiter username and password based auth From 7599bfdecac3f641c1e7c0c3eaa2f0a1000053f3 Mon Sep 17 00:00:00 2001 From: Tomaz Muraus Date: Sat, 17 Dec 2011 14:47:45 -0800 Subject: [PATCH 04/25] Remove unused 'os' import. --- face_client/face_client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/face_client/face_client.py b/face_client/face_client.py index 3f4b5d2..556e3a7 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -9,7 +9,6 @@ # Author: Tomaž Muraus (http://www.tomaz.me) # License: BSD -import os import urllib import urllib2 import os.path From 42a66c74f5a4d54fbc46009b9b24377e2cdc2e4d Mon Sep 17 00:00:00 2001 From: Sebastian Noack Date: Mon, 19 Dec 2011 08:28:27 +0100 Subject: [PATCH 05/25] Used consecutive instead of random filenames for anonymous files. That way it is more robust against clashing file/field names and less code to maintain. --- face_client/face_client.py | 17 +++++++---------- face_client/utils.py | 7 ------- 2 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 face_client/utils.py diff --git a/face_client/face_client.py b/face_client/face_client.py index 556e3a7..27e9269 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -14,8 +14,6 @@ import os.path import warnings -from utils import get_random_string - try: import json except ImportError: @@ -349,18 +347,17 @@ def send_request(self, method=None, parameters=None, files=None): for key, value in data.iteritems(): form.field(key, value) - for value in files: - if hasattr(value, 'read'): - if hasattr(value, 'name'): - name = os.path.basename(value.name) + for i, file in enumerate(files, 1): + if hasattr(file, 'read'): + if hasattr(file, 'name'): + name = os.path.basename(file.name) else: - name = get_random_string(10) + name = 'attachment_%d' % i close_file = False - file = value else: - name = os.path.basename(value) + name = os.path.basename(file) + file = open(file, 'r') close_file = True - file = open(value, 'r') try: form.file(name, name, file.read()) diff --git a/face_client/utils.py b/face_client/utils.py deleted file mode 100644 index 64fecca..0000000 --- a/face_client/utils.py +++ /dev/null @@ -1,7 +0,0 @@ -import random -import string - -def get_random_string(length): - value = ''.join(random.choice(string.letters + string.digits) for i in - xrange(length)) - return value From 970457fd5872f2b9b8043df51cde73dcdda7db57 Mon Sep 17 00:00:00 2001 From: Sebastian Noack Date: Mon, 19 Dec 2011 08:32:34 +0100 Subject: [PATCH 06/25] Convert headers to str. Otherwise if some headers are given as unicode, it would try to decode any other data in the mutlipart response when concatenating, which will usually fail, as image data can't be decoded as ascii text. --- face_client/multipart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/face_client/multipart.py b/face_client/multipart.py index 9d294ab..836b968 100644 --- a/face_client/multipart.py +++ b/face_client/multipart.py @@ -74,7 +74,7 @@ def get(self): lines = [] lines.append('--' + Part.BOUNDARY) for (key, val) in self._headers.items(): - lines.append('%s: %s' % (key, val)) + lines.append(str('%s: %s' % (key, val))) lines.append('') lines.append(self._body) return lines From da79177fc09470282a22665c1480d48b180c3064 Mon Sep 17 00:00:00 2001 From: Sebastian Noack Date: Mon, 19 Dec 2011 08:43:46 +0100 Subject: [PATCH 07/25] Added .gitignore file. --- face_client/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 face_client/.gitignore diff --git a/face_client/.gitignore b/face_client/.gitignore new file mode 100644 index 0000000..56e27b0 --- /dev/null +++ b/face_client/.gitignore @@ -0,0 +1,2 @@ +*.py[co] +.*.sw? From 984d590da72f30a8d98ef068b0fdfb83a9b1f342 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 2 Feb 2013 14:12:51 +0200 Subject: [PATCH 08/25] Replaced endpoint to api.skybiometry.com/fc. Because SkyBiometry is intended to be used as a drop-in replacement for developers using face.com API most of functionality should work. --- face_client/face_client.py | 724 ++++++++++++++++++------------------- 1 file changed, 354 insertions(+), 370 deletions(-) diff --git a/face_client/face_client.py b/face_client/face_client.py index 27e9269..8701cb8 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- # -# Name: face.com Python API client library -# Description: face.com REST API Python client library. +# Name: SkyBiometry Face Detection And Recognition API Python client library +# Description: SkyBiometry Face Detection And Recognition REST API Python client library. # # For more information about the API and the return values, -# visit the official documentation at http://developers.face.com/docs/api/. +# visit the official documentation at http://www.skybiometry.com/Documentation # # Author: Tomaž Muraus (http://www.tomaz.me) # License: BSD @@ -15,379 +15,363 @@ import warnings try: - import json + import json except ImportError: - import simplejson as json + import simplejson as json -API_HOST = 'api.face.com' +API_HOST = 'api.skybiometry.com/fc' USE_SSL = True - class FaceClient(object): - def __init__(self, api_key=None, api_secret=None): - if not api_key or not api_secret: - raise AttributeError('Missing api_key or api_secret argument') - - self.api_key = api_key - self.api_secret = api_secret - self.format = 'json' - - self.twitter_credentials = None - self.facebook_credentials = None - - def set_twitter_user_credentials(self, *args, **kwargs): - warnings.warn(('Twitter username & password auth has been ' + - 'deprecated. Please use oauth based auth - ' + - 'set_twitter_oauth_credentials()')) - - def set_twitter_oauth_credentials(self, user=None, secret=None, - token=None): - if not user or not secret or not token: - raise AttributeError('Missing one of the required arguments') - - self.twitter_credentials = {'twitter_oauth_user': user, - 'twitter_oauth_secret': secret, - 'twitter_oauth_token': token} - - def set_facebook_access_token(self, *args, **kwargs): - warnings.warn(('Method has been renamed to ' + - ' set_facebook_oauth_credentials(). Support for' + - 'username & password based auth has also been dropped.' + - 'Now only oAuth2 token based auth is supported')) - - def set_facebook_oauth_credentials(self, user_id=None, session_id=None, - oauth_token=None): - for (key, value) in [('user_id', user_id), ('session_id', session_id), - ('oauth_token', oauth_token)]: - if not value: - raise AttributeError('Missing required argument: %s' % (key)) - - self.facebook_credentials = {'fb_user_id': user_id, - 'fb_session_id': session_id, - 'fb_oauth_token': oauth_token} - - ### Recognition engine methods ### - def faces_detect(self, urls=None, file=None, aggressive=False): - """ - Returns tags for detected faces in one or more photos, with geometric - information of the tag, eyes, nose and mouth, as well as the gender, - glasses, and smiling attributes. - - http://developers.face.com/docs/api/faces-detect/ - """ - if not urls and not file: - raise AttributeError('Missing URLs/filename argument') - - data = {'attributes': 'all'} - files = [] - - if file: - # Check if the file exists - if not hasattr(file, 'read') and not os.path.exists(file): - raise IOError('File %s does not exist' % (file)) - - files.append(file) - else: - data['urls'] = urls - - if aggressive: - data['detector'] = 'Aggressive' - - response = self.send_request('faces/detect', data, files) - return response - - def faces_status(self, uids=None, namespace=None): - """ - Reports training set status for the specified UIDs. - - http://developers.face.com/docs/api/faces-status/ - """ - if not uids: - raise AttributeError('Missing user IDs') - - (facebook_uids, twitter_uids) = \ - self.__check_user_auth_credentials(uids) - - data = {'uids': uids} - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, namespace=namespace) - - response = self.send_request('faces/status', data) - return response - - def faces_recognize(self, uids=None, urls=None, file=None, train=None, - namespace=None): - """ - Attempts to detect and recognize one or more user IDs' faces, in one - or more photos. - For each detected face, the face.com engine will return the most likely - user IDs, or empty result for unrecognized faces. In addition, each - tag includes a threshold score - any score below this number is - considered a low-probability hit. - - http://developers.face.com/docs/api/faces-recognize/ - """ - if not uids or (not urls and not file): - raise AttributeError('Missing required arguments') - - (facebook_uids, twitter_uids) = \ - self.__check_user_auth_credentials(uids) - - data = {'uids': uids, 'attributes': 'all'} - files = [] - - if file: - # Check if the file exists - if not hasattr(file, 'read') and not os.path.exists(file): - raise IOError('File %s does not exist' % (file)) - - files.append(file) - else: - data.update({'urls': urls}) - - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, train=train, - namespace=namespace) - - response = self.send_request('faces/recognize', data, files) - return response - - def faces_train(self, uids=None, namespace=None): - """ - Calls the training procedure for the specified UIDs, and reports back - changes. - - http://developers.face.com/docs/api/faces-train/ - """ - if not uids: - raise AttributeError('Missing user IDs') - - (facebook_uids, twitter_uids) = \ - self.__check_user_auth_credentials(uids) - - data = {'uids': uids} - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, namespace=namespace) - - response = self.send_request('faces/train', data) - return response - - ### Methods for managing face tags ### - def tags_get(self, uids=None, urls=None, pids=None, order='recent', \ - limit=5, together=False, filter=None, namespace=None): - """ - Returns saved tags in one or more photos, or for the specified - User ID(s). - This method also accepts multiple filters for finding tags - corresponding to a more specific criteria such as front-facing, - recent, or where two or more users appear together in same photos. - - http://developers.face.com/docs/api/tags-get/ - """ - (facebook_uids, twitter_uids) = \ - self.__check_user_auth_credentials(uids) - - data = {'uids': uids, - 'urls': urls, - 'together': together, - 'limit': limit} - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, pids=pids, filter=filter, - namespace=namespace) - - response = self.send_request('tags/get', data) - return response - - def tags_add(self, url=None, x=None, y=None, width=None, uid=None, - tagger_id=None, label=None, password=None): - """ - Add a (manual) face tag to a photo. Use this method to add face tags - where those were not detected for completeness of your service. - - http://developers.face.com/docs/api/tags-add/ - """ - if not url or not x or not y or not width or not uid or not tagger_id: - raise AttributeError('Missing one of the required arguments') - - (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uid) - - data = {'url': url, - 'x': x, - 'y': y, - 'width': width, - 'uid': uid, - 'tagger_id': tagger_id} - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, label=label, password=password) - - response = self.send_request('tags/add', data) - return response - - def tags_save(self, tids=None, uid=None, tagger_id=None, label=None, \ - password=None): - """ - Saves a face tag. Use this method to save tags for training the - face.com index, or for future use of the faces.detect and tags.get - methods. - - http://developers.face.com/docs/api/tags-save/ - """ - if not tids or not uid: - raise AttributeError('Missing required argument') - - (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uid) - - data = {'tids': tids, - 'uid': uid} - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, tagger_id=tagger_id, - label=label, password=password) - - response = self.send_request('tags/save', data) - return response - - def tags_remove(self, tids=None, password=None): - """ - Remove a previously saved face tag from a photo. - - http://developers.face.com/docs/api/tags-remove/ - """ - if not tids: - raise AttributeError('Missing tag IDs') - - data = {'tids': tids} - - response = self.send_request('tags/remove', data) - return response - - ### Account management methods ### - def account_limits(self): - """ - Returns current rate limits for the account represented by the passed - API key and Secret. - - http://developers.face.com/docs/api/account-limits/ - """ - response = self.send_request('account/limits') - return response['usage'] - - def account_users(self, namespaces=None): - """ - Returns current rate limits for the account represented by the passed - API key and Secret. - - http://developers.face.com/docs/api/account-limits/ - """ - if not namespaces: - raise AttributeError('Missing namespaces argument') - - response = self.send_request('account/users', - {'namespaces': namespaces}) - - return response - - def __check_user_auth_credentials(self, uids): - # Check if needed credentials are provided - facebook_uids = [uid for uid in uids.split(',') \ - if uid.find('@facebook.com') != -1] - twitter_uids = [uid for uid in uids.split(',') \ - if uid.find('@twitter.com') != -1] - - if facebook_uids and not self.facebook_credentials: - raise AttributeError('You need to set Facebook credentials ' + - 'to perform action on Facebook users') - - if twitter_uids and not self.twitter_credentials: - raise AttributeError('You need to set Twitter credentials to ' + - 'perform action on Twitter users') - - return (facebook_uids, twitter_uids) - - def __append_user_auth_data(self, data, facebook_uids, twitter_uids): - if facebook_uids: - data.update({'user_auth': 'fb_user:%s,fb_session:%s,' + - 'fb_oauth_token:%s' % - (self.facebook_credentials['fb_user_id'], - self.facebook_credentials['fb_session_id'], - self.facebook_credentials['fb_oauth_token'])}) - - if twitter_uids: - data.update({'user_auth': - ('twitter_oauth_user:%s,twitter_oauth_secret:%s,' - 'twitter_oauth_token:%s' % - (self.twitter_credentials['twitter_oauth_user'], - self.twitter_credentials['twitter_oauth_secret'], - self.twitter_credentials['twitter_oauth_token']))}) - - def __append_optional_arguments(self, data, **kwargs): - for key, value in kwargs.iteritems(): - if value: - data.update({key: value}) - - def send_request(self, method=None, parameters=None, files=None): - if USE_SSL: - protocol = 'https://' - else: - protocol = 'http://' - - url = '%s%s/%s' % (protocol, API_HOST, method) - - data = {'api_key': self.api_key, - 'api_secret': self.api_secret, - 'format': self.format} - - if parameters: - data.update(parameters) - - # Local file is provided, use multi-part form - if files: - from multipart import Multipart - form = Multipart() - - for key, value in data.iteritems(): - form.field(key, value) - - for i, file in enumerate(files, 1): - if hasattr(file, 'read'): - if hasattr(file, 'name'): - name = os.path.basename(file.name) - else: - name = 'attachment_%d' % i - close_file = False - else: - name = os.path.basename(file) - file = open(file, 'r') - close_file = True - - try: - form.file(name, name, file.read()) - finally: - if close_file: - file.close() - - (content_type, post_data) = form.get() - headers = {'Content-Type': content_type} - else: - post_data = urllib.urlencode(data) - headers = {} - - request = urllib2.Request(url, headers=headers, data=post_data) - response = urllib2.urlopen(request) - response = response.read() - response_data = json.loads(response) - - if 'status' in response_data and \ - response_data['status'] == 'failure': - raise FaceError(response_data['error_code'], - response_data['error_message']) - - return response_data + def __init__(self, api_key=None, api_secret=None): + if not api_key or not api_secret: + raise AttributeError('Missing api_key or api_secret argument') + + self.api_key = api_key + self.api_secret = api_secret + self.format = 'json' + + self.twitter_credentials = None + self.facebook_credentials = None + + def set_twitter_user_credentials(self, *args, **kwargs): + warnings.warn(('Twitter username & password auth has been ' + + 'deprecated. Please use oauth based auth - ' + + 'set_twitter_oauth_credentials()')) + + def set_twitter_oauth_credentials(self, user=None, secret=None, token=None): + if not user or not secret or not token: + raise AttributeError('Missing one of the required arguments') + + self.twitter_credentials = {'twitter_oauth_user': user, + 'twitter_oauth_secret': secret, + 'twitter_oauth_token': token} + + def set_facebook_access_token(self, *args, **kwargs): + warnings.warn(('Method has been renamed to ' + + 'set_facebook_oauth_credentials(). Support for ' + + 'username & password based auth has also been dropped. ' + + 'Now only oAuth2 token based auth is supported')) + + def set_facebook_oauth_credentials(self, user_id=None, session_id=None, oauth_token=None): + for (key, value) in [('user_id', user_id), ('session_id', session_id), ('oauth_token', oauth_token)]: + if not value: + raise AttributeError('Missing required argument: %s' % (key)) + + self.facebook_credentials = {'fb_user_id': user_id, + 'fb_session_id': session_id, + 'fb_oauth_token': oauth_token} + + ### Recognition engine methods ### + def faces_detect(self, urls=None, file=None, buffer=None, aggressive=False): + """ + Returns tags for detected faces in one or more photos, with geometric + information of the tag, eyes, nose and mouth, as well as the gender, + glasses, and smiling attributes. + + http://developers.face.com/docs/api/faces-detect/ + """ + if not urls and not file and not buffer: + raise AttributeError('Missing URLs/filename/buffer argument') + + data = {'attributes': 'all'} + files = [] + buffers = [] + + if file: + # Check if the file exists + if not hasattr(file, 'read') and not os.path.exists(file): + raise IOError('File %s does not exist' % (file)) + + files.append(file) + elif buffer: + buffers.append(buffer) + else: + data['urls'] = urls + + if aggressive: + data['detector'] = 'Aggressive' + + response = self.send_request('faces/detect', data, files, buffers) + return response + + def faces_status(self, uids=None, namespace=None): + """ + Reports training set status for the specified UIDs. + + http://developers.face.com/docs/api/faces-status/ + """ + if not uids: + raise AttributeError('Missing user IDs') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) + + data = {'uids': uids} + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, namespace=namespace) + + response = self.send_request('faces/status', data) + return response + + def faces_recognize(self, uids=None, urls=None, file=None, buffer=None, aggressive=False, train=None, namespace=None): + """ + Attempts to detect and recognize one or more user IDs' faces, in one + or more photos. + For each detected face, the face.com engine will return the most likely + user IDs, or empty result for unrecognized faces. In addition, each + tag includes a threshold score - any score below this number is + considered a low-probability hit. + + http://developers.face.com/docs/api/faces-recognize/ + """ + if not uids or (not urls and not file and not buffer): + raise AttributeError('Missing required arguments') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) + + data = {'uids': uids, 'attributes': 'all'} + files = [] + buffers = [] + + if file: + # Check if the file exists + if not hasattr(file, 'read') and not os.path.exists(file): + raise IOError('File %s does not exist' % (file)) + files.append(file) + elif buffer: + buffers.append(buffer) + else: + data.update({'urls': urls}) + + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, train=train, namespace=namespace) + + response = self.send_request('faces/recognize', data, files, buffers) + return response + + def faces_train(self, uids=None, namespace=None): + """ + Calls the training procedure for the specified UIDs, and reports back + changes. + + http://developers.face.com/docs/api/faces-train/ + """ + if not uids: + raise AttributeError('Missing user IDs') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) + + data = {'uids': uids} + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, namespace=namespace) + + response = self.send_request('faces/train', data) + return response + + ### Methods for managing face tags ### + def tags_get(self, uids=None, urls=None, pids=None, order='recent', limit=5, together=False, filter=None, namespace=None): + """ + Returns saved tags in one or more photos, or for the specified + User ID(s). + This method also accepts multiple filters for finding tags + corresponding to a more specific criteria such as front-facing, + recent, or where two or more users appear together in same photos. + + http://developers.face.com/docs/api/tags-get/ + """ + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) + + data = {'uids': uids, + 'urls': urls, + 'together': together, + 'limit': limit} + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, pids=pids, filter=filter, namespace=namespace) + + response = self.send_request('tags/get', data) + return response + + def tags_add(self, url=None, x=None, y=None, width=None, uid=None, tagger_id=None, label=None, password=None): + """ + Add a (manual) face tag to a photo. Use this method to add face tags + where those were not detected for completeness of your service. + + http://developers.face.com/docs/api/tags-add/ + """ + if not url or not x or not y or not width or not uid or not tagger_id: + raise AttributeError('Missing one of the required arguments') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uid) + + data = {'url': url, + 'x': x, + 'y': y, + 'width': width, + 'uid': uid, + 'tagger_id': tagger_id} + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, label=label, password=password) + + response = self.send_request('tags/add', data) + return response + + def tags_save(self, tids=None, uid=None, tagger_id=None, label=None, \ + password=None): + """ + Saves a face tag. Use this method to save tags for training the + face.com index, or for future use of the faces.detect and tags.get + methods. + + http://developers.face.com/docs/api/tags-save/ + """ + if not tids or not uid: + raise AttributeError('Missing required argument') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uid) + + data = {'tids': tids, + 'uid': uid} + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, tagger_id=tagger_id, label=label, password=password) + + response = self.send_request('tags/save', data) + return response + + def tags_remove(self, tids=None, password=None): + """ + Remove a previously saved face tag from a photo. + + http://developers.face.com/docs/api/tags-remove/ + """ + if not tids: + raise AttributeError('Missing tag IDs') + + data = {'tids': tids} + + response = self.send_request('tags/remove', data) + return response + + ### Account management methods ### + def account_limits(self): + """ + Returns current rate limits for the account represented by the passed + API key and Secret. + + http://developers.face.com/docs/api/account-limits/ + """ + response = self.send_request('account/limits') + return response['usage'] + + def account_users(self, namespaces=None): + """ + Returns current rate limits for the account represented by the passed + API key and Secret. + + http://developers.face.com/docs/api/account-limits/ + """ + if not namespaces: + raise AttributeError('Missing namespaces argument') + + response = self.send_request('account/users', + {'namespaces': namespaces}) + + return response + + def __check_user_auth_credentials(self, uids): + # Check if needed credentials are provided + facebook_uids = [uid for uid in uids.split(',') if uid.find('@facebook.com') != -1] + twitter_uids = [uid for uid in uids.split(',') if uid.find('@twitter.com') != -1] + + if facebook_uids and not self.facebook_credentials: + raise AttributeError('You need to set Facebook credentials ' + + 'to perform action on Facebook users') + + if twitter_uids and not self.twitter_credentials: + raise AttributeError('You need to set Twitter credentials to ' + + 'perform action on Twitter users') + + return (facebook_uids, twitter_uids) + + def __append_user_auth_data(self, data, facebook_uids, twitter_uids): + if facebook_uids: + data.update({'user_auth': 'fb_user:%s,fb_session:%s,' + + 'fb_oauth_token:%s' % + (self.facebook_credentials['fb_user_id'], + self.facebook_credentials['fb_session_id'], + self.facebook_credentials['fb_oauth_token'])}) + + if twitter_uids: + data.update({'user_auth': + ('twitter_oauth_user:%s,twitter_oauth_secret:%s,' + 'twitter_oauth_token:%s' % + (self.twitter_credentials['twitter_oauth_user'], + self.twitter_credentials['twitter_oauth_secret'], + self.twitter_credentials['twitter_oauth_token']))}) + + def __append_optional_arguments(self, data, **kwargs): + for key, value in kwargs.iteritems(): + if value: + data.update({key: value}) + + def send_request(self, method=None, parameters=None, files=None, buffers=None): + protocol = 'https://' if USE_SSL else 'http://' + url = '%s%s/%s.%s' % (protocol, API_HOST, method, self.format) + data = { 'api_key': self.api_key, 'api_secret': self.api_secret } + + if parameters: + data.update(parameters) + + # Local file is provided, use multi-part form + if files or buffers: + from multipart import Multipart + form = Multipart() + + for key, value in data.iteritems(): + form.field(key, value) + + if files: + for i, file in enumerate(files, 1): + if hasattr(file, 'read'): + if hasattr(file, 'name'): + name = os.path.basename(file.name) + else: + name = 'attachment_%d' % i + close_file = False + else: + name = os.path.basename(file) + file = open(file, 'rb') + close_file = True + + try: + form.file(name, name, file.read()) + finally: + if close_file: + file.close() + else: + for i, buffer in enumerate(buffers, 1): + name = 'attachment_%d' % i + form.file(name, name, buffer) + (content_type, post_data) = form.get() + headers = {'Content-Type': content_type} + else: + post_data = urllib.urlencode(data) + headers = {} + + request = urllib2.Request(url, headers=headers, data=post_data) + response = urllib2.urlopen(request) + response = response.read() + response_data = json.loads(response) + + if 'status' in response_data and response_data['status'] == 'failure': + raise FaceError(response_data['error_code'], response_data['error_message']) + + return response_data class FaceError(Exception): - def __init__(self, error_code, error_message): - self.error_code = error_code - self.error_message = error_message + def __init__(self, error_code, error_message): + self.error_code = error_code + self.error_message = error_message - def __str__(self): - return '%s (%d)' % (self.error_message, self.error_code) + def __str__(self): + return '%s (%d)' % (self.error_message, self.error_code) From e824e51329924f4963dbdd0ed5f711b45b6ab810 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 2 Feb 2013 15:41:15 +0200 Subject: [PATCH 09/25] Changed links to documentation and account. --- EXAMPLE.rst | 212 ++++++++++++++++++------------------- README.rst | 47 ++++---- face_client/face_client.py | 4 +- setup.py | 88 +++++++-------- 4 files changed, 175 insertions(+), 176 deletions(-) diff --git a/EXAMPLE.rst b/EXAMPLE.rst index 35d861d..6b7b71f 100644 --- a/EXAMPLE.rst +++ b/EXAMPLE.rst @@ -1,106 +1,106 @@ -EXAMPLE -======= - -Here is a short example demonstrating how you can use this client. - -Lets say that we want to create our own private namespace and train it to recognize Guido Van Rossum. - -Here are the images which we will use for training our namespace index: - -| http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg -| http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg -| http://farm1.static.flickr.com/67/200126290_2798330e61.jpg - -And here is the image which hopefully, after training our index will be recognized as "Guido Van Rossum": - -http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg - -#. First we create our private namespace named **testns** (this can be done on the `face.com page`_) - -#. Now we import the module and instantiate the class with our face.com **api_key** and **api_secret** (you can get them by registering your application on `face.com page`_):: - - >> from face_client import FaceClient - >> client = FaceClient('API_KEY', 'API_SECRET') - -#. Before training our namespace index I just want to show you that the image is not already recognized:: - - >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - {u'no_training_set': [u'guido@testns'], - u'photos': [{u'height': 375, - ...omitted for clarity... - u'tid': u'TEMP_F@51b67ae268617da2c99c69091ab8f3b0_cf224a584e806722a7fa15a936ed1367_48.00_41.82_0', - u'uids': [], - u'width': 47, - u'yaw': 31.649999999999999}], - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500}], - ...omitted for clarity... - - As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. - -#. Saving the tags and training our index - - For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. - - In this example, I will use faces_detect:: - - >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') - >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] - - >> tids - - [u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', - u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', - u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0'] - - We can also check that the tags were saved by using the **tags_get** method:: - - >> client.tags_get('guido@testns') - - {u'message': u'Tags saved with uid: guido@testns ,label: Guido Van Rossum', - u'saved_tags': [{u'detected_tid': u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', - u'tid': u'21319_cf224a584e80672ea7fa15a936ed1367'}, - {u'detected_tid': u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', - u'tid': u'21321_cf224a584e80672ea7fa15a936ed1367'}, - {u'detected_tid': u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0', - u'tid': u'21323_cf224a584e80672ea7fa15a936ed1367'}], - u'status': u'success'} - -#. Now when we have the temporary tag ids, we can use them save to save the tags and train our namespace index:: - - >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') - >> client.faces_train('guido@testns') - - {u'status': u'success', - u'unchanged': [{u'last_trained': 1274462404, - u'training_in_progress': False, - u'training_set_size': 3, - u'uid': u'guido@testns'}]} - -#. Now after we have trained our index, lets check if Guido is recognized:: - - >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - {u'photos': [{u'height': 375, - u'pid': u'F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367', - ...omitted for clarity... - u'roll': -1.3400000000000001, - u'tagger_id': None, - u'threshold': 60, - u'tid': u'TEMP_F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367_51.00_35.20_2', - u'uids': [{u'confidence': 20, - u'uid': u'guido@testns'}], - u'width': 18.600000000000001, - u'yaw': 36}], - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500}], - u'status': u'success', - ...omitted for clarity... - - As you can see by looking at the uids key, Guido was now recognized with a 20% confidence! - -For more information about the face.com API and how to use it with Facebook and Twitter, visit the `official documentation`_. - -.. _face.com page: http://developers.face.com/account/ -.. _official documentation: http://developers.face.com/docs/recognition-howto/ +EXAMPLE +======= + +Here is a short example demonstrating how you can use this client. + +Lets say that we want to create our own private namespace and train it to recognize Guido Van Rossum. + +Here are the images which we will use for training our namespace index: + +| http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg +| http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg +| http://farm1.static.flickr.com/67/200126290_2798330e61.jpg + +And here is the image which hopefully, after training our index will be recognized as "Guido Van Rossum": + +http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg + +#. First we create our private namespace named **testns** (this can be done on the `face.com page`_) + +#. Now we import the module and instantiate the class with our SkyBiometry **api_key** and **api_secret** (you can get them by registering your application on `face.com page`_):: + + >> from face_client import FaceClient + >> client = FaceClient('API_KEY', 'API_SECRET') + +#. Before training our namespace index I just want to show you that the image is not already recognized:: + + >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') + + {u'no_training_set': [u'guido@testns'], + u'photos': [{u'height': 375, + ...omitted for clarity... + u'tid': u'TEMP_F@51b67ae268617da2c99c69091ab8f3b0_cf224a584e806722a7fa15a936ed1367_48.00_41.82_0', + u'uids': [], + u'width': 47, + u'yaw': 31.649999999999999}], + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500}], + ...omitted for clarity... + + As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. + +#. Saving the tags and training our index + + For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. + + In this example, I will use faces_detect:: + + >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') + >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] + + >> tids + + [u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', + u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', + u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0'] + + We can also check that the tags were saved by using the **tags_get** method:: + + >> client.tags_get('guido@testns') + + {u'message': u'Tags saved with uid: guido@testns ,label: Guido Van Rossum', + u'saved_tags': [{u'detected_tid': u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', + u'tid': u'21319_cf224a584e80672ea7fa15a936ed1367'}, + {u'detected_tid': u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', + u'tid': u'21321_cf224a584e80672ea7fa15a936ed1367'}, + {u'detected_tid': u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0', + u'tid': u'21323_cf224a584e80672ea7fa15a936ed1367'}], + u'status': u'success'} + +#. Now when we have the temporary tag ids, we can use them save to save the tags and train our namespace index:: + + >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') + >> client.faces_train('guido@testns') + + {u'status': u'success', + u'unchanged': [{u'last_trained': 1274462404, + u'training_in_progress': False, + u'training_set_size': 3, + u'uid': u'guido@testns'}]} + +#. Now after we have trained our index, lets check if Guido is recognized:: + + >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') + + {u'photos': [{u'height': 375, + u'pid': u'F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367', + ...omitted for clarity... + u'roll': -1.3400000000000001, + u'tagger_id': None, + u'threshold': 60, + u'tid': u'TEMP_F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367_51.00_35.20_2', + u'uids': [{u'confidence': 20, + u'uid': u'guido@testns'}], + u'width': 18.600000000000001, + u'yaw': 36}], + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500}], + u'status': u'success', + ...omitted for clarity... + + As you can see by looking at the uids key, Guido was now recognized with a 20% confidence! + +For more information about the face.com API and how to use it with Facebook and Twitter, visit the `official documentation`_. + +.. _face.com page: http://www.skybiometry.com/Account +.. _official documentation: http://www.skybiometry.com/Documentation diff --git a/README.rst b/README.rst index 3661b1e..71f60c6 100644 --- a/README.rst +++ b/README.rst @@ -1,24 +1,23 @@ -face.com Python API client library -================================== - -face.com_ REST API Python client library. - -For a demonstration how to use this library, see EXAMPLE.RST. - -For more information about the API and the return values, visit the `official documentation`_. - -Performing actions involving Facebook or Twitter users -====================================================== - -If you want to perform actions involving Facebook or Twitter users you need to provide the necessary credentials. - -#. **Facebook**:: - - client.set_facebook_oauth_credentials('FB_USER_ID', 'FB_SESSION_ID', 'FB_OAUTH_TOKEN') - -#. **Twitter (OAuth)**:: - - client.set_twitter_oauth_credentials('OAUTH_USER', 'OAUTH_SECRET', 'OAUTH_TOKEN') - -.. _face.com: http://developers.face.com/ -.. _official documentation: http://developers.face.com/docs/api/ +SkyBiometry Face Detection and Recognition API client library +============================================================= + +SkyBiometry Face Detection and Recognition REST API client library. + +For a demonstration how to use this library, see EXAMPLE.RST. + +For more information about the API and the return values, visit the `official documentation`_. + +Performing actions involving Facebook or Twitter users +====================================================== + +If you want to perform actions involving Facebook or Twitter users you need to provide the necessary credentials. + +#. **Facebook**:: + + client.set_facebook_oauth_credentials('FB_USER_ID', 'FB_SESSION_ID', 'FB_OAUTH_TOKEN') + +#. **Twitter (OAuth)**:: + + client.set_twitter_oauth_credentials('OAUTH_USER', 'OAUTH_SECRET', 'OAUTH_TOKEN') + +.. _official documentation: http://www.skybiometry.com/Documentation diff --git a/face_client/face_client.py b/face_client/face_client.py index 8701cb8..62f8a85 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # -# Name: SkyBiometry Face Detection And Recognition API Python client library -# Description: SkyBiometry Face Detection And Recognition REST API Python client library. +# Name: SkyBiometry Face Detection and Recognition API Python client library +# Description: SkyBiometry Face Detection and Recognition REST API Python client library. # # For more information about the API and the return values, # visit the official documentation at http://www.skybiometry.com/Documentation diff --git a/setup.py b/setup.py index 89a1d65..ff7da13 100644 --- a/setup.py +++ b/setup.py @@ -1,44 +1,44 @@ -# -*- coding: utf-8 -*- -#!/usr/bin/env python -import os -import re -from distutils.core import setup - -version_re = re.compile( - r'__version__ = (\(.*?\))') - -cwd = os.path.dirname(os.path.abspath(__file__)) -fp = open(os.path.join(cwd, 'face_client', '__init__.py')) - -version = None -for line in fp: - match = version_re.search(line) - if match: - version = eval(match.group(1)) - break -else: - raise Exception('Cannot find version in __init__.py') -fp.close() - -setup(name='face_client', - version='.' . join(map(str, version)), - description='face.com face recognition Python API client library', - author='Tomaž Muraus', - author_email='tomaz@tomaz.me', - license='BSD', - url='http://github.com/Kami/python-face-client', - download_url='http://github.com/Kami/python-face-client/', - packages=['face_client'], - provides=['face_client'], - - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Security', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], -) +# -*- coding: utf-8 -*- +#!/usr/bin/env python +import os +import re +from distutils.core import setup + +version_re = re.compile( + r'__version__ = (\(.*?\))') + +cwd = os.path.dirname(os.path.abspath(__file__)) +fp = open(os.path.join(cwd, 'face_client', '__init__.py')) + +version = None +for line in fp: + match = version_re.search(line) + if match: + version = eval(match.group(1)) + break +else: + raise Exception('Cannot find version in __init__.py') +fp.close() + +setup(name='face_client', + version='.' . join(map(str, version)), + description='SkyBiometry Face Detection and Recognition API Python client library', + author='Tomaž Muraus', + author_email='tomaz@tomaz.me', + license='BSD', + url='http://github.com/Kami/python-face-client', + download_url='http://github.com/Kami/python-face-client/', + packages=['face_client'], + provides=['face_client'], + + classifiers=[ + 'Development Status :: 4 - Beta', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Security', + 'Topic :: Software Development :: Libraries :: Python Modules', + ], +) From 011d4da6b14ff33abc91b8324586d5b3ff02646f Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 2 Feb 2013 15:46:22 +0200 Subject: [PATCH 10/25] Updated links. --- EXAMPLE.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EXAMPLE.rst b/EXAMPLE.rst index 6b7b71f..acb911d 100644 --- a/EXAMPLE.rst +++ b/EXAMPLE.rst @@ -15,9 +15,9 @@ And here is the image which hopefully, after training our index will be recogniz http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg -#. First we create our private namespace named **testns** (this can be done on the `face.com page`_) +#. First we create our private namespace named **testns** (this can be done on the `SkyBiometry page`_) -#. Now we import the module and instantiate the class with our SkyBiometry **api_key** and **api_secret** (you can get them by registering your application on `face.com page`_):: +#. Now we import the module and instantiate the class with our SkyBiometry **api_key** and **api_secret** (you can get them by registering your application on `SkyBiometry page`_):: >> from face_client import FaceClient >> client = FaceClient('API_KEY', 'API_SECRET') @@ -100,7 +100,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg As you can see by looking at the uids key, Guido was now recognized with a 20% confidence! -For more information about the face.com API and how to use it with Facebook and Twitter, visit the `official documentation`_. +For more information about the SkyBiometry Face Detection and Recognition API and how to use it with Facebook and Twitter, visit the `official documentation`_. -.. _face.com page: http://www.skybiometry.com/Account +.. _SkyBiometry page: http://www.skybiometry.com/Account .. _official documentation: http://www.skybiometry.com/Documentation From 4f359d1cf67e32c90290694f2c7be0e3c5473950 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 2 Feb 2013 15:52:52 +0200 Subject: [PATCH 11/25] Switch EOLs to UNIX/OSX. --- EXAMPLE.rst | 212 ++++++++++++++++++++++++++-------------------------- README.rst | 46 ++++++------ setup.py | 88 +++++++++++----------- 3 files changed, 173 insertions(+), 173 deletions(-) diff --git a/EXAMPLE.rst b/EXAMPLE.rst index acb911d..3732d71 100644 --- a/EXAMPLE.rst +++ b/EXAMPLE.rst @@ -1,106 +1,106 @@ -EXAMPLE -======= - -Here is a short example demonstrating how you can use this client. - -Lets say that we want to create our own private namespace and train it to recognize Guido Van Rossum. - -Here are the images which we will use for training our namespace index: - -| http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg -| http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg -| http://farm1.static.flickr.com/67/200126290_2798330e61.jpg - -And here is the image which hopefully, after training our index will be recognized as "Guido Van Rossum": - -http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg - -#. First we create our private namespace named **testns** (this can be done on the `SkyBiometry page`_) - -#. Now we import the module and instantiate the class with our SkyBiometry **api_key** and **api_secret** (you can get them by registering your application on `SkyBiometry page`_):: - - >> from face_client import FaceClient - >> client = FaceClient('API_KEY', 'API_SECRET') - -#. Before training our namespace index I just want to show you that the image is not already recognized:: - - >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - {u'no_training_set': [u'guido@testns'], - u'photos': [{u'height': 375, - ...omitted for clarity... - u'tid': u'TEMP_F@51b67ae268617da2c99c69091ab8f3b0_cf224a584e806722a7fa15a936ed1367_48.00_41.82_0', - u'uids': [], - u'width': 47, - u'yaw': 31.649999999999999}], - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500}], - ...omitted for clarity... - - As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. - -#. Saving the tags and training our index - - For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. - - In this example, I will use faces_detect:: - - >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') - >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] - - >> tids - - [u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', - u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', - u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0'] - - We can also check that the tags were saved by using the **tags_get** method:: - - >> client.tags_get('guido@testns') - - {u'message': u'Tags saved with uid: guido@testns ,label: Guido Van Rossum', - u'saved_tags': [{u'detected_tid': u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', - u'tid': u'21319_cf224a584e80672ea7fa15a936ed1367'}, - {u'detected_tid': u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', - u'tid': u'21321_cf224a584e80672ea7fa15a936ed1367'}, - {u'detected_tid': u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0', - u'tid': u'21323_cf224a584e80672ea7fa15a936ed1367'}], - u'status': u'success'} - -#. Now when we have the temporary tag ids, we can use them save to save the tags and train our namespace index:: - - >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') - >> client.faces_train('guido@testns') - - {u'status': u'success', - u'unchanged': [{u'last_trained': 1274462404, - u'training_in_progress': False, - u'training_set_size': 3, - u'uid': u'guido@testns'}]} - -#. Now after we have trained our index, lets check if Guido is recognized:: - - >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - {u'photos': [{u'height': 375, - u'pid': u'F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367', - ...omitted for clarity... - u'roll': -1.3400000000000001, - u'tagger_id': None, - u'threshold': 60, - u'tid': u'TEMP_F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367_51.00_35.20_2', - u'uids': [{u'confidence': 20, - u'uid': u'guido@testns'}], - u'width': 18.600000000000001, - u'yaw': 36}], - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500}], - u'status': u'success', - ...omitted for clarity... - - As you can see by looking at the uids key, Guido was now recognized with a 20% confidence! - -For more information about the SkyBiometry Face Detection and Recognition API and how to use it with Facebook and Twitter, visit the `official documentation`_. - -.. _SkyBiometry page: http://www.skybiometry.com/Account -.. _official documentation: http://www.skybiometry.com/Documentation +EXAMPLE +======= + +Here is a short example demonstrating how you can use this client. + +Lets say that we want to create our own private namespace and train it to recognize Guido Van Rossum. + +Here are the images which we will use for training our namespace index: + +| http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg +| http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg +| http://farm1.static.flickr.com/67/200126290_2798330e61.jpg + +And here is the image which hopefully, after training our index will be recognized as "Guido Van Rossum": + +http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg + +#. First we create our private namespace named **testns** (this can be done on the `SkyBiometry page`_) + +#. Now we import the module and instantiate the class with our SkyBiometry **api_key** and **api_secret** (you can get them by registering your application on `SkyBiometry page`_):: + + >> from face_client import FaceClient + >> client = FaceClient('API_KEY', 'API_SECRET') + +#. Before training our namespace index I just want to show you that the image is not already recognized:: + + >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') + + {u'no_training_set': [u'guido@testns'], + u'photos': [{u'height': 375, + ...omitted for clarity... + u'tid': u'TEMP_F@51b67ae268617da2c99c69091ab8f3b0_cf224a584e806722a7fa15a936ed1367_48.00_41.82_0', + u'uids': [], + u'width': 47, + u'yaw': 31.649999999999999}], + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500}], + ...omitted for clarity... + + As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. + +#. Saving the tags and training our index + + For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. + + In this example, I will use faces_detect:: + + >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') + >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] + + >> tids + + [u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', + u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', + u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0'] + + We can also check that the tags were saved by using the **tags_get** method:: + + >> client.tags_get('guido@testns') + + {u'message': u'Tags saved with uid: guido@testns ,label: Guido Van Rossum', + u'saved_tags': [{u'detected_tid': u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', + u'tid': u'21319_cf224a584e80672ea7fa15a936ed1367'}, + {u'detected_tid': u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', + u'tid': u'21321_cf224a584e80672ea7fa15a936ed1367'}, + {u'detected_tid': u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0', + u'tid': u'21323_cf224a584e80672ea7fa15a936ed1367'}], + u'status': u'success'} + +#. Now when we have the temporary tag ids, we can use them save to save the tags and train our namespace index:: + + >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') + >> client.faces_train('guido@testns') + + {u'status': u'success', + u'unchanged': [{u'last_trained': 1274462404, + u'training_in_progress': False, + u'training_set_size': 3, + u'uid': u'guido@testns'}]} + +#. Now after we have trained our index, lets check if Guido is recognized:: + + >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') + + {u'photos': [{u'height': 375, + u'pid': u'F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367', + ...omitted for clarity... + u'roll': -1.3400000000000001, + u'tagger_id': None, + u'threshold': 60, + u'tid': u'TEMP_F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367_51.00_35.20_2', + u'uids': [{u'confidence': 20, + u'uid': u'guido@testns'}], + u'width': 18.600000000000001, + u'yaw': 36}], + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500}], + u'status': u'success', + ...omitted for clarity... + + As you can see by looking at the uids key, Guido was now recognized with a 20% confidence! + +For more information about the SkyBiometry Face Detection and Recognition API and how to use it with Facebook and Twitter, visit the `official documentation`_. + +.. _SkyBiometry page: http://www.skybiometry.com/Account +.. _official documentation: http://www.skybiometry.com/Documentation diff --git a/README.rst b/README.rst index 71f60c6..1fc9d9e 100644 --- a/README.rst +++ b/README.rst @@ -1,23 +1,23 @@ -SkyBiometry Face Detection and Recognition API client library -============================================================= - -SkyBiometry Face Detection and Recognition REST API client library. - -For a demonstration how to use this library, see EXAMPLE.RST. - -For more information about the API and the return values, visit the `official documentation`_. - -Performing actions involving Facebook or Twitter users -====================================================== - -If you want to perform actions involving Facebook or Twitter users you need to provide the necessary credentials. - -#. **Facebook**:: - - client.set_facebook_oauth_credentials('FB_USER_ID', 'FB_SESSION_ID', 'FB_OAUTH_TOKEN') - -#. **Twitter (OAuth)**:: - - client.set_twitter_oauth_credentials('OAUTH_USER', 'OAUTH_SECRET', 'OAUTH_TOKEN') - -.. _official documentation: http://www.skybiometry.com/Documentation +SkyBiometry Face Detection and Recognition API client library +============================================================= + +SkyBiometry Face Detection and Recognition REST API client library. + +For a demonstration how to use this library, see EXAMPLE.RST. + +For more information about the API and the return values, visit the `official documentation`_. + +Performing actions involving Facebook or Twitter users +====================================================== + +If you want to perform actions involving Facebook or Twitter users you need to provide the necessary credentials. + +#. **Facebook**:: + + client.set_facebook_oauth_credentials('FB_USER_ID', 'FB_SESSION_ID', 'FB_OAUTH_TOKEN') + +#. **Twitter (OAuth)**:: + + client.set_twitter_oauth_credentials('OAUTH_USER', 'OAUTH_SECRET', 'OAUTH_TOKEN') + +.. _official documentation: http://www.skybiometry.com/Documentation diff --git a/setup.py b/setup.py index ff7da13..a7e4739 100644 --- a/setup.py +++ b/setup.py @@ -1,44 +1,44 @@ -# -*- coding: utf-8 -*- -#!/usr/bin/env python -import os -import re -from distutils.core import setup - -version_re = re.compile( - r'__version__ = (\(.*?\))') - -cwd = os.path.dirname(os.path.abspath(__file__)) -fp = open(os.path.join(cwd, 'face_client', '__init__.py')) - -version = None -for line in fp: - match = version_re.search(line) - if match: - version = eval(match.group(1)) - break -else: - raise Exception('Cannot find version in __init__.py') -fp.close() - -setup(name='face_client', - version='.' . join(map(str, version)), - description='SkyBiometry Face Detection and Recognition API Python client library', - author='Tomaž Muraus', - author_email='tomaz@tomaz.me', - license='BSD', - url='http://github.com/Kami/python-face-client', - download_url='http://github.com/Kami/python-face-client/', - packages=['face_client'], - provides=['face_client'], - - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Security', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], -) +# -*- coding: utf-8 -*- +#!/usr/bin/env python +import os +import re +from distutils.core import setup + +version_re = re.compile( + r'__version__ = (\(.*?\))') + +cwd = os.path.dirname(os.path.abspath(__file__)) +fp = open(os.path.join(cwd, 'face_client', '__init__.py')) + +version = None +for line in fp: + match = version_re.search(line) + if match: + version = eval(match.group(1)) + break +else: + raise Exception('Cannot find version in __init__.py') +fp.close() + +setup(name='face_client', + version='.' . join(map(str, version)), + description='SkyBiometry Face Detection and Recognition API Python client library', + author='Tomaž Muraus', + author_email='tomaz@tomaz.me', + license='BSD', + url='http://github.com/Kami/python-face-client', + download_url='http://github.com/Kami/python-face-client/', + packages=['face_client'], + provides=['face_client'], + + classifiers=[ + 'Development Status :: 4 - Beta', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Security', + 'Topic :: Software Development :: Libraries :: Python Modules', + ], +) From 44b7846b64b679a540dde367ad8d07078f56061e Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 23 Feb 2013 12:14:16 +0200 Subject: [PATCH 12/25] Updated changes and moved examples to readme. --- CHANGES | 5 ++- EXAMPLE.rst | 106 --------------------------------------------------- README.rst | 108 +++++++++++++++++++++++++++++++++++++++++++++++----- setup.py | 88 +++++++++++++++++++++--------------------- 4 files changed, 147 insertions(+), 160 deletions(-) delete mode 100644 EXAMPLE.rst diff --git a/CHANGES b/CHANGES index e145281..da46944 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,11 @@ -1.3 - in development: +1.3 - 02.02.2013: - Allow user to pass file-like object for the 'file' argument to the faces_detect and faces_recognize function. [Sebastian Noack] + - Switched to SkyBiometry Face Detection and Recognition API. + - Added possibility to pass image file content for the 'buffer' + argument to faces_detect and faces_recognize function. 1.2 - 25.09.2011: diff --git a/EXAMPLE.rst b/EXAMPLE.rst deleted file mode 100644 index 3732d71..0000000 --- a/EXAMPLE.rst +++ /dev/null @@ -1,106 +0,0 @@ -EXAMPLE -======= - -Here is a short example demonstrating how you can use this client. - -Lets say that we want to create our own private namespace and train it to recognize Guido Van Rossum. - -Here are the images which we will use for training our namespace index: - -| http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg -| http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg -| http://farm1.static.flickr.com/67/200126290_2798330e61.jpg - -And here is the image which hopefully, after training our index will be recognized as "Guido Van Rossum": - -http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg - -#. First we create our private namespace named **testns** (this can be done on the `SkyBiometry page`_) - -#. Now we import the module and instantiate the class with our SkyBiometry **api_key** and **api_secret** (you can get them by registering your application on `SkyBiometry page`_):: - - >> from face_client import FaceClient - >> client = FaceClient('API_KEY', 'API_SECRET') - -#. Before training our namespace index I just want to show you that the image is not already recognized:: - - >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - {u'no_training_set': [u'guido@testns'], - u'photos': [{u'height': 375, - ...omitted for clarity... - u'tid': u'TEMP_F@51b67ae268617da2c99c69091ab8f3b0_cf224a584e806722a7fa15a936ed1367_48.00_41.82_0', - u'uids': [], - u'width': 47, - u'yaw': 31.649999999999999}], - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500}], - ...omitted for clarity... - - As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. - -#. Saving the tags and training our index - - For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. - - In this example, I will use faces_detect:: - - >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') - >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] - - >> tids - - [u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', - u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', - u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0'] - - We can also check that the tags were saved by using the **tags_get** method:: - - >> client.tags_get('guido@testns') - - {u'message': u'Tags saved with uid: guido@testns ,label: Guido Van Rossum', - u'saved_tags': [{u'detected_tid': u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', - u'tid': u'21319_cf224a584e80672ea7fa15a936ed1367'}, - {u'detected_tid': u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', - u'tid': u'21321_cf224a584e80672ea7fa15a936ed1367'}, - {u'detected_tid': u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0', - u'tid': u'21323_cf224a584e80672ea7fa15a936ed1367'}], - u'status': u'success'} - -#. Now when we have the temporary tag ids, we can use them save to save the tags and train our namespace index:: - - >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') - >> client.faces_train('guido@testns') - - {u'status': u'success', - u'unchanged': [{u'last_trained': 1274462404, - u'training_in_progress': False, - u'training_set_size': 3, - u'uid': u'guido@testns'}]} - -#. Now after we have trained our index, lets check if Guido is recognized:: - - >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - {u'photos': [{u'height': 375, - u'pid': u'F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367', - ...omitted for clarity... - u'roll': -1.3400000000000001, - u'tagger_id': None, - u'threshold': 60, - u'tid': u'TEMP_F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367_51.00_35.20_2', - u'uids': [{u'confidence': 20, - u'uid': u'guido@testns'}], - u'width': 18.600000000000001, - u'yaw': 36}], - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500}], - u'status': u'success', - ...omitted for clarity... - - As you can see by looking at the uids key, Guido was now recognized with a 20% confidence! - -For more information about the SkyBiometry Face Detection and Recognition API and how to use it with Facebook and Twitter, visit the `official documentation`_. - -.. _SkyBiometry page: http://www.skybiometry.com/Account -.. _official documentation: http://www.skybiometry.com/Documentation diff --git a/README.rst b/README.rst index 1fc9d9e..c79d3d7 100644 --- a/README.rst +++ b/README.rst @@ -3,21 +3,111 @@ SkyBiometry Face Detection and Recognition API client library SkyBiometry Face Detection and Recognition REST API client library. -For a demonstration how to use this library, see EXAMPLE.RST. - For more information about the API and the return values, visit the `official documentation`_. -Performing actions involving Facebook or Twitter users -====================================================== +EXAMPLE +======= + +Here is a short example demonstrating how you can use this client. + +Lets say that we want to create our own private namespace and train it to recognize Guido Van Rossum. + +Here are the images which we will use for training our namespace index: + +| http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg +| http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg +| http://farm1.static.flickr.com/67/200126290_2798330e61.jpg + +And here is the image which hopefully, after training our index will be recognized as "Guido Van Rossum": + +http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg + +#. First we create our private namespace named **testns** (this can be done on the `SkyBiometry page`_) + +#. Now we import the module and instantiate the class with our SkyBiometry **api_key** and **api_secret** (you can get them by registering your application on `SkyBiometry page`_):: + + >> from face_client import FaceClient + >> client = FaceClient('API_KEY', 'API_SECRET') + +#. Before training our namespace index I just want to show you that the image is not already recognized:: + + >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') + + {u'no_training_set': [u'guido@testns'], + u'photos': [{u'height': 375, + ...omitted for clarity... + u'tid': u'TEMP_F@51b67ae268617da2c99c69091ab8f3b0_cf224a584e806722a7fa15a936ed1367_48.00_41.82_0', + u'uids': [], + u'width': 47, + u'yaw': 31.649999999999999}], + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500}], + ...omitted for clarity... + + As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. + +#. Saving the tags and training our index + + For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. + + In this example, I will use faces_detect:: + + >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') + >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] + + >> tids + + [u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', + u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', + u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0'] + + We can also check that the tags were saved by using the **tags_get** method:: + + >> client.tags_get('guido@testns') + + {u'message': u'Tags saved with uid: guido@testns ,label: Guido Van Rossum', + u'saved_tags': [{u'detected_tid': u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', + u'tid': u'21319_cf224a584e80672ea7fa15a936ed1367'}, + {u'detected_tid': u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', + u'tid': u'21321_cf224a584e80672ea7fa15a936ed1367'}, + {u'detected_tid': u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0', + u'tid': u'21323_cf224a584e80672ea7fa15a936ed1367'}], + u'status': u'success'} + +#. Now when we have the temporary tag ids, we can use them save to save the tags and train our namespace index:: + + >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') + >> client.faces_train('guido@testns') + + {u'status': u'success', + u'unchanged': [{u'last_trained': 1274462404, + u'training_in_progress': False, + u'training_set_size': 3, + u'uid': u'guido@testns'}]} -If you want to perform actions involving Facebook or Twitter users you need to provide the necessary credentials. +#. Now after we have trained our index, lets check if Guido is recognized:: -#. **Facebook**:: + >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - client.set_facebook_oauth_credentials('FB_USER_ID', 'FB_SESSION_ID', 'FB_OAUTH_TOKEN') + {u'photos': [{u'height': 375, + u'pid': u'F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367', + ...omitted for clarity... + u'roll': -1.3400000000000001, + u'tagger_id': None, + u'threshold': 60, + u'tid': u'TEMP_F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367_51.00_35.20_2', + u'uids': [{u'confidence': 20, + u'uid': u'guido@testns'}], + u'width': 18.600000000000001, + u'yaw': 36}], + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500}], + u'status': u'success', + ...omitted for clarity... -#. **Twitter (OAuth)**:: + As you can see by looking at the uids key, Guido was now recognized with a 20% confidence! - client.set_twitter_oauth_credentials('OAUTH_USER', 'OAUTH_SECRET', 'OAUTH_TOKEN') +For more information about the SkyBiometry Face Detection and Recognition API and how to use it with Facebook and Twitter, visit the `official documentation`_. +.. _SkyBiometry page: http://www.skybiometry.com/Account .. _official documentation: http://www.skybiometry.com/Documentation diff --git a/setup.py b/setup.py index a7e4739..7b812b2 100644 --- a/setup.py +++ b/setup.py @@ -1,44 +1,44 @@ -# -*- coding: utf-8 -*- -#!/usr/bin/env python -import os -import re -from distutils.core import setup - -version_re = re.compile( - r'__version__ = (\(.*?\))') - -cwd = os.path.dirname(os.path.abspath(__file__)) -fp = open(os.path.join(cwd, 'face_client', '__init__.py')) - -version = None -for line in fp: - match = version_re.search(line) - if match: - version = eval(match.group(1)) - break -else: - raise Exception('Cannot find version in __init__.py') -fp.close() - -setup(name='face_client', - version='.' . join(map(str, version)), - description='SkyBiometry Face Detection and Recognition API Python client library', - author='Tomaž Muraus', - author_email='tomaz@tomaz.me', - license='BSD', - url='http://github.com/Kami/python-face-client', - download_url='http://github.com/Kami/python-face-client/', - packages=['face_client'], - provides=['face_client'], - - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Security', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], -) +# -*- coding: utf-8 -*- +#!/usr/bin/env python +import os +import re +from distutils.core import setup + +version_re = re.compile( + r'__version__ = (\(.*?\))') + +cwd = os.path.dirname(os.path.abspath(__file__)) +fp = open(os.path.join(cwd, 'face_client', '__init__.py')) + +version = None +for line in fp: + match = version_re.search(line) + if match: + version = eval(match.group(1)) + break +else: + raise Exception('Cannot find version in __init__.py') +fp.close() + +setup(name='face_client', + version='.' . join(map(str, version)), + description='SkyBiometry Face Detection and Recognition API Python client library', + author='Tomaž Muraus', + author_email='tomaz@tomaz.me', + license='BSD', + url='http://github.com/Liuftvafas/python-face-client', + download_url='http://github.com/Liuftvafas/python-face-client/', + packages=['face_client'], + provides=['face_client'], + + classifiers=[ + 'Development Status :: 4 - Beta', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Security', + 'Topic :: Software Development :: Libraries :: Python Modules', + ], +) From d66115de76539323dab1a3f23a5c8ce74a0656e4 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 23 Feb 2013 21:46:35 +0200 Subject: [PATCH 13/25] Added real response from SkyBiometry service. --- README.rst | 70 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/README.rst b/README.rst index c79d3d7..7e1c471 100644 --- a/README.rst +++ b/README.rst @@ -5,8 +5,8 @@ SkyBiometry Face Detection and Recognition REST API client library. For more information about the API and the return values, visit the `official documentation`_. -EXAMPLE -======= +Example +------- Here is a short example demonstrating how you can use this client. @@ -24,27 +24,57 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg #. First we create our private namespace named **testns** (this can be done on the `SkyBiometry page`_) -#. Now we import the module and instantiate the class with our SkyBiometry **api_key** and **api_secret** (you can get them by registering your application on `SkyBiometry page`_):: +#. Now we import the module and instantiate the class with our SkyBiometry **API_KEY** and **API_SECRET** (you can get them by registering your application on `SkyBiometry page`_):: - >> from face_client import FaceClient - >> client = FaceClient('API_KEY', 'API_SECRET') + >> from face_client import FaceClient + >> client = FaceClient('API_KEY', 'API_SECRET') #. Before training our namespace index I just want to show you that the image is not already recognized:: - >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - {u'no_training_set': [u'guido@testns'], - u'photos': [{u'height': 375, - ...omitted for clarity... - u'tid': u'TEMP_F@51b67ae268617da2c99c69091ab8f3b0_cf224a584e806722a7fa15a936ed1367_48.00_41.82_0', - u'uids': [], - u'width': 47, - u'yaw': 31.649999999999999}], - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500}], - ...omitted for clarity... - - As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. + >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') + + { + u'status': u'success', + u'photos': [{ + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500, + u'tags': [{ + u'eye_left': {u'y': 31.2, u'x': 55.6}, + u'confirmed': False, + u'uids': [], + u'yaw': -45, + u'manual': False, + u'height': 18.13, + u'width': 13.6, + u'mouth_center': {u'y': 43.47, u'x': 52.6}, + u'nose': {u'y': 36.53, u'x': 53.4}, + u'eye_right': {u'y': 30.93, u'x': 48.0}, + u'pitch': 0, + u'tid': u'TEMP_F@08e31221350a43d267be01d500f10086_1d12ece6a6ea2_48.20_35.73_0_1', + u'attributes': { + u'gender': {u'confidence': 47, u'value': u'male'}, + u'smiling': {u'confidence': 85, u'value': u'false'}, + u'glasses': {u'confidence': 27, u'value': u'false'}, + u'dark_glasses': {u'confidence': 89, u'value': u'false'}, + u'face': {u'confidence': 71, u'value': u'true'} + }, + u'recognizable': True, + u'roll': 3, + u'center': {u'y': 35.73, u'x': 48.2} + }], + u'pid': u'F@08e31221350a43d267be01d572dc824b_1d12ece6a6ea2', + u'height': 375 + }], + u'usage': { + u'reset_time_text': u'Sat, 23 February 2013 19:38:28 +0000', + u'used': 1, + u'limit': 10000, + u'remaining': 9999, + u'reset_time': 1361648308 + } + } + + As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. #. Saving the tags and training our index @@ -107,7 +137,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg As you can see by looking at the uids key, Guido was now recognized with a 20% confidence! -For more information about the SkyBiometry Face Detection and Recognition API and how to use it with Facebook and Twitter, visit the `official documentation`_. +For more information about the SkyBiometry Face Detection and Recognition API and how to use it, visit the `official documentation`_. .. _SkyBiometry page: http://www.skybiometry.com/Account .. _official documentation: http://www.skybiometry.com/Documentation From 8589ecf13266933c1ccd5e517c46de0e9422c292 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 23 Feb 2013 21:52:53 +0200 Subject: [PATCH 14/25] Bold on uids list. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7e1c471..12de82b 100644 --- a/README.rst +++ b/README.rst @@ -41,7 +41,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg u'tags': [{ u'eye_left': {u'y': 31.2, u'x': 55.6}, u'confirmed': False, - u'uids': [], + **u'uids': [],** u'yaw': -45, u'manual': False, u'height': 18.13, From 2a3ce1c3c6d515e3a9f1264650db10b4bf01c4cb Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 23 Feb 2013 22:58:06 +0200 Subject: [PATCH 15/25] Added real responses from SkyBiometry service. Fixed tags_get() arguments processing. --- README.rst | 137 +++++++++++++++++++++++-------------- face_client/face_client.py | 11 +-- 2 files changed, 90 insertions(+), 58 deletions(-) diff --git a/README.rst b/README.rst index 12de82b..0369257 100644 --- a/README.rst +++ b/README.rst @@ -41,7 +41,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg u'tags': [{ u'eye_left': {u'y': 31.2, u'x': 55.6}, u'confirmed': False, - **u'uids': [],** + u'uids': [], u'yaw': -45, u'manual': False, u'height': 18.13, @@ -65,77 +65,108 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg u'pid': u'F@08e31221350a43d267be01d572dc824b_1d12ece6a6ea2', u'height': 375 }], - u'usage': { - u'reset_time_text': u'Sat, 23 February 2013 19:38:28 +0000', - u'used': 1, - u'limit': 10000, - u'remaining': 9999, - u'reset_time': 1361648308 - } + u'usage': {...omitted for clarity...} } As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. #. Saving the tags and training our index - For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. + For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. - In this example, I will use faces_detect:: + In this example, I will use faces_detect:: - >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') - >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] + >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') + >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] + >> tids - >> tids + [ + u'TEMP_F@0bf0294f6c43162105c9bdfa00bc00ab_15e78870a332a_47.00_28.50_0_1', + u'TEMP_F@008f7f3d4f93956f2fd24b1e01000084_e29f2ba8f58c6_51.20_35.20_0_1', + u'TEMP_F@0d38a4e97c5c63042b5da6da00a10088_73a8fb3908097_48.35_27.20_0_1' + ] - [u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', - u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', - u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0'] +#. Now when we have the temporary tag ids, we can use them to save the tags and train our namespace index:: - We can also check that the tags were saved by using the **tags_get** method:: + >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') - >> client.tags_get('guido@testns') + { + u'status': u'success', + u'message': u'Tags saved with uid: guido@tag, label: Guido Van Rossum', + u'saved_tags': [ + {u'tid': u'00bc00ab_15e78870a332a', u'detected_tid': u'TEMP_F@0bf0294f6c43162105c9bdfa00bc00ab_15e78870a332a_47.00_28.50_0_1'}, + {u'tid': u'01000084_e29f2ba8f58c6', u'detected_tid': u'TEMP_F@008f7f3d4f93956f2fd24b1e01000084_e29f2ba8f58c6_51.20_35.20_0_1'}, + {u'tid': u'00a10088_73a8fb3908097', u'detected_tid': u'TEMP_F@0d38a4e97c5c63042b5da6da00a10088_73a8fb3908097_48.35_27.20_0_1'} + ] + } - {u'message': u'Tags saved with uid: guido@testns ,label: Guido Van Rossum', - u'saved_tags': [{u'detected_tid': u'TEMP_F@cc96b0429a7946711de5693c5ff67c46_cf224a584e80672ea7fa15a936ed1367_47.00_27.83_0', - u'tid': u'21319_cf224a584e80672ea7fa15a936ed1367'}, - {u'detected_tid': u'TEMP_F@e2ee88f20076bc1a60c3629281f34197_cf224a584e80672ea7fa15a936ed1367_48.00_34.93_0', - u'tid': u'21321_cf224a584e80672ea7fa15a936ed1367'}, - {u'detected_tid': u'TEMP_F@33c91a546bbba775628e7d7ca969f7ce_cf224a584e80672ea7fa15a936ed1367_48.35_26.40_0', - u'tid': u'21323_cf224a584e80672ea7fa15a936ed1367'}], - u'status': u'success'} + >> client.faces_train('guido@testns') -#. Now when we have the temporary tag ids, we can use them save to save the tags and train our namespace index:: + { + u'status': u'success', + u'created': [{ + u'training_set_size': 3, + u'last_trained': 1361651583, + u'uid': u'guido@tag', + u'training_in_progress': False} + ] + } - >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') - >> client.faces_train('guido@testns') +#. We can also check that the tags were saved by using the **tags_get** method:: - {u'status': u'success', - u'unchanged': [{u'last_trained': 1274462404, - u'training_in_progress': False, - u'training_set_size': 3, - u'uid': u'guido@testns'}]} + >> client.tags_get('guido@testns') + + { + u'status': u'success', + u'photos': [ + {u'url': u'http://farm1.static.flickr.com/67/200126290_2798330e61.jpg', ...omitted for clarity...}, + {u'url': u'http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg', ...omitted for clarity...}, + {u'url': u'http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg', ...omitted for clarity...} + ], + u'usage': {...omitted for clarity...} + } #. Now after we have trained our index, lets check if Guido is recognized:: - >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - {u'photos': [{u'height': 375, - u'pid': u'F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367', - ...omitted for clarity... - u'roll': -1.3400000000000001, - u'tagger_id': None, - u'threshold': 60, - u'tid': u'TEMP_F@2981c22e78cc0f12276825aa0b05df86_cf224a584e80672ea7fa15a936ed1367_51.00_35.20_2', - u'uids': [{u'confidence': 20, - u'uid': u'guido@testns'}], - u'width': 18.600000000000001, - u'yaw': 36}], - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500}], - u'status': u'success', - ...omitted for clarity... - - As you can see by looking at the uids key, Guido was now recognized with a 20% confidence! + >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') + + { + u'status': u'success', + u'photos': [{ + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500, + u'tags': [{ + u'eye_left': {u'y': 31.2, u'x': 55.6}, + u'confirmed': False, + u'uids': [{u'confidence': 34, u'uid': u'guido@tag'}], + u'width': 13.6, + u'yaw': -45, + u'manual': False, + u'height': 18.13, + u'threshold': 30, + u'mouth_center': {u'y': 43.47, u'x': 52.6}, + u'nose': {u'y': 36.53, u'x': 53.4}, + u'eye_right': {u'y': 30.93, u'x': 48.0}, + u'pitch': 0, + u'tid': u'TEMP_F@08e31221350a43d267be01d500f10086_1d12ece6a6ea2_48.20_35.73_0_1', + u'attributes': { + u'gender': {u'confidence': 47, u'value': u'male'}, + u'smiling': {u'confidence': 85, u'value': u'false'}, + u'glasses': {u'confidence': 27, u'value': u'false'}, + u'dark_glasses': {u'confidence': 89, u'value': u'false'}, + u'face': {u'confidence': 71, u'value': u'true'} + }, + u'recognizable': True, + u'roll': 3, + u'center': {u'y': 35.73, u'x': 48.2} + }], + u'pid': u'F@08e31221350a43d267be01d572dc824b_1d12ece6a6ea2', + u'height': 375 + }], + u'usage': {...omitted for clarity...} + } + + As you can see by looking at the uids key, Guido was now recognized with a 34% confidence! For more information about the SkyBiometry Face Detection and Recognition API and how to use it, visit the `official documentation`_. diff --git a/face_client/face_client.py b/face_client/face_client.py index 62f8a85..aa5240d 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -179,14 +179,13 @@ def tags_get(self, uids=None, urls=None, pids=None, order='recent', limit=5, tog http://developers.face.com/docs/api/tags-get/ """ + if not uids and not urls: + raise AttributeError('Missing user IDs or URLs') (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) - data = {'uids': uids, - 'urls': urls, - 'together': together, - 'limit': limit} + data = { 'together': 'true' if together else 'false', 'limit': limit } self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, pids=pids, filter=filter, namespace=namespace) + self.__append_optional_arguments(data, uids=uids, urls=urls, pids=pids, filter=filter, namespace=namespace) response = self.send_request('tags/get', data) return response @@ -357,6 +356,8 @@ def send_request(self, method=None, parameters=None, files=None, buffers=None): post_data = urllib.urlencode(data) headers = {} + print post_data + request = urllib2.Request(url, headers=headers, data=post_data) response = urllib2.urlopen(request) response = response.read() From 2bfb9cd84f3a16522bc15032888494b3d137a218 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 23 Feb 2013 23:01:42 +0200 Subject: [PATCH 16/25] Fixed namespace name in responses. --- README.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 0369257..5972f08 100644 --- a/README.rst +++ b/README.rst @@ -68,7 +68,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg u'usage': {...omitted for clarity...} } - As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. +As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. #. Saving the tags and training our index @@ -92,7 +92,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg { u'status': u'success', - u'message': u'Tags saved with uid: guido@tag, label: Guido Van Rossum', + u'message': u'Tags saved with uid: guido@testns, label: Guido Van Rossum', u'saved_tags': [ {u'tid': u'00bc00ab_15e78870a332a', u'detected_tid': u'TEMP_F@0bf0294f6c43162105c9bdfa00bc00ab_15e78870a332a_47.00_28.50_0_1'}, {u'tid': u'01000084_e29f2ba8f58c6', u'detected_tid': u'TEMP_F@008f7f3d4f93956f2fd24b1e01000084_e29f2ba8f58c6_51.20_35.20_0_1'}, @@ -107,7 +107,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg u'created': [{ u'training_set_size': 3, u'last_trained': 1361651583, - u'uid': u'guido@tag', + u'uid': u'guido@testns', u'training_in_progress': False} ] } @@ -138,7 +138,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg u'tags': [{ u'eye_left': {u'y': 31.2, u'x': 55.6}, u'confirmed': False, - u'uids': [{u'confidence': 34, u'uid': u'guido@tag'}], + u'uids': [{u'confidence': 34, u'uid': u'guido@testns'}], u'width': 13.6, u'yaw': -45, u'manual': False, @@ -166,7 +166,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg u'usage': {...omitted for clarity...} } - As you can see by looking at the uids key, Guido was now recognized with a 34% confidence! +As you can see by looking at the "uids" list, Guido was now recognized with a 34% confidence! For more information about the SkyBiometry Face Detection and Recognition API and how to use it, visit the `official documentation`_. From 0e271bc0a4ac0f805597ef0f89c5426305718000 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 23 Feb 2013 23:05:16 +0200 Subject: [PATCH 17/25] Minor changes. --- README.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 5972f08..1c2931b 100644 --- a/README.rst +++ b/README.rst @@ -68,13 +68,11 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg u'usage': {...omitted for clarity...} } -As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. + As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. -#. Saving the tags and training our index +#. Saving the tags and training our index:: - For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. - - In this example, I will use faces_detect:: + For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. In this example, I will use faces_detect. >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] @@ -166,7 +164,7 @@ As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not y u'usage': {...omitted for clarity...} } -As you can see by looking at the "uids" list, Guido was now recognized with a 34% confidence! + As you can see by looking at the "uids" list, Guido was now recognized with a 34% confidence! For more information about the SkyBiometry Face Detection and Recognition API and how to use it, visit the `official documentation`_. From 2334399314afb6e07a775e6a18ca00b0cb356d08 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 23 Feb 2013 23:09:27 +0200 Subject: [PATCH 18/25] Changes tabs to spaces. --- README.rst | 232 ++++++++++++++++++++++++++--------------------------- 1 file changed, 116 insertions(+), 116 deletions(-) diff --git a/README.rst b/README.rst index 1c2931b..ae12581 100644 --- a/README.rst +++ b/README.rst @@ -26,47 +26,47 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg #. Now we import the module and instantiate the class with our SkyBiometry **API_KEY** and **API_SECRET** (you can get them by registering your application on `SkyBiometry page`_):: - >> from face_client import FaceClient - >> client = FaceClient('API_KEY', 'API_SECRET') + >> from face_client import FaceClient + >> client = FaceClient('API_KEY', 'API_SECRET') #. Before training our namespace index I just want to show you that the image is not already recognized:: - >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - { - u'status': u'success', - u'photos': [{ - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500, - u'tags': [{ - u'eye_left': {u'y': 31.2, u'x': 55.6}, - u'confirmed': False, - u'uids': [], - u'yaw': -45, - u'manual': False, - u'height': 18.13, - u'width': 13.6, - u'mouth_center': {u'y': 43.47, u'x': 52.6}, - u'nose': {u'y': 36.53, u'x': 53.4}, - u'eye_right': {u'y': 30.93, u'x': 48.0}, - u'pitch': 0, - u'tid': u'TEMP_F@08e31221350a43d267be01d500f10086_1d12ece6a6ea2_48.20_35.73_0_1', - u'attributes': { - u'gender': {u'confidence': 47, u'value': u'male'}, - u'smiling': {u'confidence': 85, u'value': u'false'}, - u'glasses': {u'confidence': 27, u'value': u'false'}, - u'dark_glasses': {u'confidence': 89, u'value': u'false'}, - u'face': {u'confidence': 71, u'value': u'true'} - }, - u'recognizable': True, - u'roll': 3, - u'center': {u'y': 35.73, u'x': 48.2} - }], - u'pid': u'F@08e31221350a43d267be01d572dc824b_1d12ece6a6ea2', - u'height': 375 - }], - u'usage': {...omitted for clarity...} - } + >> client.faces_recognize('guido', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') + + { + u'status': u'success', + u'photos': [{ + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500, + u'tags': [{ + u'eye_left': {u'y': 31.2, u'x': 55.6}, + u'confirmed': False, + u'uids': [], + u'yaw': -45, + u'manual': False, + u'height': 18.13, + u'width': 13.6, + u'mouth_center': {u'y': 43.47, u'x': 52.6}, + u'nose': {u'y': 36.53, u'x': 53.4}, + u'eye_right': {u'y': 30.93, u'x': 48.0}, + u'pitch': 0, + u'tid': u'TEMP_F@08e31221350a43d267be01d500f10086_1d12ece6a6ea2_48.20_35.73_0_1', + u'attributes': { + u'gender': {u'confidence': 47, u'value': u'male'}, + u'smiling': {u'confidence': 85, u'value': u'false'}, + u'glasses': {u'confidence': 27, u'value': u'false'}, + u'dark_glasses': {u'confidence': 89, u'value': u'false'}, + u'face': {u'confidence': 71, u'value': u'true'} + }, + u'recognizable': True, + u'roll': 3, + u'center': {u'y': 35.73, u'x': 48.2} + }], + u'pid': u'F@08e31221350a43d267be01d572dc824b_1d12ece6a6ea2', + u'height': 375 + }], + u'usage': {...omitted for clarity...} + } As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. @@ -74,95 +74,95 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. In this example, I will use faces_detect. - >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') - >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] - >> tids + >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') + >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] + >> tids - [ - u'TEMP_F@0bf0294f6c43162105c9bdfa00bc00ab_15e78870a332a_47.00_28.50_0_1', - u'TEMP_F@008f7f3d4f93956f2fd24b1e01000084_e29f2ba8f58c6_51.20_35.20_0_1', - u'TEMP_F@0d38a4e97c5c63042b5da6da00a10088_73a8fb3908097_48.35_27.20_0_1' - ] + [ + u'TEMP_F@0bf0294f6c43162105c9bdfa00bc00ab_15e78870a332a_47.00_28.50_0_1', + u'TEMP_F@008f7f3d4f93956f2fd24b1e01000084_e29f2ba8f58c6_51.20_35.20_0_1', + u'TEMP_F@0d38a4e97c5c63042b5da6da00a10088_73a8fb3908097_48.35_27.20_0_1' + ] #. Now when we have the temporary tag ids, we can use them to save the tags and train our namespace index:: - >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') - - { - u'status': u'success', - u'message': u'Tags saved with uid: guido@testns, label: Guido Van Rossum', - u'saved_tags': [ - {u'tid': u'00bc00ab_15e78870a332a', u'detected_tid': u'TEMP_F@0bf0294f6c43162105c9bdfa00bc00ab_15e78870a332a_47.00_28.50_0_1'}, - {u'tid': u'01000084_e29f2ba8f58c6', u'detected_tid': u'TEMP_F@008f7f3d4f93956f2fd24b1e01000084_e29f2ba8f58c6_51.20_35.20_0_1'}, - {u'tid': u'00a10088_73a8fb3908097', u'detected_tid': u'TEMP_F@0d38a4e97c5c63042b5da6da00a10088_73a8fb3908097_48.35_27.20_0_1'} - ] - } - - >> client.faces_train('guido@testns') - - { - u'status': u'success', - u'created': [{ - u'training_set_size': 3, - u'last_trained': 1361651583, - u'uid': u'guido@testns', - u'training_in_progress': False} - ] - } + >> client.tags_save(tids = ',' . join(tids), uid = 'guido@testns', label = 'Guido Van Rossum') + + { + u'status': u'success', + u'message': u'Tags saved with uid: guido@testns, label: Guido Van Rossum', + u'saved_tags': [ + {u'tid': u'00bc00ab_15e78870a332a', u'detected_tid': u'TEMP_F@0bf0294f6c43162105c9bdfa00bc00ab_15e78870a332a_47.00_28.50_0_1'}, + {u'tid': u'01000084_e29f2ba8f58c6', u'detected_tid': u'TEMP_F@008f7f3d4f93956f2fd24b1e01000084_e29f2ba8f58c6_51.20_35.20_0_1'}, + {u'tid': u'00a10088_73a8fb3908097', u'detected_tid': u'TEMP_F@0d38a4e97c5c63042b5da6da00a10088_73a8fb3908097_48.35_27.20_0_1'} + ] + } + + >> client.faces_train('guido@testns') + + { + u'status': u'success', + u'created': [{ + u'training_set_size': 3, + u'last_trained': 1361651583, + u'uid': u'guido@testns', + u'training_in_progress': False} + ] + } #. We can also check that the tags were saved by using the **tags_get** method:: - >> client.tags_get('guido@testns') + >> client.tags_get('guido@testns') - { - u'status': u'success', - u'photos': [ - {u'url': u'http://farm1.static.flickr.com/67/200126290_2798330e61.jpg', ...omitted for clarity...}, - {u'url': u'http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg', ...omitted for clarity...}, - {u'url': u'http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg', ...omitted for clarity...} - ], - u'usage': {...omitted for clarity...} - } + { + u'status': u'success', + u'photos': [ + {u'url': u'http://farm1.static.flickr.com/67/200126290_2798330e61.jpg', ...omitted for clarity...}, + {u'url': u'http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg', ...omitted for clarity...}, + {u'url': u'http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg', ...omitted for clarity...} + ], + u'usage': {...omitted for clarity...} + } #. Now after we have trained our index, lets check if Guido is recognized:: - >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') - - { - u'status': u'success', - u'photos': [{ - u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', - u'width': 500, - u'tags': [{ - u'eye_left': {u'y': 31.2, u'x': 55.6}, - u'confirmed': False, - u'uids': [{u'confidence': 34, u'uid': u'guido@testns'}], - u'width': 13.6, - u'yaw': -45, - u'manual': False, - u'height': 18.13, - u'threshold': 30, - u'mouth_center': {u'y': 43.47, u'x': 52.6}, - u'nose': {u'y': 36.53, u'x': 53.4}, - u'eye_right': {u'y': 30.93, u'x': 48.0}, - u'pitch': 0, - u'tid': u'TEMP_F@08e31221350a43d267be01d500f10086_1d12ece6a6ea2_48.20_35.73_0_1', - u'attributes': { - u'gender': {u'confidence': 47, u'value': u'male'}, - u'smiling': {u'confidence': 85, u'value': u'false'}, - u'glasses': {u'confidence': 27, u'value': u'false'}, - u'dark_glasses': {u'confidence': 89, u'value': u'false'}, - u'face': {u'confidence': 71, u'value': u'true'} - }, - u'recognizable': True, - u'roll': 3, - u'center': {u'y': 35.73, u'x': 48.2} - }], - u'pid': u'F@08e31221350a43d267be01d572dc824b_1d12ece6a6ea2', - u'height': 375 - }], - u'usage': {...omitted for clarity...} - } + >> client.faces_recognize('all', 'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', namespace = 'testns') + + { + u'status': u'success', + u'photos': [{ + u'url': u'http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg', + u'width': 500, + u'tags': [{ + u'eye_left': {u'y': 31.2, u'x': 55.6}, + u'confirmed': False, + u'uids': [{u'confidence': 34, u'uid': u'guido@testns'}], + u'width': 13.6, + u'yaw': -45, + u'manual': False, + u'height': 18.13, + u'threshold': 30, + u'mouth_center': {u'y': 43.47, u'x': 52.6}, + u'nose': {u'y': 36.53, u'x': 53.4}, + u'eye_right': {u'y': 30.93, u'x': 48.0}, + u'pitch': 0, + u'tid': u'TEMP_F@08e31221350a43d267be01d500f10086_1d12ece6a6ea2_48.20_35.73_0_1', + u'attributes': { + u'gender': {u'confidence': 47, u'value': u'male'}, + u'smiling': {u'confidence': 85, u'value': u'false'}, + u'glasses': {u'confidence': 27, u'value': u'false'}, + u'dark_glasses': {u'confidence': 89, u'value': u'false'}, + u'face': {u'confidence': 71, u'value': u'true'} + }, + u'recognizable': True, + u'roll': 3, + u'center': {u'y': 35.73, u'x': 48.2} + }], + u'pid': u'F@08e31221350a43d267be01d572dc824b_1d12ece6a6ea2', + u'height': 375 + }], + u'usage': {...omitted for clarity...} + } As you can see by looking at the "uids" list, Guido was now recognized with a 34% confidence! From 1e7c9b860b45a8ba84fe17ca6ea34c231d0eba18 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 23 Feb 2013 23:12:54 +0200 Subject: [PATCH 19/25] Minor changes. --- README.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.rst b/README.rst index ae12581..721d63c 100644 --- a/README.rst +++ b/README.rst @@ -70,9 +70,7 @@ http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg As you can see, the "uids" list is empty, meaning that Guido Van Rossum is not yet recognized in our **testns** namespace. -#. Saving the tags and training our index:: - - For saving the tags, we need to provide the **tags_save** method with the tag ids, which we can obtain by using the **faces_detect** or **faces_recognize** method. In this example, I will use faces_detect. +#. Saving the tags and training our index. For saving the tags, we need to provide the **tags_save** method with the tag ids, which we are obtained by using the **faces_detect** or **faces_recognize** method. In this example, I will use **faces_detect**:: >> response = client.faces_detect('http://savasplace.com/wp-content/uploads/2009/04/guido-van-rossum.jpg,http://farm1.static.flickr.com/43/104506247_c748f20b83.jpg,http://farm1.static.flickr.com/67/200126290_2798330e61.jpg') >> tids = [photo['tags'][0]['tid'] for photo in response['photos']] From c766e4b475409e5d9b5275b11cc0f6cda1dcc49c Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 23 Feb 2013 23:16:38 +0200 Subject: [PATCH 20/25] Minor changes. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 721d63c..a0ed59c 100644 --- a/README.rst +++ b/README.rst @@ -22,7 +22,7 @@ And here is the image which hopefully, after training our index will be recogniz http://farm1.static.flickr.com/41/104498903_bad315cee0.jpg -#. First we create our private namespace named **testns** (this can be done on the `SkyBiometry page`_) +#. First we create our private namespace named **testns** (this can be done on the `SkyBiometry page`_). #. Now we import the module and instantiate the class with our SkyBiometry **API_KEY** and **API_SECRET** (you can get them by registering your application on `SkyBiometry page`_):: From 3e7d4b865afc1e97a75da1e46c1c683c5cfd1315 Mon Sep 17 00:00:00 2001 From: JimJty Date: Thu, 28 Feb 2013 13:16:26 -0700 Subject: [PATCH 21/25] Update face_client.py Some minor fixes: - removed print statement - added account/namespaces method - 'detector' parameter was missing in faces/recognize call --- face_client/face_client.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/face_client/face_client.py b/face_client/face_client.py index aa5240d..5e611c3 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -142,6 +142,9 @@ def faces_recognize(self, uids=None, urls=None, file=None, buffer=None, aggressi buffers.append(buffer) else: data.update({'urls': urls}) + + if aggressive: + data['detector'] = 'Aggressive' self.__append_user_auth_data(data, facebook_uids, twitter_uids) self.__append_optional_arguments(data, train=train, namespace=namespace) @@ -275,6 +278,19 @@ def account_users(self, namespaces=None): {'namespaces': namespaces}) return response + + def account_namespaces(self): + """ + Returns all valid data namespaces for user authorized by specified api_key. + + http://api.skybiometry.com/fc/account/namespaces + """ + + response = self.send_request('account/namespaces', + ) + + return response + def __check_user_auth_credentials(self, uids): # Check if needed credentials are provided @@ -356,8 +372,6 @@ def send_request(self, method=None, parameters=None, files=None, buffers=None): post_data = urllib.urlencode(data) headers = {} - print post_data - request = urllib2.Request(url, headers=headers, data=post_data) response = urllib2.urlopen(request) response = response.read() From 1256cf0627f0b685b6672a29b183e60ba045916e Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Mon, 4 Mar 2013 22:27:32 +0200 Subject: [PATCH 22/25] Fixed whitespace and links to documentation. --- face_client/face_client.py | 55 +++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/face_client/face_client.py b/face_client/face_client.py index 5e611c3..4626e2f 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -69,7 +69,7 @@ def faces_detect(self, urls=None, file=None, buffer=None, aggressive=False): information of the tag, eyes, nose and mouth, as well as the gender, glasses, and smiling attributes. - http://developers.face.com/docs/api/faces-detect/ + http://www.skybiometry.com/Documentation#faces/detect """ if not urls and not file and not buffer: raise AttributeError('Missing URLs/filename/buffer argument') @@ -90,7 +90,7 @@ def faces_detect(self, urls=None, file=None, buffer=None, aggressive=False): data['urls'] = urls if aggressive: - data['detector'] = 'Aggressive' + data['detector'] = 'aggressive' response = self.send_request('faces/detect', data, files, buffers) return response @@ -99,7 +99,7 @@ def faces_status(self, uids=None, namespace=None): """ Reports training set status for the specified UIDs. - http://developers.face.com/docs/api/faces-status/ + http://www.skybiometry.com/Documentation#faces/status """ if not uids: raise AttributeError('Missing user IDs') @@ -117,12 +117,12 @@ def faces_recognize(self, uids=None, urls=None, file=None, buffer=None, aggressi """ Attempts to detect and recognize one or more user IDs' faces, in one or more photos. - For each detected face, the face.com engine will return the most likely + For each detected face, the SkyBiometry engine will return the most likely user IDs, or empty result for unrecognized faces. In addition, each tag includes a threshold score - any score below this number is considered a low-probability hit. - http://developers.face.com/docs/api/faces-recognize/ + http://www.skybiometry.com/Documentation#faces/recognize """ if not uids or (not urls and not file and not buffer): raise AttributeError('Missing required arguments') @@ -142,9 +142,9 @@ def faces_recognize(self, uids=None, urls=None, file=None, buffer=None, aggressi buffers.append(buffer) else: data.update({'urls': urls}) - + if aggressive: - data['detector'] = 'Aggressive' + data['detector'] = 'aggressive' self.__append_user_auth_data(data, facebook_uids, twitter_uids) self.__append_optional_arguments(data, train=train, namespace=namespace) @@ -157,7 +157,7 @@ def faces_train(self, uids=None, namespace=None): Calls the training procedure for the specified UIDs, and reports back changes. - http://developers.face.com/docs/api/faces-train/ + http://www.skybiometry.com/Documentation#faces/train """ if not uids: raise AttributeError('Missing user IDs') @@ -180,7 +180,7 @@ def tags_get(self, uids=None, urls=None, pids=None, order='recent', limit=5, tog corresponding to a more specific criteria such as front-facing, recent, or where two or more users appear together in same photos. - http://developers.face.com/docs/api/tags-get/ + http://www.skybiometry.com/Documentation#tags/get """ if not uids and not urls: raise AttributeError('Missing user IDs or URLs') @@ -198,7 +198,7 @@ def tags_add(self, url=None, x=None, y=None, width=None, uid=None, tagger_id=Non Add a (manual) face tag to a photo. Use this method to add face tags where those were not detected for completeness of your service. - http://developers.face.com/docs/api/tags-add/ + http://www.skybiometry.com/Documentation#tags/add """ if not url or not x or not y or not width or not uid or not tagger_id: raise AttributeError('Missing one of the required arguments') @@ -217,14 +217,12 @@ def tags_add(self, url=None, x=None, y=None, width=None, uid=None, tagger_id=Non response = self.send_request('tags/add', data) return response - def tags_save(self, tids=None, uid=None, tagger_id=None, label=None, \ - password=None): + def tags_save(self, tids=None, uid=None, tagger_id=None, label=None, password=None): """ Saves a face tag. Use this method to save tags for training the - face.com index, or for future use of the faces.detect and tags.get - methods. + index, or for future use of the faces.detect and tags.get methods. - http://developers.face.com/docs/api/tags-save/ + http://www.skybiometry.com/Documentation#tags/save """ if not tids or not uid: raise AttributeError('Missing required argument') @@ -243,7 +241,7 @@ def tags_remove(self, tids=None, password=None): """ Remove a previously saved face tag from a photo. - http://developers.face.com/docs/api/tags-remove/ + http://www.skybiometry.com/Documentation#tags/remove """ if not tids: raise AttributeError('Missing tag IDs') @@ -259,7 +257,7 @@ def account_limits(self): Returns current rate limits for the account represented by the passed API key and Secret. - http://developers.face.com/docs/api/account-limits/ + http://www.skybiometry.com/Documentation#account/limits """ response = self.send_request('account/limits') return response['usage'] @@ -269,28 +267,25 @@ def account_users(self, namespaces=None): Returns current rate limits for the account represented by the passed API key and Secret. - http://developers.face.com/docs/api/account-limits/ + http://www.skybiometry.com/Documentation#account/users """ if not namespaces: raise AttributeError('Missing namespaces argument') - response = self.send_request('account/users', - {'namespaces': namespaces}) + response = self.send_request('account/users', { 'namespaces': namespaces }) return response - + def account_namespaces(self): - """ - Returns all valid data namespaces for user authorized by specified api_key. - - http://api.skybiometry.com/fc/account/namespaces - """ + """ + Returns all valid data namespaces for user authorized by specified API key. - response = self.send_request('account/namespaces', - ) + http://www.skybiometry.com/Documentation#account/namespaces + """ + + response = self.send_request('account/namespaces') - return response - + return response def __check_user_auth_credentials(self, uids): # Check if needed credentials are provided From 48aa50f0c449975919066586ffbc7128de87835d Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Tue, 5 Mar 2013 09:19:52 +0200 Subject: [PATCH 23/25] Added reading of response in case of HTTPError. --- face_client/face_client.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/face_client/face_client.py b/face_client/face_client.py index 4626e2f..f42cc38 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -368,8 +368,11 @@ def send_request(self, method=None, parameters=None, files=None, buffers=None): headers = {} request = urllib2.Request(url, headers=headers, data=post_data) - response = urllib2.urlopen(request) - response = response.read() + try: + response = urllib2.urlopen(request) + response = response.read() + except urllib2.HTTPError as e: + response = e.read() response_data = json.loads(response) if 'status' in response_data and response_data['status'] == 'failure': From fd3fbd50232bab3e134492a2e6e03760bf79017b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justinas=20Cic=C4=97nas?= Date: Wed, 27 Dec 2017 12:34:13 +0200 Subject: [PATCH 24/25] Added Python 3 support --- face_client/face_client.py | 739 +++++++++++++++++++------------------ setup.py | 9 +- 2 files changed, 380 insertions(+), 368 deletions(-) diff --git a/face_client/face_client.py b/face_client/face_client.py index f42cc38..dc9292d 100644 --- a/face_client/face_client.py +++ b/face_client/face_client.py @@ -9,382 +9,391 @@ # Author: Tomaž Muraus (http://www.tomaz.me) # License: BSD -import urllib -import urllib2 import os.path import warnings +import requests try: - import json + from urllib.parse import urlencode except ImportError: - import simplejson as json + from urllib import urlencode + +try: + import json +except ImportError: + import simplejson as json + +from future.utils import iteritems API_HOST = 'api.skybiometry.com/fc' USE_SSL = True class FaceClient(object): - def __init__(self, api_key=None, api_secret=None): - if not api_key or not api_secret: - raise AttributeError('Missing api_key or api_secret argument') - - self.api_key = api_key - self.api_secret = api_secret - self.format = 'json' - - self.twitter_credentials = None - self.facebook_credentials = None - - def set_twitter_user_credentials(self, *args, **kwargs): - warnings.warn(('Twitter username & password auth has been ' + - 'deprecated. Please use oauth based auth - ' + - 'set_twitter_oauth_credentials()')) - - def set_twitter_oauth_credentials(self, user=None, secret=None, token=None): - if not user or not secret or not token: - raise AttributeError('Missing one of the required arguments') - - self.twitter_credentials = {'twitter_oauth_user': user, - 'twitter_oauth_secret': secret, - 'twitter_oauth_token': token} - - def set_facebook_access_token(self, *args, **kwargs): - warnings.warn(('Method has been renamed to ' + - 'set_facebook_oauth_credentials(). Support for ' + - 'username & password based auth has also been dropped. ' + - 'Now only oAuth2 token based auth is supported')) - - def set_facebook_oauth_credentials(self, user_id=None, session_id=None, oauth_token=None): - for (key, value) in [('user_id', user_id), ('session_id', session_id), ('oauth_token', oauth_token)]: - if not value: - raise AttributeError('Missing required argument: %s' % (key)) - - self.facebook_credentials = {'fb_user_id': user_id, - 'fb_session_id': session_id, - 'fb_oauth_token': oauth_token} - - ### Recognition engine methods ### - def faces_detect(self, urls=None, file=None, buffer=None, aggressive=False): - """ - Returns tags for detected faces in one or more photos, with geometric - information of the tag, eyes, nose and mouth, as well as the gender, - glasses, and smiling attributes. - - http://www.skybiometry.com/Documentation#faces/detect - """ - if not urls and not file and not buffer: - raise AttributeError('Missing URLs/filename/buffer argument') - - data = {'attributes': 'all'} - files = [] - buffers = [] - - if file: - # Check if the file exists - if not hasattr(file, 'read') and not os.path.exists(file): - raise IOError('File %s does not exist' % (file)) - - files.append(file) - elif buffer: - buffers.append(buffer) - else: - data['urls'] = urls - - if aggressive: - data['detector'] = 'aggressive' - - response = self.send_request('faces/detect', data, files, buffers) - return response - - def faces_status(self, uids=None, namespace=None): - """ - Reports training set status for the specified UIDs. - - http://www.skybiometry.com/Documentation#faces/status - """ - if not uids: - raise AttributeError('Missing user IDs') - - (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) - - data = {'uids': uids} - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, namespace=namespace) - - response = self.send_request('faces/status', data) - return response - - def faces_recognize(self, uids=None, urls=None, file=None, buffer=None, aggressive=False, train=None, namespace=None): - """ - Attempts to detect and recognize one or more user IDs' faces, in one - or more photos. - For each detected face, the SkyBiometry engine will return the most likely - user IDs, or empty result for unrecognized faces. In addition, each - tag includes a threshold score - any score below this number is - considered a low-probability hit. - - http://www.skybiometry.com/Documentation#faces/recognize - """ - if not uids or (not urls and not file and not buffer): - raise AttributeError('Missing required arguments') - - (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) - - data = {'uids': uids, 'attributes': 'all'} - files = [] - buffers = [] - - if file: - # Check if the file exists - if not hasattr(file, 'read') and not os.path.exists(file): - raise IOError('File %s does not exist' % (file)) - files.append(file) - elif buffer: - buffers.append(buffer) - else: - data.update({'urls': urls}) - - if aggressive: - data['detector'] = 'aggressive' - - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, train=train, namespace=namespace) - - response = self.send_request('faces/recognize', data, files, buffers) - return response - - def faces_train(self, uids=None, namespace=None): - """ - Calls the training procedure for the specified UIDs, and reports back - changes. - - http://www.skybiometry.com/Documentation#faces/train - """ - if not uids: - raise AttributeError('Missing user IDs') - - (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) - - data = {'uids': uids} - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, namespace=namespace) - - response = self.send_request('faces/train', data) - return response - - ### Methods for managing face tags ### - def tags_get(self, uids=None, urls=None, pids=None, order='recent', limit=5, together=False, filter=None, namespace=None): - """ - Returns saved tags in one or more photos, or for the specified - User ID(s). - This method also accepts multiple filters for finding tags - corresponding to a more specific criteria such as front-facing, - recent, or where two or more users appear together in same photos. - - http://www.skybiometry.com/Documentation#tags/get - """ - if not uids and not urls: - raise AttributeError('Missing user IDs or URLs') - (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) - - data = { 'together': 'true' if together else 'false', 'limit': limit } - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, uids=uids, urls=urls, pids=pids, filter=filter, namespace=namespace) - - response = self.send_request('tags/get', data) - return response - - def tags_add(self, url=None, x=None, y=None, width=None, uid=None, tagger_id=None, label=None, password=None): - """ - Add a (manual) face tag to a photo. Use this method to add face tags - where those were not detected for completeness of your service. - - http://www.skybiometry.com/Documentation#tags/add - """ - if not url or not x or not y or not width or not uid or not tagger_id: - raise AttributeError('Missing one of the required arguments') - - (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uid) - - data = {'url': url, - 'x': x, - 'y': y, - 'width': width, - 'uid': uid, - 'tagger_id': tagger_id} - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, label=label, password=password) - - response = self.send_request('tags/add', data) - return response - - def tags_save(self, tids=None, uid=None, tagger_id=None, label=None, password=None): - """ - Saves a face tag. Use this method to save tags for training the - index, or for future use of the faces.detect and tags.get methods. - - http://www.skybiometry.com/Documentation#tags/save - """ - if not tids or not uid: - raise AttributeError('Missing required argument') - - (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uid) - - data = {'tids': tids, - 'uid': uid} - self.__append_user_auth_data(data, facebook_uids, twitter_uids) - self.__append_optional_arguments(data, tagger_id=tagger_id, label=label, password=password) - - response = self.send_request('tags/save', data) - return response - - def tags_remove(self, tids=None, password=None): - """ - Remove a previously saved face tag from a photo. - - http://www.skybiometry.com/Documentation#tags/remove - """ - if not tids: - raise AttributeError('Missing tag IDs') - - data = {'tids': tids} - - response = self.send_request('tags/remove', data) - return response - - ### Account management methods ### - def account_limits(self): - """ - Returns current rate limits for the account represented by the passed - API key and Secret. - - http://www.skybiometry.com/Documentation#account/limits - """ - response = self.send_request('account/limits') - return response['usage'] - - def account_users(self, namespaces=None): - """ - Returns current rate limits for the account represented by the passed - API key and Secret. - - http://www.skybiometry.com/Documentation#account/users - """ - if not namespaces: - raise AttributeError('Missing namespaces argument') - - response = self.send_request('account/users', { 'namespaces': namespaces }) - - return response - - def account_namespaces(self): - """ - Returns all valid data namespaces for user authorized by specified API key. - - http://www.skybiometry.com/Documentation#account/namespaces - """ - - response = self.send_request('account/namespaces') - - return response - - def __check_user_auth_credentials(self, uids): - # Check if needed credentials are provided - facebook_uids = [uid for uid in uids.split(',') if uid.find('@facebook.com') != -1] - twitter_uids = [uid for uid in uids.split(',') if uid.find('@twitter.com') != -1] - - if facebook_uids and not self.facebook_credentials: - raise AttributeError('You need to set Facebook credentials ' + - 'to perform action on Facebook users') - - if twitter_uids and not self.twitter_credentials: - raise AttributeError('You need to set Twitter credentials to ' + - 'perform action on Twitter users') - - return (facebook_uids, twitter_uids) - - def __append_user_auth_data(self, data, facebook_uids, twitter_uids): - if facebook_uids: - data.update({'user_auth': 'fb_user:%s,fb_session:%s,' + - 'fb_oauth_token:%s' % - (self.facebook_credentials['fb_user_id'], - self.facebook_credentials['fb_session_id'], - self.facebook_credentials['fb_oauth_token'])}) - - if twitter_uids: - data.update({'user_auth': - ('twitter_oauth_user:%s,twitter_oauth_secret:%s,' - 'twitter_oauth_token:%s' % - (self.twitter_credentials['twitter_oauth_user'], - self.twitter_credentials['twitter_oauth_secret'], - self.twitter_credentials['twitter_oauth_token']))}) - - def __append_optional_arguments(self, data, **kwargs): - for key, value in kwargs.iteritems(): - if value: - data.update({key: value}) - - def send_request(self, method=None, parameters=None, files=None, buffers=None): - protocol = 'https://' if USE_SSL else 'http://' - url = '%s%s/%s.%s' % (protocol, API_HOST, method, self.format) - data = { 'api_key': self.api_key, 'api_secret': self.api_secret } - - if parameters: - data.update(parameters) - - # Local file is provided, use multi-part form - if files or buffers: - from multipart import Multipart - form = Multipart() - - for key, value in data.iteritems(): - form.field(key, value) - - if files: - for i, file in enumerate(files, 1): - if hasattr(file, 'read'): - if hasattr(file, 'name'): - name = os.path.basename(file.name) - else: - name = 'attachment_%d' % i - close_file = False - else: - name = os.path.basename(file) - file = open(file, 'rb') - close_file = True - - try: - form.file(name, name, file.read()) - finally: - if close_file: - file.close() - else: - for i, buffer in enumerate(buffers, 1): - name = 'attachment_%d' % i - form.file(name, name, buffer) - (content_type, post_data) = form.get() - headers = {'Content-Type': content_type} - else: - post_data = urllib.urlencode(data) - headers = {} - - request = urllib2.Request(url, headers=headers, data=post_data) - try: - response = urllib2.urlopen(request) - response = response.read() - except urllib2.HTTPError as e: - response = e.read() - response_data = json.loads(response) - - if 'status' in response_data and response_data['status'] == 'failure': - raise FaceError(response_data['error_code'], response_data['error_message']) - - return response_data + def __init__(self, api_key=None, api_secret=None): + if not api_key or not api_secret: + raise AttributeError('Missing api_key or api_secret argument') + + self.api_key = api_key + self.api_secret = api_secret + self.format = 'json' + + self.twitter_credentials = None + self.facebook_credentials = None + + def set_twitter_user_credentials(self, *args, **kwargs): + warnings.warn(('Twitter username & password auth has been ' + + 'deprecated. Please use oauth based auth - ' + + 'set_twitter_oauth_credentials()')) + + def set_twitter_oauth_credentials(self, user=None, secret=None, token=None): + if not user or not secret or not token: + raise AttributeError('Missing one of the required arguments') + + self.twitter_credentials = {'twitter_oauth_user': user, + 'twitter_oauth_secret': secret, + 'twitter_oauth_token': token} + + def set_facebook_access_token(self, *args, **kwargs): + warnings.warn(('Method has been renamed to ' + + 'set_facebook_oauth_credentials(). Support for ' + + 'username & password based auth has also been dropped. ' + + 'Now only oAuth2 token based auth is supported')) + + def set_facebook_oauth_credentials(self, user_id=None, session_id=None, oauth_token=None): + for (key, value) in [('user_id', user_id), ('session_id', session_id), ('oauth_token', oauth_token)]: + if not value: + raise AttributeError('Missing required argument: %s' % (key)) + + self.facebook_credentials = {'fb_user_id': user_id, + 'fb_session_id': session_id, + 'fb_oauth_token': oauth_token} + + ### Recognition engine methods ### + def faces_detect(self, urls=None, file=None, buffer=None, aggressive=False): + """ + Returns tags for detected faces in one or more photos, with geometric + information of the tag, eyes, nose and mouth, as well as the gender, + glasses, and smiling attributes. + + http://www.skybiometry.com/Documentation#faces/detect + """ + if not urls and not file and not buffer: + raise AttributeError('Missing URLs/filename/buffer argument') + + data = {'attributes': 'all', 'force_reprocess_image': 'true'} + files = [] + buffers = [] + + if file: + # Check if the file exists + if not hasattr(file, 'read') and not os.path.exists(file): + raise IOError('File %s does not exist' % (file)) + + files.append(file) + elif buffer: + buffers.append(buffer) + else: + data['urls'] = urls + + if aggressive: + data['detector'] = 'aggressive' + + response = self.send_request('faces/detect', data, files, buffers) + return response + + def faces_status(self, uids=None, namespace=None): + """ + Reports training set status for the specified UIDs. + + http://www.skybiometry.com/Documentation#faces/status + """ + if not uids: + raise AttributeError('Missing user IDs') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) + + data = {'uids': uids} + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, namespace=namespace) + + response = self.send_request('faces/status', data) + return response + + def faces_recognize(self, uids=None, urls=None, file=None, buffer=None, aggressive=False, train=None, namespace=None): + """ + Attempts to detect and recognize one or more user IDs' faces, in one + or more photos. + For each detected face, the SkyBiometry engine will return the most likely + user IDs, or empty result for unrecognized faces. In addition, each + tag includes a threshold score - any score below this number is + considered a low-probability hit. + + http://www.skybiometry.com/Documentation#faces/recognize + """ + if not uids or (not urls and not file and not buffer): + raise AttributeError('Missing required arguments') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) + + data = {'uids': uids, 'attributes': 'all'} + files = [] + buffers = [] + + if file: + # Check if the file exists + if not hasattr(file, 'read') and not os.path.exists(file): + raise IOError('File %s does not exist' % (file)) + files.append(file) + elif buffer: + buffers.append(buffer) + else: + data.update({'urls': urls}) + + if aggressive: + data['detector'] = 'aggressive' + + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, train=train, namespace=namespace) + + response = self.send_request('faces/recognize', data, files, buffers) + return response + + def faces_train(self, uids=None, namespace=None): + """ + Calls the training procedure for the specified UIDs, and reports back + changes. + + http://www.skybiometry.com/Documentation#faces/train + """ + if not uids: + raise AttributeError('Missing user IDs') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) + + data = {'uids': uids} + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, namespace=namespace) + + response = self.send_request('faces/train', data) + return response + + ### Methods for managing face tags ### + def tags_get(self, uids=None, urls=None, pids=None, order='recent', limit=5, together=False, filter=None, namespace=None): + """ + Returns saved tags in one or more photos, or for the specified + User ID(s). + This method also accepts multiple filters for finding tags + corresponding to a more specific criteria such as front-facing, + recent, or where two or more users appear together in same photos. + + http://www.skybiometry.com/Documentation#tags/get + """ + if not uids and not urls: + raise AttributeError('Missing user IDs or URLs') + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uids) + + data = { 'together': 'true' if together else 'false', 'limit': limit } + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, uids=uids, urls=urls, pids=pids, filter=filter, namespace=namespace) + + response = self.send_request('tags/get', data) + return response + + def tags_add(self, url=None, x=None, y=None, width=None, uid=None, tagger_id=None, label=None, password=None): + """ + Add a (manual) face tag to a photo. Use this method to add face tags + where those were not detected for completeness of your service. + + http://www.skybiometry.com/Documentation#tags/add + """ + if not url or not x or not y or not width or not uid or not tagger_id: + raise AttributeError('Missing one of the required arguments') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uid) + + data = {'url': url, + 'x': x, + 'y': y, + 'width': width, + 'uid': uid, + 'tagger_id': tagger_id} + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, label=label, password=password) + + response = self.send_request('tags/add', data) + return response + + def tags_save(self, tids=None, uid=None, tagger_id=None, label=None, password=None): + """ + Saves a face tag. Use this method to save tags for training the + index, or for future use of the faces.detect and tags.get methods. + + http://www.skybiometry.com/Documentation#tags/save + """ + if not tids or not uid: + raise AttributeError('Missing required argument') + + (facebook_uids, twitter_uids) = self.__check_user_auth_credentials(uid) + + data = {'tids': tids, + 'uid': uid} + self.__append_user_auth_data(data, facebook_uids, twitter_uids) + self.__append_optional_arguments(data, tagger_id=tagger_id, label=label, password=password) + + response = self.send_request('tags/save', data) + return response + + def tags_remove(self, tids=None, password=None): + """ + Remove a previously saved face tag from a photo. + + http://www.skybiometry.com/Documentation#tags/remove + """ + if not tids: + raise AttributeError('Missing tag IDs') + + data = {'tids': tids} + + response = self.send_request('tags/remove', data) + return response + + ### Account management methods ### + def account_limits(self): + """ + Returns current rate limits for the account represented by the passed + API key and Secret. + + http://www.skybiometry.com/Documentation#account/limits + """ + response = self.send_request('account/limits') + return response['usage'] + + def account_users(self, namespaces=None): + """ + Returns current rate limits for the account represented by the passed + API key and Secret. + + http://www.skybiometry.com/Documentation#account/users + """ + if not namespaces: + raise AttributeError('Missing namespaces argument') + + response = self.send_request('account/users', { 'namespaces': namespaces }) + + return response + + def account_namespaces(self): + """ + Returns all valid data namespaces for user authorized by specified API key. + + http://www.skybiometry.com/Documentation#account/namespaces + """ + + response = self.send_request('account/namespaces') + + return response + + def __check_user_auth_credentials(self, uids): + # Check if needed credentials are provided + facebook_uids = [uid for uid in uids.split(',') if uid.find('@facebook.com') != -1] + twitter_uids = [uid for uid in uids.split(',') if uid.find('@twitter.com') != -1] + + if facebook_uids and not self.facebook_credentials: + raise AttributeError('You need to set Facebook credentials ' + + 'to perform action on Facebook users') + + if twitter_uids and not self.twitter_credentials: + raise AttributeError('You need to set Twitter credentials to ' + + 'perform action on Twitter users') + + return (facebook_uids, twitter_uids) + + def __append_user_auth_data(self, data, facebook_uids, twitter_uids): + if facebook_uids: + data.update({'user_auth': 'fb_user:%s,fb_session:%s,' + + 'fb_oauth_token:%s' % + (self.facebook_credentials['fb_user_id'], + self.facebook_credentials['fb_session_id'], + self.facebook_credentials['fb_oauth_token'])}) + + if twitter_uids: + data.update({'user_auth': + ('twitter_oauth_user:%s,twitter_oauth_secret:%s,' + 'twitter_oauth_token:%s' % + (self.twitter_credentials['twitter_oauth_user'], + self.twitter_credentials['twitter_oauth_secret'], + self.twitter_credentials['twitter_oauth_token']))}) + + def __append_optional_arguments(self, data, **kwargs): + for key, value in iteritems(kwargs): + if value: + data.update({key: value}) + + def send_request(self, method=None, parameters=None, files=None, buffers=None): + protocol = 'https://' if USE_SSL else 'http://' + url = '%s%s/%s.%s' % (protocol, API_HOST, method, self.format) + data = { 'api_key': self.api_key, 'api_secret': self.api_secret } + + if parameters: + data.update(parameters) + + # Local file is provided, use multi-part form + if files or buffers: + from multipart import Multipart + form = Multipart() + + for key, value in iteritems (data): + form.field(key, value) + + if files: + for i, file in enumerate(files, 1): + if hasattr(file, 'read'): + if hasattr(file, 'name'): + name = os.path.basename(file.name) + else: + name = 'attachment_%d' % i + close_file = False + else: + name = os.path.basename(file) + file = open(file, 'rb') + close_file = True + + try: + form.file(name, name, file.read()) + finally: + if close_file: + file.close() + else: + for i, buffer in enumerate(buffers, 1): + name = 'attachment_%d' % i + form.file(name, name, buffer) + (content_type, post_data) = form.get() + headers = {'Content-Type': content_type} + else: + print(data) + post_data = urlencode(data) + headers = {} + + + try: + r = requests.post(url, headers=headers, data=post_data) + response = r.text + except HTTPError as e: + response = e.response.text + + response_data = json.loads(response) + + if 'status' in response_data and response_data['status'] == 'failure': + raise FaceError(response_data['error_code'], response_data['error_message']) + + return response_data class FaceError(Exception): - def __init__(self, error_code, error_message): - self.error_code = error_code - self.error_message = error_message + def __init__(self, error_code, error_message): + self.error_code = error_code + self.error_message = error_message + + def __str__(self): + return '%s (%d)' % (self.error_message, self.error_code) - def __str__(self): - return '%s (%d)' % (self.error_message, self.error_code) diff --git a/setup.py b/setup.py index 7b812b2..8e13ea2 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ #!/usr/bin/env python import os import re -from distutils.core import setup +from setuptools import setup version_re = re.compile( r'__version__ = (\(.*?\))') @@ -29,8 +29,11 @@ url='http://github.com/Liuftvafas/python-face-client', download_url='http://github.com/Liuftvafas/python-face-client/', packages=['face_client'], - provides=['face_client'], - + provides=['face_client'], + install_requires=[ + 'requests', + 'future' + ], classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', From 193d23ab1bffbff19538321700c1b147647ac47c Mon Sep 17 00:00:00 2001 From: Matas Malickas Date: Fri, 12 Nov 2021 17:41:07 +0200 Subject: [PATCH 25/25] UPD: Multipart request Python 3.X compatibility. --- .gitignore | 3 +++ CHANGES | 4 ++++ face_client/__init__.py | 2 +- face_client/multipart.py | 9 ++++++++- 4 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f448e31 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +dist +face_client.egg-info \ No newline at end of file diff --git a/CHANGES b/CHANGES index da46944..b624ffc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +1.4 - 12.11.2021: + + - Added Multipart request Python 3.X compatibility + 1.3 - 02.02.2013: - Allow user to pass file-like object for the 'file' argument to the diff --git a/face_client/__init__.py b/face_client/__init__.py index 33b5cb5..e3248fd 100644 --- a/face_client/__init__.py +++ b/face_client/__init__.py @@ -1,3 +1,3 @@ -__version__ = (1, 2, 'dev') +__version__ = (1, 4, 'dev') from face_client import * diff --git a/face_client/multipart.py b/face_client/multipart.py index 836b968..31006ff 100644 --- a/face_client/multipart.py +++ b/face_client/multipart.py @@ -45,7 +45,14 @@ def __init__(self, name, filename, body, headers): self._headers = headers.copy() self._name = name self._filename = filename - self._body = body + + # If body is a byte string - decode it to a regular string. + # Required for Python 3.X compatibility as string handling has changed. + if filename and 'b\'' in str(body): + self._body = body.decode('latin') + else: + self._body = body + # We respect any content type passed in, but otherwise set it here. # We set the content disposition now, overwriting any prior value. if self._filename == None: