Skip to content

AI_Recommendations#29

Open
LinusAltemark wants to merge 11 commits into
mainfrom
AI-Rekommendationer
Open

AI_Recommendations#29
LinusAltemark wants to merge 11 commits into
mainfrom
AI-Rekommendationer

Conversation

@LinusAltemark

@LinusAltemark LinusAltemark commented Apr 12, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Introduced a web form for submitting cat breed information and receiving AI-generated care recommendations.
    • Added a results page to display personalized AI recommendations for cat breeds.
    • Enabled an API endpoint to retrieve AI recommendations for cat breeds in JSON format.
  • Bug Fixes

    • Improved input validation and error handling for breed submissions.
  • Tests

    • Added unit tests to verify AI recommendation functionality for various input scenarios.
  • Chores

    • Updated .gitignore to exclude additional environment files.
    • Adjusted Docker Compose configuration for improved build management.

Signed-off-by: LinusAltemark <Linalt0905@gmail.com>
@coderabbitai

coderabbitai Bot commented Apr 12, 2025

Copy link
Copy Markdown

Walkthrough

This update introduces a new AI-powered cat breed recommendation feature, including both REST and web-based interfaces. New controllers handle form display and result rendering for user interactions, as well as an API endpoint for programmatic access. The service layer integrates with the OpenAI API to generate breed-specific care tips. Supporting HTML templates for the form and result views are added. The .gitignore and Docker Compose configurations are updated for environment management and build clarity. Comprehensive unit tests are included for the recommendation service.

Changes

File(s) Change Summary
src/main/resources/templates/ai_recommendation/ai_recommendation_form.html
src/main/resources/templates/ai_recommendation/ai_recommendation_result.html
Added HTML templates for cat breed input form and AI-generated recommendation result display.
src/main/java/org/example/springboot25/controller/AiRecommendationRestController.java Introduced REST controller for AI cat breed recommendations with error handling and JSON responses.
src/main/java/org/example/springboot25/controller/AiRecommendationViewController.java Added view controller for handling form display and result rendering for AI recommendations.
src/main/java/org/example/springboot25/service/AiRecommendationService.java Implemented service class integrating with OpenAI API to generate breed care tips.
src/test/java/org/example/springboot25/service/AiRecommendationServiceTest.java Added unit tests for the AI recommendation service, covering various input scenarios.
.gitignore Updated to ignore .env.properties files and clarified environment file patterns with comments.
compose.yaml Modified to specify build context and Dockerfile for the app service, and adjusted image declaration ordering.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ViewController as AiRecommendationViewController
    participant Service as AiRecommendationService
    participant OpenAI as OpenAI API
    participant ResultPage

    User->>ViewController: GET /ai-recommendations
    ViewController->>User: Render ai_recommendation_form.html

    User->>ViewController: POST /ai-recommendations (breed)
    ViewController->>Service: getRecommendationForBreed(breed)
    Service->>OpenAI: POST /v1/chat/completions
    OpenAI-->>Service: AI-generated recommendation
    Service->>ViewController: Recommendation string
    ViewController->>ResultPage: Render ai_recommendation_result.html with breed & recommendation
    ResultPage->>User: Show recommendation
Loading
sequenceDiagram
    participant Client
    participant RestController as AiRecommendationRestController
    participant Service as AiRecommendationService
    participant OpenAI as OpenAI API

    Client->>RestController: GET /api/ai-recommendations/{breed}
    RestController->>Service: getRecommendationForBreed(breed)
    Service->>OpenAI: POST /v1/chat/completions
    OpenAI-->>Service: AI-generated recommendation
    Service->>RestController: Recommendation string
    RestController->>Client: JSON response (200 or 404)
Loading

Suggested reviewers

  • malvamalmgren
  • Minhya

Poem

In fields of code where kittens roam,
AI now helps you pick a home.
A breed, a tip, a friendly nudge—
With OpenAI, we never fudge!
Forms and tests, controllers too,
The Docker build is fresh and new.
🐾 Cheers to cats and clever code—let’s see what else this spring will bode!

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (8)
src/main/java/org/example/springboot25/entities/CatBreed.java (2)

6-17: Good enum implementation but consider adding utility methods

The enum is well-structured with the top 10 cat breeds. To make it more robust, consider adding utility methods for conversion between string representations and enum values.

public enum CatBreed {
    PERSIAN,
    MAINE_COON,
    SIAMESE,
    RAGDOLL,
    BENGAL,
    SPHYNX,
    BRITISH_SHORTHAIR,
    SCOTTISH_FOLD,
    ABYSSINIAN,
    AMERICAN_SHORTHAIR;
+
+    /**
+     * Safely converts a string to a CatBreed enum value
+     * @param name the breed name to convert
+     * @return the matching CatBreed or null if not found
+     */
+    public static CatBreed fromString(String name) {
+        try {
+            return name != null ? valueOf(name.toUpperCase().replace(' ', '_')) : null;
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns a display-friendly name for the breed
+     * @return the breed name with spaces instead of underscores
+     */
+    public String getDisplayName() {
+        return name().replace('_', ' ');
+    }
}

3-5: Enhance the documentation with more details

The current documentation is minimal. Consider expanding it to provide more context about the enum's purpose and usage.

/**
 * Enum representing the top 10 most popular cat breeds.
+ * 
+ * This enum is used by the AI recommendation system to provide breed-specific
+ * recommendations. Each value represents a cat breed that the system can
+ * recognize and process.
 */
src/main/resources/templates/ai_recommendation/ai_recommendation_form.html (1)

4-5: Add basic styling to improve user interface

The form lacks styling, which affects user experience. Consider adding some basic CSS to make it more appealing.

<head>
    <title>AI Recommendation</title>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            margin: 20px;
+            line-height: 1.6;
+        }
+        h1 {
+            color: #333;
+        }
+        form {
+            margin-top: 20px;
+        }
+        label {
+            display: block;
+            margin-bottom: 5px;
+        }
+        select, input, button {
+            margin-bottom: 15px;
+            padding: 8px;
+        }
+        button {
+            background-color: #4CAF50;
+            color: white;
+            border: none;
+            cursor: pointer;
+        }
+        button:hover {
+            opacity: 0.8;
+        }
+    </style>
</head>
src/main/resources/templates/ai_recommendation/ai_recommendation_result.html (1)

4-5: Add consistent styling with the form page

For a consistent user experience, add the same styling as suggested for the form page.

<head>
    <title>Recommendation Result</title>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            margin: 20px;
+            line-height: 1.6;
+        }
+        h2 {
+            color: #333;
+        }
+        p {
+            background-color: #f9f9f9;
+            padding: 15px;
+            border-radius: 5px;
+        }
+        a {
+            display: inline-block;
+            margin-top: 20px;
+            background-color: #4CAF50;
+            color: white;
+            padding: 8px 16px;
+            text-decoration: none;
+            border-radius: 4px;
+        }
+        a:hover {
+            opacity: 0.8;
+        }
+    </style>
</head>
src/main/java/org/example/springboot25/controller/AI_RecommendationRestController.java (1)

3-4: Add documentation annotations for API clarity

As this is a REST API, add Swagger or Spring REST Docs annotations to improve documentation.

import org.example.springboot25.service.AI_RecommendationService;
import org.springframework.web.bind.annotation.*;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;

And then add the annotations to the method:

@GetMapping("/{breed}")
+@Operation(
+    summary = "Get AI recommendation for a cat breed",
+    description = "Returns a personalized recommendation based on the provided cat breed."
+)
+@ApiResponse(responseCode = "200", description = "Successful recommendation")
+@ApiResponse(responseCode = "404", description = "Unknown cat breed")
public String getRecommendation(
+    @Parameter(description = "Name of the cat breed") 
    @PathVariable String breed) {
    return aiRecommendationService.getRecommendationForBreed(breed);
}

Note: This requires adding the SpringDoc OpenAPI dependency to your project.

src/main/java/org/example/springboot25/controller/AI_RecommendationViewController.java (1)

10-10: Consider renaming class to follow Java naming conventions

Java class names typically use CamelCase without underscores. Consider renaming to AiRecommendationViewController for better consistency with standard Java conventions.

-public class AI_RecommendationViewController {
+public class AiRecommendationViewController {
src/main/java/org/example/springboot25/service/AI_RecommendationService.java (2)

11-27: Consider input sanitization and more structured breed handling

The method implementation has several areas for improvement:

  1. Input sanitization: trim the input to handle spaces
  2. The conversion to uppercase could be more robust
  3. A Map-based approach might be cleaner than a switch expression for maintainability
-public String getRecommendationForBreed(String breedName) {
+public String getRecommendationForBreed(String breedName) {
+    if (breedName == null || breedName.trim().isEmpty()) {
+        return "Please provide a cat breed name.";
+    }
+    
+    String normalizedBreedName = breedName.trim().toUpperCase();
     try {
-        CatBreed breed = CatBreed.valueOf(breedName.toUpperCase());
+        CatBreed breed = CatBreed.valueOf(normalizedBreedName);

         return switch (breed) {

7-31: Consider using a more maintainable approach with a Map

For better maintainability as the number of breeds grows, consider refactoring to use a Map-based approach instead of a switch statement.

@Service
public class AiRecommendationService {

    private final Map<CatBreed, String> breedRecommendations;
    
    public AiRecommendationService() {
        breedRecommendations = new EnumMap<>(CatBreed.class);
        breedRecommendations.put(CatBreed.PERSIAN, "Groom daily and keep indoors. Loves cozy places.");
        breedRecommendations.put(CatBreed.MAINE_COON, "Needs climbing structures and interactive play.");
        breedRecommendations.put(CatBreed.SIAMESE, "Talkative! Needs lots of attention and toys.");
        breedRecommendations.put(CatBreed.RAGDOLL, "Very chill. Enjoys soft beds and cuddles.");
        breedRecommendations.put(CatBreed.BENGAL, "Super energetic. Needs stimulation and high spaces.");
        breedRecommendations.put(CatBreed.SPHYNX, "No fur, so keep warm. Needs weekly baths.");
        breedRecommendations.put(CatBreed.BRITISH_SHORTHAIR, "Calm and independent. Likes puzzle feeders.");
        breedRecommendations.put(CatBreed.SCOTTISH_FOLD, "Needs gentle handling and soft toys.");
        breedRecommendations.put(CatBreed.ABYSSINIAN, "Incredibly active. Needs high shelves and games.");
        breedRecommendations.put(CatBreed.AMERICAN_SHORTHAIR, "Easy-going. Enjoys feather toys and companionship.");
    }

    public String getRecommendationForBreed(String breedName) {
        if (breedName == null || breedName.trim().isEmpty()) {
            return "Please provide a cat breed name.";
        }
        
        try {
            CatBreed breed = CatBreed.valueOf(breedName.trim().toUpperCase());
            return breedRecommendations.get(breed);
        } catch (IllegalArgumentException e) {
            return "Unknown breed. Please enter one of the top 10 popular breeds: " +
                   String.join(", ", Arrays.stream(CatBreed.values())
                   .map(CatBreed::name)
                   .collect(Collectors.toList()));
        }
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3f9d63 and 57a94c0.

📒 Files selected for processing (6)
  • src/main/java/org/example/springboot25/controller/AI_RecommendationRestController.java (1 hunks)
  • src/main/java/org/example/springboot25/controller/AI_RecommendationViewController.java (1 hunks)
  • src/main/java/org/example/springboot25/entities/CatBreed.java (1 hunks)
  • src/main/java/org/example/springboot25/service/AI_RecommendationService.java (1 hunks)
  • src/main/resources/templates/ai_recommendation/ai_recommendation_form.html (1 hunks)
  • src/main/resources/templates/ai_recommendation/ai_recommendation_result.html (1 hunks)
🔇 Additional comments (3)
src/main/java/org/example/springboot25/controller/AI_RecommendationRestController.java (1)

1-4:

Details

✅ Verification successful

Request service implementation confirmation

Since we don't see the implementation of AI_RecommendationService, ensure it properly handles case-insensitive breed names and unknown breeds.


🏁 Script executed:

#!/bin/bash
# Check if AI_RecommendationService exists and inspect its implementation

echo "Searching for AI_RecommendationService implementation..."
if fd -t f "AI_RecommendationService.java" ; then
  cat $(fd -t f "AI_RecommendationService.java")
else
  echo "Service implementation file not found"
fi

Length of output: 1804


Service Implementation Verified

The AI_RecommendationService implementation correctly handles both case-insensitive breed names—by converting the input to uppercase—and unknown breeds by catching the IllegalArgumentException to return a default message.

No changes are required in the service implementation based on the verification.

src/main/java/org/example/springboot25/controller/AI_RecommendationViewController.java (2)

12-16: Good use of constructor injection

Constructor injection is a best practice for dependency management in Spring applications. This implementation correctly uses constructor injection rather than field injection, making the code more testable and the dependencies explicit.


18-21: Endpoint implementation looks good

The GET endpoint is correctly implemented to display the form.

Comment on lines +8 to +12
<form action="#" th:action="@{/ai-recommendations}" method="post">
<label for="breed">Cat Breed:</label>
<input type="text" id="breed" name="breed" required>
<button type="submit">Get Recommendation</button>
</form>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve form usability with a dropdown menu instead of text input

Since you have a fixed set of cat breeds defined in the CatBreed enum, a dropdown would be more user-friendly than free text input, preventing invalid entries.

<form action="#" th:action="@{/ai-recommendations}" method="post">
    <label for="breed">Cat Breed:</label>
-    <input type="text" id="breed" name="breed" required>
+    <select id="breed" name="breed" required>
+        <option value="">-- Select a breed --</option>
+        <option th:each="breedOption : ${T(org.example.springboot25.entities.CatBreed).values()}" 
+                th:value="${breedOption.name()}" 
+                th:text="${breedOption.name().replace('_', ' ')}">
+        </option>
+    </select>
    <button type="submit">Get Recommendation</button>
</form>

This requires passing the CatBreed enum to the template from your controller:

@GetMapping
public String showForm(Model model) {
    return "ai_recommendation/ai_recommendation_form";
}

<body>
<h2>Recommendation for <span th:text="${breed}"></span>:</h2>
<p th:text="${recommendation}"></p>
<a href="/ai-recommendations">Try another</a>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use Thymeleaf for the back link

Using a direct link may cause issues if the application context path changes. Replace it with a Thymeleaf link.

-<a href="/ai-recommendations">Try another</a>
+<a th:href="@{/ai-recommendations}">Try another</a>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a href="/ai-recommendations">Try another</a>
<a th:href="@{/ai-recommendations}">Try another</a>

Comment thread src/main/java/org/example/springboot25/service/AI_RecommendationService.java Outdated
Comment thread src/main/java/org/example/springboot25/service/AI_RecommendationService.java Outdated
Comment thread src/main/java/org/example/springboot25/service/AI_RecommendationService.java Outdated
Signed-off-by: LinusAltemark <Linalt0905@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/main/java/org/example/springboot25/service/AiRecommendationService.java (1)

9-32: Robust implementation with good error handling

The service correctly handles various input formats (case sensitivity, spaces) and provides meaningful recommendations based on cat breeds. The error handling is also well-implemented, catching exceptions and returning user-friendly messages for unknown breeds.

Consider extracting the long error message with breed names to a constant to improve maintainability:

+ private static final String UNKNOWN_BREED_MESSAGE = "Unknown breed. Please enter one of the top 10 popular breeds: " +
+         "PERSIAN, MAINE_COON, SIAMESE, RAGDOLL, BENGAL, SPHYNX, " +
+         "BRITISH_SHORTHAIR, SCOTTISH_FOLD, ABYSSINIAN, AMERICAN_SHORTHAIR.";

  public String getRecommendationForBreed(String breed) {
      try {
          if (breed == null) throw new IllegalArgumentException("Null input");

          CatBreed catBreed = CatBreed.valueOf(breed.trim().toUpperCase().replace(" ", "_"));

          return switch (catBreed) {
              case PERSIAN -> "Groom daily and keep indoors. Loves cozy places.";
              case MAINE_COON -> "Needs climbing structures and interactive play.";
              case SIAMESE -> "Talkative! Needs lots of attention and toys.";
              case RAGDOLL -> "Very chill. Enjoys soft beds and cuddles.";
              case BENGAL -> "Super energetic. Needs stimulation and high spaces.";
              case SPHYNX -> "No fur, so keep warm. Needs weekly baths.";
              case BRITISH_SHORTHAIR -> "Calm and independent. Likes puzzle feeders.";
              case SCOTTISH_FOLD -> "Needs gentle handling and soft toys.";
              case ABYSSINIAN -> "Incredibly active. Needs high shelves and games.";
              case AMERICAN_SHORTHAIR -> "Easy-going. Enjoys feather toys and companionship.";
          };
      } catch (IllegalArgumentException e) {
-         return "Unknown breed. Please enter one of the top 10 popular breeds: " +
-                 "PERSIAN, MAINE_COON, SIAMESE, RAGDOLL, BENGAL, SPHYNX, " +
-                 "BRITISH_SHORTHAIR, SCOTTISH_FOLD, ABYSSINIAN, AMERICAN_SHORTHAIR.";
+         return UNKNOWN_BREED_MESSAGE;
      }
  }
src/main/java/org/example/springboot25/controller/AiRecommendationRestController.java (1)

21-39: Well-structured REST endpoint with proper error handling

The implementation correctly handles both successful recommendations and unknown breeds with appropriate HTTP status codes. The JSON responses are well-structured with relevant information.

Two suggestions for improvement:

  1. Consider using a more robust method to detect unknown breeds rather than string matching:
- if (recommendation.contains("Unknown breed")) {
+ if (recommendation.startsWith("Unknown breed")) {
  1. Consider creating a dedicated response model class instead of using HashMap for more type safety:
class RecommendationResponse {
    private String breed;
    private String recommendation;
    // Getters, setters, constructors
}

class ErrorResponse {
    private String error;
    private String message;
    // Getters, setters, constructors
}
src/main/java/org/example/springboot25/controller/AiRecommendationViewController.java (1)

24-37: Good validation and clean form handling

The implementation properly validates user input, handles empty/null cases, and passes data to the view. The controller correctly trims the breed name before processing it.

Consider adding more specific validation messages for different error conditions:

  @PostMapping
  public String showResult(@RequestParam String breed, Model model) {
      // Validate input: ensure the breed is not null or empty
-     if (breed == null || breed.trim().isEmpty()) {
-         model.addAttribute("error", "Please enter a breed name");
+     if (breed == null) {
+         model.addAttribute("error", "Breed name cannot be null");
+         return "ai_recommendation_form";
+     }
+     
+     if (breed.trim().isEmpty()) {
+         model.addAttribute("error", "Please enter a non-empty breed name");
          return "ai_recommendation_form";
      }

      breed = breed.trim();
      String recommendation = aiRecommendationService.getRecommendationForBreed(breed);
      model.addAttribute("breed", breed);
      model.addAttribute("recommendation", recommendation);
      return "ai_recommendation_result";
  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57a94c0 and 73e732d.

📒 Files selected for processing (4)
  • src/main/java/org/example/springboot25/controller/AiRecommendationRestController.java (1 hunks)
  • src/main/java/org/example/springboot25/controller/AiRecommendationViewController.java (1 hunks)
  • src/main/java/org/example/springboot25/service/AiRecommendationService.java (1 hunks)
  • src/test/java/org/example/springboot25/service/AiRecommendationServiceTest.java (1 hunks)
🔇 Additional comments (1)
src/test/java/org/example/springboot25/service/AiRecommendationServiceTest.java (1)

1-57: Well-structured test suite with comprehensive coverage

The test class provides excellent coverage for the AiRecommendationService, testing valid inputs, edge cases, and error conditions. The tests validate behavior for different formats of breed names (uppercase, lowercase, with spaces) and handle invalid inputs gracefully (unknown breeds, empty strings, whitespace, null).

One minor enhancement to consider: the assertions currently check for substrings (using contains). For even stronger tests, you might consider using exact matching in some cases to verify the complete response message.

@malvamalmgren

Copy link
Copy Markdown
Collaborator

https://code.mayoubang.cn — 你的免费 AI 代码加速器!

@kappsegla Is Storkforge public?

@kappsegla

kappsegla commented Apr 14, 2025

Copy link
Copy Markdown

Yes, otherwise we won't get free ci runtime or ai analyzes. Maybe you can limit who can do Pr or comment?

@Minhya

Minhya commented Apr 14, 2025

Copy link
Copy Markdown
Collaborator

src/.../entities/CatBreed.java | Added new CatBreed enum defining the top 10 popular cat breeds. What is this for? If it's to only show popular catbreeds, feel free to rename it in order not to clash with the other Cat stuff :D

Signed-off-by: LinusAltemark <Linalt0905@gmail.com>
Signed-off-by: LinusAltemark <Linalt0905@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
src/main/java/org/example/springboot25/service/AiRecommendationService.java (3)

11-18: Consider dependency injection for RestTemplate for better testability

The RestTemplate instance is currently hard-coded as a field. For better testability and conformance with Spring best practices, it would be better to inject it as a dependency.

@Service
public class AiRecommendationService {

    @Value("${openai.api.key}")
    private String apiKey;

-   private final RestTemplate restTemplate = new RestTemplate();
+   private final RestTemplate restTemplate;
    private static final String OPENAI_API_URL = "https://api.openai.com/v1/chat/completions";
+
+   public AiRecommendationService(RestTemplate restTemplate) {
+       this.restTemplate = restTemplate;
+   }

You'd also need to define a RestTemplate bean in a configuration class:

@Configuration
public class RestClientConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

35-42: Improve request body construction and model configuration

The current implementation uses hardcoded values and a HashMap-based approach for constructing the request.

Consider the following improvements:

  1. Make the model name configurable via application properties
  2. Create a proper object model for requests/responses
  3. Adjust max_tokens to allow for more comprehensive responses
- message.put("content", "Give me a short but useful care tip for the cat breed: " + breed);
+ message.put("content", "Give me a comprehensive care tip for the cat breed: " + breed);

Map<String, Object> body = new HashMap<>();
- body.put("model", "gpt-3.5-turbo");
+ body.put("model", modelName); // Inject from application properties
body.put("messages", new Object[]{message});
- body.put("max_tokens", 50);
+ body.put("max_tokens", 150);

You could also consider creating dedicated request/response classes:

public class OpenAiMessage {
    private String role;
    private String content;
    // getters, setters, constructors
}

public class OpenAiRequest {
    private String model;
    private List<OpenAiMessage> messages;
    private int maxTokens;
    // getters, setters, constructors
}

27-62: Add timeout configuration for the OpenAI API call

The code doesn't set timeouts for the OpenAI API call, which could lead to hung threads if the API is slow to respond.

Add timeout configuration to prevent long-running requests:

@Configuration
public class RestClientConfig {
    @Bean
    public RestTemplate restTemplate() {
-       return new RestTemplate();
+       SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
+       factory.setConnectTimeout(5000); // 5 seconds
+       factory.setReadTimeout(10000);   // 10 seconds
+       return new RestTemplate(factory);
    }
}

This ensures your application remains responsive even when the OpenAI API is experiencing delays.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73e732d and 26dd449.

📒 Files selected for processing (1)
  • src/main/java/org/example/springboot25/service/AiRecommendationService.java (1 hunks)

Comment on lines +51 to +57
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
Map<String, Object> choice = ((java.util.List<Map<String, Object>>) response.getBody().get("choices")).get(0);
Map<String, Object> messageContent = (Map<String, Object>) choice.get("message");
return (String) messageContent.get("content");
} else {
return "Something went wrong while getting recommendation. Try again later.";
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve response handling with proper model classes

The current response parsing uses multiple casts and map operations which is error-prone.

Create proper model classes for the OpenAI API response to make the code more maintainable and type-safe.

- if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
-     Map<String, Object> choice = ((java.util.List<Map<String, Object>>) response.getBody().get("choices")).get(0);
-     Map<String, Object> messageContent = (Map<String, Object>) choice.get("message");
-     return (String) messageContent.get("content");
- } else {
-     return "Something went wrong while getting recommendation. Try again later.";
- }

+ // Create response model classes
+ if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
+     try {
+         OpenAiResponse openAiResponse = objectMapper.convertValue(response.getBody(), OpenAiResponse.class);
+         if (openAiResponse.getChoices() != null && !openAiResponse.getChoices().isEmpty()) {
+             return openAiResponse.getChoices().get(0).getMessage().getContent();
+         }
+     } catch (Exception e) {
+         logger.error("Error parsing OpenAI response", e);
+     }
+ }
+ return "Something went wrong while getting recommendation. Try again later.";

And define these model classes:

public class OpenAiResponse {
    private List<OpenAiChoice> choices;
    // getters, setters
}

public class OpenAiChoice {
    private OpenAiMessage message;
    // getters, setters
}

public class OpenAiMessage {
    private String role;
    private String content;
    // getters, setters
}

Comment on lines +59 to +61
} catch (Exception e) {
return "Error calling AI service: " + e.getMessage();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add logging for exceptions and sanitize error messages

The current exception handling includes the raw exception message in the response, which could expose sensitive information and doesn't provide logging for debugging.

Add proper logging and sanitize error messages:

+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;

@Service
public class AiRecommendationService {
+   private static final Logger logger = LoggerFactory.getLogger(AiRecommendationService.class);

    // Other code...

    } catch (Exception e) {
+       logger.error("Error calling OpenAI API for breed {}: {}", breed, e.getMessage(), e);
-       return "Error calling AI service: " + e.getMessage();
+       return "Error calling AI service. Please try again later.";
    }

Signed-off-by: LinusAltemark <Linalt0905@gmail.com>
# Conflicts:
#	src/main/resources/application.properties

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
compose.yaml (1)

2-11: 🛠️ Refactor suggestion

Pin database version and add resilience measures for Postgres service.

Using postgres:latest can introduce non‑reproducible builds and unexpected breaking changes when a new major PostgreSQL version is released. It’s recommended to pin to a specific patch version (e.g., postgres:14.9). Additionally, consider adding a restart policy (e.g., restart: unless-stopped) and a healthcheck to ensure the database is fully ready before the app service starts.

Example diff:

 services:
   postgres:
-    image: 'postgres:latest'
+    image: 'postgres:14.9'
     container_name: 'postgres-db'
     environment:
       - 'POSTGRES_DB=mydatabase'
+    restart: unless-stopped
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U myuser"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
🧹 Nitpick comments (1)
compose.yaml (1)

1-2: Consider adding a Compose file version.

If you’re targeting older Docker Compose installations or want to explicitly declare features, adding a version: '3.8' (or higher) at the top improves clarity about the Compose schema version in use.

Example:

+version: '3.8'
 services:
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41c029d and 4108fd9.

📒 Files selected for processing (2)
  • .gitignore (1 hunks)
  • compose.yaml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🔇 Additional comments (1)
compose.yaml (1)

19-24:

Details

✅ Verification successful

Validate handling of sensitive environment variables.

You’re loading GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET from an .env file. Please confirm that .env is gitignored and not checked into source control to avoid leaking credentials.

Run:

to ensure it’s listed.


🏁 Script executed:

grep -R ".env" -n .gitignore

Length of output: 74


.env Confirmed in .gitignore – No Further Action Needed

The .env file is explicitly listed in .gitignore (lines 7–9), so your sensitive variables won’t be committed. No additional changes required.

Comment thread compose.yaml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants