Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into EFRS-937_fix_and_r…
Browse files Browse the repository at this point in the history
…efactoring
  • Loading branch information
endypanda committed Mar 10, 2021
2 parents 249d123 + d2363ea commit f9d1dfe
Show file tree
Hide file tree
Showing 42 changed files with 291 additions and 162 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/Push-Python-to-Dockerhub.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ jobs:
run: |
make build-images
docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
docker push ${DOCKER_REGISTRY}compreface-core
docker push --all-tags ${DOCKER_REGISTRY}compreface-core
Original file line number Diff line number Diff line change
Expand Up @@ -16,47 +16,47 @@

package com.exadel.frs.controller;

import static com.exadel.frs.system.global.Constants.GUID_EXAMPLE;
import static org.springframework.http.HttpStatus.CREATED;

import com.exadel.frs.dto.ui.*;
import com.exadel.frs.commonservice.entity.Model;
import com.exadel.frs.commonservice.exception.IncorrectModelTypeException;
import com.exadel.frs.dto.ui.ModelCloneDto;
import com.exadel.frs.dto.ui.ModelCreateDto;
import com.exadel.frs.dto.ui.ModelResponseDto;
import com.exadel.frs.dto.ui.ModelUpdateDto;
import com.exadel.frs.helpers.SecurityUtils;
import com.exadel.frs.mapper.MlModelMapper;
import com.exadel.frs.service.ModelService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import java.util.List;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

import static com.exadel.frs.system.global.Constants.GUID_EXAMPLE;
import static org.springframework.http.HttpStatus.CREATED;

@RestController
@RequestMapping("/app/{appGuid}")
@RequiredArgsConstructor
public class ModelController {

public static final String DETECTION = "DETECTION";
public static final String RECOGNITION = "RECOGNITION";
public static final String VERIFY = "VERIFY";

private final ModelService modelService;
private final MlModelMapper modelMapper;

@GetMapping("/model/{guid}")
@ApiOperation(value = "Get model")
public ModelResponseDto getModel(
@ApiParam(value = "GUID of application", required = true, example = GUID_EXAMPLE)
@PathVariable
final String appGuid,
@PathVariable final String appGuid,
@ApiParam(value = "GUID of model to return", required = true, example = GUID_EXAMPLE)
@PathVariable
final String guid
@PathVariable final String guid
) {
return modelMapper.toResponseDto(
modelService.getModel(appGuid, guid, SecurityUtils.getPrincipalId()),
Expand All @@ -68,8 +68,7 @@ public ModelResponseDto getModel(
@ApiOperation(value = "Get all models in application")
public List<ModelResponseDto> getModels(
@ApiParam(value = "GUID of application", required = true, example = GUID_EXAMPLE)
@PathVariable
final String appGuid
@PathVariable final String appGuid
) {
return modelMapper.toResponseDto(
modelService.getModels(appGuid, SecurityUtils.getPrincipalId()),
Expand All @@ -85,16 +84,27 @@ public List<ModelResponseDto> getModels(
})
public ModelResponseDto createModel(
@ApiParam(value = "GUID of application", required = true, example = GUID_EXAMPLE)
@PathVariable
final String appGuid,
@PathVariable final String appGuid,
@ApiParam(value = "Model object that needs to be created", required = true)
@Valid
@RequestBody
final ModelCreateDto modelCreateDto
@RequestBody final ModelCreateDto modelCreateDto
) {
return modelMapper.toResponseDto(
modelService.createModel(modelCreateDto, appGuid, SecurityUtils.getPrincipalId()), appGuid
);
Model model;
switch (modelCreateDto.getType()) {
case DETECTION:
model = modelService.createDetectionModel(modelCreateDto, appGuid, SecurityUtils.getPrincipalId());
break;
case RECOGNITION:
model = modelService.createRecognitionModel(modelCreateDto, appGuid, SecurityUtils.getPrincipalId());
break;
case VERIFY:
model = modelService.createVerificationModel(modelCreateDto, appGuid, SecurityUtils.getPrincipalId());
break;
default:
throw new IncorrectModelTypeException(modelCreateDto.getType());
}

return modelMapper.toResponseDto(model, appGuid);
}

@PostMapping("/model/{guid}")
Expand All @@ -104,15 +114,12 @@ public ModelResponseDto createModel(
})
public ModelResponseDto cloneModel(
@ApiParam(value = "GUID of application", required = true, example = GUID_EXAMPLE)
@PathVariable
final String appGuid,
@PathVariable final String appGuid,
@ApiParam(value = "GUID of model that needs to be cloned", required = true, example = GUID_EXAMPLE)
@PathVariable
final String guid,
@PathVariable final String guid,
@ApiParam(value = "Model data", required = true)
@Valid
@RequestBody
final ModelCloneDto modelCloneDto) {
@RequestBody final ModelCloneDto modelCloneDto) {

var clonedModel = modelService.cloneModel(modelCloneDto, appGuid, guid, SecurityUtils.getPrincipalId());

Expand All @@ -126,15 +133,12 @@ public ModelResponseDto cloneModel(
})
public ModelResponseDto updateModel(
@ApiParam(value = "GUID of application", required = true, example = GUID_EXAMPLE)
@PathVariable
final String appGuid,
@PathVariable final String appGuid,
@ApiParam(value = "GUID of model that needs to be updated", required = true, example = GUID_EXAMPLE)
@PathVariable
final String guid,
@PathVariable final String guid,
@ApiParam(value = "Model data", required = true)
@Valid
@RequestBody
final ModelUpdateDto modelUpdateDto
@RequestBody final ModelUpdateDto modelUpdateDto
) {
var updatedModel = modelService.updateModel(modelUpdateDto, appGuid, guid, SecurityUtils.getPrincipalId());

Expand All @@ -145,11 +149,9 @@ public ModelResponseDto updateModel(
@ApiOperation(value = "Generate new api-key for model")
public ModelResponseDto regenerateApiKey(
@ApiParam(value = "GUID of application", required = true, example = GUID_EXAMPLE)
@PathVariable
final String appGuid,
@PathVariable final String appGuid,
@ApiParam(value = "GUID of the model which GUID needs to be regenerated", required = true, example = GUID_EXAMPLE)
@PathVariable
final String guid
@PathVariable final String guid
) {
modelService.regenerateApiKey(appGuid, guid, SecurityUtils.getPrincipalId());

Expand All @@ -160,11 +162,9 @@ public ModelResponseDto regenerateApiKey(
@ApiOperation(value = "Delete model")
public void deleteModel(
@ApiParam(value = "GUID of application", required = true, example = GUID_EXAMPLE)
@PathVariable
final String appGuid,
@PathVariable final String appGuid,
@ApiParam(value = "GUID of the model that needs to be deleted", required = true, example = GUID_EXAMPLE)
@PathVariable
final String guid
@PathVariable final String guid
) {
modelService.deleteModel(appGuid, guid, SecurityUtils.getPrincipalId());
}
Expand Down
48 changes: 39 additions & 9 deletions java/admin/src/main/java/com/exadel/frs/service/ModelService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,25 @@

package com.exadel.frs.service;

import com.exadel.frs.commonservice.annotation.CollectStatistics;
import com.exadel.frs.commonservice.entity.*;
import com.exadel.frs.commonservice.enums.ModelType;
import com.exadel.frs.commonservice.enums.StatisticsType;
import com.exadel.frs.commonservice.exception.IncorrectModelTypeException;
import com.exadel.frs.commonservice.exception.ModelNotFoundException;
import com.exadel.frs.commonservice.repository.FacesRepository;
import com.exadel.frs.commonservice.repository.ModelRepository;
import com.exadel.frs.dto.ui.ModelCloneDto;
import com.exadel.frs.dto.ui.ModelCreateDto;
import com.exadel.frs.dto.ui.ModelUpdateDto;
import com.exadel.frs.exception.NameIsNotUniqueException;
import com.exadel.frs.commonservice.repository.FacesRepository;
import com.exadel.frs.repository.ImagesRepository;
import com.exadel.frs.commonservice.repository.ModelRepository;
import com.exadel.frs.system.security.AuthorizationManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.transaction.Transactional;
import java.util.ArrayList;
Expand All @@ -39,8 +44,8 @@

@Service
@RequiredArgsConstructor
@Slf4j
public class ModelService {

private final ModelRepository modelRepository;
private final AppService appService;
private final AuthorizationManager authManager;
Expand All @@ -50,7 +55,7 @@ public class ModelService {

public Model getModel(final String modelGuid) {
return modelRepository.findByGuid(modelGuid)
.orElseThrow(() -> new ModelNotFoundException(modelGuid));
.orElseThrow(() -> new ModelNotFoundException(modelGuid, ""));
}

private void verifyNameIsUnique(final String name, final Long appId) {
Expand Down Expand Up @@ -78,23 +83,48 @@ public List<Model> getModels(final String appGuid, final Long userId) {
return modelRepository.findAllByAppId(app.getId());
}

public Model createModel(final ModelCreateDto modelCreateDto, final String appGuid, final Long userId) {
val app = appService.getApp(appGuid);
val user = userService.getUser(userId);
private Model createModel(final ModelCreateDto modelCreateDto, final String appGuid, final Long userId) {
App app = appService.getApp(appGuid);
User user = userService.getUser(userId);

authManager.verifyWritePrivilegesToApp(user, app);

verifyNameIsUnique(modelCreateDto.getName(), app.getId());

val model = Model.builder()
log.info("model type: {}", modelCreateDto.getType());

return modelRepository.save(buildModel(modelCreateDto, app));
}

public Model buildModel(ModelCreateDto modelCreateDto, App app) {
return Model.builder()
.name(modelCreateDto.getName())
.guid(randomUUID().toString())
.apiKey(randomUUID().toString())
.app(app)
.type(ModelType.valueOf(modelCreateDto.getType()))
.build();
}

return modelRepository.save(model);
@CollectStatistics(type = StatisticsType.FACE_RECOGNITION_CREATE)
public Model createRecognitionModel(ModelCreateDto modelCreateDto, final String appGuid, final Long userId) {
Model model = createModel(modelCreateDto, appGuid, userId);
log.info("recognition model created: {} ", model);
return model;
}

@CollectStatistics(type = StatisticsType.FACE_VERIFICATION_CREATE)
public Model createVerificationModel(ModelCreateDto modelCreateDto, final String appGuid, final Long userId) {
Model model = createModel(modelCreateDto, appGuid, userId);
log.info("verification model created: {}", model);
return model;
}

@CollectStatistics(type = StatisticsType.FACE_DETECTION_CREATE)
public Model createDetectionModel(ModelCreateDto modelCreateDto, final String appGuid, final Long userId) {
Model model = createModel(modelCreateDto, appGuid, userId);
log.info("detection model created: {}", model);
return model;
}

@Transactional
Expand Down
4 changes: 2 additions & 2 deletions java/admin/src/test/java/com/exadel/frs/ModelServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ void successCreateModel() {
when(appServiceMock.getApp(APPLICATION_GUID)).thenReturn(app);
when(userServiceMock.getUser(USER_ID)).thenReturn(user);

modelService.createModel(modelCreateDto, APPLICATION_GUID, USER_ID);
modelService.createRecognitionModel(modelCreateDto, APPLICATION_GUID, USER_ID);

val varArgs = ArgumentCaptor.forClass(Model.class);
verify(modelRepositoryMock).existsByNameAndAppId("model-name", APPLICATION_ID);
Expand All @@ -195,7 +195,7 @@ void failCreateModelNameIsNotUnique() {
when(modelRepositoryMock.existsByNameAndAppId(anyString(), anyLong())).thenReturn(true);

assertThatThrownBy(() ->
modelService.createModel(modelCreateDto, APPLICATION_GUID, USER_ID)
modelService.createRecognitionModel(modelCreateDto, APPLICATION_GUID, USER_ID)
).isInstanceOf(NameIsNotUniqueException.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ void shouldReturnCreatedModel() throws Exception {
val responseDto = new ModelResponseDto();
responseDto.setName(MODEL_NAME);

when(modelService.createModel(any(ModelCreateDto.class), eq(APP_GUID), anyLong())).thenReturn(model);
when(modelService.createRecognitionModel(any(ModelCreateDto.class), eq(APP_GUID), anyLong())).thenReturn(model);
when(modelMapper.toResponseDto(any(Model.class), eq(APP_GUID))).thenReturn(responseDto);

mockMvc.perform(createRequest)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ public class DetectionController {
value = "Api key of application and model",
required = true)
})
@CollectStatistics(type = StatisticsType.FACE_DETECTION_CREATE)
public FacesDetectionResponseDto detect(
@ApiParam(value = "Image for recognizing", required = true)
@RequestParam
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,11 @@

package com.exadel.frs.core.trainservice.controller;

import com.exadel.frs.commonservice.annotation.CollectStatistics;
import com.exadel.frs.commonservice.enums.StatisticsType;
import com.exadel.frs.core.trainservice.dto.FacesRecognitionResponseDto;
import com.exadel.frs.core.trainservice.dto.ProcessImageParams;
import com.exadel.frs.core.trainservice.service.FaceProcessService;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
Expand All @@ -43,7 +40,6 @@ public class RecognizeController {
private final FaceProcessService recognitionService;

@PostMapping(value = "/faces/recognize")
@CollectStatistics(type = StatisticsType.FACE_RECOGNITION_CREATE)
public FacesRecognitionResponseDto recognize(
@ApiParam(value = "Api key of application and model", required = true)
@RequestHeader(X_FRS_API_KEY_HEADER) final String apiKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ public class VerifyController {
private final FaceProcessService verificationService;

@PostMapping(value = "/verify")
@CollectStatistics(type = StatisticsType.FACE_VERIFICATION_CREATE)
public Map<String, List<VerifyFacesResponse>> verify(
@ApiParam(value = "Api key of application and model", required = true)
@RequestHeader(X_FRS_API_KEY_HEADER) final String apiKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,22 @@
package com.exadel.frs.core.trainservice.dto;

import java.util.List;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@JsonInclude(NON_NULL)
public class FacePredictionResultDto extends FindFacesResultDto {

List<FaceSimilarityDto> faces;
List<FaceSimilarityDto> subjects;
List<List<Integer>> landmarks;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@

package com.exadel.frs.core.trainservice.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Value;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;

@Value
@JsonInclude(NON_NULL)
public class FaceSimilarityDto {

@JsonProperty("face_name")
String faceName;
@JsonProperty("subject")
String subject;

float similarity;
}
Loading

0 comments on commit f9d1dfe

Please sign in to comment.