recombee_api_client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +157 -0
  5. data/Rakefile +6 -0
  6. data/lib/recombee_api_client/api/add_bookmark.rb +70 -0
  7. data/lib/recombee_api_client/api/add_cart_addition.rb +70 -0
  8. data/lib/recombee_api_client/api/add_detail_view.rb +73 -0
  9. data/lib/recombee_api_client/api/add_group.rb +53 -0
  10. data/lib/recombee_api_client/api/add_item.rb +56 -0
  11. data/lib/recombee_api_client/api/add_item_property.rb +59 -0
  12. data/lib/recombee_api_client/api/add_purchase.rb +70 -0
  13. data/lib/recombee_api_client/api/add_rating.rb +73 -0
  14. data/lib/recombee_api_client/api/add_series.rb +53 -0
  15. data/lib/recombee_api_client/api/add_user.rb +54 -0
  16. data/lib/recombee_api_client/api/batch.rb +64 -0
  17. data/lib/recombee_api_client/api/delete_bookmark.rb +61 -0
  18. data/lib/recombee_api_client/api/delete_cart_addition.rb +61 -0
  19. data/lib/recombee_api_client/api/delete_detail_view.rb +61 -0
  20. data/lib/recombee_api_client/api/delete_group.rb +56 -0
  21. data/lib/recombee_api_client/api/delete_item.rb +58 -0
  22. data/lib/recombee_api_client/api/delete_item_property.rb +54 -0
  23. data/lib/recombee_api_client/api/delete_purchase.rb +61 -0
  24. data/lib/recombee_api_client/api/delete_rating.rb +61 -0
  25. data/lib/recombee_api_client/api/delete_series.rb +56 -0
  26. data/lib/recombee_api_client/api/delete_user.rb +56 -0
  27. data/lib/recombee_api_client/api/get_item_property_info.rb +54 -0
  28. data/lib/recombee_api_client/api/get_item_values.rb +55 -0
  29. data/lib/recombee_api_client/api/insert_to_group.rb +69 -0
  30. data/lib/recombee_api_client/api/insert_to_series.rb +72 -0
  31. data/lib/recombee_api_client/api/item_based_recommendation.rb +131 -0
  32. data/lib/recombee_api_client/api/list_group_items.rb +53 -0
  33. data/lib/recombee_api_client/api/list_groups.rb +50 -0
  34. data/lib/recombee_api_client/api/list_item_bookmarks.rb +54 -0
  35. data/lib/recombee_api_client/api/list_item_cart_additions.rb +54 -0
  36. data/lib/recombee_api_client/api/list_item_detail_views.rb +54 -0
  37. data/lib/recombee_api_client/api/list_item_properties.rb +51 -0
  38. data/lib/recombee_api_client/api/list_item_purchases.rb +54 -0
  39. data/lib/recombee_api_client/api/list_item_ratings.rb +54 -0
  40. data/lib/recombee_api_client/api/list_items.rb +63 -0
  41. data/lib/recombee_api_client/api/list_series.rb +50 -0
  42. data/lib/recombee_api_client/api/list_series_items.rb +53 -0
  43. data/lib/recombee_api_client/api/list_user_bookmarks.rb +53 -0
  44. data/lib/recombee_api_client/api/list_user_cart_additions.rb +53 -0
  45. data/lib/recombee_api_client/api/list_user_detail_views.rb +53 -0
  46. data/lib/recombee_api_client/api/list_user_purchases.rb +53 -0
  47. data/lib/recombee_api_client/api/list_user_ratings.rb +53 -0
  48. data/lib/recombee_api_client/api/list_users.rb +50 -0
  49. data/lib/recombee_api_client/api/merge_users.rb +72 -0
  50. data/lib/recombee_api_client/api/remove_from_group.rb +59 -0
  51. data/lib/recombee_api_client/api/remove_from_series.rb +62 -0
  52. data/lib/recombee_api_client/api/request.rb +7 -0
  53. data/lib/recombee_api_client/api/reset_database.rb +51 -0
  54. data/lib/recombee_api_client/api/set_item_values.rb +70 -0
  55. data/lib/recombee_api_client/api/user_based_recommendation.rb +116 -0
  56. data/lib/recombee_api_client/errors.rb +44 -0
  57. data/lib/recombee_api_client/version.rb +3 -0
  58. data/lib/recombee_api_client.rb +105 -0
  59. data/recombee_api_client.gemspec +26 -0
  60. metadata +173 -0
@@ -0,0 +1,59 @@
1
+ #
2
+ # This file is auto-generated, do not edit
3
+ #
4
+
5
+ module RecombeeApiClient
6
+ require_relative 'request'
7
+ require_relative '../errors'
8
+
9
+ ##
10
+ #Removes an existing group item from the group.
11
+ class RemoveFromGroup < ApiRequest
12
+ attr_reader :group_id, :item_type, :item_id
13
+ attr_accessor :timeout
14
+
15
+ ##
16
+ # * *Required arguments*
17
+ # - +group_id+ -> ID of the group from which a group item is to be removed.
18
+ # - +item_type+ -> Type of the item to be removed.
19
+ # - +item_id+ -> ID of the item iff `itemType` is `item`. ID of the group iff `itemType` is `group`.
20
+ #
21
+ def initialize(group_id, item_type, item_id)
22
+ @group_id = group_id
23
+ @item_type = item_type
24
+ @item_id = item_id
25
+ @timeout = 1000
26
+ end
27
+
28
+ # HTTP method
29
+ def method
30
+ :delete
31
+ end
32
+
33
+ # Values of body parameters as a Hash
34
+ def body_parameters
35
+ p = Hash.new
36
+ p
37
+ end
38
+
39
+ # Values of query path parameters as a Hash.
40
+ # name of parameter => value of the parameter
41
+ def query_parameters
42
+ params = {}
43
+ params['itemType'] = @item_type
44
+ params['itemId'] = @item_id
45
+ params
46
+ end
47
+
48
+ # Relative path to the endpoint
49
+ def basic_path
50
+ "/{databaseId}/groups/#{@group_id}/items/"
51
+ end
52
+
53
+ # Relative path to the endpoint including query parameters
54
+ def path
55
+ p = "/{databaseId}/groups/#{@group_id}/items/?itemType=#{@item_type}&itemId=#{@item_id}"
56
+ p
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,62 @@
1
+ #
2
+ # This file is auto-generated, do not edit
3
+ #
4
+
5
+ module RecombeeApiClient
6
+ require_relative 'request'
7
+ require_relative '../errors'
8
+
9
+ ##
10
+ #Removes an existing series item from the series.
11
+ class RemoveFromSeries < ApiRequest
12
+ attr_reader :series_id, :item_type, :item_id, :time
13
+ attr_accessor :timeout
14
+
15
+ ##
16
+ # * *Required arguments*
17
+ # - +series_id+ -> ID of the series from which a series item is to be removed.
18
+ # - +item_type+ -> Type of the item to be removed.
19
+ # - +item_id+ -> ID of the item iff `itemType` is `item`. ID of the series iff `itemType` is `series`.
20
+ # - +time+ -> Time index of the item to be removed.
21
+ #
22
+ def initialize(series_id, item_type, item_id, time)
23
+ @series_id = series_id
24
+ @item_type = item_type
25
+ @item_id = item_id
26
+ @time = time
27
+ @timeout = 1000
28
+ end
29
+
30
+ # HTTP method
31
+ def method
32
+ :delete
33
+ end
34
+
35
+ # Values of body parameters as a Hash
36
+ def body_parameters
37
+ p = Hash.new
38
+ p
39
+ end
40
+
41
+ # Values of query path parameters as a Hash.
42
+ # name of parameter => value of the parameter
43
+ def query_parameters
44
+ params = {}
45
+ params['itemType'] = @item_type
46
+ params['itemId'] = @item_id
47
+ params['time'] = @time
48
+ params
49
+ end
50
+
51
+ # Relative path to the endpoint
52
+ def basic_path
53
+ "/{databaseId}/series/#{@series_id}/items/"
54
+ end
55
+
56
+ # Relative path to the endpoint including query parameters
57
+ def path
58
+ p = "/{databaseId}/series/#{@series_id}/items/?itemType=#{@item_type}&itemId=#{@item_id}&time=#{@time}"
59
+ p
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,7 @@
1
+ module RecombeeApiClient
2
+ ##
3
+ # Parent class for API requests
4
+ #
5
+ class ApiRequest
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ #
2
+ # This file is auto-generated, do not edit
3
+ #
4
+
5
+ module RecombeeApiClient
6
+ require_relative 'request'
7
+ require_relative '../errors'
8
+
9
+ ##
10
+ #Completely erases all your data, including items, item properties, series, user database, purchases, ratings, detail views, and bookmarks. Make sure the request to be never executed in production environment! Resetting your database is irreversible.
11
+ #
12
+ class ResetDatabase < ApiRequest
13
+
14
+ attr_accessor :timeout
15
+
16
+ ##
17
+ #
18
+ def initialize()
19
+ @timeout = 3000
20
+ end
21
+
22
+ # HTTP method
23
+ def method
24
+ :delete
25
+ end
26
+
27
+ # Values of body parameters as a Hash
28
+ def body_parameters
29
+ p = Hash.new
30
+ p
31
+ end
32
+
33
+ # Values of query path parameters as a Hash.
34
+ # name of parameter => value of the parameter
35
+ def query_parameters
36
+ params = {}
37
+ params
38
+ end
39
+
40
+ # Relative path to the endpoint
41
+ def basic_path
42
+ "/{databaseId}/"
43
+ end
44
+
45
+ # Relative path to the endpoint including query parameters
46
+ def path
47
+ p = "/{databaseId}/"
48
+ p
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,70 @@
1
+ #
2
+ # This file is auto-generated, do not edit
3
+ #
4
+
5
+ module RecombeeApiClient
6
+ require_relative 'request'
7
+ require_relative '../errors'
8
+
9
+ ##
10
+ #Set/update (some) property values of a given item.
11
+ #
12
+ class SetItemValues < ApiRequest
13
+ attr_reader :item_id, :values
14
+ attr_accessor :timeout
15
+
16
+ ##
17
+ # * *Required arguments*
18
+ # - +item_id+ -> ID of the item which will be modified.
19
+ #
20
+ # - +values+ -> The values for the individual properties.
21
+ #
22
+ #Example of body:
23
+ #```
24
+ # {
25
+ # "string_property": "strvalue",
26
+ # "integer_property": 42,
27
+ # "!cascadeCreate": true
28
+ # }
29
+ #```
30
+ #
31
+ #Special parameter `!cascadeCreate` may be used. It indicates that the item of the given itemId should be created if it does not exist in the database, as if the corresponding PUT method was used. Note the exclamation mark (!) at the beginning of the parameter's name to distinguish it from item property names.
32
+ #
33
+ #
34
+ def initialize(item_id, values)
35
+ @item_id = item_id
36
+ @values = values
37
+ @timeout = 1000
38
+ end
39
+
40
+ # HTTP method
41
+ def method
42
+ :post
43
+ end
44
+
45
+ # Values of body parameters as a Hash
46
+ def body_parameters
47
+ p = Hash.new
48
+ p = p.merge(@values)
49
+ p
50
+ end
51
+
52
+ # Values of query path parameters as a Hash.
53
+ # name of parameter => value of the parameter
54
+ def query_parameters
55
+ params = {}
56
+ params
57
+ end
58
+
59
+ # Relative path to the endpoint
60
+ def basic_path
61
+ "/{databaseId}/items/#{@item_id}"
62
+ end
63
+
64
+ # Relative path to the endpoint including query parameters
65
+ def path
66
+ p = "/{databaseId}/items/#{@item_id}"
67
+ p
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,116 @@
1
+ #
2
+ # This file is auto-generated, do not edit
3
+ #
4
+
5
+ module RecombeeApiClient
6
+ require_relative 'request'
7
+ require_relative '../errors'
8
+
9
+ ##
10
+ #Based on user's past interactions (purchases, ratings, etc.) with the items, recommends top-N items that are most likely to be of high value for a given user.
11
+ #
12
+ class UserBasedRecommendation < ApiRequest
13
+ attr_reader :user_id, :count, :filter, :booster, :allow_nonexistent, :diversity, :min_relevance, :rotation_rate, :rotation_time
14
+ attr_accessor :timeout
15
+
16
+ ##
17
+ # * *Required arguments*
18
+ # - +user_id+ -> ID of the user whose personalized recommendations are to be generated.
19
+ # - +count+ -> Number of items to be recommended (N for the top-N recommendation).
20
+ #
21
+ # * *Optional arguments (given as hash optional)*
22
+ # - +filter+ -> Boolean-returning [ReQL](https://docs.recombee.com/reql.html) expression which allows you to filter recommended items based on the values of their attributes.
23
+ # - +booster+ -> Number-returning [ReQL](https://docs.recombee.com/reql.html) expression which allows you to boost recommendation rate of some items based on the values of their attributes.
24
+ # - +allowNonexistent+ -> If the user does not exist in the database, returns a list of non-personalized recommendations instead of causing HTTP 404 error.
25
+ # - +diversity+ -> **Expert option** Real number from [0.0, 1.0] which determines how much mutually dissimilar should the recommended items be. The default value is 0.0, i.e., no diversification. Value 1.0 means maximal diversification.
26
+ #
27
+ # - +minRelevance+ -> **Expert option** Specifies the threshold of how much relevant must the recommended items be to the user. Possible values one of: "low", "medium", "high". The default value is "low", meaning that the system attempts to recommend number of items equal to *count* at any cost. If there are not enough data (such as interactions or item properties), this may even lead to bestseller-based recommendations to be appended to reach the full *count*. This behavior may be suppressed by using "medium" or "high" values. In such case, the system only recommends items of at least the requested qualit, and may return less than *count* items when there is not enough data to fulfill it.
28
+ #
29
+ # - +rotationRate+ -> **Expert option** If your users browse the system in real-time, it may easily happen that you wish to offer them recommendations multiple times. Here comes the question: how much should the recommendations change? Should they remain the same, or should they rotate? Recombee API allows you to control this per-request in backward fashion. You may penalize an item for being recommended in the near past. For the specific user, `rotationRate=1` means maximal rotation, `rotationRate=0` means absolutely no rotation. You may also use, for example `rotationRate=0.2` for only slight rotation of recommended items.
30
+ #
31
+ # - +rotationTime+ -> **Expert option** Taking *rotationRate* into account, specifies how long time it takes to an item to fully recover from the penalization. By example, `rotationTime=7200.0` means that items recommended more than 2 hours ago are definitely not penalized anymore. Currently, the penalization is linear, so for `rotationTime=7200.0`, an item is still penalized by `0.5` to the user after 1 hour. |
32
+ #
33
+ #
34
+ def initialize(user_id, count, optional = {})
35
+ @user_id = user_id
36
+ @count = count
37
+ @filter = optional['filter']
38
+ @booster = optional['booster']
39
+ @allow_nonexistent = optional['allowNonexistent']
40
+ @diversity = optional['diversity']
41
+ @min_relevance = optional['minRelevance']
42
+ @rotation_rate = optional['rotationRate']
43
+ @rotation_time = optional['rotationTime']
44
+ @optional = optional
45
+ @timeout = 3000
46
+ @optional.each do |par, _|
47
+ fail UnknownOptionalParameter.new(par) unless ["filter","booster","allowNonexistent","diversity","minRelevance","rotationRate","rotationTime"].include? par
48
+ end
49
+ end
50
+
51
+ # HTTP method
52
+ def method
53
+ :get
54
+ end
55
+
56
+ # Values of body parameters as a Hash
57
+ def body_parameters
58
+ p = Hash.new
59
+ p
60
+ end
61
+
62
+ # Values of query path parameters as a Hash.
63
+ # name of parameter => value of the parameter
64
+ def query_parameters
65
+ params = {}
66
+ params['count'] = @count
67
+ params['filter'] = @optional['filter'] if @optional['filter']
68
+ params['booster'] = @optional['booster'] if @optional['booster']
69
+ params['allowNonexistent'] = @optional['allowNonexistent'] if @optional['allowNonexistent']
70
+ params['diversity'] = @optional['diversity'] if @optional['diversity']
71
+ params['minRelevance'] = @optional['minRelevance'] if @optional['minRelevance']
72
+ params['rotationRate'] = @optional['rotationRate'] if @optional['rotationRate']
73
+ params['rotationTime'] = @optional['rotationTime'] if @optional['rotationTime']
74
+ params
75
+ end
76
+
77
+ # Relative path to the endpoint
78
+ def basic_path
79
+ "/{databaseId}/users/#{@user_id}/recomms/"
80
+ end
81
+
82
+ # Relative path to the endpoint including query parameters
83
+ def path
84
+ p = "/{databaseId}/users/#{@user_id}/recomms/?count=#{@count}"
85
+ if @optional.include? 'filter'
86
+ p += (p.include? '?') ? '&' : '?'
87
+ p += "filter=#{@optional['filter']}"
88
+ end
89
+ if @optional.include? 'booster'
90
+ p += (p.include? '?') ? '&' : '?'
91
+ p += "booster=#{@optional['booster']}"
92
+ end
93
+ if @optional.include? 'allowNonexistent'
94
+ p += (p.include? '?') ? '&' : '?'
95
+ p += "allowNonexistent=#{@optional['allowNonexistent']}"
96
+ end
97
+ if @optional.include? 'diversity'
98
+ p += (p.include? '?') ? '&' : '?'
99
+ p += "diversity=#{@optional['diversity']}"
100
+ end
101
+ if @optional.include? 'minRelevance'
102
+ p += (p.include? '?') ? '&' : '?'
103
+ p += "minRelevance=#{@optional['minRelevance']}"
104
+ end
105
+ if @optional.include? 'rotationRate'
106
+ p += (p.include? '?') ? '&' : '?'
107
+ p += "rotationRate=#{@optional['rotationRate']}"
108
+ end
109
+ if @optional.include? 'rotationTime'
110
+ p += (p.include? '?') ? '&' : '?'
111
+ p += "rotationTime=#{@optional['rotationTime']}"
112
+ end
113
+ p
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,44 @@
1
+ module RecombeeApiClient
2
+ # Errors in API
3
+ class APIError < StandardError
4
+ end
5
+
6
+ # Response is not 200 or 201
7
+ class ResponseError < APIError
8
+ attr_reader :request
9
+ attr_reader :status_code
10
+ attr_reader :description
11
+
12
+ def initialize(request, status_code, description)
13
+ @status_code = status_code
14
+ @description = description
15
+ end
16
+
17
+ def to_s
18
+ "ResponseError: status: #{@status_code}, description: #{@description}"
19
+ end
20
+ end
21
+
22
+ class UnknownOptionalParameter < StandardError
23
+ def initialize(parameter)
24
+ @parameter = parameter
25
+ end
26
+
27
+ def to_s
28
+ "UnknownOptionalParameter: unknown parameter #{@parameter} was given to the request"
29
+ end
30
+ end
31
+
32
+ class ApiTimeout < APIError
33
+ attr_reader :request
34
+
35
+ def initialize(request)
36
+ @request = request
37
+ end
38
+
39
+ def to_s
40
+ "ApiTimeout: client did not get response within #{@request.timeout} ms"
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,3 @@
1
+ module RecombeeApiClient
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,105 @@
1
+ require 'recombee_api_client/version'
2
+ require 'securerandom'
3
+ require 'digest/hmac'
4
+ require 'httparty'
5
+ require 'json'
6
+ require 'open-uri'
7
+ require 'net/https'
8
+ require 'timeout'
9
+
10
+ require 'recombee_api_client/errors'
11
+ Gem.find_files('recombee_api_client/api/*.rb').each { |path| require path }
12
+
13
+ module RecombeeApiClient
14
+ class RecombeeClient
15
+ include HTTParty
16
+
17
+ def initialize(account, token, options = {})
18
+ @account = account
19
+ @token = token
20
+ @base_uri = options[:base_uri] ||= 'https://rapi.recombee.com'
21
+ end
22
+
23
+ def send(request)
24
+ @request = request
25
+ uri = request.path
26
+ uri.slice! ('/{databaseId}/')
27
+ uri = URI.escape uri
28
+ timeout = request.timeout / 1000
29
+ # puts uri
30
+ begin
31
+ case request.method
32
+ when :put
33
+ hmac_put(uri, timeout)
34
+ when :get
35
+ hmac_get(uri, timeout)
36
+ when :post
37
+ hmac_post(uri, timeout, request.body_parameters.to_json)
38
+ when :delete
39
+ hmac_delete(uri, timeout)
40
+ end
41
+ rescue Timeout::Error
42
+ fail ApiTimeout.new(@request)
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def hmac_put(uri, timeout, options = {})
49
+ r = self.class.put(sign_url(uri), query: options, timeout: timeout)
50
+ check_errors r
51
+ r.body
52
+ end
53
+
54
+ def hmac_get(uri, timeout, options = {})
55
+ r = self.class.get(sign_url(uri), query: options, timeout: timeout)
56
+ check_errors r
57
+ JSON.parse(r.body)
58
+ end
59
+
60
+ def hmac_post(uri, timeout, options = {})
61
+ url = sign_url(uri)
62
+ # pass arguments in body
63
+ r = self.class.post(url, body: options,
64
+ headers: { 'Content-Type' => 'application/json' },
65
+ timeout: timeout)
66
+ check_errors r
67
+ begin
68
+ return JSON.parse(r.body)
69
+ rescue JSON::ParserError
70
+ return r.body
71
+ end
72
+ end
73
+
74
+ def hmac_delete(uri, timeout, options = {})
75
+ r = self.class.delete(sign_url(uri), query: options, timeout: timeout)
76
+ check_errors r
77
+ r.body
78
+ end
79
+
80
+ def check_errors(response)
81
+ status_code = response.code
82
+ return if status_code == 200 || status_code == 201
83
+ fail ResponseError.new(@request, status_code, response.body)
84
+ end
85
+
86
+ # Sign request with HMAC, request URI must be exacly the same
87
+ # We have 30s to complete request with this token
88
+ def sign_url(req)
89
+ uri = "/#{@account}/#{req}"
90
+ time = hmac_time(uri)
91
+ sign = hmac_sign(uri, time)
92
+ @base_uri + uri + time + "&hmac_sign=#{sign}"
93
+ end
94
+
95
+ def hmac_time(uri)
96
+ res = (uri.include? '?') ? '&' : '?'
97
+ res << "hmac_timestamp=#{Time.now.utc.to_i}"
98
+ end
99
+
100
+ def hmac_sign(uri, time)
101
+ url = uri + time
102
+ Digest::HMAC.hexdigest(url, @token, Digest::SHA1)
103
+ end
104
+ end
105
+ end