File Coverage

blib/lib/WebService/Face/Client.pm
Criterion Covered Total %
statement 24 132 18.1
branch 0 10 0.0
condition 0 25 0.0
subroutine 8 23 34.7
pod 13 13 100.0
total 45 203 22.1


line stmt bran cond sub pod time code
1             package WebService::Face::Client;
2              
3 6     6   168335 use 5.006;
  6         26  
  6         253  
4 6     6   34 use strict;
  6         13  
  6         227  
5 6     6   28 use warnings;
  6         17  
  6         175  
6 6     6   30 use Carp;
  6         13  
  6         587  
7              
8 6     6   3380 use WebService::Face::Response;
  6         18  
  6         253  
9 6     6   46 use WebService::Face::Response::Tag;
  6         9  
  6         125  
10 6     6   7340 use JSON;
  6         119341  
  6         37  
11 6     6   6751 use REST::Client;
  6         468477  
  6         19370  
12              
13             =head1 NAME
14              
15             WebService::Face::Client - Client to the Face.com REST API
16              
17             =head1 VERSION
18              
19             Version 0.04
20              
21             =cut
22              
23             our $VERSION = '0.04';
24              
25             =head1 SYNOPSIS
26              
27             ******************* Caution : Work in progress !!! ******************
28              
29             The API isn't fully covered, the module is barely usable yet.
30              
31             API change : All params now passed through hashref (for consistency)
32              
33             faces_xxxt() methods
34             tags_xxx() methods
35             account_xxx() methods
36            
37             now require a hashref as parameter
38              
39             *********************************************************************
40              
41             This module aims to provide a high-level interface to
42             the Face.com face recognition REST API.
43              
44              
45             Face recognition scenario :
46              
47             # First submit pictures
48             @tags = $client->faces_detect(urls => "http://img.clubic.com/03520176-photo-kevin-polizzi-fondateur-jaguar-network.jpg,http://media.linkedin.com/mpr/pub/image-ydXbyfluDqrF4odQH8fDyBF07ONcpJdQHNaYyXk1s4K8Dk6Q/kevin-polizzi.jpg,http://experts-it.fr/files/2011/01/Jaguar-Kevin-Polizzi.jpg,http://www.jaguar-network.com/jn/templates/images/img57.jpg");
49            
50             # Then save the tags id with the associated user id
51             my $ids = join ",", map {$_->tid} @tags;
52             my @st = $client->tags_save(tids => $ids,uid => 'kevin.polizzi@face-client-perl');
53              
54             # Train for the use
55             $client->faces_train(uids => 'kevin.polizzi@face-client-perl');
56              
57             # From now on, you can try to recognize user on urL
58             @tags = $client->faces_recognize(urls => "http://img.clubic.com/03520176-photo-kevin-polizzi-fondateur-jaguar-network.jpg", uids => 'kevin.polizzi@face-client-perl');
59             if ($tags[0]->recognized) {
60             ...
61             }
62              
63             For more information about the API see :
64              
65             =over 4
66              
67             =item *
68              
69             =item *
70              
71             =item *
72              
73             =item *
74              
75             =item *
76              
77             =back
78              
79             =head1 SUBROUTINES/METHODS
80              
81             =head2 new ( \%params )
82              
83             Constructor for the WebService::Face::Client class
84              
85             Valid keys for %params are currently :
86             server Server providing the REST service (default to 'http://api.face.com')
87             api_key Credential to be used while connecting to the Face's service (see: http://developers.face.com/account/)
88             api_secret Credential to be used while connecting to the Face's service (see: http://developers.face.com/account/)
89              
90             =cut
91              
92             sub new {
93 0     0 1   my $class = shift;
94 0   0       my $params = shift || {};
95              
96 0           my $self = bless {}, $class;
97 0           $self->{server} = 'http://api.face.com';
98 0           $self->{api_key} = $ENV{'FACE_API_KEY'};
99 0           $self->{api_secret} = $ENV{'FACE_API_SECRET'};
100              
101 0           for my $key ( keys %$params ) {
102 0 0         if ( $key =~ /^api_key$/i ) {
103 0           $self->{'api_key'} = $params->{$key};
104 0           next;
105             }
106 0 0         if ( $key =~ /^api_secret$/i ) {
107 0           $self->{'api_secret'} = $params->{$key};
108 0           next;
109             }
110 0           carp("Unknown parameter $key");
111 0           return undef;
112             }
113              
114 0 0 0       die "No API credentials provided"
115             unless $self->{api_key} and $self->{api_secret};
116              
117 0           $self->{rest} = REST::Client->new();
118              
119             # Automatically follow redirect
120 0           $self->{rest}->setFollow(1);
121 0           $self->{rest}->setHost( $self->{server} );
122              
123             # $self->set_header(Authorization => "Basic $creds");
124             # $self->set_header(Accept => "application/json");
125              
126 0           return $self;
127             }
128              
129             =head2 faces_detect ( \%params )
130              
131             Returns tags for detected faces in one or more photos, with geometric information of the tag, eyes, nose and mouth, as well as various attributes such as gender, is wearing glasses, and is smiling.
132              
133             Photos can also be uploaded directly in the API request. A requests that uploads a photo must be formed as a MIME multi-part message sent using POST data. Each argument, including the raw image data, should be specified as a separate chunk of form data.
134              
135             More information : http://developers.face.com/docs/api/faces-detect/
136              
137             =cut
138              
139             sub faces_detect {
140 0     0 1   my $self = shift;
141 0   0       my $params = shift || {};
142              
143 0           my $parameters = '';
144              
145 0           for my $key ( keys %$params ) {
146 0           $parameters .= "&$key=" . $params->{$key};
147             }
148              
149 0           return $self->_process_response( 'GET', "/faces/detect.json?" . $self->_get_credential_parameters() . $parameters );
150             }
151              
152             =head2 faces_train ( \%params )
153              
154             Calls the training procedure for the specified UIDs, and reports back changes.
155              
156             The training procedure uses information from previous tags.save calls to build a training set for the specified UIDs. For Facebook UIDs, you can skip the tags.save stage and call faces.train directly - we will use the passed credentials to create a training set from the users' tagged photos on Facebook.
157              
158             More information : http://developers.face.com/docs/api/faces-train/
159              
160             =cut
161              
162             sub faces_train {
163 0     0 1   my $self = shift;
164 0   0       my $params = shift || {};
165              
166 0           my $parameters = '';
167              
168 0           for my $key ( keys %$params ) {
169 0           $parameters .= "&$key=" . $params->{$key};
170             }
171              
172 0           return $self->_process_response( 'GET', "/faces/train.json?" . $self->_get_credential_parameters() . $parameters );
173             }
174              
175             =head2 faces_recognize ( \%params )
176              
177             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.
178              
179             You can also save the recognized faces by calling tags.save with the returned temporary tag id (tid), along with the relevant user ID. Saving tags is also the way to train the platform how users look like, for later calls to faces.recognize.
180              
181             The first step in recognition is face detection, which is applied automatically for each photo sent for recognition. Therefor these calls generally use the same tag output with the addition of recognized user IDs (see faces.detect for more details and usage notes).
182              
183             In addition, when passing specific uids, (not special list as "friends" and "all"), we will return a list of uids that have no train set, and there for cannot be recognized, under "no_training_set" list.
184              
185             Photos can also be uploaded directly in the API request. A requests that uploads a photo must be formed as a MIME multi-part message sent using POST data. Each argument, including the raw image data, should be specified as a separate chunk of form data.
186              
187             More information : http://developers.face.com/docs/api/faces-recognize/
188              
189             =cut
190              
191             sub faces_recognize {
192 0     0 1   my $self = shift;
193 0   0       my $params = shift || {};
194              
195 0           my $parameters = '';
196              
197 0           for my $key ( keys %$params ) {
198 0           $parameters .= "&$key=" . $params->{$key};
199             }
200              
201 0           return $self->_process_response( 'GET', "/faces/recognize.json?" . $self->_get_credential_parameters() . $parameters );
202             }
203              
204             =head2 faces_status ( \%params )
205              
206             Reports training set status for the specified UIDs.
207              
208             This method only reports the status of the current training-set status, and does not change it. To improve, or create training set for a uid, use faces.train.
209              
210             More information : http://developers.face.com/docs/api/faces-status/
211              
212             =cut
213              
214             sub faces_status {
215 0     0 1   my $self = shift;
216 0   0       my $params = shift || {};
217              
218 0           my $parameters = '';
219              
220 0           for my $key ( keys %$params ) {
221 0           $parameters .= "&$key=" . $params->{$key};
222             }
223              
224 0           return $self->_process_response( 'GET', "/faces/status.json?" . $self->_get_credential_parameters() . $parameters );
225             }
226              
227             =head2 tags_add ( \%params )
228              
229             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. Manual tags are treated like automatic tags, except they are not used to train the system how a user looks like. See the tags.save method to learn how to save automatic face tags for recognition purposes.
230              
231             More information : http://developers.face.com/docs/api/tags-add/
232              
233             =cut
234              
235             sub tags_add {
236 0     0 1   my $self = shift;
237 0   0       my $params = shift || {};
238              
239 0           my $parameters = '';
240              
241 0           for my $key ( keys %$params ) {
242 0           $parameters .= "&$key=" . $params->{$key};
243             }
244              
245 0           return $self->_process_response( 'GET', "/tags/add.json?" . $self->_get_credential_parameters() . $parameters );
246             }
247              
248             =head2 tags_remove ( \%params )
249              
250             Remove a previously saved face tag from a photo.
251              
252             More information : http://developers.face.com/docs/api/tags-remove/
253              
254             =cut
255              
256             sub tags_remove {
257 0     0 1   my $self = shift;
258 0   0       my $params = shift || {};
259              
260 0           my $parameters = '';
261              
262 0           for my $key ( keys %$params ) {
263 0           $parameters .= "&$key=" . $params->{$key};
264             }
265              
266 0           return $self->_process_response( 'GET', "/tags/remove.json?" . $self->_get_credential_parameters() . $parameters );
267             }
268              
269             =head2 tags_get ( \%params )
270              
271             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.
272              
273             Photos can also be uploaded directly in the API request. A requests that uploads a photo must be formed as a MIME multi-part message sent using POST data. Each argument, including the raw image data, should be specified as a separate chunk of form data.
274              
275             More information : http://developers.face.com/docs/api/tags-get/
276              
277             =cut
278              
279             sub tags_get {
280 0     0 1   my $self = shift;
281 0           my $params = shift;
282              
283 0           my $parameters = '';
284              
285 0           for my $key ( keys %$params ) {
286 0           $parameters .= "&$key=" . $params->{$key};
287             }
288              
289 0           return $self->_process_response( 'GET', "/tags/get.json?" . $self->_get_credential_parameters() . $parameters );
290             }
291              
292             =head2 tags_save ( \%params )
293              
294             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.
295              
296             This method accepts 2 primary parameters: User ID (uid) and a list of one or more Tag IDs (tids). The uid field represents a single user ID to associate with the saved tags with, while the tids is a list of tag ids previously acquired through calls to faces.detect or faces.recognize. When photos are processed through the detect and recognize methods, their response includes temporary tag IDs for use in subsequent tags.save calls. The temporary tag IDs are replaced with permanent tag IDs after calling the tags.save method, and are returned in the method's response for future reference.
297              
298             More information : http://developers.face.com/docs/api/tags-save/
299              
300             =cut
301              
302             sub tags_save {
303 0     0 1   my $self = shift;
304 0   0       my $params = shift || {};
305              
306 0           my $parameters = '';
307              
308 0           for my $key ( keys %$params ) {
309 0           $parameters .= "&$key=" . $params->{$key};
310             }
311              
312 0           $self->_process_response( 'GET', "/tags/save.json?" . $self->_get_credential_parameters() . $parameters );
313              
314 0           return $self->response->saved_tags;
315             }
316              
317             =head2 account_limits ( \%params )
318              
319             Returns current rate limits for the account represented by the passed API key and Secret.
320              
321             More information : http://developers.face.com/docs/api/account-limits/
322              
323             =cut
324              
325             sub account_limits {
326 0     0 1   my $self = shift;
327 0   0       my $params = shift || {};
328              
329 0           my $parameters = '';
330              
331 0           for my $key ( keys %$params ) {
332 0           $parameters .= "&$key=" . $params->{$key};
333             }
334              
335 0           $self->_process_response( 'GET', "/account/limits.json?" . $self->_get_credential_parameters() . $parameters );
336              
337 0           return $self->response->account;
338             }
339              
340             =head2 account_users ( \%params )
341              
342             Returns current users registered in the account's private namespaces. Users in a private namespace get registered implicitly through tags.save calls.
343              
344             More information : http://developers.face.com/docs/api/account-users/
345              
346             =cut
347              
348             sub account_users {
349 0     0 1   my $self = shift;
350 0   0       my $params = shift || {};
351              
352 0           my $parameters = '';
353              
354 0           for my $key ( keys %$params ) {
355 0           $parameters .= "&$key=" . $params->{$key};
356             }
357              
358 0           $self->_process_response( 'GET', "/account/users.json?" . $self->_get_credential_parameters() . $parameters );
359              
360 0           return $self->response->account->users;
361             }
362              
363             =head2 account_namespaces ( \%params )
364              
365             Returns all authorized namespaces that given api_key can use with the API.
366              
367             Authorized namespaces can be:
368              
369             =over 4
370              
371             =item * Namespace owned by the owner of the api_key.
372              
373             =item * Namespace defined as Public or Public Read only by other users
374              
375             =item * Special Public Namespace: Facebook and Twitter
376              
377             =back
378              
379             More information : http://developers.face.com/docs/api/account-namespaces/
380              
381             =cut
382              
383             sub account_namespaces {
384 0     0 1   my $self = shift;
385 0   0       my $params = shift || {};
386              
387 0           my $parameters = '';
388              
389 0           for my $key ( keys %$params ) {
390 0           $parameters .= "&$key=" . $params->{$key};
391             }
392              
393 0           $self->_process_response( 'GET', "/account/namespaces.json?" . $self->_get_credential_parameters() . $parameters );
394              
395 0           return $self->response->account->namespaces;
396             }
397              
398             =head2 _get_credential_parameters ()
399              
400             Return the query string part with credentials api_key and api_secret
401              
402             =cut
403              
404             sub _get_credential_parameters {
405 0     0     my $self = shift;
406              
407 0           return "&api_key=" . $self->{api_key} . "&api_secret=" . $self->{api_secret};
408             }
409              
410             =head2 _process_response ( $method, $url )
411              
412             Query a remote URL and process the server's response (json) and convert it to a WebService::Face::Response object
413              
414             Currently only GET method is handled
415              
416             =cut
417              
418             sub _process_response {
419 0     0     my $self = shift;
420 0           my $method = shift;
421 0           my $url = shift;
422              
423 0           my @responses;
424             my @tags;
425              
426 0 0         if ( $method eq 'GET' ) {
427 0           $self->{rest}->GET($url);
428             }
429              
430 0           my $response = decode_json( $self->{rest}->responseContent );
431              
432 0 0         if ( ref $response !~ /^HASH/ ) {
433 0           croak "Invalid response ($response)";
434             }
435              
436 0           $self->{response} = WebService::Face::Response->new($response);
437              
438 0           for my $photo ( $self->response->photos() ) {
439 0           for my $tag ( $photo->tags() ) {
440 0           push @tags, $tag;
441             }
442             }
443              
444 0           return @tags;
445             # return @responses;
446             }
447              
448             =head2 response ()
449              
450             Getter for the 'response' attribute
451              
452             =cut
453              
454             sub response {
455 0     0 1   my $self = shift;
456              
457 0           return $self->{response};
458             }
459              
460             =head1 AUTHOR
461              
462             Arnaud (Arhuman) ASSAD, C<< >>
463              
464             =head1 BUGS
465              
466             Please report any bugs or feature requests to C< arhuman at gmail.com>, or through
467             the web interface at L. I will be notified, and then you'll
468             automatically be notified of progress on your bug as I make changes.
469              
470             =head1 SUPPORT
471              
472             You can find documentation for this module with the perldoc command.
473              
474             perldoc WebService::Face::Client
475              
476             You can also look for information at:
477              
478             =over 4
479              
480             =item * Github repository
481              
482             L
483              
484             =item * AnnoCPAN: Annotated CPAN documentation
485              
486             L
487              
488             =item * CPAN Ratings
489              
490             L
491              
492             =back
493              
494             More information about Face.com service :
495              
496             L
497              
498             =head1 ACKNOWLEDGEMENTS
499              
500             Thanks to Face.com for the service they provide.
501             Thanks to Jaguar Network for allowing me to publish my work.
502              
503             =head1 LICENSE AND COPYRIGHT
504              
505             Copyright 2012 Arnaud (Arhuman) ASSAD.
506              
507             This program is free software; you can redistribute it and/or modify it
508             under the terms of either: the GNU General Public License as published
509             by the Free Software Foundation; or the Artistic License.
510              
511             See http://dev.perl.org/licenses/ for more information.
512              
513             =cut
514              
515             1;