Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generative AI support for Spring Petclinic Microservices #281

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ target/

# Branch switching
generated/

**/.DS_Store
**/creds.yaml
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Distributed version of the Spring PetClinic Sample Application built with Spring Cloud
# Distributed version of the Spring PetClinic Sample Application built with Spring Cloud and Spring AI

[![Build Status](https://github.com/spring-petclinic/spring-petclinic-microservices/actions/workflows/maven-build.yml/badge.svg)](https://github.com/spring-petclinic/spring-petclinic-microservices/actions/workflows/maven-build.yml)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
Expand All @@ -17,7 +17,7 @@ If everything goes well, you can access the following services at given location
* Discovery Server - http://localhost:8761
* Config Server - http://localhost:8888
* AngularJS frontend (API Gateway) - http://localhost:8080
* Customers, Vets and Visits Services - random port, check Eureka Dashboard
* Customers, Vets, Visits and GenAI Services - random port, check Eureka Dashboard
* Tracing Server (Zipkin) - http://localhost:9411/zipkin/ (we use [openzipkin](https://github.com/openzipkin/zipkin/tree/main/zipkin-server))
* Admin Server (Spring Boot Admin) - http://localhost:9090
* Grafana Dashboards - http://localhost:3000
Expand Down Expand Up @@ -46,7 +46,7 @@ For instance, if you target container images for an Apple M2, you could use the
```

Once images are ready, you can start them with a single command
`docker-compose up` or `podman-compose up`.
`docker compose up` or `podman-compose up`.

Containers startup order is coordinated with the `service_healthy` condition of the Docker Compose [depends-on](https://github.com/compose-spec/compose-spec/blob/main/spec.md#depends_on) expression
and the [healthcheck](https://github.com/compose-spec/compose-spec/blob/main/spec.md#healthcheck) of the service containers.
Expand Down Expand Up @@ -93,7 +93,25 @@ Each service has its own specific role and communicates via REST APIs.

![Spring Petclinic Microservices architecture](docs/microservices-architecture-diagram.jpg)

## Integrating the Spring AI Chatbot

Copy link
Member

Choose a reason for hiding this comment

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

suggestion: we need to offer a solution to developers who don't have an Azure or OpenAI account and don't want to pay for it: either enable fallback by default, or disable chat, or have a local solution with ollama. What do you think @odedia ?

Copy link
Author

Choose a reason for hiding this comment

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

I began with using Llama 3.1, but the chat client became incredibly verbose and not as useful as OpenAI, that's why I switched to it.
image

Spring Petclinic integrates a Chatbot that allows you to interact with the application in a natural language. Here are some examples of what you could ask:

1. Please list the owners that come to the clinic.
2. Are there any vets that specialize in surgery?
3. Is there an owner named Betty?
4. Which owners have dogs?
5. Add a dog for Betty. Its name is Moopsie.
6. Create a new owner

![alt text](spring-ai.png)

This Microservice currently supports OpenAI or Azure's OpenAI as the LLM provider.
In order to enable Spring AI, perform the following steps:

1. Decide which provider you want to use. By default, the `spring-ai-azure-openai-spring-boot-starter` dependency is enabled. You can change it to `spring-ai-openai-spring-boot-starter`in `pom.xml`.
2. Copy `src/main/resources/creds-template.yaml` into `src/main/resources/creds.yaml`, and edit its contents with your API key and API endpoint. Refer to OpenAI's or Azure's documentation for further information on how to obtain these. You only need to populate the provider you're using - either openai, or azure-openai.
3. Boot the `spring-petclinic-genai-service` microservice.
## In case you find a bug/suggested improvement for Spring Petclinic Microservices

Our issue tracker is available here: https://github.com/spring-petclinic/spring-petclinic-microservices/issues
Expand Down
19 changes: 18 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,23 @@ services:
ports:
- 8083:8083


genai-service:
image: springcommunity/spring-petclinic-genai-service
container_name: genai-service
deploy:
resources:
limits:
memory: 512M
depends_on:
config-server:
condition: service_healthy
discovery-server:
condition: service_healthy
ports:
- 8084:8084


api-gateway:
image: springcommunity/spring-petclinic-api-gateway
container_name: api-gateway
Expand Down Expand Up @@ -131,7 +148,7 @@ services:
limits:
memory: 256M
ports:
- 3000:3000
- 3030:3030

prometheus-server:
build: ./docker/prometheus
Expand Down
5 changes: 3 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.7</version>
<version>3.3.4</version>
</parent>

<groupId>org.springframework.samples</groupId>
<artifactId>spring-petclinic-microservices</artifactId>
<version>3.2.7</version>
<version>3.3.4</version>
<name>${project.artifactId}</name>
<packaging>pom</packaging>

Expand All @@ -20,6 +20,7 @@
<module>spring-petclinic-customers-service</module>
<module>spring-petclinic-vets-service</module>
<module>spring-petclinic-visits-service</module>
<module>spring-petclinic-genai-service</module>
<module>spring-petclinic-config-server</module>
<module>spring-petclinic-discovery-server</module>
<module>spring-petclinic-api-gateway</module>
Expand Down
5 changes: 3 additions & 2 deletions scripts/run_all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ set -o pipefail

pkill -9 -f spring-petclinic || echo "Failed to kill any apps"

docker-compose kill || echo "No docker containers are running"
docker compose kill || echo "No docker containers are running"

echo "Running infra"
docker-compose up -d grafana-server prometheus-server tracing-server
docker compose up -d grafana-server prometheus-server tracing-server

echo "Running apps"
mkdir -p target
Expand All @@ -23,6 +23,7 @@ sleep 20
nohup java -jar spring-petclinic-customers-service/target/*.jar --server.port=8081 --spring.profiles.active=chaos-monkey > target/customers-service.log 2>&1 &
nohup java -jar spring-petclinic-visits-service/target/*.jar --server.port=8082 --spring.profiles.active=chaos-monkey > target/visits-service.log 2>&1 &
nohup java -jar spring-petclinic-vets-service/target/*.jar --server.port=8083 --spring.profiles.active=chaos-monkey > target/vets-service.log 2>&1 &
nohup java -jar spring-petclinic-genai-service/target/*.jar --server.port=8084 --spring.profiles.active=chaos-monkey > target/genai-service.log 2>&1 &
nohup java -jar spring-petclinic-api-gateway/target/*.jar --server.port=8080 --spring.profiles.active=chaos-monkey > target/gateway-service.log 2>&1 &
nohup java -jar spring-petclinic-admin-server/target/*.jar --server.port=9090 --spring.profiles.active=chaos-monkey > target/admin-server.log 2>&1 &
echo "Waiting for apps to start"
Expand Down
Binary file added spring-ai.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion spring-petclinic-admin-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<parent>
<groupId>org.springframework.samples</groupId>
<artifactId>spring-petclinic-microservices</artifactId>
<version>3.2.7</version>
<version>3.3.4</version>
</parent>

<properties>
Expand Down
2 changes: 1 addition & 1 deletion spring-petclinic-api-gateway/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<parent>
<groupId>org.springframework.samples</groupId>
<artifactId>spring-petclinic-microservices</artifactId>
<version>3.2.7</version>
<version>3.3.4</version>
</parent>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ RouterFunction<?> routerFunction() {
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
.timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(4)).build())
.timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(10)).build())
.build());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.springframework.samples.petclinic.api.boundary.web;

import org.apache.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FallbackController {

@RequestMapping("/fallback")
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: add POST (and GET ?) in the method attributes

Copy link
Author

Choose a reason for hiding this comment

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

Agreed

public ResponseEntity<String> fallback() {
return ResponseEntity.status(HttpStatus.SC_SERVICE_UNAVAILABLE)
.body("Chat is currently unavailable. Please try again later.");
}
}
19 changes: 17 additions & 2 deletions spring-petclinic-api-gateway/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ spring:
import: optional:configserver:${CONFIG_SERVER_URL:http://localhost:8888/}
cloud:
gateway:
default-filters:
- name: CircuitBreaker
args:
name: defaultCircuitBreaker
fallbackUri: forward:/fallback
- name: Retry
args:
retries: 1
statuses: SERVICE_UNAVAILABLE
methods: GET, POST
Copy link
Member

Choose a reason for hiding this comment

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

The POST looks like to be enough. Isn't it?

Copy link
Author

Choose a reason for hiding this comment

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

Seems like it, yes.

routes:
- id: vets-service
uri: lb://vets-service
Expand All @@ -24,8 +34,13 @@ spring:
- Path=/api/customer/**
filters:
- StripPrefix=2


- id: genai-service
uri: lb://genai-service
predicates:
- Path=/api/genai/**
filters:
- StripPrefix=2
- CircuitBreaker=name=genaiCircuitBreaker,fallbackUri=/fallback

---
spring:
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading