From 984d590da72f30a8d98ef068b0fdfb83a9b1f342 Mon Sep 17 00:00:00 2001 From: Justas Kranauskas Date: Sat, 2 Feb 2013 14:12:51 +0200 Subject: [PATCH 01/18] 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 02/18] 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 03/18] 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 04/18] 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 05/18] 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 06/18] 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 07/18] 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 08/18] 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 09/18] 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 10/18] 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 11/18] 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 12/18] 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 13/18] 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 14/18] 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 15/18] 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 16/18] 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 17/18] 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 18/18] 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: