Skip to content
Merged
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 @@ -10,6 +10,17 @@

import java.net.URI;

/**
* Configuration class for setting up the RestClient bean used to interact with the OpenRouter service.
* Integrates resilient methods to enable fault tolerance when communicating with the API.
*
* This configuration retrieves API properties such as the base URL and API key from the application's
* externalized configuration and injects them as properties. The RestClient is configured with an HTTP client
* that disables automatic retries and includes default headers required for authentication and proper content type.
*
* An instance of the RestClient.Builder is autowired and used to construct the RestClient based on the provided
* configuration properties.
*/
@Configuration
@EnableResilientMethods
public class RestClientConfiguration {
Expand Down
15 changes: 9 additions & 6 deletions src/main/java/org/example/projectbifrost/domain/ChatMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@

import java.time.LocalDateTime;


/**
* Represents a chat message in a conversation.
* This class encapsulates the details of a single message, including its role, content,
* and the timestamp at which it was created.
* Represents a chat message within a chat session.
*
* This class encapsulates the details of a message exchanged
* during a chat session, including its role (e.g., "user", "assistant"),
* the message content, the sender's name, and the timestamp
* of when the message was created. Instances of this class
* are typically used and managed in the context of a {@link ChatSession}.
*
* The role typically signifies the sender's identity (e.g., user, system, assistant),
* while the message contains the text content of the chat.
* The timestamp indicates when the message was generated.
* The timestamp is automatically generated at the time of message creation.
*/
@Getter
@Setter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

import java.util.List;

/**
* A data transfer object representing a request to interact with the OpenRouter API.
* This DTO encapsulates the model to be used and a list of message exchanges.
*
* @param model The specific model to use for generating responses, typically representing
* the desired large language model or OpenRouter configuration.
* @param messages A list of message exchanges that define the context of the interaction.
* Each message contains a role (e.g., "user" or "assistant") and the message content.
*/
public record OpenRouterRequestDTO(String model,
List<Message> messages) {
public record Message(String role, String content) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

import java.util.List;

/**
* A data transfer object representing a response from the OpenRouter API.
* This DTO encapsulates the choices returned by the API, where each choice
* contains a message representing a specific response.
*
* @param choices A list of choices provided in the response. Each choice contains
* a message with the content generated by the OpenRouter API.
*/
public record OpenRouterResponseDTO(List<Choice> choices) {
public record Choice(Message message) {}
public record Message(String content){}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/example/projectbifrost/dto/Personality.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
import lombok.AllArgsConstructor;
import lombok.Getter;

/**
* Enum representing various personalities inspired by Norse mythology for use in chat interactions.
* Each personality encapsulates a unique prompt that guides the tone and style of responses.
*/
@Getter
@AllArgsConstructor
public enum Personality {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@

import java.time.Instant;

/**
* Global exception handler for managing and translating exceptions into client-friendly responses.
*
* This class contains multiple exception handler methods that map specific types of exceptions
* to appropriate HTTP response statuses and error messages. It provides a centralized approach
* to exception handling for the application, ensuring consistent and informative API responses.
*/
@ControllerAdvice
@Slf4j //Structured logging
public class GlobalExceptionHandler {
Expand Down
43 changes: 36 additions & 7 deletions src/main/java/org/example/projectbifrost/service/ChatService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
import java.util.ArrayList;
import java.util.List;

/**
* Service class responsible for managing chat interactions with a Large Language Model (LLM).
* This class handles the processing and storage of chat sessions, sending requests to the
* LLM API, and managing fallback mechanisms in case of service unavailability.
*/
@Slf4j
@Service
public class ChatService {
Expand All @@ -35,15 +40,17 @@ public ChatService(ChatSessionStorage chatSessionStorage, RestClient restClient)
}



/**
* Sends a chat request to a large language model (LLM) using the supplied chat request data.
* The method manages the chat session, compiles the request for the LLM, and processes the response.
* It also maintains the history of chat messages within the session.
* Handles the process of interacting with a Large Language Model (LLM) by sending user input and
* contextual information, and receiving the model's response. The method also manages the storage
* of chat history for the associated session, ensuring that each conversation is tracked effectively.
*
* @param dto the {@link ChatRequestDTO} containing the user message, chat session ID, and personality configuration.
* @return the response from the LLM as a string.
* @throws InvalidLLMResponseException if an error occurs during communication with the LLM,
* or if the LLM response is empty or malformed.
* @param dto an instance of {@link ChatRequestDTO} containing the session identifier, user message,
* and personality settings for the chat interaction.
* @return the response generated by the LLM as a string.
* @throws RetryableHttpException if the LLM service is unavailable or if circuit breaker fallback
* is triggered.
*/
public String chatWithLLM(ChatRequestDTO dto) {
ChatSession chatSession = chatSessionStorage.getOrCreateChatSession(dto.sessionId());
Expand All @@ -70,6 +77,17 @@ public String chatWithLLM(ChatRequestDTO dto) {

}

/**
* Sends a list of formatted messages and model information to a Large Language Model (LLM)
* API endpoint and retrieves the response, handling retries and circuit breaker mechanisms
* for improved robustness in case of transient failures.
*
* @param apiMessages a list of {@link OpenRouterRequestDTO.Message} objects representing the
* messages and contextual input to be sent to the LLM.
* @return the content of the response message generated by the LLM as a string.
* @throws RetryableHttpException if the LLM service returns a retryable HTTP status code (e.g., 429, 500).
* @throws InvalidLLMResponseException if the LLM returns an invalid or empty response.
*/
@CircuitBreaker(name = "chatService", fallbackMethod = "fallback")
//Break stream of tries if too many failures, and call fallback method
@Retry(name = "chatService") //Try again if fails, up to max-attempts
Expand Down Expand Up @@ -99,6 +117,17 @@ public String fetchResponseFromLLM(List<OpenRouterRequestDTO.Message> apiMessage

}

/**
* Handles the fallback mechanism for the circuit breaker. This method is triggered when
* the circuit breaker is open, indicating that the dependent service is currently unavailable
* or under excessive load. Logs the exception and throws a {@link RetryableHttpException} to
* signal that the operation can be retried later.
*
* @param e the exception that caused the fallback to be triggered.
* @return this method does not return a value as it always throws a {@link RetryableHttpException}.
* @throws RetryableHttpException indicating that the upstream service is unavailable and the
* operation should be retried at a later time.
*/
public String fallback(Exception e) {
// Circuit breaker is open - throw exception so it doesn't pollute chat history
log.warn("Circuit breaker fallback triggered for LLM call. Cause: {}", e.getMessage(), e);
Expand Down
Loading