Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iris: Change Pyris response type #7352

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;

import de.tum.in.www1.artemis.domain.iris.IrisTemplate;
import de.tum.in.www1.artemis.service.connectors.iris.dto.IrisErrorResponseDTO;
import de.tum.in.www1.artemis.service.connectors.iris.dto.IrisMessageResponseDTO;
import de.tum.in.www1.artemis.service.connectors.iris.dto.IrisModelDTO;
import de.tum.in.www1.artemis.service.connectors.iris.dto.IrisRequestDTO;
import de.tum.in.www1.artemis.service.connectors.iris.dto.*;
import de.tum.in.www1.artemis.service.iris.exception.*;

/**
Expand Down Expand Up @@ -57,7 +54,23 @@ public IrisConnectorService(@Qualifier("irisRestTemplate") RestTemplate restTemp
@Async
public CompletableFuture<IrisMessageResponseDTO> sendRequest(IrisTemplate template, String preferredModel, Map<String, Object> parameters) {
var request = new IrisRequestDTO(template, preferredModel, parameters);
return sendRequest(request);
return sendRequest(request, "v1", IrisMessageResponseDTO.class);
}

/**
* Requests a response from an LLM using the V2 API
*
* @param template The template that should be used with the respective parameters (e.g., for initial system message)
* @param preferredModel The LLM model to be used (e.g., GPT3.5-turbo). Note: The used model might not be the preferred model (e.g., if an error occurs or the preferredModel is
* not reachable)
* @param parameters A map of parameters to be included in the template through handlebars (if they are specified
* in the template)
* @return The message response to the request which includes the {@link de.tum.in.www1.artemis.domain.iris.IrisMessage} and the used IrisModel
*/
@Async
public CompletableFuture<IrisMessageResponseV2DTO> sendRequestV2(IrisTemplate template, String preferredModel, Map<String, Object> parameters) {
var request = new IrisRequestDTO(template, preferredModel, parameters);
return sendRequest(request, "v2", IrisMessageResponseV2DTO.class);
}

/**
Expand All @@ -78,14 +91,14 @@ public List<IrisModelDTO> getOfferedModels() throws IrisConnectorException {
}
}

private CompletableFuture<IrisMessageResponseDTO> sendRequest(IrisRequestDTO request) {
private <Response> CompletableFuture<Response> sendRequest(IrisRequestDTO request, String version, Class<Response> responseType) {
try {
try {
var response = restTemplate.postForEntity(irisUrl + "/api/v1/messages", objectMapper.valueToTree(request), JsonNode.class);
var response = restTemplate.postForEntity(irisUrl + "/api/" + version + "/messages", objectMapper.valueToTree(request), JsonNode.class);
if (!response.hasBody()) {
return CompletableFuture.failedFuture(new IrisNoResponseException());
}
return CompletableFuture.completedFuture(parseResponse(response.getBody(), IrisMessageResponseDTO.class));
return CompletableFuture.completedFuture(parseResponse(response.getBody(), responseType));
}
catch (HttpStatusCodeException e) {
switch (e.getStatusCode()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package de.tum.in.www1.artemis.service.connectors.iris.dto;

import java.time.ZonedDateTime;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;

public record IrisMessageResponseV2DTO(String usedModel, ZonedDateTime sentAt, JsonNode content) {

/**
* Create a new IrisMessageResponseDTO. Jackson uses this constructor to create the object.
* This is necessary because Jackson was not throwing an exception when the response from Iris did not contain
* the expected fields, which resulted in a NullPointerException when trying to access the fields.
* Not sure if this is a bug in Jackson or if it is intended behavior, either way this is a workaround.
*/
@JsonCreator
public IrisMessageResponseV2DTO(@JsonProperty(value = "used_model", required = true) String usedModel, @JsonProperty(value = "sent_at", required = true) ZonedDateTime sentAt,
@JsonProperty(value = "content", required = true) JsonNode content) {
this.usedModel = usedModel;
this.sentAt = sentAt;
this.content = content;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,14 @@ public void reset() throws Exception {
}

/**
* Mocks response call for the pyris call
* Mocks a message response from the call to pyris
*/
public void mockMessageResponse(String responseMessage) throws JsonProcessingException {
if (responseMessage == null) {
mockServer.expect(ExpectedCount.once(), requestTo(messagesApiURL.toString())).andExpect(method(HttpMethod.POST)).andRespond(withSuccess());
return;
}

var irisMessage = new IrisMessage();
var irisMessageContent = new IrisMessageContent();
irisMessageContent.setTextContent(responseMessage);
Expand All @@ -86,12 +87,13 @@ public void mockMessageResponse(String responseMessage) throws JsonProcessingExc
irisMessage.setSentAt(ZonedDateTime.now());

var response = new IrisMessageResponseDTO(null, irisMessage);

var json = mapper.writeValueAsString(response);

mockServer.expect(ExpectedCount.once(), requestTo(messagesApiURL.toString())).andExpect(method(HttpMethod.POST)).andRespond(withSuccess(json, MediaType.APPLICATION_JSON));
}

public void mockCustomJsonResponse(String responseMessage) throws JsonProcessingException {
public void mockCustomJsonResponse(String responseMessage) {
mockServer.expect(ExpectedCount.once(), requestTo(messagesApiURL.toString())).andExpect(method(HttpMethod.POST))
.andRespond(withSuccess(responseMessage, MediaType.APPLICATION_JSON));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ void testParseException() throws Exception {
irisRequestMockProvider.mockCustomJsonResponse("{\"message\": \"invalid\"}");

irisConnectorService.sendRequest(template, "TEST_MODEL", Collections.emptyMap()).handle((response, throwable) -> {
assertThat(response).isNull();
assertThat(throwable).isNotNull();
assertThat(throwable.getCause()).isNotNull().isInstanceOf(IrisParseResponseException.class);
return null;
}).get();
Expand Down