package com.visenze.visearch.internal;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.visenze.visearch.*;
import com.visenze.visearch.internal.http.ViSearchHttpClient;
import com.visenze.visearch.internal.http.ViSearchHttpResponse;
import java.io.*;
import java.util.List;
import java.util.Map;
public class SearchOperationsImpl extends BaseViSearchOperations implements SearchOperations {
private static final String ENDPOINT_UPLOAD_SEARCH = "/uploadsearch";
private static final String ENDPOINT_SEARCH = "/search";
private static final String ENDPOINT_RECOMMENDATION = "/recommendation";
private static final String ENDPOINT_COLOR_SEARCH = "/colorsearch";
private static final String ENDPOINT_SIMILAR_PRODUCTS_SEARCH = "/similarproducts";
private static final String DETECTION_ALL = "all";
public SearchOperationsImpl(ViSearchHttpClient viSearchHttpClient, ObjectMapper objectMapper) {
super(viSearchHttpClient, objectMapper);
}
@Override
public PagedSearchResult search(SearchParams searchParams) {
try {
ViSearchHttpResponse response = viSearchHttpClient.get(ENDPOINT_SEARCH, searchParams.toMap());
return getPagedResult(response);
} catch (InternalViSearchException e) {
return new PagedSearchResult(e.getMessage(), e.getCause(), e.getServerRawResponse());
}
}
@Override
public PagedSearchResult recommendation(SearchParams searchParams) {
try {
ViSearchHttpResponse response = viSearchHttpClient.get(ENDPOINT_RECOMMENDATION, searchParams.toMap());
return getPagedResult(response);
} catch (InternalViSearchException e) {
return new PagedSearchResult(e.getMessage(), e.getCause(), e.getServerRawResponse());
}
}
@Override
public PagedSearchResult colorSearch(ColorSearchParams colorSearchParams) {
try {
ViSearchHttpResponse response = viSearchHttpClient.get(ENDPOINT_COLOR_SEARCH, colorSearchParams.toMap());
return getPagedResult(response);
} catch (InternalViSearchException e) {
return new PagedSearchResult(e.getMessage(), e.getCause(), e.getServerRawResponse());
}
}
@Override
public PagedSearchResult uploadSearch(UploadSearchParams uploadSearchParams) {
try {
return uploadSearchInternal(uploadSearchParams);
} catch (InternalViSearchException e) {
return new PagedSearchResult(e.getMessage(), e.getCause(), e.getServerRawResponse());
}
}
@Override
public PagedSearchGroupResult similarProductsSearch(UploadSearchParams similarProductsSearchPararms) {
try {
return similarProductsSearchInternal(similarProductsSearchPararms);
} catch (InternalViSearchException e) {
return new PagedSearchGroupResult(e.getMessage(), e.getCause(), e.getServerRawResponse());
}
}
/**
* @deprecated
* */
@Deprecated
@Override
public PagedSearchResult uploadSearch(UploadSearchParams uploadSearchParams, ResizeSettings resizeSettings) {
try {
return uploadSearchInternal(uploadSearchParams);
} catch (InternalViSearchException e) {
return new PagedSearchResult(e.getMessage(), e.getCause(), e.getServerRawResponse());
}
}
private PagedSearchResult uploadSearchInternal(UploadSearchParams uploadSearchParams) {
File imageFile = uploadSearchParams.getImageFile();
InputStream imageStream = uploadSearchParams.getImageStream();
String imageUrl = uploadSearchParams.getImageUrl();
ViSearchHttpResponse response;
// if im_id is available no need to check for image
if (!Strings.isNullOrEmpty(uploadSearchParams.getImId())){
response = viSearchHttpClient.post(ENDPOINT_UPLOAD_SEARCH, uploadSearchParams.toMap());
}
else if (imageFile == null && imageStream == null && (Strings.isNullOrEmpty(imageUrl))) {
throw new InternalViSearchException(ResponseMessages.INVALID_IMAGE_SOURCE);
// throw new IllegalArgumentException("Must provide either an image File, InputStream of the image, or a valid image url to perform upload search");
} else if (imageFile != null) {
try {
response = viSearchHttpClient.postImage(ENDPOINT_UPLOAD_SEARCH, uploadSearchParams.toMap(), new FileInputStream(imageFile), imageFile.getName());
} catch (FileNotFoundException e) {
throw new InternalViSearchException(ResponseMessages.INVALID_IMAGE_OR_URL, e);
// throw new IllegalArgumentException("Could not open the image file.", e);
}
} else if (imageStream != null) {
response = viSearchHttpClient.postImage(ENDPOINT_UPLOAD_SEARCH, uploadSearchParams.toMap(), imageStream, "image-stream");
} else {
response = viSearchHttpClient.post(ENDPOINT_UPLOAD_SEARCH, uploadSearchParams.toMap());
}
return getPagedResult(response);
}
private PagedSearchGroupResult similarProductsSearchInternal(UploadSearchParams uploadSearchParams) {
File imageFile = uploadSearchParams.getImageFile();
InputStream imageStream = uploadSearchParams.getImageStream();
String imageUrl = uploadSearchParams.getImageUrl();
//detection should always set to "all"
uploadSearchParams.setDetection(DETECTION_ALL);
ViSearchHttpResponse response;
if (imageFile == null && imageStream == null && (Strings.isNullOrEmpty(imageUrl))) {
throw new InternalViSearchException(ResponseMessages.INVALID_IMAGE_SOURCE);
// throw new IllegalArgumentException("Must provide either an image File, InputStream of the image, or a valid image url to perform upload search");
} else if (imageFile != null) {
try {
response = viSearchHttpClient.postImage(ENDPOINT_SIMILAR_PRODUCTS_SEARCH, uploadSearchParams.toMap(), new FileInputStream(imageFile), imageFile.getName());
} catch (FileNotFoundException e) {
throw new InternalViSearchException(ResponseMessages.INVALID_IMAGE_OR_URL, e);
// throw new IllegalArgumentException("Could not open the image file.", e);
}
} else if (imageStream != null) {
response = viSearchHttpClient.postImage(ENDPOINT_SIMILAR_PRODUCTS_SEARCH, uploadSearchParams.toMap(), imageStream, "image-stream");
} else {
response = viSearchHttpClient.post(ENDPOINT_SIMILAR_PRODUCTS_SEARCH, uploadSearchParams.toMap());
}
return getPagedSearchGroupResult(response);
}
private PagedSearchGroupResult getPagedSearchGroupResult(ViSearchHttpResponse httpResponse) {
String response = httpResponse.getBody();
Map<String, String> headers = httpResponse.getHeaders();
JsonNode node;
try {
node = objectMapper.readTree(response);
} catch (JsonProcessingException e) {
throw new InternalViSearchException(ResponseMessages.PARSE_RESPONSE_ERROR, e, response);
// throw new ViSearchException("Could not parse the ViSearch response: " + response, e, response);
} catch (IOException e) {
throw new InternalViSearchException(ResponseMessages.PARSE_RESPONSE_ERROR, e, response);
// throw new ViSearchException("Could not parse the ViSearch response: " + response, e, response);
}
checkResponseStatus(node);
PagedResult<GroupImageResult> pagedResult = pagify(response, response, GroupImageResult.class);
PagedSearchGroupResult result = new PagedSearchGroupResult(pagedResult);
JsonNode productTypesNode = node.get("product_types");
if (productTypesNode != null) {
List<ProductType> productTypes = deserializeListResult(response, productTypesNode, ProductType.class);
result.setProductTypes(productTypes);
}
JsonNode productTypesListNode = node.get("product_types_list");
if (productTypesListNode != null) {
List<ProductType> productTypesList = deserializeListResult(response, productTypesListNode, ProductType.class);
result.setProductTypesList(productTypesList);
}
JsonNode imIdNode = node.get("im_id");
if (imIdNode != null) {
result.setImId(imIdNode.asText());
}
JsonNode qinfoNode = node.get("qinfo");
if (qinfoNode != null) {
Map<String, String> qinfo = deserializeMapResult(response, qinfoNode, String.class, String.class);
result.setQueryInfo(qinfo);
}
result.setRawJson(node.toString());
result.setHeaders(headers);
return result;
}
private PagedSearchResult getPagedResult(ViSearchHttpResponse httpResponse) {
String response = httpResponse.getBody();
Map<String, String> headers = httpResponse.getHeaders();
JsonNode node;
try {
node = objectMapper.readTree(response);
} catch (JsonProcessingException e) {
throw new InternalViSearchException(ResponseMessages.PARSE_RESPONSE_ERROR, e, response);
// throw new ViSearchException("Could not parse the ViSearch response: " + response, e, response);
} catch (IOException e) {
throw new InternalViSearchException(ResponseMessages.PARSE_RESPONSE_ERROR, e, response);
// throw new ViSearchException("Could not parse the ViSearch response: " + response, e, response);
}
checkResponseStatus(node);
PagedResult<ImageResult> pagedResult = pagify(response, response, ImageResult.class);
PagedSearchResult result = new PagedSearchResult(pagedResult);
JsonNode productTypesNode = node.get("product_types");
if (productTypesNode != null) {
List<ProductType> productTypes = deserializeListResult(response, productTypesNode, ProductType.class);
result.setProductTypes(productTypes);
}
JsonNode productTypesListNode = node.get("product_types_list");
if (productTypesListNode != null) {
List<ProductType> productTypesList = deserializeListResult(response, productTypesListNode, ProductType.class);
result.setProductTypesList(productTypesList);
}
JsonNode imIdNode = node.get("im_id");
if (imIdNode != null) {
result.setImId(imIdNode.asText());
}
JsonNode facetsNode = node.get("facets");
if (facetsNode != null) {
List<Facet> facets = deserializeListResult(response, facetsNode, Facet.class);
result.setFacets(facets);
}
JsonNode qinfoNode = node.get("qinfo");
if (qinfoNode != null) {
Map<String, String> qinfo = deserializeMapResult(response, qinfoNode, String.class, String.class);
result.setQueryInfo(qinfo);
}
result.setRawJson(node.toString());
result.setHeaders(headers);
return result;
}
private static void checkResponseStatus(JsonNode node) {
String json = node.toString();
JsonNode statusNode = node.get("status");
if (statusNode == null) {
throw new InternalViSearchException(ResponseMessages.INVALID_RESPONSE_FORMAT, json);
// throw new ViSearchException("There was a malformed ViSearch response: " + json, json);
} else {
String status = statusNode.asText();
if (!"OK".equals(status)) {
JsonNode errorNode = node.get("error");
if (errorNode == null) {
throw new InternalViSearchException(ResponseMessages.INVALID_RESPONSE_FORMAT, json);
// throw new ViSearchException("An unknown error occurred in ViSearch: " + json, json);
}
String message = errorNode.path(0).asText();
throw new InternalViSearchException(message, json);
// throw new ViSearchException("An error occurred calling ViSearch: " + message, json);
}
}
}
}