Skip to content

Commit

Permalink
Implement Endpoint for AI-Generated Eco-News
Browse files Browse the repository at this point in the history
  • Loading branch information
Maryna-511750 committed Dec 11, 2024
1 parent b748bbe commit 84904f8
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 6 deletions.
19 changes: 19 additions & 0 deletions core/src/main/java/greencity/controller/AIController.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Locale;

Expand Down Expand Up @@ -43,4 +44,22 @@ public ResponseEntity<String> forecast(@Parameter(hidden = true) @CurrentUser Us
return ResponseEntity.status(HttpStatus.OK)
.body(aiService.getForecast(userVO.getId(), locale.getDisplayLanguage()));
}

@Operation(summary = "Generates news content based on the specified language and query")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = HttpStatuses.OK),
@ApiResponse(responseCode = "400", description = HttpStatuses.BAD_REQUEST,
content = @Content(examples = @ExampleObject(HttpStatuses.BAD_REQUEST))),
@ApiResponse(responseCode = "401", description = HttpStatuses.UNAUTHORIZED,
content = @Content(examples = @ExampleObject(HttpStatuses.UNAUTHORIZED))),
@ApiResponse(responseCode = "404", description = HttpStatuses.NOT_FOUND,
content = @Content(examples = @ExampleObject(HttpStatuses.NOT_FOUND)))
})
@ApiLocale
@GetMapping("/generate/eco-news")
public ResponseEntity<String> creatingEcoNews(@Parameter(hidden = true) Locale locale,
@RequestParam(required = false) String query) {
return ResponseEntity.status(HttpStatus.OK)
.body(aiService.getNews(locale.getDisplayLanguage(), query));
}
}
14 changes: 13 additions & 1 deletion core/src/test/java/greencity/controller/AIControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void setup() {
}

@Test
void forecast_ReturnsForecast_FromAIService() throws Exception {
void forecastReturnsForecastFromAIServiceTest() throws Exception {
Locale testLocale = Locale.forLanguageTag("en");

mockMvc.perform(get("/ai/forecast")
Expand All @@ -52,4 +52,16 @@ void forecast_ReturnsForecast_FromAIService() throws Exception {

verify(aiService, times(1)).getForecast(any(), eq(testLocale.getDisplayLanguage()));
}

@Test
void creatingEcoNewsReturnsEcoNewsFromAIServiceTest() throws Exception {
Locale testLocale = Locale.forLanguageTag("en");

mockMvc.perform(get("/ai/generate/eco-news")
.principal(principal)
.locale(testLocale))
.andExpect(status().isOk());

verify(aiService, times(1)).getNews(eq(testLocale.getDisplayLanguage()), any());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ public class OpenAIRequest {
+ "over the specified number of days:";
public static final String ADVICE = "answer by starting with the words \"since you don't have active habits\" "
+ "in the specified language. and then advertise the benefits of this habit:";
public static final String NEWS_BY_QUERY = "generate real and relevant eco news "
+ "(maximum length 1350 characters) on the topic:";
public static final String NEWS_WITHOUT_QUERY = "generate a real and relevant eco-news story on any topic according"
+ " to the latest trends in the world (maximum length 1350 characters)";
}
10 changes: 10 additions & 0 deletions service-api/src/main/java/greencity/service/AIService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,14 @@ public interface AIService {
* @return The advice as a string in the specified language.
*/
String getAdvice(Long userId, String language);

/**
* Generates news content based on the specified language and topic.
*
* @param language The preferred language for the news content.
* @param query The topic for the news. If the query is empty, generates news
* on a random eco-friendly topic.
* @return The generated news as a string in the specified language.
*/
String getNews(String language, String query);
}
6 changes: 6 additions & 0 deletions service/src/main/java/greencity/service/AIServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,10 @@ public String getAdvice(Long userId, String language) {
ShortHabitDto shortHabitDto = modelMapper.map(habit, ShortHabitDto.class);
return openAIService.makeRequest(language + OpenAIRequest.ADVICE + shortHabitDto);
}

@Override
public String getNews(String language, String query) {
return query == null ? openAIService.makeRequest(language + OpenAIRequest.NEWS_WITHOUT_QUERY)
: openAIService.makeRequest(language + OpenAIRequest.NEWS_BY_QUERY + query);
}
}
42 changes: 37 additions & 5 deletions service/src/test/java/greencity/service/AIServiceImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
import java.util.List;
import static greencity.ModelUtils.getHabitAssign;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.times;

@ExtendWith(MockitoExtension.class)
class AIServiceImplTest {
Expand Down Expand Up @@ -49,7 +52,7 @@ class AIServiceImplTest {
private final ShortHabitDto shortHabitDto = new ShortHabitDto(id, habitTranslationName);

@Test
void getForecastReturnsResponseFromOpenAIService() {
void getForecastReturnsResponseFromOpenAIServiceTest() {
when(habitAssignRepo.findAllByUserId(id)).thenReturn(List.of(habitAssign));
when(modelMapper.map(habitAssign, DurationHabitDto.class)).thenReturn(durationHabitDto);
when(openAIService.makeRequest("en" + OpenAIRequest.FORECAST + List.of(durationHabitDto)))
Expand All @@ -64,7 +67,7 @@ void getForecastReturnsResponseFromOpenAIService() {
}

@Test
void getForecastThrowsExceptionWhenOpenAIServiceFails() {
void getForecastThrowsExceptionWhenOpenAIServiceFailsTest() {
when(habitAssignRepo.findAllByUserId(id)).thenReturn(List.of(habitAssign));
when(modelMapper.map(habitAssign, DurationHabitDto.class)).thenReturn(durationHabitDto);
when(openAIService.makeRequest("en" + OpenAIRequest.FORECAST + List.of(durationHabitDto)))
Expand All @@ -78,7 +81,7 @@ void getForecastThrowsExceptionWhenOpenAIServiceFails() {
}

@Test
void getForecastCallsGetAdviceWhenHabitAssignsIsEmpty() {
void getForecastCallsGetAdviceWhenHabitAssignsIsEmptyTest() {
when(habitAssignRepo.findAllByUserId(id)).thenReturn(Collections.emptyList());
when(habitRepo.findRandomHabit()).thenReturn(habit);
when(modelMapper.map(habit, ShortHabitDto.class)).thenReturn(shortHabitDto);
Expand All @@ -95,7 +98,7 @@ void getForecastCallsGetAdviceWhenHabitAssignsIsEmpty() {
}

@Test
void getAdviceReturnsResponseFromOpenAIService() {
void getAdviceReturnsResponseFromOpenAIServiceTest() {
when(habitRepo.findRandomHabit()).thenReturn(habit);
when(modelMapper.map(habit, ShortHabitDto.class)).thenReturn(shortHabitDto);
when(openAIService.makeRequest("en" + OpenAIRequest.ADVICE + shortHabitDto))
Expand All @@ -110,7 +113,7 @@ void getAdviceReturnsResponseFromOpenAIService() {
}

@Test
void getAdviceThrowsExceptionWhenOpenAIServiceFails() {
void getAdviceThrowsExceptionWhenOpenAIServiceFailsTest() {
when(habitRepo.findRandomHabit()).thenReturn(habit);
when(modelMapper.map(habit, ShortHabitDto.class)).thenReturn(shortHabitDto);
when(openAIService.makeRequest("en" + OpenAIRequest.ADVICE + shortHabitDto))
Expand All @@ -122,4 +125,33 @@ void getAdviceThrowsExceptionWhenOpenAIServiceFails() {
verify(modelMapper).map(habit, ShortHabitDto.class);
verify(openAIService).makeRequest("en" + OpenAIRequest.ADVICE + shortHabitDto);
}

@Test
void getNewsShouldReturnWithoutQueryWhenQueryIsNullTest() {
String expectedResponse = "Mocked Response";
when(openAIService.makeRequest(language + OpenAIRequest.NEWS_WITHOUT_QUERY))
.thenReturn(expectedResponse);

String actualResponse = aiServiceImpl.getNews(language, null);

assertEquals(expectedResponse, actualResponse);
verify(openAIService, times(1))
.makeRequest(language + OpenAIRequest.NEWS_WITHOUT_QUERY);
verifyNoMoreInteractions(openAIService);
}

@Test
void getNewsShouldReturnWithQueryWhenQueryIsNotNullTest() {
String query = "climate change";
String expectedResponse = "Mocked Response";
when(openAIService.makeRequest(language + OpenAIRequest.NEWS_BY_QUERY + query))
.thenReturn(expectedResponse);

String actualResponse = aiServiceImpl.getNews(language, query);

assertEquals(expectedResponse, actualResponse);
verify(openAIService, times(1))
.makeRequest(language + OpenAIRequest.NEWS_BY_QUERY + query);
verifyNoMoreInteractions(openAIService);
}
}

0 comments on commit 84904f8

Please sign in to comment.