Skip to content

Commit

Permalink
Update dependencies of AI project (#197)
Browse files Browse the repository at this point in the history
* update payment.yml

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* Optimize image size of samples

* Update dependencies of AI project

* update bom
  • Loading branch information
dingmeng-xue authored Mar 14, 2024
1 parent 37df7e9 commit b277eb1
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 155 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/assist.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,4 @@ jobs:
--build-env BP_JVM_VERSION=17 \
--env \
SPRING_AI_AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT} \
SPRING_AI_AZURE_OPENAI_APIKEY=${AZURE_OPENAI_APIKEY} \
SPRING_AI_AZURE_OPENAI_MODEL=${AZURE_OPENAI_MODEL} \
SPRING_AI_AZURE_OPENAI_EMBEDDINGMODEL=${AZURE_OPENAI_EMBEDDINGMODEL} \
SPRING_AI_AZURE_OPENAI_API_KEY=${AZURE_OPENAI_APIKEY}
28 changes: 23 additions & 5 deletions apps/acme-assist/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<version>3.2.3</version>
</parent>
<groupId>com.azure.acme</groupId>
<artifactId>acme-assist</artifactId>
Expand All @@ -32,17 +32,24 @@
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-ai-openai</artifactId>
<version>1.0.0-beta.3</version>
<version>1.0.0-beta.7</version>
</dependency>
<dependency>
<groupId>org.springframework.experimental.ai</groupId>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-azure-vector-store-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.knuddels</groupId>
<artifactId>jtokkit</artifactId>
<version>0.6.1</version>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
Expand All @@ -57,6 +64,17 @@
<artifactId>log4j-slf4j-impl</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>0.8.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
package com.example.acme.assist;

import com.azure.ai.openai.models.ChatRole;
import com.example.acme.assist.model.AcmeChatRequest;
import com.example.acme.assist.model.Product;
import io.micrometer.common.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.logging.log4j.util.Strings;
import org.springframework.ai.client.AiClient;
import org.springframework.ai.client.AiResponse;
import org.springframework.ai.client.Generation;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.messages.ChatMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.prompt.Prompt;
import org.springframework.ai.prompt.SystemPromptTemplate;
import org.springframework.ai.prompt.messages.ChatMessage;
import org.springframework.ai.prompt.messages.Message;
import org.springframework.ai.vectorstore.impl.SimplePersistentVectorStore;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.azure.ai.openai.models.ChatRole;
import com.example.acme.assist.model.AcmeChatRequest;
import com.example.acme.assist.model.Product;

import io.micrometer.common.util.StringUtils;

@Service
public class ChatService {

@Autowired
private SimplePersistentVectorStore store;
private SimpleVectorStore store;

@Autowired
private ProductRepository productRepository;

@Autowired
private AiClient aiClient;
private ChatClient chatClient;

@Value("classpath:/prompts/chatWithoutProductId.st")
private Resource chatWithoutProductIdResource;
Expand Down Expand Up @@ -66,7 +67,7 @@ private List<String> chatWithProductId(Product product, List<AcmeChatRequest.Mes
String question = chatRequestMessages.get(chatRequestMessages.size() - 1).getContent();

// step 1. Query for documents that are related to the question from the vector store
List<Document> candidateDocuments = this.store.similaritySearch(question, 5, 0.4);
List<Document> candidateDocuments = this.store.similaritySearch(question);

// step 2. Create a SystemMessage that contains the product information in addition to related documents.
List<Message> messages = new ArrayList<>();
Expand All @@ -89,13 +90,13 @@ protected List<String> chatWithoutProductId(List<AcmeChatRequest.Message> acmeCh
String question = acmeChatRequestMessages.get(acmeChatRequestMessages.size() - 1).getContent();

// step 1. Query for documents that are related to the question from the vector store
List<Document> relatedDocuments = store.similaritySearch(question, 5, 0.4);
List<Document> relatedDocuments = store.similaritySearch(question);

// step 2. Create the system message with the related documents;
List<Message> messages = new ArrayList<>();
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.chatWithoutProductIdResource);
String relatedDocsAsString = relatedDocuments.stream()
.map(entry -> String.format("Product Name: %s\nText: %s\n", entry.getMetadata().get("name"), entry.getText()))
.map(entry -> String.format("Product Name: %s\nText: %s\n", entry.getMetadata().get("name"), entry.getContent()))
.collect(Collectors.joining("\n"));
Message systemMessage = systemPromptTemplate.createMessage(Map.of("context", relatedDocsAsString));
messages.add(systemMessage);
Expand All @@ -113,7 +114,7 @@ private List<String> addUserMessagesAndSendToAI(List<AcmeChatRequest.Message> ac

// Call to OpenAI chat API
Prompt prompt = new Prompt(messages);
AiResponse aiResponse = this.aiClient.generate(prompt);
ChatResponse aiResponse = this.chatClient.call(prompt);

// Process the result and return to client
List<String> response = processResult(aiResponse);
Expand All @@ -123,21 +124,21 @@ private List<String> addUserMessagesAndSendToAI(List<AcmeChatRequest.Message> ac

public Message getProductDetailMessage(Product product, List<Document> documents) {
String additionalContext = documents.stream()
.map(entry -> String.format("Product Name: %s\nText: %s\n", entry.getMetadata().get("name"), entry.getText()))
.map(entry -> String.format("Product Name: %s\nText: %s\n", entry.getMetadata().get("name"), entry.getContent()))
.collect(Collectors.joining("\n"));
Map map = Map.of(
Map<String,Object> map = Map.of(
"name", product.getName(),
"tags", String.join(",", product.getTags()),
"shortDescription", product.getShortDescription(),
"fullDescription", product.getDescription(),
"additionalContext", additionalContext);
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.chatWithProductIdResource);
return systemPromptTemplate.create(map).getMessages().get(0);
return systemPromptTemplate.create(map).getInstructions().get(0);
}

private List<String> processResult(AiResponse aiResponse) {
List<String> response = aiResponse.getGenerations().stream()
.map(Generation::getText)
private List<String> processResult(ChatResponse aiResponse) {
List<String> response = aiResponse.getResults().stream()
.map(result -> result.getOutput().getContent())
.filter(text -> !StringUtils.isEmpty(text))
.map(this::filterMessage)
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.example.acme.assist.config;

import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.vectorstore.impl.SimplePersistentVectorStore;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -12,9 +12,10 @@ public class FitAssistConfiguration {

@Value("classpath:/vector_store.json")
private Resource vectorDbResource;

@Bean
public SimplePersistentVectorStore simpleVectorStore(EmbeddingClient embeddingClient) {
SimplePersistentVectorStore simpleVectorStore = new SimplePersistentVectorStore(embeddingClient);
public SimpleVectorStore simpleVectorStore(EmbeddingClient embeddingClient) {
SimpleVectorStore simpleVectorStore = new SimpleVectorStore(embeddingClient);
simpleVectorStore.load(vectorDbResource);
return simpleVectorStore;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.example.acme.assist.tools;

import org.springframework.ai.document.Document;
import org.springframework.ai.loader.impl.JsonLoader;
import org.springframework.ai.loader.impl.JsonMetadataGenerator;
import org.springframework.ai.vectorstore.impl.SimplePersistentVectorStore;
import org.springframework.ai.reader.JsonMetadataGenerator;
import org.springframework.ai.reader.JsonReader;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.DefaultApplicationArguments;
Expand All @@ -25,7 +25,7 @@
public class BuildVectorStoreApplication implements CommandLineRunner {

@Autowired
private SimplePersistentVectorStore simpleVectorStore;
private SimpleVectorStore simpleVectorStore;

public static void main(String[] args) {
new SpringApplicationBuilder(BuildVectorStoreApplication.class)
Expand All @@ -50,10 +50,10 @@ public void run(String... originalArgs) throws Exception {

for (var file : jsonFiles) {
File sourceFile = new File(file);
JsonLoader jsonLoader = new JsonLoader(new FileSystemResource(sourceFile),
JsonReader jsonLoader = new JsonReader(new FileSystemResource(sourceFile),
new ProductMetadataGenerator(),
"price", "name", "shortDescription", "description", "tags");
List<Document> documents = jsonLoader.load();
List<Document> documents = jsonLoader.get();
this.simpleVectorStore.add(documents);
}
this.simpleVectorStore.save(new File(to.get(0)));
Expand Down
7 changes: 6 additions & 1 deletion apps/acme-assist/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ spring:
ai:
azure:
openai:
model: gpt-35-turbo-16k
chat:
options:
deployment-name: gpt-35-turbo-16k
embedding:
options:
deployment-name: text-embedding-ada-002
management:
endpoints:
web:
Expand Down
65 changes: 57 additions & 8 deletions apps/acme-assist/src/main/resources/prompts/chatWithProductId.st
Original file line number Diff line number Diff line change
@@ -1,17 +1,66 @@
You are an AI assistant of this website named 'Acme Fitness Store', which sells bikes and accessories online.
You help people find information.
Please answer the questions based the following product details with the text that follows the placeholder """PRODUCT-DETAILS""" and then
try to improve your answer with additional text that follows the placeholder """ADDITIONAL-CONTEXT"""
[Overall Rules to follow]
* You are an AI assistant of the website named 'Acme Fitness Store', which sells bikes and accessories online.
* Content in [PRODUCT-INFO] is introduction of commodity user is watching.
* User's question only relates to this website, bikes and accessories.
* Answer user's question according to content in [PRODUCT-INFO] or reference [Examples]
* Improve answer using [ADDITIONAL-CONTEXT]
* Answer 'Sorry, I cannot answer your question. Please contact us.' if question is not related to given content.

"""PRODUCT-DETAILS"""
[PRODUCT-INFO]
[Begin]
Name: {name}
Tags: {tags}
Short description:
{shortDescription}
Full description:
{fullDescription}
[End]



"""ADDITIONAL-CONTEXT"""
[ADDITIONAL-CONTEXT]
[Begin]
{additionalContext}
[End]

[EXAMPLES]
[Begin]
[Question]
How long will it take to get the bike delivered to me?
[Answer]
We offer two shipping options: 1. Free standard: With our standard shipping option, you can expect your products to arrive within 3-7 business days. 2. Premium: If you prefer priority handling and express delivery, our premium shipping option ensures delivery within 1-3 business days. Feeling reassured by the estimated delivery time, Alex completes the remaining form fields, including his credit card information. With the order finalized, Alex is excitedly looking forward to receiving his new e-bike and accessories. He's grateful for the helpful guidance provided by FitAssist throughout the entire shopping experience.
[Question]
How will you ship my bike?
[Answer]
Great question! We offer two shipping options: Free Shipping: Get your Model A e-bike and Rear Rack delivered to your doorstep at no additional cost with our standard shipping option. Estimated delivery time is 3-7 business days. Premium Shipping: If you prefer priority handling and express delivery, you can choose our premium shipping option. Your e-bike and accessories will arrive within 1-3 business days. Please let me know which option you'd like, or if you have any other questions. I'm here to assist you throughout the process.
[Question]
How do I place an order for a bike on your website?
[Answer]
To place an order, browse through our selection of bikes and click on the one you wish to purchase. On the product page, you'll find an "Add to Cart" button. Click on it, and the bike will be added to your shopping cart. Proceed to the checkout page to complete your order.
[Question]
What payment methods do you accept for bike purchases?
[Answer]
We accept various payment methods, including credit/debit cards (Visa, Mastercard, etc.), PayPal, and other secure online payment options. You can select your preferred payment method during the checkout process.
[Question]
Do you offer free shipping for bike orders?
[Answer]
Absolutely! We offer free standard shipping for all bike orders. With our free shipping option, it will be delivered to your doorstep at no additional cost. Estimated delivery time is 3-7 business days. If you prefer faster delivery, we also have a premium shipping option available for a small additional fee, which ensures express delivery within 1-3 business days. Please let me know if you have any more questions or if there's anything else I can assist you with!
[Question]
Can I return or exchange the bike if I'm not satisfied?
[Answer]
Yes, we have a hassle-free return and exchange policy. If you are not satisfied with your bike, you can return it within 30 days of delivery for a full refund or exchange. The bike must be in its original condition, and you may be responsible for return shipping costs.
[Question]
Are the bikes on your website pre-assembled or do I need to assemble them myself?
[Answer]
The bikes are usually shipped partially assembled for safer transportation. You will receive detailed instructions and the necessary tools to complete the assembly easily at home. If you need assistance, you can contact our customer support team.
[Question]
Do you offer any warranties on your bikes?
[Answer]
Yes, all our bikes come with a manufacturer's warranty that covers defects in materials and workmanship. The duration and coverage of the warranty may vary depending on the bike model. Please check the product page or contact us for specific warranty information.
[Question]
Can I get expert advice on choosing the right bike for me?
[Answer]
Absolutely! We have a team of knowledgeable bike experts ready to assist you. You can reach out to our customer support through email, phone, or live chat, and they will be happy to help you find the perfect bike based on your needs and preferences.
[Question]
Do you offer any discounts or promotions on bike purchases?
[Answer]
Yes, we frequently run promotions and special offers on our website. Keep an eye on our homepage and subscribe to our newsletter to stay updated on the latest deals and discounts.
[End]
Loading

0 comments on commit b277eb1

Please sign in to comment.