|
1 | | -# Recombee API Client |
| 1 | +<div align="center"> |
| 2 | + <img |
| 3 | + src="https://raw.githubusercontent.com/recombee/.github/refs/heads/main/assets/mark.svg" |
| 4 | + width="64px" |
| 5 | + align="center" |
| 6 | + alt="Recombee" |
| 7 | + /> |
| 8 | + <br /> |
| 9 | + <h1>Recombee API Client</h1> |
| 10 | +</div> |
| 11 | + |
| 12 | +<p align="center"> |
| 13 | +<a href="https://mvnrepository.com/artifact/com.recombee/apiclientkotlin" rel="nofollow"><img src="https://img.shields.io/maven-central/v/com.recombee/apiclientkotlin" alt="Version"></a> |
| 14 | +<a href="https://opensource.org/licenses/MIT" rel="nofollow"><img src="https://img.shields.io/github/license/recombee/kotlin-api-client" alt="License"></a> |
| 15 | +</p> |
| 16 | + |
| 17 | +<div align="center"> |
| 18 | + <a href="https://docs.recombee.com/kotlin_client">Documentation</a> |
| 19 | + <span> • </span> |
| 20 | + <a href="https://github.com/recombee/kotlin-api-client/issues/new">Issues</a> |
| 21 | + <span> • </span> |
| 22 | + < a href= "mailto:[email protected]">Support</ a> |
| 23 | + <br /> |
| 24 | +</div> |
| 25 | + |
| 26 | +## ✨ Features |
| 27 | + |
| 28 | +- Thin Kotlin wrapper around the Recombee API |
| 29 | +- Supported endpoints: [Interactions](https://docs.recombee.com/api#user-item-interactions), [Recommendations](https://docs.recombee.com/api#recommendations) & [Search](https://docs.recombee.com/api#search) |
| 30 | +- Made for Android apps and Compose Multiplatform |
| 31 | + |
| 32 | +## 🚀 Getting Started |
| 33 | + |
| 34 | +Add the dependency into your `build.gradle.kts`: |
2 | 35 |
|
3 | | -A Kotlin client (SDK) for easy use of the [Recombee](https://www.recombee.com/) recommendation API in Android applications. |
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 | | -The client is available in the [Maven Central Repository](https://mvnrepository.com/artifact/com.recombee/apiclientkotlin/), so you just need to add the following entry to your gradle.build file: |
12 | | - |
13 | | -```gradle |
14 | | -repositories { |
15 | | - mavenCentral() |
16 | | -} |
17 | | -
|
18 | | -dependencies { |
19 | | - implementation "com.recombee.apiclientkotlin:5.0.0" |
20 | | -} |
| 36 | +```kotlin |
| 37 | +implementation("com.recombee:apiclientkotlin:5.0.0") |
21 | 38 | ``` |
22 | 39 |
|
23 | | -## How to use |
| 40 | +### 📚 Version Catalogs |
24 | 41 |
|
25 | | -This library allows you to request recommendations and send interactions between users and items (views, bookmarks, purchases ...) to Recombee. It uses the **public token** for authentication. |
| 42 | +If you're using [version catalogs](https://developer.android.com/build/migrate-to-catalogs), first add the dependency into your `libs.versions.toml`: |
26 | 43 |
|
27 | | -It is intentionally not possible to change the item catalog (properties of items) with the public token, so you should use one of the following ways to send it to Recombee: |
| 44 | +```toml |
| 45 | +[versions] |
| 46 | +recombee = "5.0.0" |
28 | 47 |
|
29 | | - - Use one of the server-side SDKs (Node.js, PHP, Java...). The synchronization can done for example by a peridodically run script. See [this section](https://docs.recombee.com/gettingstarted.html#managing-item-catalog) for more details. |
30 | | - - Set a catalog feed at [Recombee web admin](https://admin.recombee.com/). |
| 48 | +[libraries] |
| 49 | +recombee = { group = "com.recombee", name = "apiclientkotlin", version.ref = "recombee" } |
| 50 | +``` |
31 | 51 |
|
32 | | -### Sending interactions |
| 52 | +Then reference it in your `build.gradle.kts`: |
33 | 53 |
|
34 | 54 | ```kotlin |
35 | | -import com.recombee.apiclientkotlin.RecombeeClient |
36 | | -import com.recombee.apiclientkotlin.util.Region |
37 | | -import com.recombee.apiclientkotlin.exceptions.ApiException |
38 | | -import com.recombee.apiclientkotlin.requests.* |
39 | | - |
40 | | - |
41 | | -// Initialize client with name of your database and PUBLIC token |
42 | | -val client = RecombeeClient( |
43 | | - databaseId = "id-of-your-db", |
44 | | - publicToken = "...db-public-token...", |
45 | | - region = Region.UsWest |
46 | | -) |
47 | | - |
48 | | -// Interactions take the ID of the user and the ID of the item |
49 | | -client.send(AddBookmark(userId = "user-13434", itemId = "item-256")) |
50 | | -client.send(AddCartAddition(userId = "user-4395", itemId = "item-129")) |
51 | | -client.send(AddDetailView(userId = "user-9318", itemId = "item-108")) |
52 | | -client.send(AddPurchase(userId = "user-7499", itemId = "item-750")) |
53 | | -client.send(AddRating(userId = "user-3967", itemId = "item-365", rating = 0.5)) |
54 | | -client.send(SetViewPortion(userId = "user-4289", itemId = "item-487", portion = 0.3)) |
| 55 | +implementation(libs.recombee) |
55 | 56 | ``` |
56 | 57 |
|
57 | | -### Requesting recommendations |
58 | | - |
59 | | -You can [recommend items to user](https://docs.recombee.com/api.html#recommend-items-to-user), [recommend items to item](https://docs.recombee.com/api.html#recommend-items-to-item) or even [recommend Item Segments](https://docs.recombee.com/api#recommend-item-segments-to-user) such as categories, genres or artists. |
60 | | - |
61 | | -It is possible to use callbacks (`send` method) or coroutines (`sendAsync` method). |
| 58 | +### 🏗️ Example |
62 | 59 |
|
63 | | -#### Callbacks |
64 | | - |
65 | | -There are two callbacks (both are optional): |
66 | | -- `onResponse`: Callback function invoked in case of successful response. |
67 | | - |
68 | | -- `onFailure`: Callback function invoked with an *ApiException* in case of a failure. |
| 60 | +You can send user-item interactions and receive recommendations as follows: |
69 | 61 |
|
70 | 62 | ```kotlin |
71 | | -val request = RecommendItemsToUser( |
72 | | - userId = "user-x", |
73 | | - count = 10, |
74 | | - scenario = "homepage-for-you" |
| 63 | +// Initialize the API client with the ID of your database and the associated PUBLIC token |
| 64 | +val client = |
| 65 | + RecombeeClient( |
| 66 | + databaseId = "database-id", |
| 67 | + publicToken = "...db-public-token...", |
| 68 | + region = Region.UsWest // the region of your database |
| 69 | + ) |
| 70 | + |
| 71 | +// Send interactions |
| 72 | +client.send( |
| 73 | + AddDetailView( |
| 74 | + userId = "user-4395", |
| 75 | + itemId = "item-129", |
| 76 | + recommId = "23eaa09b-0e24-4487-ba9c-8e255feb01bb", |
| 77 | + ) |
75 | 78 | ) |
76 | 79 |
|
77 | | -client.send(request, |
78 | | - { recommendationResponse: RecommendationResponse -> |
79 | | - for (recommendedItem in recommendationResponse.recomms) { |
80 | | - println("ID: ${recommendedItem.id}") |
| 80 | +// Request recommendations |
| 81 | +client.send( |
| 82 | + // Get 10 items for "user-x" using the "homepage-top-for-you" scenario from the Admin UI |
| 83 | + RecommendItemsToUser( |
| 84 | + userId = "user-x", |
| 85 | + count = 10, |
| 86 | + scenario = "homepage-top-for-you", |
| 87 | + returnProperties = true, |
| 88 | + includedProperties = listOf("title") |
| 89 | + ), |
| 90 | + { response: RecommendationResponse -> |
| 91 | + // `recommId` needs to be sent with interactions based on recommendations |
| 92 | + println("recommId: ${response.recommId}") |
| 93 | + |
| 94 | + // The `recomms` object contains the `id` (and `values` if `returnProperties` is true) |
| 95 | + for (item in response.recomms) { |
| 96 | + println("ID: ${item.id}, Title: ${item.getValues()["title"]}") |
81 | 97 | } |
82 | 98 | }, |
83 | 99 | { exception: ApiException -> |
84 | 100 | println("Exception: $exception") |
85 | | - // use fallback ... |
| 101 | + // Ideally, you should provide a fallback if an error occurs... |
86 | 102 | } |
87 | 103 | ) |
88 | 104 | ``` |
89 | 105 |
|
90 | | - |
91 | | -#### Coroutines |
| 106 | +Coroutine support is also available, simply replace `send` with `sendAsync`: |
92 | 107 |
|
93 | 108 | ```kotlin |
94 | | -// Assuming this is inside a CoroutineScope |
95 | | - |
96 | | -val request = RecommendItemsToUser( |
97 | | - userId = "user-x", |
98 | | - count = 10, |
99 | | - scenario = "homepage-for-you" |
100 | | -) |
101 | | - |
102 | | -val result = client.sendAsync(request) |
103 | | - |
104 | | -result.onSuccess { recommendationResponse: RecommendationResponse -> |
105 | | - for (recommendedItem in recommendationResponse.recomms) { |
106 | | - println("ID: ${recommendedItem.id}") |
| 109 | +suspend fun getItems(): List<Item> { |
| 110 | + // Get 10 items for "user-x" using the "homepage-top-for-you" scenario from the Admin UI |
| 111 | + val result = |
| 112 | + client.sendAsync( |
| 113 | + RecommendItemsToUser( |
| 114 | + userId = "user-x", |
| 115 | + count = 10, |
| 116 | + scenario = "homepage-top-for-you", |
| 117 | + returnProperties = true, |
| 118 | + includedProperties = listOf("title", "images") |
| 119 | + ) |
| 120 | + ) |
| 121 | + |
| 122 | + // Ideally, you should provide a fallback if an error occurs |
| 123 | + if (result.isFailure) { |
| 124 | + return listOf() |
107 | 125 | } |
108 | | -}.onFailure { exception -> // ApiException |
109 | | - println("Exception: $exception") |
110 | | - // use fallback ... |
111 | | -} |
112 | 126 |
|
113 | | -``` |
| 127 | + val data = result.getOrNull() ?: return listOf() |
114 | 128 |
|
115 | | -### Personalized search |
| 129 | + // `recommId` needs to be sent with interactions based on recommendations |
| 130 | + println("recommId: ${data.recommId}") |
116 | 131 |
|
117 | | -[Personalized full-text search](https://docs.recombee.com/api.html#search-items) is requested in the same way as recommendations. |
118 | | - |
119 | | -#### Callbacks |
120 | | - |
121 | | -```kotlin |
122 | | -val request = SearchItems( |
123 | | - userId = "user-x", |
124 | | - searchQuery = "..user's search query", |
125 | | - count = 10, |
126 | | - scenario = "search", |
127 | | - returnProperties = true |
128 | | -) |
129 | | - |
130 | | -client.send(request, |
131 | | - { searchResponse: SearchResponse -> |
132 | | - for (recommendedItem in searchResponse.recomms) { |
133 | | - println("ID: ${recommendedItem.id} Values: ${recommendedItem.getValues()}") |
134 | | - } |
135 | | - }, |
136 | | - { exception: ApiException -> |
137 | | - println("Exception: $exception") |
138 | | - // use fallback ... |
| 132 | + // Map the recommendations to your own internal data type |
| 133 | + return data.recomms.map { item -> |
| 134 | + Item( |
| 135 | + id = item.id, |
| 136 | + title = item.getValues()["title"] as? String ?: "", |
| 137 | + images = item.getValues()["images"] as? List<String> ?: listOf(), |
| 138 | + recommId = data.recommId |
| 139 | + ) |
139 | 140 | } |
140 | | -) |
| 141 | +} |
141 | 142 | ``` |
142 | 143 |
|
| 144 | +> [!TIP] |
| 145 | +> We also published a simple [example Android app](https://github.com/recombee/android-demo) to help you with the integration. Feel free to use it as a reference. |
| 146 | +> |
| 147 | +>  |
143 | 148 |
|
144 | | -#### Coroutines |
145 | | - |
146 | | -```kotlin |
147 | | -// Assuming this is inside a CoroutineScope |
148 | | - |
149 | | -val request = SearchItems( |
150 | | - userId = "user-x", |
151 | | - searchQuery = "..user's search query", |
152 | | - count = 10, |
153 | | - scenario = "search", |
154 | | - returnProperties = true |
155 | | -) |
156 | | - |
157 | | -val result = client.sendAsync(request) |
| 149 | +## 📝 Documentation |
158 | 150 |
|
159 | | -result.onSuccess { searchResponse: SearchResponse -> |
160 | | - for (recommendedItem in searchResponse.recomms) { |
161 | | - println("ID: ${recommendedItem.id} Values: ${recommendedItem.getValues()}") |
162 | | - } |
163 | | -}.onFailure { exception -> // ApiException |
164 | | - println("Exception: $exception") |
165 | | - // use fallback ... |
166 | | -} |
167 | | -``` |
| 151 | +Discover the full [Kotlin API Client documentation](https://docs.recombee.com/kotlin_client) for comprehensive guides and examples. |
168 | 152 |
|
169 | | -### Recommend Next Items |
| 153 | +For a complete breakdown of all endpoints and their responses, check out our [API Reference](https://docs.recombee.com/api). |
170 | 154 |
|
171 | | -Recombee can return items that shall be shown to a user as next recommendations when the user e.g. scrolls the page down (infinite scroll) or goes to the next page. See [Recommend next items](https://docs.recombee.com/api.html#recommend-next-items) for more info. |
| 155 | +## 🤝 Contributing |
172 | 156 |
|
173 | | -```kotlin |
174 | | -client.sendAsync(RecommendItemsToUser("user-1", 5)) |
175 | | - .onSuccess { firstResponse: RecommendationResponse -> |
| 157 | +We welcome all contributions—whether it’s fixing a bug, improving documentation, or suggesting a new feature. |
176 | 158 |
|
177 | | - client.sendAsync(RecommendNextItems(firstResponse.recommId, 5)) |
178 | | - .onSuccess { secondResponse: RecommendationResponse -> |
179 | | - // Show next recommendations |
180 | | - } |
181 | | - } |
182 | | -``` |
| 159 | +To contribute, simply fork the repository, make your changes, and submit a pull request. Be sure to provide a clear description of your changes. |
183 | 160 |
|
184 | | -### Optional parameters |
| 161 | +Thanks for helping make this project better! |
185 | 162 |
|
186 | | -Recommendation requests accept various optional parameters (see [the docs](https://docs.recombee.com/api.html#recommendations)). Following example shows some of them: |
| 163 | +## 🔧 Troubleshooting |
187 | 164 |
|
188 | | -```kotlin |
189 | | -val request = RecommendItemsToUser( |
190 | | - userId = "user-13434", |
191 | | - count = 5, |
192 | | - scenario = "homepage-for-you", // Label particular usage |
193 | | - returnProperties = true, // Return properties of the recommended items |
194 | | - includedProperties = listOf("title", "img_url", "url", "price"), // Properties to be included in the response |
195 | | - filter = "'title' != null AND 'availability' == \"in stock\"" // Filter condition |
196 | | -) |
197 | | -``` |
| 165 | +Are you having issues? We recommend checking [our documentation](https://docs.recombee.com/kotlin_client) to see if it contains a possible solution. |
198 | 166 |
|
199 | | -## Exception handling |
| 167 | +If you want to reach out, you can either [open a GitHub issue](https://github.com/recombee/kotlin-api-client/issues/new) or send an email to [email protected]. |
200 | 168 |
|
201 | | -Following types of exceptions can be produced: |
202 | | -- *ResponseException*: Recombee API returned an error code (e.g. due to passing an invalid value to a parameter) |
203 | | -- *ApiIOException*: Request did not succeed |
204 | | - - In case of an timeout a subtype *ApiTimeoutException* is produced |
| 169 | +## 📄 License |
205 | 170 |
|
206 | | -*ApiException* is the base class of both *ResponseException* and *ApiIOException*. |
| 171 | +The Recombee Kotlin API Client is provided under the [MIT License](https://opensource.org/licenses/MIT). |
0 commit comments