Skip to content

Commit b453c38

Browse files
Merge pull request #18626 from hmdrzsharifi/BAEL-9291
Bael 9291: Spring AI with Docker Model Runner
2 parents 2961038 + e3036d4 commit b453c38

File tree

6 files changed

+135
-1
lines changed

6 files changed

+135
-1
lines changed

spring-ai-3/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
<artifactId>spring-ai-spring-boot-testcontainers</artifactId>
7474
<scope>test</scope>
7575
</dependency>
76+
<dependency>
77+
<groupId>org.testcontainers</groupId>
78+
<artifactId>junit-jupiter</artifactId>
79+
<scope>test</scope>
80+
</dependency>
7681
<dependency>
7782
<groupId>org.testcontainers</groupId>
7883
<artifactId>chromadb</artifactId>
@@ -143,7 +148,7 @@
143148
<spring-ai-mongodb-atlas.version>1.0.0-M7</spring-ai-mongodb-atlas.version>
144149
<junit-jupiter.version>5.9.0</junit-jupiter.version>
145150
<spring-boot-docker-compose.version>3.1.1</spring-boot-docker-compose.version>
146-
<spring-boot.version>3.4.5</spring-boot.version>
151+
<spring-boot.version>3.5.0</spring-boot.version>
147152
<spring-ai.version>1.0.0-M6</spring-ai.version>
148153
<spring-ai-start-model-openai.version>1.0.0-M7</spring-ai-start-model-openai.version>
149154
</properties>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.baeldung.springai.docker.modelrunner;
2+
3+
import org.springframework.ai.autoconfigure.chat.client.ChatClientAutoConfiguration;
4+
import org.springframework.ai.autoconfigure.mistralai.MistralAiAutoConfiguration;
5+
import org.springframework.ai.model.openai.autoconfigure.OpenAiAudioSpeechAutoConfiguration;
6+
import org.springframework.boot.SpringApplication;
7+
import org.springframework.boot.autoconfigure.SpringBootApplication;
8+
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
9+
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
10+
11+
12+
@SpringBootApplication(exclude = {
13+
ChatClientAutoConfiguration.class,
14+
MongoAutoConfiguration.class,
15+
MongoDataAutoConfiguration.class,
16+
org.springframework.ai.autoconfigure.vectorstore.mongo.MongoDBAtlasVectorStoreAutoConfiguration.class,
17+
org.springframework.ai.vectorstore.mongodb.autoconfigure.MongoDBAtlasVectorStoreAutoConfiguration.class,
18+
OpenAiAudioSpeechAutoConfiguration.class,
19+
MistralAiAutoConfiguration.class
20+
})
21+
class ModelRunnerApplication {
22+
23+
public static void main(String[] args) {
24+
SpringApplication app = new SpringApplication(ModelRunnerApplication.class);
25+
app.setAdditionalProfiles("dockermodelrunner");
26+
app.run(args);
27+
}
28+
29+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.baeldung.springai.docker.modelrunner;
2+
3+
import org.springframework.ai.chat.client.ChatClient;
4+
import org.springframework.web.bind.annotation.GetMapping;
5+
import org.springframework.web.bind.annotation.RequestParam;
6+
import org.springframework.web.bind.annotation.RestController;
7+
8+
@RestController
9+
class ModelRunnerController {
10+
11+
private final ChatClient chatClient;
12+
13+
public ModelRunnerController(ChatClient.Builder chatClientBuilder) {
14+
this.chatClient = chatClientBuilder.build();
15+
}
16+
17+
@GetMapping("/chat")
18+
public String chat(@RequestParam("message") String message) {
19+
return this.chatClient.prompt()
20+
.user(message)
21+
.call()
22+
.content();
23+
}
24+
25+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
spring.ai.openai.api-key=${OPENAI_API_KEY}
2+
spring.ai.openai.base-url=http://localhost:12434/engines
3+
spring.ai.openai.chat.options.model=ai/gemma3
4+
5+
spring.docker.compose.enabled=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.baeldung.springai.docker.modelrunner;
2+
3+
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
4+
5+
import org.junit.jupiter.api.BeforeEach;
6+
import org.junit.jupiter.api.Test;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.boot.test.context.SpringBootTest;
9+
import org.springframework.boot.test.web.client.TestRestTemplate;
10+
import org.springframework.boot.test.web.server.LocalServerPort;
11+
import org.springframework.context.annotation.Import;
12+
import org.springframework.http.ResponseEntity;
13+
14+
15+
@Import(TestcontainersConfiguration.class)
16+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
17+
class ModelRunnerApplicationManualTest {
18+
19+
@LocalServerPort
20+
private int port;
21+
22+
@Autowired
23+
private TestRestTemplate restTemplate;
24+
25+
private String baseUrl;
26+
27+
@BeforeEach
28+
void setUp() {
29+
baseUrl = "http://localhost:" + port;
30+
}
31+
32+
@Test
33+
void givenMessage_whenCallChatController_thenSuccess() {
34+
// given
35+
String userMessage = "Hello, how are you?";
36+
37+
// when
38+
ResponseEntity<String> response = restTemplate.getForEntity(
39+
baseUrl + "/chat?message=" + userMessage, String.class);
40+
41+
// then
42+
assertThat(response.getStatusCode().is2xxSuccessful()).isTrue();
43+
assertThat(response.getBody()).isNotEmpty();
44+
}
45+
46+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.baeldung.springai.docker.modelrunner;
2+
3+
import org.springframework.boot.test.context.TestConfiguration;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.test.context.DynamicPropertyRegistrar;
6+
import org.testcontainers.containers.DockerModelRunnerContainer;
7+
8+
@TestConfiguration(proxyBeanMethods = false)
9+
class TestcontainersConfiguration {
10+
11+
@Bean
12+
DockerModelRunnerContainer socat() {
13+
return new DockerModelRunnerContainer("alpine/socat:1.8.0.1");
14+
}
15+
16+
@Bean
17+
DynamicPropertyRegistrar properties(DockerModelRunnerContainer dmr) {
18+
return (registrar) -> {
19+
registrar.add("spring.ai.openai.base-url", dmr::getOpenAIEndpoint);
20+
registrar.add("spring.ai.openai.api-key", () -> "test-api-key");
21+
registrar.add("spring.ai.openai.chat.options.model", () -> "ai/gemma3");
22+
};
23+
}
24+
}

0 commit comments

Comments
 (0)