Add last inference to RecipeDraftView.
This commit is contained in:
parent
d61fb97dbb
commit
77b94e6988
@ -6,6 +6,8 @@ import app.mealsmadeeasy.api.ai.OcrService;
|
||||
import app.mealsmadeeasy.api.auth.AuthService;
|
||||
import app.mealsmadeeasy.api.auth.LoginException;
|
||||
import app.mealsmadeeasy.api.recipe.body.RecipeDraftUpdateBody;
|
||||
import app.mealsmadeeasy.api.recipe.job.RecipeInferJobHandler;
|
||||
import app.mealsmadeeasy.api.recipe.view.RecipeDraftView;
|
||||
import app.mealsmadeeasy.api.user.User;
|
||||
import app.mealsmadeeasy.api.user.UserCreateException;
|
||||
import app.mealsmadeeasy.api.user.UserService;
|
||||
@ -14,17 +16,21 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
@ -52,6 +58,12 @@ public class RecipeDraftsControllerIntegrationTests {
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@MockitoBean
|
||||
private OcrService ocrService;
|
||||
|
||||
@MockitoBean
|
||||
private InferenceService inferenceService;
|
||||
|
||||
private static final String TEST_PASSWORD = "test";
|
||||
|
||||
private User seedUser() {
|
||||
@ -177,12 +189,6 @@ public class RecipeDraftsControllerIntegrationTests {
|
||||
@Nested
|
||||
public class AiDraftTestsWithMocks {
|
||||
|
||||
@MockitoBean
|
||||
private OcrService ocrService;
|
||||
|
||||
@MockitoBean
|
||||
private InferenceService inferenceService;
|
||||
|
||||
@Test
|
||||
public void whenAiDraft_returnsDraft() throws Exception {
|
||||
final User owner = seedUser();
|
||||
@ -190,7 +196,7 @@ public class RecipeDraftsControllerIntegrationTests {
|
||||
"sourceFile",
|
||||
"recipe.jpeg",
|
||||
MimeTypeUtils.IMAGE_JPEG_VALUE,
|
||||
AiDraftTestsWithMocks.class.getResourceAsStream("recipe.jpeg")
|
||||
this.getClass().getResourceAsStream("/recipe.jpeg")
|
||||
);
|
||||
mockMvc.perform(
|
||||
multipart("/recipe-drafts/ai")
|
||||
@ -205,6 +211,46 @@ public class RecipeDraftsControllerIntegrationTests {
|
||||
.andExpect(jsonPath("$.owner.username", is(owner.getUsername())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pollingAfterAiDraft_returnsDraftWithInference() throws Exception {
|
||||
Mockito.when(ocrService.readMarkdown(Mockito.any())).thenReturn("# Recipe");
|
||||
Mockito.when(inferenceService.extract(
|
||||
Mockito.any(),
|
||||
Mockito.any(),
|
||||
Mockito.any()
|
||||
)).thenReturn(new RecipeInferJobHandler.RecipeExtraction("Recipe", List.of()));
|
||||
|
||||
final User owner = seedUser();
|
||||
final MockMultipartFile sourceFile = new MockMultipartFile(
|
||||
"sourceFile",
|
||||
"recipe.jpeg",
|
||||
MimeTypeUtils.IMAGE_JPEG_VALUE,
|
||||
this.getClass().getResourceAsStream("/recipe.jpeg")
|
||||
);
|
||||
final MvcResult result = mockMvc.perform(
|
||||
multipart("/recipe-drafts/ai")
|
||||
.file(sourceFile)
|
||||
.param("sourceFileName", sourceFile.getOriginalFilename())
|
||||
.header("Authorization", "Bearer " + getAccessToken(owner))
|
||||
).andReturn();
|
||||
final UUID draftId = objectMapper.readValue(
|
||||
result.getResponse().getContentAsString(),
|
||||
RecipeDraftView.class
|
||||
).id();
|
||||
await().atMost(3, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
mockMvc.perform(
|
||||
get("/recipe-drafts/{id}", draftId)
|
||||
.header("Authorization", "Bearer " + getAccessToken(owner))
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.state", is(RecipeDraft.State.ENTER_DATA.toString())))
|
||||
.andExpect(jsonPath("$.lastInference", is(notNullValue())))
|
||||
.andExpect(jsonPath("$.lastInference.inferredAt", is(notNullValue())))
|
||||
.andExpect(jsonPath("$.lastInference.title", is("Recipe")))
|
||||
.andExpect(jsonPath("$.lastInference.rawText", is("# Recipe")));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static RecipeDraftUpdateBody getTestRecipeDraftUpdateBody() {
|
||||
|
||||
@ -10,6 +10,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RecipeDraftToViewConverter {
|
||||
@ -20,6 +22,17 @@ public class RecipeDraftToViewConverter {
|
||||
final @Nullable ImageView mainImageView = recipeDraft.getMainImage() != null
|
||||
? this.imageToViewConverter.convert(recipeDraft.getMainImage(), viewer, false)
|
||||
: null;
|
||||
final @Nullable RecipeDraftView.RecipeDraftInferenceView lastInference = recipeDraft.getInferences() != null
|
||||
? recipeDraft.getInferences().stream()
|
||||
.max(Comparator.comparing(RecipeDraft.RecipeDraftInference::getInferredAt))
|
||||
.map(inference -> RecipeDraftView.RecipeDraftInferenceView.builder()
|
||||
.inferredAt(inference.getInferredAt())
|
||||
.title(inference.getTitle())
|
||||
.rawText(inference.getRawText())
|
||||
.build()
|
||||
)
|
||||
.orElse(null)
|
||||
: null;
|
||||
return RecipeDraftView.builder()
|
||||
.id(recipeDraft.getId())
|
||||
.created(recipeDraft.getCreated())
|
||||
@ -34,6 +47,7 @@ public class RecipeDraftToViewConverter {
|
||||
.ingredients(recipeDraft.getIngredients())
|
||||
.owner(UserInfoView.from(recipeDraft.getOwner()))
|
||||
.mainImage(mainImageView)
|
||||
.lastInference(lastInference)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import app.mealsmadeeasy.api.recipe.RecipeDraft;
|
||||
import app.mealsmadeeasy.api.recipe.RecipeService;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -32,12 +33,14 @@ import java.util.List;
|
||||
@RequiredArgsConstructor
|
||||
public class RecipeInferJobHandler implements JobHandler<RecipeInferJobPayload> {
|
||||
|
||||
private record RecipeExtraction(
|
||||
@ApiStatus.Internal
|
||||
public record RecipeExtraction(
|
||||
@JsonProperty(required = true) String title,
|
||||
@JsonProperty(required = true) List<IngredientExtraction> ingredients
|
||||
) {}
|
||||
|
||||
private record IngredientExtraction(
|
||||
@ApiStatus.Internal
|
||||
public record IngredientExtraction(
|
||||
String amount,
|
||||
@JsonProperty(required = true) String name,
|
||||
String notes
|
||||
|
||||
@ -24,5 +24,15 @@ public record RecipeDraftView(
|
||||
@Nullable String rawText,
|
||||
@Nullable List<RecipeDraft.IngredientDraft> ingredients,
|
||||
UserInfoView owner,
|
||||
@Nullable ImageView mainImage
|
||||
@Nullable ImageView mainImage,
|
||||
@Nullable RecipeDraftInferenceView lastInference
|
||||
) {
|
||||
|
||||
@Builder
|
||||
public record RecipeDraftInferenceView(
|
||||
OffsetDateTime inferredAt,
|
||||
String title,
|
||||
String rawText
|
||||
) {}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user