Skip to content

Commit dfbbd49

Browse files
codebase/spring-ai-introduction [BAEL-9418] [Improvement] (#18760)
* add new codebase to spring-ai-modules parent dir * remove old codebase * fix API endpoint convention * update LLM
1 parent d5d225b commit dfbbd49

File tree

17 files changed

+186
-258
lines changed

17 files changed

+186
-258
lines changed

spring-ai-modules/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
</parent>
1717

1818
<modules>
19+
<module>spring-ai-introduction</module>
1920
<module>spring-ai-mcp</module>
2021
<module>spring-ai-text-to-sql</module>
2122
<module>spring-ai-vector-stores</module>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>com.baeldung</groupId>
8+
<artifactId>spring-ai-modules</artifactId>
9+
<version>0.0.1</version>
10+
<relativePath>../pom.xml</relativePath>
11+
</parent>
12+
13+
<groupId>com.baeldung</groupId>
14+
<artifactId>spring-ai-introduction</artifactId>
15+
<version>0.0.1</version>
16+
<name>spring-ai-introduction</name>
17+
18+
<dependencies>
19+
<dependency>
20+
<groupId>org.springframework.boot</groupId>
21+
<artifactId>spring-boot-starter-web</artifactId>
22+
</dependency>
23+
<dependency>
24+
<groupId>org.springframework.ai</groupId>
25+
<artifactId>spring-ai-starter-model-openai</artifactId>
26+
<version>${spring-ai.version}</version>
27+
</dependency>
28+
<dependency>
29+
<groupId>org.springframework.boot</groupId>
30+
<artifactId>spring-boot-starter-test</artifactId>
31+
<scope>test</scope>
32+
</dependency>
33+
</dependencies>
34+
35+
<properties>
36+
<java.version>21</java.version>
37+
<spring-ai.version>1.0.1</spring-ai.version>
38+
</properties>
39+
40+
<build>
41+
<plugins>
42+
<plugin>
43+
<groupId>org.springframework.boot</groupId>
44+
<artifactId>spring-boot-maven-plugin</artifactId>
45+
</plugin>
46+
</plugins>
47+
</build>
48+
49+
</project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.baeldung.springai;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
import org.springframework.ai.openai.api.common.OpenAiApiClientErrorException;
6+
import org.springframework.http.HttpStatus;
7+
import org.springframework.http.ProblemDetail;
8+
import org.springframework.web.bind.annotation.ExceptionHandler;
9+
import org.springframework.web.bind.annotation.RestControllerAdvice;
10+
11+
@RestControllerAdvice
12+
class APIExceptionHandler {
13+
14+
private static final Logger logger = LoggerFactory.getLogger(APIExceptionHandler.class);
15+
private static final String LLM_COMMUNICATION_ERROR =
16+
"Unable to communicate with the configured LLM. Please try again later.";
17+
18+
@ExceptionHandler(OpenAiApiClientErrorException.class)
19+
ProblemDetail handle(OpenAiApiClientErrorException exception) {
20+
logger.error("OpenAI returned an error.", exception);
21+
return ProblemDetail.forStatusAndDetail(HttpStatus.SERVICE_UNAVAILABLE, LLM_COMMUNICATION_ERROR);
22+
}
23+
24+
}
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
package com.baeldung;
1+
package com.baeldung.springai;
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
55

66
@SpringBootApplication
7-
public class SpringAIProjectApplication {
7+
class Application {
8+
89
public static void main(String[] args) {
9-
SpringApplication.run(SpringAIProjectApplication.class, args);
10+
SpringApplication.run(Application.class, args);
1011
}
1112

12-
}
13+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.baeldung.springai;
2+
3+
record Poem(
4+
String title,
5+
String content,
6+
String genre,
7+
String theme) {
8+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.baeldung.springai;
2+
3+
import org.springframework.http.ResponseEntity;
4+
import org.springframework.web.bind.annotation.PostMapping;
5+
import org.springframework.web.bind.annotation.RequestBody;
6+
import org.springframework.web.bind.annotation.RestController;
7+
8+
@RestController
9+
class PoetryController {
10+
11+
private final PoetryService poetryService;
12+
13+
PoetryController(PoetryService poetryService) {
14+
this.poetryService = poetryService;
15+
}
16+
17+
@PostMapping("/poems")
18+
ResponseEntity<Poem> generate(@RequestBody PoemGenerationRequest request) {
19+
Poem response = poetryService.generate(request.genre, request.theme);
20+
return ResponseEntity.ok(response);
21+
}
22+
23+
record PoemGenerationRequest(String genre, String theme) {}
24+
25+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.baeldung.springai;
2+
3+
import org.springframework.ai.chat.client.ChatClient;
4+
import org.springframework.ai.chat.prompt.Prompt;
5+
import org.springframework.ai.chat.prompt.PromptTemplate;
6+
import org.springframework.stereotype.Service;
7+
8+
import java.util.Map;
9+
10+
@Service
11+
class PoetryService {
12+
13+
private final static PromptTemplate PROMPT_TEMPLATE
14+
= new PromptTemplate("Write a {genre} haiku about {theme} following the traditional 5-7-5 syllable structure.");
15+
16+
private final ChatClient chatClient;
17+
18+
PoetryService(ChatClient.Builder chatClientBuilder) {
19+
this.chatClient = chatClientBuilder.build();
20+
}
21+
22+
Poem generate(String genre, String theme) {
23+
Prompt prompt = PROMPT_TEMPLATE
24+
.create(Map.of(
25+
"genre", genre,
26+
"theme", theme));
27+
return chatClient
28+
.prompt(prompt)
29+
.call()
30+
.entity(Poem.class);
31+
}
32+
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
spring:
2+
ai:
3+
openai:
4+
api-key: ${OPENAI_API_KEY}
5+
chat:
6+
options:
7+
model: gpt-5
8+
temperature: 1
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.baeldung.springai;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
5+
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.boot.test.context.SpringBootTest;
7+
8+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
9+
10+
@SpringBootTest
11+
@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".*")
12+
class PoetryServiceLiveTest {
13+
14+
@Autowired
15+
private PoetryService poetryService;
16+
17+
@Test
18+
void whenPoemGenerationRequested_thenCorrectResponseReturned() {
19+
String genre = "playful";
20+
String theme = "morning coffee";
21+
22+
Poem poem = poetryService.generate(genre, theme);
23+
24+
assertThat(poem)
25+
.hasNoNullFieldsOrProperties()
26+
.satisfies(p -> {
27+
String[] lines = p.content().trim().split("\\n");
28+
assertThat(lines)
29+
.hasSize(3);
30+
});
31+
}
32+
33+
}

spring-ai/postman/Spring_AI_Poetry.postman_environment.json

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)