package app.mealsmadeeasy.api.recipe.job; import app.mealsmadeeasy.api.job.Job; import app.mealsmadeeasy.api.job.JobHandler; import app.mealsmadeeasy.api.recipe.Recipe; import app.mealsmadeeasy.api.recipe.RecipeEmbedding; import app.mealsmadeeasy.api.recipe.RecipeRepository; import app.mealsmadeeasy.api.recipe.RecipeService; import app.mealsmadeeasy.api.util.NoSuchEntityWithIdException; import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.stereotype.Component; import java.time.OffsetDateTime; @Component @RequiredArgsConstructor public class RecipeEmbeddingJobHandler implements JobHandler { public static final String JOB_KEY = "RECIPE_EMBEDDING"; private static final Logger logger = LoggerFactory.getLogger(RecipeEmbeddingJobHandler.class); private final RecipeRepository recipeRepository; private final RecipeService recipeService; private final EmbeddingModel embeddingModel; @Override public Class getPayloadType() { return RecipeEmbeddingJobPayload.class; } @Override public String getJobKey() { return JOB_KEY; } @Override public void handle(Job job, RecipeEmbeddingJobPayload payload) { logger.info("Calculating embedding for recipeId {}", payload.recipeId()); final Recipe recipe = this.recipeRepository.findById(payload.recipeId()) .orElseThrow(() -> new NoSuchEntityWithIdException(Recipe.class, payload.recipeId())); final String renderedMarkdown = this.recipeService.getRenderedMarkdown(recipe); final String toEmbed = "

" + recipe.getTitle() + "

\n" + renderedMarkdown; final float[] embedding = this.embeddingModel.embed(toEmbed); final RecipeEmbedding recipeEmbedding = new RecipeEmbedding(); recipeEmbedding.setRecipe(recipe); recipeEmbedding.setEmbedding(embedding); recipeEmbedding.setTimestamp(OffsetDateTime.now()); recipe.setEmbedding(recipeEmbedding); this.recipeRepository.save(recipe); logger.info("Finished calculating embedding for recipeId {}", payload.recipeId()); } }