Skip to content

Commit

Permalink
add product search autocomplete
Browse files Browse the repository at this point in the history
  • Loading branch information
thehung111 committed Nov 27, 2023
1 parent 69d4347 commit 46c1201
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.visenze.datatracking.Tracker;
import com.visenze.datatracking.VisenzeAnalytics;
import com.visenze.datatracking.data.DataCollection;
import com.visenze.visearch.android.model.AutoCompleteResponse;
import com.visenze.visearch.android.model.ErrorData;
import com.visenze.visearch.android.model.ProductResponse;
import com.visenze.visearch.android.network.ProductSearchService;
Expand Down Expand Up @@ -39,7 +40,7 @@ public void searchById(ProductSearchByIdParams visualSimilarParams, ResultListen
productSearchService.searchById(visualSimilarParams, listener);
}

public void multisearcch(ProductSearchByImageParams imageSearchParams, ResultListener listener) {
public void multisearch(ProductSearchByImageParams imageSearchParams, ResultListener listener) {
addAnalyticsParams(imageSearchParams);
productSearchService.searchByImage(imageSearchParams, listener, true);
}
Expand Down Expand Up @@ -165,9 +166,12 @@ public ProductSearch build(Context context) {
}
}

public static interface ResultListener {
public void onSearchResult(final ProductResponse response, ErrorData error);
public interface ResultListener {
void onSearchResult(final ProductResponse response, ErrorData error);
}

public interface AutoCompleteResultListener {
void onResult(final AutoCompleteResponse response, ErrorData error);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.visenze.visearch.android.model;

import com.google.gson.annotations.SerializedName;

import java.util.List;

public class AutoCompleteResponse {

@SerializedName("status")
private String status;

@SerializedName("method")
private String method;

@SerializedName("error")
private ErrorData error;

@SerializedName("result")
private List<AutoCompleteResultItem> result;

@SerializedName("page")
private int page;

@SerializedName("limit")
private int limit;

@SerializedName("total")
private int total;

@SerializedName("reqid")
private String reqId;

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getMethod() {
return method;
}

public void setMethod(String method) {
this.method = method;
}

public ErrorData getError() {
return error;
}

public void setError(ErrorData error) {
this.error = error;
}

public List<AutoCompleteResultItem> getResult() {
return result;
}

public void setResult(List<AutoCompleteResultItem> result) {
this.result = result;
}

public int getPage() {
return page;
}

public void setPage(int page) {
this.page = page;
}

public int getLimit() {
return limit;
}

public void setLimit(int limit) {
this.limit = limit;
}

public int getTotal() {
return total;
}

public void setTotal(int total) {
this.total = total;
}

public String getReqId() {
return reqId;
}

public void setReqId(String reqId) {
this.reqId = reqId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.visenze.visearch.android.model;

import com.google.gson.annotations.SerializedName;

public class AutoCompleteResultItem {

@SerializedName("text")
private String text;

@SerializedName("score")
private double score;

public String getText() {
return text;
}

public void setText(String text) {
this.text = text;
}

public double getScore() {
return score;
}

public void setScore(double score) {
this.score = score;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,10 @@ public void setMessage(String message) {
this.message = message;
}


public static ErrorData unknownError(String msg) {
ErrorData error = new ErrorData();
error.setMessage(msg);
error.setCode(-1);
return error;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.visenze.visearch.android.network;

import com.visenze.visearch.android.model.AutoCompleteResponse;
import com.visenze.visearch.android.model.ProductResponse;
import com.visenze.visearch.android.network.retry.Retry;

Expand Down Expand Up @@ -36,4 +37,13 @@ public interface APIProductService {
@Multipart
@POST("product/multisearch")
Call<ProductResponse> multisearch(@Part MultipartBody.Part image, @QueryMap RetrofitQueryMap query);

@Retry
@POST("product/multisearch/autocomplete")
Call<AutoCompleteResponse> multisearchAutocomplete(@QueryMap RetrofitQueryMap query);

@Retry
@Multipart
@POST("product/multisearch/autocomplete")
Call<AutoCompleteResponse> multisearchAutocomplete(@Part MultipartBody.Part image, @QueryMap RetrofitQueryMap query);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.visenze.visearch.android.ProductSearchByImageParams;
import com.visenze.visearch.android.ProductSearch;
import com.visenze.visearch.android.ProductSearchByIdParams;
import com.visenze.visearch.android.model.AutoCompleteResponse;
import com.visenze.visearch.android.model.ErrorData;
import com.visenze.visearch.android.model.ProductResponse;

Expand Down Expand Up @@ -44,6 +45,46 @@ public void searchByImage(ProductSearchByImageParams imageSearchParams, final Pr
}

public void searchByImage(ProductSearchByImageParams imageSearchParams, final ProductSearch.ResultListener listener, boolean multiSearch) {
byte[] imageBytes = validateImageParams(imageSearchParams, multiSearch);

RetrofitQueryMap params = buildQueryMap(imageSearchParams);

Call<ProductResponse> call;
if(imageBytes != null) {
RequestBody imageBody = RequestBody.create(MediaType.parse("image/*"), imageBytes);
MultipartBody.Part image = MultipartBody.Part.createFormData("image", "image", imageBody);
call = getProductResponseCall(params, image, multiSearch);
} else {
call = getProductResponseCall(params, null, multiSearch);
}
handleCallback(call, listener);
}

public void multisearchAutocomplete(ProductSearchByImageParams imageSearchParams,
final ProductSearch.AutoCompleteResultListener listener) {
byte[] imageBytes = validateImageParams(imageSearchParams, true);

RetrofitQueryMap params = buildQueryMap(imageSearchParams);

Call<AutoCompleteResponse> call;
if(imageBytes != null) {
RequestBody imageBody = RequestBody.create(MediaType.parse("image/*"), imageBytes);
MultipartBody.Part image = MultipartBody.Part.createFormData("image", "image", imageBody);
call = getAutoCompleteResponseCall(params, image);
} else {
call = getAutoCompleteResponseCall(params, null);
}
handleCallback(call, listener);
}

/**
* If not multi-search, 1 of image, im_url or im_id must be provided, throw Exception if missing
*
* @param imageSearchParams request params
* @param multiSearch whether this is multisearch related API or normal SBI
* @return image file bytes if provided
*/
private byte[] validateImageParams(ProductSearchByImageParams imageSearchParams, boolean multiSearch) {
byte[] imageBytes = null;

if (imageSearchParams.getImage() != null) {
Expand All @@ -59,18 +100,7 @@ public void searchByImage(ProductSearchByImageParams imageSearchParams, final Pr
throw new IllegalArgumentException("Please provide imUrl , imId or image parameter");
}
}

RetrofitQueryMap params = buildQueryMap(imageSearchParams);

Call<ProductResponse> call;
if(imageBytes != null) {
RequestBody imageBody = RequestBody.create(MediaType.parse("image/*"), imageBytes);
MultipartBody.Part image = MultipartBody.Part.createFormData("image", "image", imageBody);
call = getProductResponseCall(params, image, multiSearch);
} else {
call = getProductResponseCall(params, null, multiSearch);
}
handleCallback(call, listener);
return imageBytes;
}

private Call<ProductResponse> getProductResponseCall(RetrofitQueryMap params, MultipartBody.Part image, boolean multiSearch) {
Expand All @@ -89,6 +119,14 @@ private Call<ProductResponse> getProductResponseCall(RetrofitQueryMap params, Mu
}
}

private Call<AutoCompleteResponse> getAutoCompleteResponseCall(RetrofitQueryMap params, MultipartBody.Part image) {
if (image == null) {
return apiService.multisearchAutocomplete(params);
}

return apiService.multisearchAutocomplete(image, params);
}


private RetrofitQueryMap buildQueryMap(BaseProductSearchParams params) {
RetrofitQueryMap map = params.getQueryMap();
Expand All @@ -101,32 +139,28 @@ private void handleCallback(Call<ProductResponse> call, final ProductSearch.Resu
call.enqueue(new Callback<ProductResponse>() {
@Override
public void onResponse(Call<ProductResponse> call, Response<ProductResponse> response) {
if(response.isSuccessful() && response.body() !=null) {
if(response.isSuccessful() && response.body() != null) {
ProductResponse data = response.body();
handleResponse(data, resultListener);
} else {
if (response.errorBody() != null) {
Gson gson = new Gson();
ProductResponse resp = gson.fromJson(response.errorBody().charStream(), ProductResponse.class);
if (resp != null && resp.getError()!= null) {
resultListener.onSearchResult(null, resp.getError());
return;
}
return;
}

if (response.errorBody() != null) {
Gson gson = new Gson();
ProductResponse resp = gson.fromJson(response.errorBody().charStream(), ProductResponse.class);
if (resp != null && resp.getError() != null) {
resultListener.onSearchResult(null, resp.getError());
return;
}
ErrorData error = new ErrorData();
error.setMessage("api failed");
error.setCode(-1);
resultListener.onSearchResult(null, error);
}

resultListener.onSearchResult(null, ErrorData.unknownError("api failed"));

}

@Override
public void onFailure(Call<ProductResponse> call, Throwable t) {

ErrorData error = new ErrorData();
error.setMessage(t.getMessage());
error.setCode(-1);
resultListener.onSearchResult(null, error);
resultListener.onSearchResult(null, ErrorData.unknownError(t.getMessage()));
}

});
Expand All @@ -142,4 +176,44 @@ public void handleResponse(ProductResponse response, final ProductSearch.ResultL
}
}

private void handleCallback(Call<AutoCompleteResponse> call, final ProductSearch.AutoCompleteResultListener resultListener) {
call.enqueue(new Callback<AutoCompleteResponse>() {

@Override
public void onResponse(Call<AutoCompleteResponse> call, Response<AutoCompleteResponse> response) {
if(response.isSuccessful() && response.body() != null) {
AutoCompleteResponse data = response.body();
handleAutoCompleteResponse(data, resultListener);
return;
}

if (response.errorBody() != null) {
Gson gson = new Gson();
AutoCompleteResponse resp = gson.fromJson(response.errorBody().charStream(), AutoCompleteResponse.class);
if (resp != null && resp.getError() != null) {
resultListener.onResult(null, resp.getError());
return;
}
}

resultListener.onResult(null, ErrorData.unknownError("api failed"));
}

@Override
public void onFailure(Call<AutoCompleteResponse> call, Throwable t) {
resultListener.onResult(null, ErrorData.unknownError(t.getMessage()));
}

});
}

public void handleAutoCompleteResponse(AutoCompleteResponse response, final ProductSearch.AutoCompleteResultListener listener) {
ErrorData error = response.getError();
if(error != null) {
listener.onResult(null, error);
} else {
listener.onResult(response, null);
}
}

}

0 comments on commit 46c1201

Please sign in to comment.