From 56f99cb60cad4a07a7ddc89abffb6351dc74274c Mon Sep 17 00:00:00 2001 From: Antoine Rey Date: Fri, 27 Dec 2024 12:37:28 +0100 Subject: [PATCH] Fix SonarQube issues --- .../genai/AIFunctionConfiguration.java | 6 +++- .../petclinic/genai/PetclinicChatClient.java | 28 ++++++++++-------- .../genai/VectorStoreController.java | 29 +++++++++++++++---- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/AIFunctionConfiguration.java b/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/AIFunctionConfiguration.java index cca930d19..25f3ad8a0 100644 --- a/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/AIFunctionConfiguration.java +++ b/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/AIFunctionConfiguration.java @@ -3,6 +3,8 @@ import java.util.List; import java.util.function.Function; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Description; @@ -27,6 +29,8 @@ @Configuration class AIFunctionConfiguration { + private static final Logger LOG = LoggerFactory.getLogger(AIFunctionConfiguration.class); + // The @Description annotation helps the model understand when to call the function @Bean @Description("List the owners that the pet clinic has") @@ -49,7 +53,7 @@ public Function listVets(AIDataProvider petclinicAiProv return petclinicAiProvider.getVets(request); } catch (JsonProcessingException e) { - e.printStackTrace(); + LOG.error("Error processing JSON in the listVets function", e); return null; } }; diff --git a/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/PetclinicChatClient.java b/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/PetclinicChatClient.java index 7aecf24de..972704ab6 100644 --- a/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/PetclinicChatClient.java +++ b/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/PetclinicChatClient.java @@ -2,6 +2,8 @@ import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.DEFAULT_CHAT_MEMORY_CONVERSATION_ID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; @@ -20,26 +22,28 @@ @RequestMapping("/") public class PetclinicChatClient { + private static final Logger LOG = LoggerFactory.getLogger(PetclinicChatClient.class); + // ChatModel is the primary interfaces for interacting with an LLM // it is a request/response interface that implements the ModelModel // interface. Make suer to visit the source code of the ChatModel and - // checkout the interfaces in the core spring ai package. + // checkout the interfaces in the core Spring AI package. private final ChatClient chatClient; public PetclinicChatClient(ChatClient.Builder builder, ChatMemory chatMemory) { // @formatter:off this.chatClient = builder .defaultSystem(""" - You are a friendly AI assistant designed to help with the management of a veterinarian pet clinic called Spring Petclinic. - Your job is to answer questions about and to perform actions on the user's behalf, mainly around - veterinarians, owners, owners' pets and owners' visits. - You are required to answer an a professional manner. If you don't know the answer, politely tell the user - you don't know the answer, then ask the user a followup question to try and clarify the question they are asking. - If you do know the answer, provide the answer but do not provide any additional followup questions. - When dealing with vets, if the user is unsure about the returned results, explain that there may be additional data that was not returned. - Only if the user is asking about the total number of all vets, answer that there are a lot and ask for some additional criteria. - For owners, pets or visits - provide the correct data. - """) + You are a friendly AI assistant designed to help with the management of a veterinarian pet clinic called Spring Petclinic. + Your job is to answer questions about and to perform actions on the user's behalf, mainly around + veterinarians, owners, owners' pets and owners' visits. + You are required to answer an a professional manner. If you don't know the answer, politely tell the user + you don't know the answer, then ask the user a followup question to try and clarify the question they are asking. + If you do know the answer, provide the answer but do not provide any additional followup questions. + When dealing with vets, if the user is unsure about the returned results, explain that there may be additional data that was not returned. + Only if the user is asking about the total number of all vets, answer that there are a lot and ask for some additional criteria. + For owners, pets or visits - provide the correct data. + """) .defaultAdvisors( // Chat memory helps us keep context when using the chatbot for up to 10 previous messages. new MessageChatMemoryAdvisor(chatMemory, DEFAULT_CHAT_MEMORY_CONVERSATION_ID, 10), // CHAT MEMORY @@ -64,7 +68,7 @@ public String exchange(@RequestBody String query) { .call() .content(); } catch (Exception exception) { - exception.printStackTrace(); + LOG.error("Error processing chat message", exception); return "Chat is currently unavailable. Please try again later."; } } diff --git a/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/VectorStoreController.java b/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/VectorStoreController.java index eaef4810b..3b8e40330 100644 --- a/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/VectorStoreController.java +++ b/spring-petclinic-genai-service/src/main/java/org/springframework/samples/petclinic/genai/VectorStoreController.java @@ -2,8 +2,14 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.util.List; +import java.util.Set; +import org.apache.commons.lang3.SystemUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.document.Document; @@ -36,9 +42,8 @@ public class VectorStoreController { private final VectorStore vectorStore; private final WebClient webClient; - private final String vetsHostname = "http://vets-service/"; - - public VectorStoreController(VectorStore vectorStore, WebClient.Builder webClientBuilder) throws IOException { + + public VectorStoreController(VectorStore vectorStore, WebClient.Builder webClientBuilder) { this.webClient = webClientBuilder.build(); this.vectorStore = vectorStore; } @@ -61,7 +66,8 @@ public void loadVetDataToVectorStoreOnStartup(ApplicationStartedEvent event) thr // If vectorstore.json is deleted, the data will be loaded on startup every time. // Warning - this can be costly in terms of credits used with the AI provider. // Fetches all Vet entites and creates a document per vet - List vets = webClient + String vetsHostname = "http://vets-service/"; + List vets = webClient .get() .uri(vetsHostname + "vets") .retrieve() @@ -77,7 +83,18 @@ public void loadVetDataToVectorStoreOnStartup(ApplicationStartedEvent event) thr this.vectorStore.add(documents); if (vectorStore instanceof SimpleVectorStore) { - var file = File.createTempFile("vectorstore", ".json"); + File file; + if(SystemUtils.IS_OS_UNIX) { + // java:S5443 Sonar rule: Using publicly writable directories is security-sensitive + FileAttribute> attr = PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------")); + file = Files.createTempFile("vectorstore", ".json", attr).toFile(); + } + else { + file= Files.createTempFile("vectorstore", ".json").toFile(); + file.setReadable(true, true); + file.setWritable(true, true); + file.setExecutable(true, true); + } ((SimpleVectorStore) this.vectorStore).save(file); logger.info("vector store contents written to {}", file.getAbsolutePath()); } @@ -98,7 +115,7 @@ public Resource convertListToJsonResource(List vets) { return new ByteArrayResource(jsonBytes); } catch (JsonProcessingException e) { - e.printStackTrace(); + logger.error("Error processing JSON in the convertListToJsonResource function", e); return null; } }