diff --git a/src/main/java/com/krylov/refound/ai/client/ImageModerationClient.java b/src/main/java/com/krylov/refound/ai/client/ImageModerationClient.java index 76c904d..38179c4 100644 --- a/src/main/java/com/krylov/refound/ai/client/ImageModerationClient.java +++ b/src/main/java/com/krylov/refound/ai/client/ImageModerationClient.java @@ -1,7 +1,6 @@ package com.krylov.refound.ai.client; import com.krylov.refound.ai.dto.ImageModerationResponse; -import com.krylov.refound.ai.dto.ModerationResponse; import com.krylov.refound.ai.exception.AiServerException; import com.krylov.refound.ai.exception.AiUnavailableException; import lombok.RequiredArgsConstructor; @@ -29,12 +28,16 @@ public class ImageModerationClient { } @Recover - public ModerationResponse recover(AiUnavailableException e, String text) { + public ImageModerationResponse recover(AiUnavailableException e, MultipartFile file) { log.error("AI ImageModeration unavailable after retries", e); - return ModerationResponse.builder() - .approved(false) - .reason("AI_UNAVAILABLE") - .build(); + return null; + } + + @Recover + public ImageModerationResponse recover(AiServerException e, MultipartFile file) { + log.error("AI ImageModeration server error after retries", e); + + return null; } } diff --git a/src/main/java/com/krylov/refound/ai/client/TextModerationClient.java b/src/main/java/com/krylov/refound/ai/client/TextModerationClient.java index 7ecb105..1462b68 100644 --- a/src/main/java/com/krylov/refound/ai/client/TextModerationClient.java +++ b/src/main/java/com/krylov/refound/ai/client/TextModerationClient.java @@ -32,9 +32,13 @@ public class TextModerationClient { public ModerationResponse recover(AiUnavailableException e, String text) { log.error("AI TextModeration unavailable after retries", e); - return ModerationResponse.builder() - .approved(false) - .reason("AI_UNAVAILABLE") - .build(); + return null; + } + + @Recover + public ModerationResponse recover(AiServerException e, String text) { + log.error("AI TextModeration server error after retries", e); + + return null; } } diff --git a/src/main/java/com/krylov/refound/ai/facade/ContentModerationFacade.java b/src/main/java/com/krylov/refound/ai/facade/ContentModerationFacade.java index 1b431a9..ac79db0 100644 --- a/src/main/java/com/krylov/refound/ai/facade/ContentModerationFacade.java +++ b/src/main/java/com/krylov/refound/ai/facade/ContentModerationFacade.java @@ -15,7 +15,7 @@ public class ContentModerationFacade { private final ContentModerationPipeline pipeline; - public void moderate(String title, String description, List images) { + public Boolean moderate(String title, String description, List images) { log.info("moderate ContentModerationFacade get"); ModerationContext context = ModerationContext.builder() @@ -24,7 +24,7 @@ public class ContentModerationFacade { .images(images) .build(); - pipeline.execute(context); + return pipeline.execute(context); } } diff --git a/src/main/java/com/krylov/refound/ai/pipeline/ContentModerationPipeline.java b/src/main/java/com/krylov/refound/ai/pipeline/ContentModerationPipeline.java index cb70a2a..615f5c8 100644 --- a/src/main/java/com/krylov/refound/ai/pipeline/ContentModerationPipeline.java +++ b/src/main/java/com/krylov/refound/ai/pipeline/ContentModerationPipeline.java @@ -12,11 +12,15 @@ public class ContentModerationPipeline { private final List processors; - public void execute(ModerationContext context) { + public Boolean execute(ModerationContext context) { log.info("execute ContentModerationPipeline"); for (ModerationProcessor processor : processors) { - processor.process(context); + Boolean approved = processor.process(context); + if (approved == null) { + return null; + } } + return Boolean.TRUE; } } diff --git a/src/main/java/com/krylov/refound/ai/pipeline/ImageModerationProcessor.java b/src/main/java/com/krylov/refound/ai/pipeline/ImageModerationProcessor.java index 9eb455c..b7a596a 100644 --- a/src/main/java/com/krylov/refound/ai/pipeline/ImageModerationProcessor.java +++ b/src/main/java/com/krylov/refound/ai/pipeline/ImageModerationProcessor.java @@ -21,11 +21,11 @@ public class ImageModerationProcessor implements ModerationProcessor { private final ImageModerationClient client; @Override - public void process(ModerationContext context) { + public Boolean process(ModerationContext context) { List images = context.getImages(); if (images == null || images.isEmpty()) { - return; + return Boolean.TRUE; } for (MultipartFile image : images) { @@ -34,6 +34,10 @@ public class ImageModerationProcessor implements ModerationProcessor { } ImageModerationResponse response = client.moderate(image); + if (response == null) { + log.warn("AI ImageModeration вернул null, пропускаем модерацию изображения"); + return null; + } log.info("Image moderation result approved={}, score={}, reason={}, labels={}", response.getApproved(), @@ -42,10 +46,12 @@ public class ImageModerationProcessor implements ModerationProcessor { response.getDetectedLabels() ); - if (!response.getApproved()) { + if (!Boolean.TRUE.equals(response.getApproved())) { throw new ContentBlockedException(response.getReason(), response.getDetectedLabels()); } } + + return Boolean.TRUE; } } diff --git a/src/main/java/com/krylov/refound/ai/pipeline/ModerationProcessor.java b/src/main/java/com/krylov/refound/ai/pipeline/ModerationProcessor.java index efde4ae..edf0779 100644 --- a/src/main/java/com/krylov/refound/ai/pipeline/ModerationProcessor.java +++ b/src/main/java/com/krylov/refound/ai/pipeline/ModerationProcessor.java @@ -2,6 +2,6 @@ package com.krylov.refound.ai.pipeline; public interface ModerationProcessor { - void process(ModerationContext context); + Boolean process(ModerationContext context); } diff --git a/src/main/java/com/krylov/refound/ai/pipeline/TextModerationProcessor.java b/src/main/java/com/krylov/refound/ai/pipeline/TextModerationProcessor.java index edaaab6..61dcd1d 100644 --- a/src/main/java/com/krylov/refound/ai/pipeline/TextModerationProcessor.java +++ b/src/main/java/com/krylov/refound/ai/pipeline/TextModerationProcessor.java @@ -17,7 +17,7 @@ public class TextModerationProcessor implements ModerationProcessor { private final TextModerationClient client; @Override - public void process(ModerationContext context) { + public Boolean process(ModerationContext context) { log.info("process TextModerationProcessor for context {}", context); String text = buildText( context.getTitle(), @@ -25,12 +25,18 @@ public class TextModerationProcessor implements ModerationProcessor { ); ModerationResponse response = client.moderate(text); + if (response == null) { + log.warn("AI TextModeration вернул null, пропускаем модерацию текста"); + return null; + } + log.info("AI moderation result approved={}, score={}, reason={}", response.getApproved(), response.getScore(), response.getReason()); - if (!response.getApproved()) { + if (!Boolean.TRUE.equals(response.getApproved())) { throw new ContentBlockedException(response.getReason(), response.getDetectedLabels()); } + return Boolean.TRUE; } private String buildText(String title, String description) { diff --git a/src/main/java/com/krylov/refound/config/CacheConfig.java b/src/main/java/com/krylov/refound/config/CacheConfig.java deleted file mode 100644 index f250372..0000000 --- a/src/main/java/com/krylov/refound/config/CacheConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.krylov.refound.config; - -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.annotation.Configuration; - -@EnableCaching -@Configuration -public class CacheConfig { - -} diff --git a/src/main/java/com/krylov/refound/config/RedisConfig.java b/src/main/java/com/krylov/refound/config/RedisConfig.java deleted file mode 100644 index 7600024..0000000 --- a/src/main/java/com/krylov/refound/config/RedisConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.krylov.refound.config; - -import java.time.Duration; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.cache.RedisCacheConfiguration; -import org.springframework.data.redis.cache.RedisCacheManager; -import org.springframework.data.redis.connection.RedisConnectionFactory; - -@Configuration -public class RedisConfig { - @Value("${cache.ttl}") - private long ttl; - - @Bean - public RedisCacheManager cacheManager(RedisConnectionFactory factory) { - - RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() - .entryTtl(Duration.ofSeconds(ttl)) - .disableCachingNullValues(); - - return RedisCacheManager.builder(factory) - .cacheDefaults(config) - .build(); - } -} diff --git a/src/main/java/com/krylov/refound/service/PostModerationExecutorService.java b/src/main/java/com/krylov/refound/service/PostModerationExecutorService.java index 038c3dc..6d58440 100644 --- a/src/main/java/com/krylov/refound/service/PostModerationExecutorService.java +++ b/src/main/java/com/krylov/refound/service/PostModerationExecutorService.java @@ -44,7 +44,12 @@ public class PostModerationExecutorService { .map(this::toMultipartFile) .toList(); - contentModerationFacade.moderate(post.getTitle(), post.getDescription(), images); + Boolean approved = contentModerationFacade.moderate(post.getTitle(), post.getDescription(), images); + + if (approved == null) { + log.warn("Пост {} не отмодерирован из-за недоступности AI, статус не меняем", post.getId()); + return; + } postRepository.updateStatus(postId, PostStatus.ACTIVE); log.info("Пост {} прошёл модерацию.", post.getId()); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 9dea8c2..82174ca 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -23,9 +23,6 @@ spring: host: localhost port: 6379 - cache: - type: redis - liquibase: change-log: classpath:db/changelog/db.changelog-master.yaml @@ -44,9 +41,6 @@ ai: delay: 500 multiplier: 2 -cache: - ttl: 300 - jwt: secret: ${JWT_SECRET:mySuperSecretKeyForJwtTokenGenerationThatIsLongEnough2024!ReFound} access-expiration: ${JWT_ACCESS_EXPIRATION:900000} # 15 минут