Skip to content

Commit

Permalink
chat agent use same online MySQL database as other components (#52)
Browse files Browse the repository at this point in the history
## Purpose

Make chat agent use the same online MySQL database as other components.
Currently the local DB config still exists, because some UI is using it.
Will update the UI later and then we can simplify.

## Does this introduce a breaking change?
<!-- Mark one with an "x". -->
```
[ ] Yes
[x] No
```

## Pull Request Type
What kind of change does this Pull Request introduce?

<!-- Please check the one that applies to this PR using "x". -->
```
[ ] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Documentation content changes
[ ] Other... Please describe:
```

## How to Test
*  Get the code

```
git clone [repo-address]
cd [repo-name]
git checkout [branch-name]
npm install
```

* Test the code
<!-- Add steps to run the tests suite and/or manually test -->
```
```

## What to Check
Verify that the following are valid
* ...

## Other Information
<!-- Add any other helpful information that may be needed here. -->

---------

Co-authored-by: Hao Zhang <[email protected]>
  • Loading branch information
haoozhang and Hao Zhang authored Sep 24, 2024
1 parent 19ccef6 commit 6cd310c
Show file tree
Hide file tree
Showing 15 changed files with 203 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@ImportRuntimeHints(PetClinicRuntimeHints.class)
Expand All @@ -12,4 +14,8 @@ public static void main(String[] args) {
SpringApplication.run(ChatAgentApplication.class, args);
}

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.azure.identity.DefaultAzureCredentialBuilder;
import org.springframework.ai.azure.openai.AzureOpenAiChatModel;
import org.springframework.ai.azure.openai.AzureOpenAiChatOptions;
import org.springframework.ai.azure.openai.AzureOpenAiResponseFormat;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.ChatClientCustomizer;
import org.springframework.ai.chat.client.advisor.PromptChatMemoryAdvisor;
Expand Down Expand Up @@ -49,6 +50,7 @@ public AzureOpenAiChatModel chatModel(OpenAIClient openAIClient, ChatOptionsProp
var openAIChatOptions = AzureOpenAiChatOptions.builder()
.withDeploymentName(properties.getDeploymentName())
.withTemperature(properties.getTemperature())
.withResponseFormat(AzureOpenAiResponseFormat.TEXT)
.build();

// provide Context to load function callbacks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@Getter
@Setter
@ConfigurationProperties(prefix = ChatOptionsProperties.PREFIX)
class ChatOptionsProperties {
public class ChatOptionsProperties {

static final String PREFIX = "spring.ai.azure.openai.chat.options";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,51 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.samples.petclinic.agent.owner.Owner;
import org.springframework.samples.petclinic.agent.owner.OwnerRepository;
import org.springframework.samples.petclinic.agent.dto.OwnerDto;
import org.springframework.samples.petclinic.agent.service.OwnerService;

import java.util.List;
import java.util.function.Function;

@Configuration
public class OwnerTools {

private final OwnerRepository owners;
private final OwnerService ownerService;

public OwnerTools(OwnerRepository ownerRepository) {
this.owners = ownerRepository;
public OwnerTools(OwnerService ownerService) {
this.ownerService = ownerService;
}

@Bean
@Description("Query the owners by last name, the owner information include owner id, address, telephone, city, first name and last name"
@Description("Query the owners by first name, the owner information include owner id, address, telephone, city, first name and last name"
+ "\n The owner also include the pets information, include the pet name, pet type and birth"
+ "\n The pet include serveral visit record, include the visit name and visit date")
public Function<OwnerQueryRequest, List<Owner>> queryOwners() {
+ "\n The pet include several visit records, include the visit name and visit date")
public Function<OwnerQueryRequest, List<OwnerDto>> queryOwners() {
return name -> {
Pageable pageable = PageRequest.of(0, 10);
return owners.findByLastName(name.lastName, pageable).toList();
return ownerService.findByFirstName(name.firstName);
};
}

@Bean
@Description("Create a new owner by providing the owner's firstName, lastName, address, telephone and city")
public Function<OwnerCURequest, Owner> addOwner() {
public Function<OwnerCURequest, OwnerDto> addOwner() {
return request -> {
Owner owner = new Owner();
OwnerDto owner = new OwnerDto();
owner.setAddress(request.address);
owner.setTelephone(request.telephone);
owner.setCity(request.city);
owner.setLastName(request.lastName);
owner.setFirstName(request.firstName);
this.owners.save(owner);
ownerService.save(owner);
return owner;
};
}

@Bean
@Description("update a owner's firstName, lastName, address, telephone and city by providing the owner id\"")
public Function<OwnerCURequest, Owner> updateOwner() {
public Function<OwnerCURequest, OwnerDto> updateOwner() {
return request -> {
Owner owner = owners.findById(Integer.parseInt(request.ownerId));
OwnerDto owner = ownerService.findById(Integer.parseInt(request.ownerId));
if (request.address != null) {
owner.setAddress(request.address);
}
Expand All @@ -70,15 +67,15 @@ public Function<OwnerCURequest, Owner> updateOwner() {
if (request.firstName != null) {
owner.setFirstName(request.firstName);
}
this.owners.save(owner);
ownerService.save(owner);
return owner;
};
}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonClassDescription("Owner Query Request")
public record OwnerQueryRequest(@JsonProperty(required = false,
value = "lastName") @JsonPropertyDescription("The Owner last name") String lastName) {
value = "firstName") @JsonPropertyDescription("The Owner first name") String firstName) {
}

@JsonInclude(JsonInclude.Include.NON_NULL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.samples.petclinic.agent.vet.Vet;
import org.springframework.samples.petclinic.agent.vet.VetRepository;
import org.springframework.samples.petclinic.agent.dto.VetDto;
import org.springframework.samples.petclinic.agent.service.VetService;

import java.util.Collection;
import java.util.function.Function;

@Configuration
public class VetTools {

private final VetRepository vetRepository;
private final VetService vetService;

public VetTools(VetRepository vetRepository) {
this.vetRepository = vetRepository;
public VetTools(VetService vetService) {
this.vetService = vetService;
}

@Bean
@Description("return list of Vets, include their specialties")
public Function<Request, Collection<Vet>> queryVets() {
public Function<Request, Collection<VetDto>> queryVets() {
return request -> {
return vetRepository.findAll();
return vetService.findAll();
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.springframework.samples.petclinic.agent.dto;

import lombok.Data;

import java.util.Set;

@Data
public class OwnerDto {

private Integer id;

private String firstName;

private String lastName;

private String address;

private String city;

private String telephone;

private Set<PetDto> pets;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.springframework.samples.petclinic.agent.dto;

import lombok.Data;

import java.util.Date;

@Data
public class PetDto {

private Integer id;

private String name;

private Date birthDate;

private PetTypeDto type;

private OwnerDto owner;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.springframework.samples.petclinic.agent.dto;

import lombok.Data;

@Data
public class PetTypeDto {

private Integer id;

private String name;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.springframework.samples.petclinic.agent.dto;

import lombok.Data;

@Data
public class SpecialtyDto {

private Integer id;

private String name;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.springframework.samples.petclinic.agent.dto;

import lombok.Data;

import java.util.Set;

@Data
public class VetDto {

private Integer id;

private String firstName;

private String lastName;

private Set<SpecialtyDto> specialties;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.springframework.samples.petclinic.agent.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.agent.dto.OwnerDto;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

@Service
public class OwnerService {

private final RestTemplate restTemplate;

@Autowired
public OwnerService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

public List<OwnerDto> findByFirstName(String firstName) {
var owners = restTemplate.getForObject("http://customers-service/owners/firstname/{firstName}", OwnerDto[].class, firstName);
if (owners != null) {
return List.of(owners);
} else {
return new ArrayList<>();
}
}

public OwnerDto findById(int ownerId) {
return restTemplate.getForObject("http://customers-service/owners/{ownerId}", OwnerDto.class, ownerId);
}

public void save(OwnerDto owner) {
restTemplate.postForEntity("http://customers-service/owners", owner, OwnerDto.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.springframework.samples.petclinic.agent.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.agent.dto.VetDto;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

@Service
public class VetService {

private final RestTemplate restTemplate;

@Autowired
public VetService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

public List<VetDto> findAll() {
var vets = restTemplate.getForObject("http://vets-service/vets", VetDto[].class);
if (vets != null) {
return List.of(vets);
} else {
return new ArrayList<>();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ spring:
ai:
azure:
openai:
endpoint: ${AZURE_OPENAI_ENDPOINT}
client-id: ${CLIENT_ID}
endpoint: <your-azure-open-ai-endpoint>
client-id: <your-managed-identity-client-id>
chat:
options:
deployment-name: gpt-4
deployment-name: gpt-4o
temperature: 0.8
embedding:
options:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
package org.springframework.samples.petclinic.customers.model;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

/**
* Repository class for <code>Owner</code> domain objects All method names are compliant with Spring Data naming
Expand All @@ -27,4 +31,8 @@
* @author Michael Isvy
* @author Maciej Szarlinski
*/
public interface OwnerRepository extends JpaRepository<Owner, Integer> { }
public interface OwnerRepository extends JpaRepository<Owner, Integer> {

@Query("SELECT o FROM Owner o WHERE LOWER(o.firstName) = LOWER(:firstName)")
List<Owner> findByFirstName(@Param("firstName") String firstName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ public Optional<Owner> findOwner(@PathVariable("ownerId") @Min(1) int ownerId) {
return ownerRepository.findById(ownerId);
}

/**
* Find owners by first name
*/
@GetMapping(value = "/firstname/{firstName}")
public List<Owner> findOwnersByFirstName(@PathVariable("firstName") String firstName) {
return ownerRepository.findByFirstName(firstName);
}

/**
* Read List of Owners
*/
Expand Down

0 comments on commit 6cd310c

Please sign in to comment.