Skip to content

Commit fa38824

Browse files
committed
Recombee Go SDK
0 parents  commit fa38824

File tree

270 files changed

+13677
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

270 files changed

+13677
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Recombee
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
# Recombee API Client
2+
3+
A Go client (SDK) for easy use of the [Recombee](https://www.recombee.com/) recommendation API.
4+
5+
If you don't have an account at Recombee yet, you can create a free account [here](https://www.recombee.com/).
6+
7+
Documentation of the API can be found at [docs.recombee.com](https://docs.recombee.com/).
8+
9+
## Installation
10+
11+
Run the following command in your Go project:
12+
```
13+
go get github.com/recombee/go-api-client
14+
```
15+
16+
## Examples
17+
18+
### Basic example
19+
20+
The following example shows how to:
21+
- Send many interactions within a single `Batch` request
22+
- Request recommendations for a user using `RecommendItemsToUser` and `RecommendNextItems` endpoints
23+
24+
```go
25+
package main
26+
27+
import (
28+
"fmt"
29+
"math/rand"
30+
"os"
31+
32+
"github.com/recombee/go-api-client/recombee"
33+
"github.com/recombee/go-api-client/recombee/requests"
34+
)
35+
36+
func main() {
37+
client, err := recombee.NewRecombeeClient("your-database-id", "db-private-token", "us-west")
38+
if err != nil {
39+
fmt.Println(err)
40+
panic(err)
41+
}
42+
43+
const numItemsAndUsers = 100
44+
const probabilityInteracted = 0.1
45+
46+
var addDetailViewInteractions []requests.Request
47+
for i := 0; i < numItemsAndUsers; i++ {
48+
for j := 0; j < numItemsAndUsers; j++ {
49+
if rand.Float64() < probabilityInteracted {
50+
userId := fmt.Sprintf("user-%d", i)
51+
itemId := fmt.Sprintf("item-%d", j)
52+
53+
request := client.NewAddDetailView(userId, itemId).SetCascadeCreate(true)
54+
addDetailViewInteractions = append(addDetailViewInteractions, request)
55+
}
56+
}
57+
}
58+
59+
fmt.Println("Send all interactions in Batch")
60+
batchRes, err := client.NewBatch(addDetailViewInteractions).Send()
61+
if err != nil {
62+
fmt.Println(err)
63+
panic(err)
64+
}
65+
66+
fmt.Println(batchRes) // Contains responses for all requests
67+
68+
// Get 5 recommendations for user 'user-25'
69+
recommendReq := client.NewRecommendItemsToUser("user-25", 5).SetCascadeCreate(true)
70+
recommendRes, err := recommendReq.Send()
71+
if err != nil {
72+
fmt.Println(err)
73+
panic(err)
74+
}
75+
76+
fmt.Println("Recommended items:")
77+
for _, rec := range recommendRes.Recomms {
78+
fmt.Println(rec.Id)
79+
}
80+
81+
// User scrolled down - get next 3 recommended items
82+
fmt.Println("Next recommended items:")
83+
recommendNextRes, err := client.NewRecommendNextItems(recommendRes.RecommId, 3).Send()
84+
if err != nil {
85+
fmt.Println(err)
86+
panic(err)
87+
}
88+
89+
for _, rec := range recommendNextRes.Recomms {
90+
fmt.Println(rec.Id)
91+
}
92+
}
93+
94+
```
95+
96+
97+
See `examples/batch` for an extended example of using the `Batch` requests.
98+
99+
### Using property values
100+
101+
The second example shows how to:
102+
- Specify the properties (columns) of the items catalog using `AddItemProperty` requests
103+
- Upload their values for all the items using `SetItemValues` requests in a `Batch`
104+
- Get recommendations based on an item using `RecommendItemsToItem`
105+
- Search items using `SearchItems`
106+
107+
108+
```go
109+
package main
110+
111+
import (
112+
"context"
113+
"fmt"
114+
"github.com/recombee/go-api-client/recombee"
115+
"github.com/recombee/go-api-client/recombee/requests"
116+
"math/rand"
117+
"os"
118+
"time"
119+
)
120+
121+
func main() {
122+
client, err := recombee.NewRecombeeClient("your-database-id", "db-private-token", "us-west")
123+
if err != nil {
124+
fmt.Println(err)
125+
panic(err)
126+
}
127+
128+
// Add item properties
129+
// Properties are the columns of the items catalogs
130+
properties := []struct {
131+
propertyName string
132+
propertyType string
133+
}{
134+
{"price", "double"},
135+
{"num-cores", "int"},
136+
{"description", "string"},
137+
{"image", "image"},
138+
}
139+
140+
for _, p := range properties {
141+
if _, err := client.NewAddItemProperty(p.propertyName, p.propertyType).Send(); err != nil {
142+
fmt.Println(err)
143+
panic(err)
144+
}
145+
}
146+
147+
// Prepare and send a catalog of computers
148+
const numItems = 100
149+
requestsBatch := make([]requests.Request, numItems)
150+
151+
for i := 0; i < numItems; i++ {
152+
itemId := fmt.Sprintf("computer-%d", i)
153+
requestsBatch[i] = client.NewSetItemValues(itemId, map[string]interface{}{
154+
"price": 600.0 + 400*rand.Float64(),
155+
"num-cores": 1 + rand.Intn(7),
156+
"description": "Great computer",
157+
"image": fmt.Sprintf("http://examplesite.com/products/%s.jpg", itemId),
158+
}).SetCascadeCreate(true)
159+
}
160+
161+
if _, err := client.NewBatch(requestsBatch).Send(); err != nil {
162+
fmt.Println(err)
163+
panic(err)
164+
}
165+
166+
// Simulate random purchases
167+
const probabilityPurchased = 0.02
168+
var addPurchaseRequests []requests.Request
169+
170+
for i := 0; i < numItems; i++ {
171+
for j := 0; j < numItems; j++ {
172+
if rand.Float64() < probabilityPurchased {
173+
userId := fmt.Sprintf("user-%d", i)
174+
itemId := fmt.Sprintf("computer-%d", j)
175+
addPurchaseRequests = append(addPurchaseRequests, client.NewAddPurchase(userId, itemId).SetCascadeCreate(true))
176+
}
177+
}
178+
}
179+
180+
// Send the Batch request with custom timeout
181+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
182+
defer cancel()
183+
184+
if _, err := client.NewBatch(addPurchaseRequests).SendWithContext(ctx); err != nil {
185+
fmt.Println(err)
186+
panic(err)
187+
}
188+
189+
// Request recommendations with a set scenario
190+
// Behavior of the recommendations is configured per scenario in the Recombee Admin UI
191+
req := client.NewRecommendItemsToItem("computer-6", "user-42", 5).SetScenario("product_detail")
192+
193+
recommRes, err := req.Send()
194+
if err != nil {
195+
panic(err)
196+
}
197+
fmt.Println("Recommended items:")
198+
for _, rec := range recommRes.Recomms {
199+
fmt.Println(rec.Id)
200+
}
201+
202+
// Recommend items with at least 3 processor cores (dynamic filter), return property values of the items
203+
req = client.NewRecommendItemsToItem("computer-6", "user-42", 5)
204+
req = req.SetFilter("'num-cores'>=3").SetReturnProperties(true)
205+
recommRes, err = req.Send()
206+
fmt.Println("\nRecommended items with at least 3 cores:")
207+
for _, rec := range recommRes.Recomms {
208+
fmt.Println(rec.Id)
209+
fmt.Println(rec.Values)
210+
}
211+
212+
// Perform a search using "computers" query
213+
searchResponse, err := client.NewSearchItems("user-42", "computers", 5).Send()
214+
215+
if err != nil {
216+
panic(err)
217+
}
218+
fmt.Println("\nSearch matches: %s", searchResponse.Recomms)
219+
}
220+
221+
```
222+
223+
## Sending Requests
224+
225+
A request can be sent to the Recombee API using the `Send()` method.
226+
227+
If you want to provide your own `context.Context` (e.g. to set your custom timeout for the request) call the `SendWithContext(ctx context.Context)` method.
228+
229+
## RecombeeClient Initialization
230+
231+
The RecombeeClient can be created using the `NewRecombeeClient(...)` function, as per previous examples.
232+
233+
If you want to provide your own `http.Client` use `NewRecombeeClientWithOptions`:
234+
235+
```go
236+
region := "ap-se"
237+
options := recombee.ClientOptions{Region: &region, HttpClient: &myHttpClient}
238+
client, err := recombee.NewRecombeeClientWithOptions("your-database-id", "db-private-token", options)
239+
```
240+
241+
## Custom Errors
242+
243+
Various errors can occur while processing the request, for example, because of adding an already existing item or submitting interaction of a nonexistent user without *cascadeCreate* set to true. These errors lead to returning the `errors.ResponseError` by the `Send` method.
244+
245+
Another reason for producing an error is a timeout, yielding `errors.TimeoutError`.
246+
247+
We are doing our best to provide the fastest and most reliable service, but production-level applications shall implement a fallback solution since errors can always happen. The fallback might be, for example, showing the most popular items from the current category, or not displaying recommendations at all.

examples/batch/main.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/recombee/go-api-client/recombee"
7+
"github.com/recombee/go-api-client/recombee/bindings"
8+
"github.com/recombee/go-api-client/recombee/requests"
9+
"os"
10+
)
11+
12+
func main() {
13+
client, err := recombee.NewRecombeeClient(os.Getenv("DB_ID"), os.Getenv("PRIVATE_TOKEN"), "eu-west")
14+
if err != nil {
15+
fmt.Println(err)
16+
panic(err)
17+
}
18+
19+
// Batch can encapsulate requests of various types
20+
batchReq := client.NewBatch([]requests.Request{
21+
client.NewAddDetailView("user-x", "item-y").SetCascadeCreate(true),
22+
client.NewRecommendItemsToUser("user-x", 5).SetScenario("just_for_you").SetCascadeCreate(true),
23+
client.NewRecommendItemsToItem("item-y", "user-x", 5).SetCascadeCreate(true),
24+
client.NewSetItemValues("item-y", map[string]interface{}{"price": 200, "category": "furniture"}),
25+
})
26+
27+
batchResponse, err := batchReq.SendWithContext(context.Background())
28+
if err != nil {
29+
fmt.Println(err)
30+
panic(err)
31+
}
32+
33+
// Check all requests succeeded
34+
for i, resp := range batchResponse {
35+
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
36+
fmt.Printf("Request #%d failed with status code %d: %s\n", i, resp.StatusCode, resp.Error.ErrorMessage)
37+
}
38+
}
39+
40+
// Print recommended items
41+
for _, rec := range batchResponse[1].Result.(*bindings.RecommendationResponse).Recomms {
42+
fmt.Println(rec.Id)
43+
}
44+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"math/rand"
6+
"os"
7+
8+
"github.com/recombee/go-api-client/recombee"
9+
"github.com/recombee/go-api-client/recombee/requests"
10+
)
11+
12+
func main() {
13+
client, err := recombee.NewRecombeeClient(os.Getenv("DB_ID"), os.Getenv("PRIVATE_TOKEN"), "eu-west")
14+
if err != nil {
15+
fmt.Println(err)
16+
panic(err)
17+
}
18+
19+
const numItemsAndUsers = 100
20+
const probabilityInteracted = 0.1
21+
22+
var addDetailViewInteractions []requests.Request
23+
for i := 0; i < numItemsAndUsers; i++ {
24+
for j := 0; j < numItemsAndUsers; j++ {
25+
if rand.Float64() < probabilityInteracted {
26+
userId := fmt.Sprintf("user-%d", i)
27+
itemId := fmt.Sprintf("item-%d", j)
28+
29+
request := client.NewAddDetailView(userId, itemId).SetCascadeCreate(true)
30+
addDetailViewInteractions = append(addDetailViewInteractions, request)
31+
}
32+
}
33+
}
34+
35+
fmt.Println("Send all interactions in Batch")
36+
batchRes, err := client.NewBatch(addDetailViewInteractions).Send()
37+
if err != nil {
38+
fmt.Println(err)
39+
panic(err)
40+
}
41+
42+
fmt.Println(batchRes) // Contains responses for all requests
43+
44+
// Get 5 recommendations for user 'user-25'
45+
recommendReq := client.NewRecommendItemsToUser("user-25", 5).SetCascadeCreate(true)
46+
recommendRes, err := recommendReq.Send()
47+
if err != nil {
48+
fmt.Println(err)
49+
panic(err)
50+
}
51+
52+
fmt.Println("Recommended items:")
53+
for _, rec := range recommendRes.Recomms {
54+
fmt.Println(rec.Id)
55+
}
56+
57+
// User scrolled down - get next 3 recommended items
58+
fmt.Println("Next recommended items:")
59+
recommendNextRes, err := client.NewRecommendNextItems(recommendRes.RecommId, 3).Send()
60+
if err != nil {
61+
fmt.Println(err)
62+
panic(err)
63+
}
64+
65+
for _, rec := range recommendNextRes.Recomms {
66+
fmt.Println(rec.Id)
67+
}
68+
}

0 commit comments

Comments
 (0)