facer 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+ gemspec
3
+ gem 'multipart-post'
data/Manifest.txt ADDED
File without changes
data/README ADDED
@@ -0,0 +1,41 @@
1
+ This Gem is a very alpha version and is provided as is without any warranty.
2
+
3
+ I coded it as a convenient and easy interface to face.com's API for a project I'm working on and I must prepone some assumption on using it:
4
+
5
+ - you are a brave
6
+ - you will send images with only ONE recognizable face at time
7
+ - you expect some errors and bugs and have the bravery and patience to fix them
8
+
9
+ If those requirements are met, go on and use it. If not stop reading and trash the gem...
10
+
11
+ If you are reading this you are brave (or crazy).
12
+
13
+ A little example of usage:
14
+
15
+ linkr=Facer::Linker.new("yourapp","yourkey","yoursecret")
16
+ puts linkr.account.private_namespaces?.inspect
17
+ puts linkr.account.limits?.inspect
18
+
19
+ trainSet={
20
+ "vanessa_paradis" => [
21
+ "http://www.superiorpics.com/hs/vanessa_paradis/main1.jpg",
22
+ "http://nymag.com/daily/fashion/14_paradis_lgl.jpg",
23
+ "http://imstars.aufeminin.com/stars/fan/vanessa-paradis/vanessa-paradis-20060208-107457.jpg",
24
+ "http://www.realbeauty.com/cm/realbeauty/images/NF/rby-hair-vanessa-paradis-5-de.jpg",
25
+ "http://www.wallpaperweb.org/wallpaper/babes/1280x960/vanessa_paradis_20070722_0171_1280x960.jpg",
26
+ "http://chansons-fle.wikispaces.com/file/view/vanessa_paradis_reference.jpg/59524266/vanessa_paradis_reference.jpg"
27
+ ]
28
+ }
29
+
30
+ trainSet.each_pair do |key,value|
31
+ succ= linkr.faces.associate_multi(value,key,"yournamespace").inspect
32
+ puts "Associating #{key}: #{succ}"
33
+ end
34
+
35
+ puts linkr.faces.train_all("clinik").inspect
36
+
37
+ puts linkr.faces.recognize("http://static1.purepeople.com/articles/7/17/12/7/@/85769-vanessa-paradis-et-johnny-depp-637x0-1.jpg","yournamespace").inspect
38
+ puts linkr.faces.recognize("http://howzar.com/Galleries/Vanessa%20Paradis/vanessa-paradis-32.jpg","yournamespace").inspect
39
+ puts linkr.faces.recognize("http://pictures.directnews.co.uk/liveimages/Old+man+smiling_1500_19112072_0_0_7006461_300.jpg","yournamespace").inspect
40
+
41
+ Stefano Valicchia (stefano.valicchia@gmail.com)
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/lib/facer'
data/lib/facer.rb ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << './lib/facer'
3
+ require 'rubygems'
4
+ gem 'multipart-post'
5
+
6
+ require "net/http"
7
+ require "net/http/post/multipart"
8
+ require 'mime/types'
9
+ require "uri"
10
+ require "json"
11
+
12
+ require "linker"
13
+ require "namespace"
14
+ require "account"
15
+ require "faces"
16
+
17
+ # This class manage basilar operations on face.com.
18
+ # It's very alpha so you will find a very basical subset
19
+ # to use face.com services
20
+ # Author:: Stefano Valicchia (mailto:stefano.valicchiagmail.com)
21
+ # Copyright:: Copyright (c) 2002 Giano
22
+ # License:: Distributes under the same terms as Ruby
23
+ module Facer
24
+ VERSION = "0.0.3"
25
+ end
@@ -0,0 +1,54 @@
1
+ module Facer
2
+ # Base class to store security informations and obtain infos on the account
3
+ class Account
4
+ attr_reader :applicationName
5
+ attr_reader :apiKey
6
+ attr_reader :apiSecret
7
+
8
+ # Initialize the class passing a convenient linker reference
9
+ def initialize(linker, app_name,api_key,api_secret)
10
+ @linker=linker
11
+ @applicationName=applicationName
12
+ @apiKey=key
13
+ @apiSecret=secret
14
+ end
15
+
16
+ # Obtain all account's accessible namespaces
17
+ def namespaces?
18
+ t_namespaces=@linker.call("account","namespaces")
19
+ if(t_namespaces["status"].to_sym == :success)
20
+ out={}
21
+ t_namespaces["namespaces"].each do |namespace|
22
+ nm=Namespace.new(@linker,namespace["name"],namespace["size"],namespace["share_mode"].to_sym,namespace["owner"])
23
+ out[nm.name]=nm
24
+ end
25
+ return out
26
+ else
27
+ return {}
28
+ end
29
+ end
30
+
31
+ # Obtain all the namespaces owned by the account owner (public and private)
32
+ def owned_namespaces?
33
+ namespaces?.reject {|key,value| !value.owner}
34
+ end
35
+
36
+ # Obtain all account's private namespaces
37
+ def private_namespaces?
38
+ owned_namespaces?.reject {|key,value| value.shareMode!=:Private}
39
+ end
40
+
41
+ # Retrieve informations about current account's limits
42
+ def limits?
43
+ out=@linker.call("account","limits")
44
+ if(out["status"].to_sym == :success)
45
+ return out["usage"]
46
+ else
47
+ return nil
48
+ end
49
+ end
50
+
51
+ private
52
+ attr_accessor :linker
53
+ end
54
+ end
@@ -0,0 +1,107 @@
1
+ module Facer
2
+ # Base class to query the api on faces and tags info
3
+ # All the queries are in the "simplest form" of a single image/single user query
4
+ # In this version of the gem I assume to use "single face" images
5
+ # You can provide images as a file path or a public url, the library will treat them accordingly
6
+ class Faces
7
+ # Initialize the class passing a convenient linker reference
8
+ def initialize(linker)
9
+ @linker=linker
10
+ end
11
+
12
+ # Detect if the provided image contains a face and, if yes, return face's informations
13
+ def detect(image,detector = :Normal)
14
+ ret={}
15
+ if(URI.parse(image).is_a?(URI::HTTP))
16
+ ret=@linker.call("faces","detect",{"urls" => image, "detector" => detector.to_s})
17
+ else
18
+ ret=@linker.call("faces","detect",{"detector" => detector.to_s},{"upload" => image})
19
+ end
20
+ if(ret["status"].to_sym == :success && ret["photos"].length == 1)
21
+ return ret["photos"][0]
22
+ end
23
+ return nil
24
+ end
25
+
26
+ # Force train a user against the images/tags library
27
+ def train(user,namespace)
28
+ ret=@linker.call("faces","train",{"uids" => "#{user}@#{namespace}"})
29
+ return ret["status"].to_sym == :success
30
+ end
31
+
32
+ # Force train all users in a namespace (veeeery long operation)
33
+ def train_all(namespace)
34
+ namespaces=@linker.account.private_namespaces?
35
+ if(!namespaces || !namespaces[namespace])
36
+ return false
37
+ end
38
+ users=namespaces[namespace].users?
39
+ success=true
40
+ users.each do |user|
41
+ success &= train(user,namespace)
42
+ end
43
+ return success
44
+ end
45
+
46
+ # Attempt to recognize a user in a image end, if so, provide user and face infos
47
+ def recognize(image,namespace,users = "",detector = :Normal)
48
+ if(users.empty?)
49
+ users="all@#{namespace}"
50
+ end
51
+ ret={}
52
+ if(URI.parse(image).is_a?(URI::HTTP))
53
+ ret=@linker.call("faces","recognize",{"urls" => image, "uids" => users, "detector" => detector.to_s, "namespace" => namespace})
54
+ else
55
+ ret=@linker.call("faces","recognize",{"uids" => users, "detector" => detector.to_s, "namespace" => namespace},{"upload" => image})
56
+ end
57
+ if(ret["status"].to_sym == :success && ret["photos"].length == 1)
58
+ img=ret["photos"][0]
59
+ if(img["tags"].length == 1)
60
+ tag=img["tags"][0]
61
+ if(tag["uids"] && tag["uids"].length>0)
62
+ return tag["uids"][0]
63
+ else
64
+ return {"confidence" => 0, "uid" => nil}
65
+ end
66
+ else
67
+ return {"confidence" => -1, "uid" => nil}
68
+ end
69
+ end
70
+ return nil
71
+ end
72
+
73
+ # Associace many images to a user. I assume every images contains a single face
74
+ def associate_multi(images,user,namespace, force_train = false, detector = :Normal)
75
+ success=true
76
+ images.each do |image|
77
+ success &= associate(image,user,namespace,false,detector)
78
+ end
79
+ if(success && force_train)
80
+ return train(user,namespace)
81
+ end
82
+ return success
83
+ end
84
+
85
+ # Associace a face image to a user. I assume the image contains a single face
86
+ def associate(image,user,namespace, force_train = false, detector = :Normal)
87
+ img=detect(image,detector)
88
+ if(img && img["tags"].length == 1)
89
+ tag=img["tags"][0]
90
+ if(tag["attributes"]["face"] && tag["attributes"]["face"]["value"].to_s == "true")
91
+ tid=tag["tid"]
92
+ ret=@linker.call("tags","save",{"tids" => tid, "uid" => "#{user}@#{namespace}"})
93
+ if(ret["status"].to_sym == :success)
94
+ if(force_train)
95
+ return train(user,namespace)
96
+ end
97
+ return true
98
+ end
99
+ end
100
+ end
101
+ return false
102
+ end
103
+
104
+ private
105
+ attr_accessor :linker
106
+ end
107
+ end
@@ -0,0 +1,40 @@
1
+ module Facer
2
+ # Base class to store informations and obtain infos on the namespace
3
+ class Namespace
4
+ attr_reader :name
5
+ attr_reader :size
6
+ attr_reader :shareMode
7
+ attr_reader :owner
8
+
9
+ # Initialize the class passing a convenient linker reference and infos about the namespace
10
+ def initialize(linker,name,size,shareMode,owner)
11
+ @linker=linker
12
+ @name=name
13
+ @size=size
14
+ @shareMode=shareMode
15
+ @owner=owner
16
+ end
17
+
18
+ # Retrieve namespace's user list
19
+ def users?
20
+ if(@owner && @shareMode==:Private)
21
+ t_users=@linker.call("account","users",{"namespaces" => @name})
22
+ out=[]
23
+ if(t_users["status"].to_sym == :success)
24
+ t_users["users"].each_pair do |key,namespace_users|
25
+ out+=namespace_users
26
+ end
27
+ return out
28
+ else
29
+ return []
30
+ end
31
+ else
32
+ return []
33
+ end
34
+ namespaces?.reject {|key,value| !value.owner}
35
+ end
36
+
37
+ private
38
+ attr_accessor :linker
39
+ end
40
+ end
data/lib/linker.rb ADDED
@@ -0,0 +1,52 @@
1
+ require "net/http"
2
+ require "net/http/post/multipart"
3
+ require 'mime/types'
4
+ require "uri"
5
+ require "json"
6
+ module Facer
7
+
8
+ # This class hold the main linkage to face.com
9
+ # acting as a gateway to subclasses
10
+ class Linker
11
+ # The main uri to face.com api.
12
+ FaceComURI="http://api.face.com/"
13
+
14
+ attr_reader :account
15
+ attr_reader :faces
16
+
17
+ # Initialize the linker with security informations
18
+ def initialize(applicationName,key,secret)
19
+ @account=Account.new(self,applicationName,key,secret)
20
+ @faces=Faces.new(self)
21
+ end
22
+
23
+ # Call the service appending security informations to every request
24
+ def call(bclass,method,params = {},files = nil)
25
+ params ||={}
26
+ params["api_key"]=@account.apiKey
27
+ params["api_secret"]=@account.apiSecret
28
+ resp=callAPI(bclass,method,params,files)
29
+ return resp
30
+ end
31
+
32
+ private
33
+ # Call the service using post or multiform data for sending files and transpose to json the response
34
+ def callAPI(bclass,method,params,files)
35
+ uri=URI.parse("#{FaceComURI}#{bclass}/#{method}.json")
36
+ params ||= {}
37
+ if(files)
38
+ files.each_pair do |name,path|
39
+ params[name]=UploadIO.new(path, MIME::Types.type_for(path))
40
+ end
41
+ req = Net::HTTP::Post::Multipart.new(uri.path,params)
42
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
43
+ http.request(req)
44
+ end
45
+ return JSON.parse(res.body)
46
+ else
47
+ res = Net::HTTP.post_form(uri,params)
48
+ return JSON.parse(res.body)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+
3
+ class MimetypeFuTest < Test::Unit::TestCase
4
+ # Replace this with your real tests.
5
+ def test_this_plugin
6
+ flunk
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: facer
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 3
10
+ version: 0.0.3
11
+ platform: ruby
12
+ authors:
13
+ - Stefano Valicchia
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-11 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: multipart-post
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 21
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 1
34
+ version: 1.0.1
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: json
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 11
46
+ segments:
47
+ - 1
48
+ - 4
49
+ - 6
50
+ version: 1.4.6
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ description: Simple wrapper for face.com api.
54
+ email: stefano.valicchia@gmail.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files:
60
+ - Gemfile
61
+ - Manifest.txt
62
+ - README
63
+ files:
64
+ - lib/facer/account.rb
65
+ - lib/facer/faces.rb
66
+ - lib/facer/namespace.rb
67
+ - lib/facer.rb
68
+ - lib/linker.rb
69
+ - init.rb
70
+ - Manifest.txt
71
+ - Gemfile
72
+ - README
73
+ - test/facer_test.rb
74
+ has_rdoc: true
75
+ homepage:
76
+ licenses: []
77
+
78
+ post_install_message:
79
+ rdoc_options:
80
+ - --title
81
+ - Facer
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ requirements:
103
+ - The gem uses multipart-post gem and JSON gem
104
+ rubyforge_project:
105
+ rubygems_version: 1.4.1
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Wrapper for face.com API.
109
+ test_files:
110
+ - test/facer_test.rb