From 488583ec3c6b47d75d309bd9381a048743f9c891 Mon Sep 17 00:00:00 2001 From: Carl-Robert Linnupuu Date: Thu, 24 Oct 2024 11:53:35 +0100 Subject: [PATCH] feat: add auto apply integration (CodeGPT) --- .../llm/client/DeserializationUtil.java | 15 ++++++- .../llm/client/codegpt/CodeGPTClient.java | 29 +++++++++--- .../codegpt/request/AutoApplyRequest.java | 23 ++++++++++ .../codegpt/response/AutoApplyResponse.java | 14 ++++++ .../codegpt/response/CodeGPTException.java | 44 +++++++++++++++++++ 5 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 src/main/java/ee/carlrobert/llm/client/codegpt/request/AutoApplyRequest.java create mode 100644 src/main/java/ee/carlrobert/llm/client/codegpt/response/AutoApplyResponse.java create mode 100644 src/main/java/ee/carlrobert/llm/client/codegpt/response/CodeGPTException.java diff --git a/src/main/java/ee/carlrobert/llm/client/DeserializationUtil.java b/src/main/java/ee/carlrobert/llm/client/DeserializationUtil.java index b28f49f..13c69fb 100644 --- a/src/main/java/ee/carlrobert/llm/client/DeserializationUtil.java +++ b/src/main/java/ee/carlrobert/llm/client/DeserializationUtil.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; +import ee.carlrobert.llm.client.codegpt.response.CodeGPTException; import java.io.IOException; import okhttp3.Response; @@ -15,10 +16,20 @@ private DeserializationUtil() { public static T mapResponse(Response response, Class clazz) { var body = response.body(); + if (body == null) { + throw new RuntimeException("Response body is null"); + } + + String json = ""; try { - return OBJECT_MAPPER.readValue(body.string(), clazz); + json = body.string(); + return OBJECT_MAPPER.readValue(json, clazz); } catch (IOException ex) { - throw new RuntimeException("Could not deserialize response", ex); + try { + throw OBJECT_MAPPER.readValue(json, CodeGPTException.class); + } catch (IOException e) { + throw new RuntimeException("Could not deserialize response", ex); + } } } } diff --git a/src/main/java/ee/carlrobert/llm/client/codegpt/CodeGPTClient.java b/src/main/java/ee/carlrobert/llm/client/codegpt/CodeGPTClient.java index 347b389..04fd4d3 100644 --- a/src/main/java/ee/carlrobert/llm/client/codegpt/CodeGPTClient.java +++ b/src/main/java/ee/carlrobert/llm/client/codegpt/CodeGPTClient.java @@ -5,8 +5,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import ee.carlrobert.llm.PropertiesLoader; import ee.carlrobert.llm.client.DeserializationUtil; +import ee.carlrobert.llm.client.codegpt.request.AutoApplyRequest; import ee.carlrobert.llm.client.codegpt.request.CodeCompletionRequest; import ee.carlrobert.llm.client.codegpt.request.chat.ChatCompletionRequest; +import ee.carlrobert.llm.client.codegpt.response.AutoApplyResponse; import ee.carlrobert.llm.client.openai.completion.ErrorDetails; import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionEventSourceListener; import ee.carlrobert.llm.client.openai.completion.OpenAITextCompletionEventSourceListener; @@ -42,10 +44,7 @@ public CodeGPTClient(String apiKey, OkHttpClient.Builder httpClientBuilder) { } public CodeGPTUserDetails getUserDetails(String apiKey) { - try (var response = new OkHttpClient.Builder().build() - .newCall(buildUserDetailsRequest(apiKey)) - .execute()) { - + try (var response = httpClient.newCall(buildUserDetailsRequest(apiKey)).execute()) { return DeserializationUtil.mapResponse(response, CodeGPTUserDetails.class); } catch (IOException e) { throw new RuntimeException("Unable to fetch user details", e); @@ -72,7 +71,15 @@ public OpenAIChatCompletionResponse getChatCompletion(ChatCompletionRequest requ try (var response = httpClient.newCall(buildChatCompletionRequest(request)).execute()) { return DeserializationUtil.mapResponse(response, OpenAIChatCompletionResponse.class); } catch (IOException e) { - throw new RuntimeException(e); + throw new RuntimeException("Unable to get chat completion", e); + } + } + + public AutoApplyResponse applySuggestedChanges(AutoApplyRequest request) { + try (var response = httpClient.newCall(buildAutoApplyRequest(request)).execute()) { + return DeserializationUtil.mapResponse(response, AutoApplyResponse.class); + } catch (IOException e) { + throw new RuntimeException("Unable to apply suggested changes", e); } } @@ -116,6 +123,18 @@ private Request buildUserDetailsRequest(String apiKey) { .build(); } + private Request buildAutoApplyRequest(AutoApplyRequest request) { + try { + return new Request.Builder() + .url(BASE_URL + "/v1/files/apply-changes") + .header("Authorization", "Bearer " + apiKey) + .post(RequestBody.create(OBJECT_MAPPER.writeValueAsString(request), APPLICATION_JSON)) + .build(); + } catch (JsonProcessingException e) { + throw new RuntimeException("Unable to build file diff request", e); + } + } + private Map getRequiredHeaders() { var headers = new HashMap<>(Map.of( "X-LLM-Application-Tag", "codegpt", diff --git a/src/main/java/ee/carlrobert/llm/client/codegpt/request/AutoApplyRequest.java b/src/main/java/ee/carlrobert/llm/client/codegpt/request/AutoApplyRequest.java new file mode 100644 index 0000000..0cf8e29 --- /dev/null +++ b/src/main/java/ee/carlrobert/llm/client/codegpt/request/AutoApplyRequest.java @@ -0,0 +1,23 @@ +package ee.carlrobert.llm.client.codegpt.request; + +public class AutoApplyRequest { + + private String suggestedChanges; + private String fileContent; + + public String getSuggestedChanges() { + return suggestedChanges; + } + + public void setSuggestedChanges(String suggestedChanges) { + this.suggestedChanges = suggestedChanges; + } + + public String getFileContent() { + return fileContent; + } + + public void setFileContent(String fileContent) { + this.fileContent = fileContent; + } +} diff --git a/src/main/java/ee/carlrobert/llm/client/codegpt/response/AutoApplyResponse.java b/src/main/java/ee/carlrobert/llm/client/codegpt/response/AutoApplyResponse.java new file mode 100644 index 0000000..2871540 --- /dev/null +++ b/src/main/java/ee/carlrobert/llm/client/codegpt/response/AutoApplyResponse.java @@ -0,0 +1,14 @@ +package ee.carlrobert.llm.client.codegpt.response; + +public class AutoApplyResponse { + + private String modifiedFileContent; + + public String getModifiedFileContent() { + return modifiedFileContent; + } + + public void setModifiedFileContent(String modifiedFileContent) { + this.modifiedFileContent = modifiedFileContent; + } +} diff --git a/src/main/java/ee/carlrobert/llm/client/codegpt/response/CodeGPTException.java b/src/main/java/ee/carlrobert/llm/client/codegpt/response/CodeGPTException.java new file mode 100644 index 0000000..a01249d --- /dev/null +++ b/src/main/java/ee/carlrobert/llm/client/codegpt/response/CodeGPTException.java @@ -0,0 +1,44 @@ +package ee.carlrobert.llm.client.codegpt.response; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CodeGPTException extends RuntimeException { + + private String title; + private int status; + private String detail; + private String instance; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public String getInstance() { + return instance; + } + + public void setInstance(String instance) { + this.instance = instance; + } +}