forked from spring-cloud-services-samples/acme-fitness-store
-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
28fc23c
commit 5955887
Showing
13 changed files
with
169 additions
and
1,230 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 0 additions & 36 deletions
36
apps/acme-assist/src/main/java/com/example/acme/assist/AzureOpenAIClient.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 5 additions & 59 deletions
64
apps/acme-assist/src/main/java/com/example/acme/assist/config/FitAssistConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,83 +1,29 @@ | ||
package com.example.acme.assist.config; | ||
|
||
import com.azure.ai.openai.OpenAIClientBuilder; | ||
import com.azure.core.credential.AzureKeyCredential; | ||
import com.example.acme.assist.AzureOpenAIClient; | ||
import com.example.acme.assist.vectorstore.CosmosDBVectorStore; | ||
import org.springframework.ai.embedding.EmbeddingClient; | ||
import org.springframework.ai.vectorstore.SimpleVectorStore; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.data.mongodb.core.MongoTemplate; | ||
|
||
import java.io.IOException; | ||
|
||
@Configuration | ||
public class FitAssistConfiguration { | ||
|
||
@Value("${spring.ai.azure.openai.embedding-model}") | ||
private String embeddingDeploymentId; | ||
|
||
@Value("${spring.ai.azure.openai.deployment-name}") | ||
private String chatDeploymentId; | ||
|
||
@Value("${spring.ai.azure.openai.endpoint}") | ||
private String endpoint; | ||
|
||
@Value("${spring.ai.azure.openai.api-key}") | ||
private String apiKey; | ||
|
||
@Value("${vector-store.file}") | ||
private String cosmosVectorJsonFile; | ||
|
||
@Value("${spring.data.mongodb.enabled}") | ||
private String cosmosEnabled; | ||
|
||
//@Autowired | ||
private MongoTemplate mongoTemplate; | ||
public FitAssistConfiguration(MongoTemplate mongoTemplate) { | ||
this.mongoTemplate = mongoTemplate; | ||
public FitAssistConfiguration() { | ||
|
||
} | ||
|
||
|
||
|
||
@Value("classpath:/vector_store.json") | ||
private Resource vectorDbResource; | ||
|
||
@Bean | ||
@ConditionalOnProperty(value="vectorstore", havingValue = "simple", matchIfMissing = true) | ||
public SimpleVectorStore simpleVectorStore(EmbeddingClient embeddingClient) { | ||
SimpleVectorStore simpleVectorStore = new SimpleVectorStore(embeddingClient); | ||
if (cosmosEnabled.equals("false")) { | ||
simpleVectorStore.load(vectorDbResource); | ||
} | ||
simpleVectorStore.load(vectorDbResource); | ||
return simpleVectorStore; | ||
} | ||
|
||
@Bean | ||
public CosmosDBVectorStore vectorStore() throws IOException { | ||
CosmosDBVectorStore store = null; | ||
if (cosmosEnabled.equals("true")) { | ||
store = new CosmosDBVectorStore(mongoTemplate); | ||
String currentPath = new java.io.File(".").getCanonicalPath(); | ||
String path = currentPath + cosmosVectorJsonFile.replace("\\", "//"); | ||
store.loadFromJsonFile(path); | ||
} | ||
else { | ||
store = new CosmosDBVectorStore(null); | ||
} | ||
return store; | ||
} | ||
|
||
@Bean | ||
public AzureOpenAIClient AzureOpenAIClient() { | ||
var innerClient = new OpenAIClientBuilder() | ||
.endpoint(endpoint) | ||
.credential(new AzureKeyCredential(apiKey)) | ||
.buildClient(); | ||
return new AzureOpenAIClient(innerClient, embeddingDeploymentId, chatDeploymentId); | ||
} | ||
|
||
|
||
} |
115 changes: 115 additions & 0 deletions
115
apps/acme-assist/src/main/java/com/example/acme/assist/mongodb/CosmosDBVectorStore.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package com.example.acme.assist.mongodb; | ||
|
||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.ai.document.Document; | ||
import org.springframework.ai.embedding.EmbeddingClient; | ||
import org.springframework.ai.vectorstore.SearchRequest; | ||
import org.springframework.ai.vectorstore.VectorStore; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.data.mongodb.core.MongoTemplate; | ||
import org.springframework.data.mongodb.core.aggregation.Aggregation; | ||
import org.springframework.data.mongodb.core.aggregation.AggregationResults; | ||
import org.springframework.stereotype.Component; | ||
|
||
import com.fasterxml.jackson.core.type.TypeReference; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import jakarta.annotation.PostConstruct; | ||
|
||
@Component | ||
@ConditionalOnProperty(value = "vectorstore", havingValue = "mongodb", matchIfMissing = false) | ||
public class CosmosDBVectorStore implements VectorStore { | ||
|
||
private static Logger LOGGER = LoggerFactory.getLogger(CosmosDBVectorStore.class); | ||
|
||
private static String COLLECTION = "vectorstore"; | ||
|
||
@Value("classpath:/vector_store.json") | ||
private Resource vectorDbResource; | ||
|
||
@Autowired | ||
private MongoTemplate template; | ||
|
||
@Autowired | ||
protected EmbeddingClient embeddingClient; | ||
|
||
@PostConstruct | ||
protected void init() { | ||
template.dropCollection(COLLECTION); | ||
this.load(vectorDbResource); | ||
LOGGER.info("initialized collection in mongodb"); | ||
} | ||
|
||
public void load(Resource resource) { | ||
TypeReference<HashMap<String, Document>> typeRef = new TypeReference<>() { | ||
}; | ||
ObjectMapper objectMapper = new ObjectMapper(); | ||
try { | ||
Map<String, Document> docs = objectMapper.readValue(resource.getInputStream(), typeRef); | ||
Optional<Document> doc = docs.values().stream().findFirst(); | ||
if (doc.isPresent()) { | ||
int dimensions = doc.get().getEmbedding().size(); | ||
template.insert(docs.values(), COLLECTION); | ||
createVectorIndex(5, dimensions, "COS"); | ||
} | ||
} catch (IOException ex) { | ||
throw new RuntimeException(ex); | ||
} | ||
} | ||
|
||
public void createVectorIndex(int numLists, int dimensions, String similarity) { | ||
String bsonCmd = "{\"createIndexes\":\"" + COLLECTION + "\",\"indexes\":" | ||
+ "[{\"name\":\"vectorsearch\",\"key\":{\"embedding\":\"cosmosSearch\"},\"cosmosSearchOptions\":" | ||
+ "{\"kind\":\"vector-ivf\",\"numLists\":" + numLists + ",\"similarity\":\"" + similarity | ||
+ "\",\"dimensions\":" + dimensions + "}}]}"; | ||
LOGGER.info("creating vector index in Cosmos DB Mongo vCore..."); | ||
try { | ||
template.executeCommand(bsonCmd); | ||
} catch (Exception e) { | ||
LOGGER.warn("Failed to create vector index in Cosmos DB Mongo vCore", e); | ||
} | ||
} | ||
|
||
@Override | ||
public void add(List<Document> documents) { | ||
// TODO Auto-generated method stub | ||
} | ||
|
||
@Override | ||
public Optional<Boolean> delete(List<String> idList) { | ||
return Optional.empty(); | ||
} | ||
|
||
private List<Double> getUserQueryEmbedding(String query) { | ||
return this.embeddingClient.embed(query); | ||
} | ||
|
||
@Override | ||
public List<Document> similaritySearch(SearchRequest request) { | ||
List<Double> embedding = getUserQueryEmbedding(request.getQuery()); | ||
|
||
// perform vector search in Cosmos DB Mongo API - vCore | ||
String command = "{\"$search\":{\"cosmosSearch\":{\"vector\":" + embedding + ",\"path\":\"embedding\",\"k\":" | ||
+ request.getTopK() + "}}}"; | ||
Aggregation agg = Aggregation.newAggregation(Aggregation.stage(command)); | ||
AggregationResults<org.bson.Document> results = template.aggregate(agg, COLLECTION, org.bson.Document.class); | ||
List<Document> ret = new ArrayList<>(); | ||
results.getMappedResults().forEach(bDoc -> { | ||
String content = bDoc.getString("content"); | ||
Document doc = new Document(content); | ||
ret.add(doc); | ||
}); | ||
return ret; | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
apps/acme-assist/src/main/java/com/example/acme/assist/mongodb/MongoDBConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package com.example.acme.assist.mongodb; | ||
|
||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.data.mongodb.core.MongoTemplate; | ||
|
||
import com.mongodb.ConnectionString; | ||
import com.mongodb.MongoClientSettings; | ||
import com.mongodb.client.MongoClients; | ||
|
||
@Configuration | ||
@ConditionalOnProperty(value = "vectorstore", havingValue = "mongodb", matchIfMissing = false) | ||
public class MongoDBConfiguration { | ||
|
||
@Value("${spring.data.mongodb.uri}") | ||
private String url; | ||
|
||
@Value("${spring.data.mongodb.database}") | ||
private String database; | ||
|
||
@Bean | ||
public MongoTemplate mongoTemplate() { | ||
ConnectionString cs = new ConnectionString(url); | ||
MongoClientSettings settings = MongoClientSettings.builder().applyConnectionString(cs).build(); | ||
|
||
return new MongoTemplate(MongoClients.create(settings), database); | ||
} | ||
} |
Oops, something went wrong.