From d35757fa097bd8ddaa2048fb736cc7c5dcf822ef Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Tue, 13 Feb 2024 14:24:07 +0000 Subject: [PATCH] Fix java build --- .../memory/redis/JsonMemoryRecord.java | 5 +- .../memory/redis/RedisException.java | 1 - .../memory/redis/RedisIndexSchemaParams.java | 7 +- .../memory/redis/RedisMemoryRecord.java | 41 +- .../memory/redis/RedisMemoryStore.java | 397 ++++++++++-------- .../redis/RedisVectorDistanceMetric.java | 7 +- .../memory/redis/RedisVectorType.java | 5 +- .../Example06_TemplateLanguage.java | 15 +- .../semantickernel/AiServiceRegistryTest.java | 2 +- .../semantickernel/DefaultKernelTest.java | 2 +- ...e04CombineLLMPromptsAndNativeCodeTest.java | 3 +- .../Example05UsingThePlannerTest.java | 5 +- .../Example12SequentialPlannerTest.java | 5 +- .../Example28ActionPlannerTest.java | 5 +- 14 files changed, 289 insertions(+), 211 deletions(-) diff --git a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/JsonMemoryRecord.java b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/JsonMemoryRecord.java index 6a2bf1a63c..e850329c2e 100644 --- a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/JsonMemoryRecord.java +++ b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/JsonMemoryRecord.java @@ -6,10 +6,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.microsoft.semantickernel.ai.embeddings.Embedding; import com.microsoft.semantickernel.memory.MemoryRecord; import com.microsoft.semantickernel.memory.MemoryRecordMetadata; - -import javax.annotation.Nullable; import java.nio.charset.StandardCharsets; import java.util.*; +import javax.annotation.Nullable; /** Represents an entry in the Semantic Kernel Memory Table. */ public class JsonMemoryRecord { @@ -49,7 +48,6 @@ public class JsonMemoryRecord { this.isReference = isReference; } - /** * Record ID. The record is not filterable to save quota, also SK uses only semantic search. * @@ -169,5 +167,4 @@ public class JsonMemoryRecord { byte[] bytes = Base64.getUrlDecoder().decode(encodedId.getBytes(StandardCharsets.UTF_8)); return new String(bytes, StandardCharsets.UTF_8); } - } diff --git a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisException.java b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisException.java index 6bd11309cb..2060938a48 100644 --- a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisException.java +++ b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisException.java @@ -2,7 +2,6 @@ package com.microsoft.semantickernel.connectors.memory.redis; import com.microsoft.semantickernel.SKException; - import javax.annotation.Nonnull; import javax.annotation.Nullable; diff --git a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisIndexSchemaParams.java b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisIndexSchemaParams.java index 1477677fa3..e3f4eb9db2 100644 --- a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisIndexSchemaParams.java +++ b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisIndexSchemaParams.java @@ -1,8 +1,9 @@ +// Copyright (c) Microsoft. All rights reserved. package com.microsoft.semantickernel.connectors.memory.redis; public class RedisIndexSchemaParams { - public static final String TYPE = "TYPE"; - public static final String DIM = "DIM"; - public static final String DIST = "DISTANCE_METRIC"; + public static final String TYPE = "TYPE"; + public static final String DIM = "DIM"; + public static final String DIST = "DISTANCE_METRIC"; } diff --git a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisMemoryRecord.java b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisMemoryRecord.java index d0f20a7ef8..db68704568 100644 --- a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisMemoryRecord.java +++ b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisMemoryRecord.java @@ -4,30 +4,40 @@ package com.microsoft.semantickernel.connectors.memory.redis; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.microsoft.semantickernel.ai.embeddings.Embedding; -import com.microsoft.semantickernel.memory.DataEntryBase; import com.microsoft.semantickernel.memory.MemoryRecord; -import redis.clients.jedis.search.Document; - import java.time.ZonedDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import redis.clients.jedis.search.Document; /** Represents an entry in the Semantic Kernel Memory Table. */ public class RedisMemoryRecord extends JsonMemoryRecord { - public RedisMemoryRecord(String id, String text, String description, String additionalMetadata, - List embedding, String externalSourceName, boolean isReference) { - super(id, text, description, additionalMetadata, embedding, externalSourceName, isReference); + public RedisMemoryRecord( + String id, + String text, + String description, + String additionalMetadata, + List embedding, + String externalSourceName, + boolean isReference) { + super( + id, + text, + description, + additionalMetadata, + embedding, + externalSourceName, + isReference); } /** * Converts a RedisSearch Document to a HashMap. * * @param document A Redis Search Document - * * @return A HashMap containing the iterator's entries */ protected Map documentToMap(Document document) { @@ -39,8 +49,8 @@ public class RedisMemoryRecord extends JsonMemoryRecord { * Gets the embedding information associated with the entry. * * @param map A hashmap with keys representing a record - * @param withEmbedding A boolean flag indicating that the embedding should be returned with the metadata - * + * @param withEmbedding A boolean flag indicating that the embedding should be returned with the + * metadata * @return A MemoryRecord object. */ public static MemoryRecord mapToRecord(Map map, boolean withEmbedding) { @@ -49,7 +59,10 @@ public class RedisMemoryRecord extends JsonMemoryRecord { ObjectMapper mapper = new ObjectMapper(); try { if (map.get(TIME) != null) { - time = mapper.readValue(map.getOrDefault(TIME, ZonedDateTime.now().toString()), ZonedDateTime.class); + time = + mapper.readValue( + map.getOrDefault(TIME, ZonedDateTime.now().toString()), + ZonedDateTime.class); } if (withEmbedding) { List embeddings = mapper.readValue(map.get(EMBEDDING), List.class); @@ -57,9 +70,7 @@ public class RedisMemoryRecord extends JsonMemoryRecord { } } catch (JsonProcessingException e) { throw new RedisException( - RedisException.ErrorCodes.REDIS_ERROR, - "Error deserializing Redis entry", - e); + RedisException.ErrorCodes.REDIS_ERROR, "Error deserializing Redis entry", e); } return MemoryRecord.localRecord( @@ -69,15 +80,13 @@ public class RedisMemoryRecord extends JsonMemoryRecord { embedding, map.get(ADDITIONAL_METADATA), map.get(EXTERNAL_SOURCE_NAME), - time - ); + time); } /** * Gets the embedding information associated with the entry. * * @param record A MemoryRecord object - * * @return A hashmap containing the entries of the record. */ public static Map recordToMap(MemoryRecord record) { diff --git a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisMemoryStore.java b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisMemoryStore.java index 368e0b9e45..ac56b18cfe 100644 --- a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisMemoryStore.java +++ b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisMemoryStore.java @@ -1,3 +1,4 @@ +// Copyright (c) Microsoft. All rights reserved. package com.microsoft.semantickernel.connectors.memory.redis; import com.microsoft.semantickernel.ai.embeddings.Embedding; @@ -5,6 +6,15 @@ import com.microsoft.semantickernel.memory.MemoryException; import com.microsoft.semantickernel.memory.MemoryException.ErrorCodes; import com.microsoft.semantickernel.memory.MemoryRecord; import com.microsoft.semantickernel.memory.MemoryStore; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.text.MessageFormat; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; import reactor.util.function.Tuples; @@ -13,29 +23,20 @@ import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.resps.ScanResult; import redis.clients.jedis.search.*; import redis.clients.jedis.search.schemafields.VectorField.VectorAlgorithm; -import javax.annotation.Nonnull; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.security.InvalidParameterException; -import java.text.MessageFormat; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneId; -import java.util.*; - -import java.util.function.Function; -import java.util.stream.Collectors; /** - * Semantic Memory implementation using Redis Vector Search. For more information about Redis - * Vector Search {@see https://redis.com/solutions/use-cases/vector-database/} + * Semantic Memory implementation using Redis Vector Search. For more information about Redis Vector + * Search {@see https://redis.com/solutions/use-cases/vector-database/} */ public class RedisMemoryStore implements MemoryStore { - private static final VectorAlgorithm DefaultIndexAlgorithm = VectorAlgorithm.HNSW; // FLAT or HNSW - private static final String DefaultVectorType = RedisVectorType.FLOAT32; // prefer better accuracy + private static final VectorAlgorithm DefaultIndexAlgorithm = + VectorAlgorithm.HNSW; // FLAT or HNSW + private static final String DefaultVectorType = + RedisVectorType.FLOAT32; // prefer better accuracy private static final String DefaultDistanceMetric = RedisVectorDistanceMetric.L2; - private static final Integer DefaultQueryDialect = 2; // this has to be >= 2 for vector functionality + private static final Integer DefaultQueryDialect = + 2; // this has to be >= 2 for vector functionality private static final Integer DefaultVectorSize = 1536; // framework model dependent - ada-002 private static final String SUFFIX = "sk"; private static final String INDEX = "idx"; @@ -58,22 +59,29 @@ public class RedisMemoryStore implements MemoryStore { * Create a new instance of semantic memory using Redis. * * @param client A Redis Database client connection. - * @param vectorSize Embedding vector size, defaults to 1536 - framework model dependent - ada-002. + * @param vectorSize Embedding vector size, defaults to 1536 - framework model dependent - + * ada-002. * @param vectorIndexAlgorithm Indexing algorithm for vectors, defaults to "HNSW" * @param vectorDistanceMetric Metric for measuring vector distances, defaults to "COSINE" - * @param queryDialect Query dialect, must be 2 or greater for vector similarity searching, defaults to 2 + * @param queryDialect Query dialect, must be 2 or greater for vector similarity searching, + * defaults to 2 */ public RedisMemoryStore( - JedisPooled client, - Integer vectorSize, - VectorAlgorithm vectorIndexAlgorithm, - String vectorDistanceMetric, - Integer queryDialect - ) { + JedisPooled client, + Integer vectorSize, + VectorAlgorithm vectorIndexAlgorithm, + String vectorDistanceMetric, + Integer queryDialect) { - isXinRange(vectorSize, 0, 8192, + isXinRange( + vectorSize, + 0, + 8192, "Invalid vector size: {x}. Vector size must be in the range 0-8192."); - isXinRange(queryDialect, 2, 4, + isXinRange( + queryDialect, + 2, + 4, "Invalid query dialect: {x}. Query dialect must be in the range 2-4."); this.client = client; @@ -84,25 +92,32 @@ public class RedisMemoryStore implements MemoryStore { this.queryDialect = queryDialect; } - /** - * Create a new instance of semantic memory using Redis. - * - * @param connectionString Provide connection URL to a Redis instance. - * @param vectorSize Embedding vector size, defaults to 1536. - * @param vectorIndexAlgorithm Indexing algorithm for vectors, defaults to "HNSW" - * @param vectorDistanceMetric Metric for measuring vector distances, defaults to "COSINE" - * @param queryDialect Query dialect, must be 2 or greater for vector similarity searching, defaults to 2 - */ + /** + * Create a new instance of semantic memory using Redis. + * + * @param connectionString Provide connection URL to a Redis instance. + * @param vectorSize Embedding vector size, defaults to 1536. + * @param vectorIndexAlgorithm Indexing algorithm for vectors, defaults to "HNSW" + * @param vectorDistanceMetric Metric for measuring vector distances, defaults to "COSINE" + * @param queryDialect Query dialect, must be 2 or greater for vector similarity searching, + * defaults to 2 + */ public RedisMemoryStore( - String connectionString, - Integer vectorSize, - VectorAlgorithm vectorIndexAlgorithm, - String vectorDistanceMetric, - Integer queryDialect) { + String connectionString, + Integer vectorSize, + VectorAlgorithm vectorIndexAlgorithm, + String vectorDistanceMetric, + Integer queryDialect) { - isXinRange(vectorSize, 0, 8192, + isXinRange( + vectorSize, + 0, + 8192, "Invalid vector size: {x}. Vector size must be in the range 0-8192."); - isXinRange(queryDialect, 2, 4, + isXinRange( + queryDialect, + 2, + 4, "Invalid query dialect: {x}. Query dialect must be in the range 2-4."); this.client = new JedisPooled(connectionString); @@ -134,7 +149,7 @@ public class RedisMemoryStore implements MemoryStore { * @return A long timestamp or -1 in the case of an error. */ private static long toTimestampLong(OffsetDateTime timestamp) { - if (timestamp != null) { + if (timestamp != null) { return timestamp.toInstant().toEpochMilli(); } return -1; @@ -156,9 +171,10 @@ public class RedisMemoryStore implements MemoryStore { @Override public Mono> getCollectionsAsync() { - return Mono.just(getIndexesAsync().block().stream() - .map(name -> name.substring(0, name.length() - "-sk-idx".length())) - .collect(Collectors.toList())); + return Mono.just( + getIndexesAsync().block().stream() + .map(name -> name.substring(0, name.length() - "-sk-idx".length())) + .collect(Collectors.toList())); } /** @@ -167,14 +183,16 @@ public class RedisMemoryStore implements MemoryStore { * @return A list of names of the embedding indexes, including suffix, in the database */ private Mono> getIndexesAsync() { - return Mono.just(this.client.ftList().stream() - .filter(name -> name.endsWith("-sk-idx")) - .collect(Collectors.toList())); + return Mono.just( + this.client.ftList().stream() + .filter(name -> name.endsWith("-sk-idx")) + .collect(Collectors.toList())); } @Override public Mono createCollectionAsync(@Nonnull String collectionName) { - // Indexes are created when sending a record; creation requires the size of the embedding vector + // Indexes are created when sending a record; creation requires the size of the embedding + // vector return Mono.empty(); } @@ -182,8 +200,8 @@ public class RedisMemoryStore implements MemoryStore { try { Map info = this.client.ftInfo(collectionName); - return Mono.just(info != null && ! info.isEmpty()); - } catch(Exception e) { + return Mono.just(info != null && !info.isEmpty()); + } catch (Exception e) { if (!(e instanceof JedisDataException)) { throw e; } @@ -205,7 +223,7 @@ public class RedisMemoryStore implements MemoryStore { name -> name.equalsIgnoreCase(collectionName) || name.equalsIgnoreCase( - normalizedIndexName))); + normalizedIndexName))); } @Override @@ -220,11 +238,12 @@ public class RedisMemoryStore implements MemoryStore { } @Override - public Mono getAsync(@Nonnull String collectionName, @Nonnull String key, - boolean withEmbedding) { + public Mono getAsync( + @Nonnull String collectionName, @Nonnull String key, boolean withEmbedding) { - Map map = this.client.hgetAll(String.format("%s:%s", - collectionName, key).toLowerCase(Locale.ROOT)); + Map map = + this.client.hgetAll( + String.format("%s:%s", collectionName, key).toLowerCase(Locale.ROOT)); if (map == null || map.isEmpty()) { return Mono.empty(); } @@ -232,16 +251,16 @@ public class RedisMemoryStore implements MemoryStore { return Mono.just(record); } - public Mono getInternalAsync(@Nonnull String collectionName, @Nonnull String key, - boolean withEmbedding) { + public Mono getInternalAsync( + @Nonnull String collectionName, @Nonnull String key, boolean withEmbedding) { Objects.requireNonNull(collectionName); Objects.requireNonNull(key); - Map entry = this.client.hgetAll(String.format("%s:%s", collectionName, key)); + Map entry = + this.client.hgetAll(String.format("%s:%s", collectionName, key)); - if (entry == null) - return Mono.empty(); + if (entry == null) return Mono.empty(); return Mono.just(RedisMemoryRecord.mapToRecord(entry, withEmbedding)); } @@ -250,7 +269,6 @@ public class RedisMemoryStore implements MemoryStore { * Converts a RedisSearch Document to a HashMap. * * @param document A Redis Search Document - * * @return A HashMap containing the iterator's entries */ protected Map documentToMap(Document document) { @@ -262,7 +280,6 @@ public class RedisMemoryStore implements MemoryStore { * Converts an Iterable> to a HashMap. * * @param entryIterator An Iterable> - * * @return A HashMap containing the iterator's entries */ protected Map iterableToMap(Iterable> entryIterator) { @@ -280,12 +297,17 @@ public class RedisMemoryStore implements MemoryStore { } @Override - public Mono> getBatchAsync(@Nonnull String collectionName, - @Nonnull Collection keys, boolean withEmbeddings) { + public Mono> getBatchAsync( + @Nonnull String collectionName, + @Nonnull Collection keys, + boolean withEmbeddings) { Objects.requireNonNull(collectionName); - // ACS issues one query per key; redis has several possible calls, fastest will be hkeys followed by hvals - Collection records = keys.stream().map(key -> getAsync(collectionName, key, withEmbeddings).block()) - .collect(Collectors.toList()); + // ACS issues one query per key; redis has several possible calls, fastest will be hkeys + // followed by hvals + Collection records = + keys.stream() + .map(key -> getAsync(collectionName, key, withEmbeddings).block()) + .collect(Collectors.toList()); return Mono.just(records); } @@ -296,21 +318,23 @@ public class RedisMemoryStore implements MemoryStore { } /** - * Returns the key of the upserted object (wraps the record in a list and calls the batch function). + * Returns the key of the upserted object (wraps the record in a list and calls the batch + * function). * * @param collectionName The name associated with a collection of embeddings. * @param record The memory record to upsert. * @return The key of the newly created record. */ - public Mono upsertRecordAsync(@Nonnull String collectionName, @Nonnull MemoryRecord record) { + public Mono upsertRecordAsync( + @Nonnull String collectionName, @Nonnull MemoryRecord record) { return upsertBatchAsync(collectionName, Collections.singletonList(record)) .map(Collection::iterator) .map(Iterator::next); } @Override - public Mono> upsertBatchAsync(@Nonnull String collectionName, - @Nonnull Collection records) { + public Mono> upsertBatchAsync( + @Nonnull String collectionName, @Nonnull Collection records) { Objects.requireNonNull(collectionName); Objects.requireNonNull(records); @@ -322,79 +346,103 @@ public class RedisMemoryStore implements MemoryStore { doesCollectionExistAsync(collectionName) .map( exists -> { - if (! exists) { - int embeddingSize = records.stream() - .map(record -> record.getEmbedding().getVector()) - .map(List::size) - .max(Integer::compareTo) - .orElse(0); + if (!exists) { + int embeddingSize = + records.stream() + .map(record -> record.getEmbedding().getVector()) + .map(List::size) + .max(Integer::compareTo) + .orElse(0); createIndexAsync(collectionName, embeddingSize); } return true; - } - ); + }); - return Mono.just(records.stream().map(record -> { - Map map = RedisMemoryRecord.recordToMap(record); - // we have to change the embeddings to bytes - it's easiest to modify the map - List embedding = record.getEmbedding().getVector(); - map.replace(RedisMemoryRecord.EMBEDDING, embedding, embeddingToBytes(embedding)); - String key = getRedisKey(collectionName, record.getMetadata().getId()); - this.client.hsetObject(key, map); - return key; - }).collect(Collectors.toList())); + return Mono.just( + records.stream() + .map( + record -> { + Map map = RedisMemoryRecord.recordToMap(record); + // we have to change the embeddings to bytes - it's easiest to + // modify the map + List embedding = record.getEmbedding().getVector(); + map.replace( + RedisMemoryRecord.EMBEDDING, + embedding, + embeddingToBytes(embedding)); + String key = + getRedisKey( + collectionName, record.getMetadata().getId()); + this.client.hsetObject(key, map); + return key; + }) + .collect(Collectors.toList())); } @Override public Mono removeAsync(@Nonnull String collectionName, @Nonnull String key) { return Mono.fromRunnable( - () -> this.client.hdel(String.format("%s:%s", collectionName, key))); - } + () -> this.client.hdel(String.format("%s:%s", collectionName, key))); + } @Override - public Mono removeBatchAsync(@Nonnull String collectionName, - @Nonnull Collection keys) { + public Mono removeBatchAsync( + @Nonnull String collectionName, @Nonnull Collection keys) { return Mono.fromRunnable( - () -> { - // ScanResult results = this.client.scan(collectionName); - // results.getResult().forEach(key -> this.client.hdel(key)); - keys.forEach(key -> this.client.hdel(String.format("%s:%s", collectionName, key))); - }); + () -> { + // ScanResult results = this.client.scan(collectionName); + // results.getResult().forEach(key -> this.client.hdel(key)); + keys.forEach( + key -> this.client.hdel(String.format("%s:%s", collectionName, key))); + }); } /** * Create a new search index. * * @param collectionName Index name - * @param embeddingSize Size of the embedding vector + * @param embeddingSize Size of the embedding vector * @return A Mono that completes when the index is created */ - private Mono createIndexAsync( - @Nonnull String collectionName, int embeddingSize) { + private Mono createIndexAsync(@Nonnull String collectionName, int embeddingSize) { if (embeddingSize < 1) { throw new RedisException( - RedisException.ErrorCodes.INVALID_EMBEDDING_SIZE, "the value must be greater than zero"); + RedisException.ErrorCodes.INVALID_EMBEDDING_SIZE, + "the value must be greater than zero"); } - Map attributes = Map.ofEntries( - new AbstractMap.SimpleEntry(RedisIndexSchemaParams.TYPE, vectorType), - new AbstractMap.SimpleEntry(RedisIndexSchemaParams.DIM, embeddingSize), - new AbstractMap.SimpleEntry(RedisIndexSchemaParams.DIST, vectorDistanceMetric)); + Map attributes = new HashMap<>(); - Schema schema = new Schema() - .addVectorField("Embedding", Schema.VectorField.VectorAlgo.FLAT, attributes).as("Embedding") - .addTextField("Id", 1.0).as("Id") - .addTextField("Text", 1.0).as("Text") - .addTextField("Description", 1.0).as("Description") - .addTextField("AdditionalMetadata", 1.0).as("AdditionalMetadata") - .addTextField("ExternalSourceName", 1.0).as("ExternalSourceName"); + attributes.put(RedisIndexSchemaParams.TYPE, vectorType); + attributes.put(RedisIndexSchemaParams.DIM, embeddingSize); + attributes.put(RedisIndexSchemaParams.DIST, vectorDistanceMetric); - IndexDefinition rule = new IndexDefinition(IndexDefinition.Type.HASH) - .setPrefixes(collectionName.toLowerCase() + ":"); - // customarily redis indexes are named -idx; we're going to suffix them (-sk-idx) so we can find them + Schema schema = + new Schema() + .addVectorField("Embedding", Schema.VectorField.VectorAlgo.FLAT, attributes) + .as("Embedding") + .addTextField("Id", 1.0) + .as("Id") + .addTextField("Text", 1.0) + .as("Text") + .addTextField("Description", 1.0) + .as("Description") + .addTextField("AdditionalMetadata", 1.0) + .as("AdditionalMetadata") + .addTextField("ExternalSourceName", 1.0) + .as("ExternalSourceName"); + + IndexDefinition rule = + new IndexDefinition(IndexDefinition.Type.HASH) + .setPrefixes(collectionName.toLowerCase() + ":"); + // customarily redis indexes are named -idx; we're going to suffix them + // (-sk-idx) so we can find them String normalizedIndexName = createIndexName(collectionName); - String result = this.client.ftCreate(normalizedIndexName, - IndexOptions.defaultOptions().setDefinition(rule), schema); + String result = + this.client.ftCreate( + normalizedIndexName, + IndexOptions.defaultOptions().setDefinition(rule), + schema); if (result.equals(OK)) { return Mono.just(true); @@ -416,38 +464,46 @@ public class RedisMemoryStore implements MemoryStore { if (limit <= 0) { return Mono.just(Collections.emptyList()); } - Query query = new Query("*=>[KNN $k @Embedding $vec AS vector_score]") - .returnFields("Id", "Text", "Description", "vector_score") - .setSortBy("vector_score", true) - .addParam("k", limit) - .addParam("vec", embeddingToBytes(embedding.getVector())) - .limit(0, limit) - .dialect(queryDialect); + Query query = + new Query("*=>[KNN $k @Embedding $vec AS vector_score]") + .returnFields("Id", "Text", "Description", "vector_score") + .setSortBy("vector_score", true) + .addParam("k", limit) + .addParam("vec", embeddingToBytes(embedding.getVector())) + .limit(0, limit) + .dialect(queryDialect); String indexName = createIndexName(collectionName); SearchResult results = this.client.ftSearch(indexName, query); // TODO convert to Collection> Collection> searchTuples = - results.getDocuments().stream() - .map(document -> { - MemoryRecord memoryRecord = documentToMemoryRecord(document, withEmbedding); - return Tuples.of(memoryRecord, document.getScore().floatValue()); - }) - .collect(Collectors.toList()); + results.getDocuments().stream() + .map( + document -> { + MemoryRecord memoryRecord = + documentToMemoryRecord(document, withEmbedding); + return Tuples.of( + memoryRecord, document.getScore().floatValue()); + }) + .collect(Collectors.toList()); return Mono.just(searchTuples); } @Override - public Mono> getNearestMatchAsync(@Nonnull String collectionName, - @Nonnull Embedding embedding, float minRelevanceScore, boolean withEmbedding) { - return getNearestMatchesAsync(collectionName, embedding, 1, minRelevanceScore, withEmbedding) - .flatMap( - nearestMatches -> { - if (nearestMatches.isEmpty()) { - return Mono.empty(); - } - return Mono.just(nearestMatches.iterator().next()); - }); + public Mono> getNearestMatchAsync( + @Nonnull String collectionName, + @Nonnull Embedding embedding, + float minRelevanceScore, + boolean withEmbedding) { + return getNearestMatchesAsync( + collectionName, embedding, 1, minRelevanceScore, withEmbedding) + .flatMap( + nearestMatches -> { + if (nearestMatches.isEmpty()) { + return Mono.empty(); + } + return Mono.just(nearestMatches.iterator().next()); + }); } /** @@ -488,22 +544,30 @@ public class RedisMemoryStore implements MemoryStore { if (collectionName.length() > 128) { throw new IllegalArgumentException("The indexName name cannot exceed 128 chars"); } - return String.format("%s-%s-%s", normalizeCollectionName(collectionName), RedisMemoryStore.SUFFIX, INDEX); + return String.format( + "%s-%s-%s", + normalizeCollectionName(collectionName), RedisMemoryStore.SUFFIX, INDEX); } protected Map getCollection(@Nonnull String collectionName) { Objects.requireNonNull(collectionName); ScanResult results = this.client.scan(collectionName); - if (results == null) throw new MemoryException( - ErrorCodes.ATTEMPTED_TO_ACCESS_NONEXISTENT_COLLECTION, - collectionName); + if (results == null) + throw new MemoryException( + ErrorCodes.ATTEMPTED_TO_ACCESS_NONEXISTENT_COLLECTION, collectionName); - return Collections.unmodifiableMap((Map) results.getResult().stream() - .map( - key -> RedisMemoryRecord.mapToRecord( - this.client.hgetAll(String.format("%s:%s", collectionName, key)), false) - )); + return Collections.unmodifiableMap( + (Map) + results.getResult().stream() + .map( + key -> + RedisMemoryRecord.mapToRecord( + this.client.hgetAll( + String.format( + "%s:%s", + collectionName, key)), + false))); } public static class Builder implements MemoryStore.Builder { @@ -517,14 +581,17 @@ public class RedisMemoryStore implements MemoryStore { this.connectionString = connectionString; return this; } + public Builder vectorSize(int vectorSize) { this.vectorSize = vectorSize; return this; } + public Builder vectorIndexAlgorithm(VectorAlgorithm vectorIndexAlgorithm) { this.vectorIndexAlgorithm = vectorIndexAlgorithm; return this; } + public Builder vectorDistanceMetric(String vectorDistanceMetric) { this.vectorDistanceMetric = vectorDistanceMetric; return this; @@ -545,28 +612,26 @@ public class RedisMemoryStore implements MemoryStore { // make sure everything we need has been set return new RedisMemoryStore( - connectionString, - vectorSize, - vectorIndexAlgorithm, - vectorDistanceMetric, - queryDialect - ); + connectionString, + vectorSize, + vectorIndexAlgorithm, + vectorDistanceMetric, + queryDialect); } /** - * Create a RedisMemoryStore object using default settings; requires a valid connection string. + * Create a RedisMemoryStore object using default settings; requires a valid connection + * string. * * @return A RedisMemoryStore object configured with default values */ public RedisMemoryStore buildDefault() { return new RedisMemoryStore( - connectionString, - DefaultVectorSize, - RedisMemoryStore.DefaultIndexAlgorithm, - RedisMemoryStore.DefaultDistanceMetric, - RedisMemoryStore.DefaultQueryDialect - ); + connectionString, + DefaultVectorSize, + RedisMemoryStore.DefaultIndexAlgorithm, + RedisMemoryStore.DefaultDistanceMetric, + RedisMemoryStore.DefaultQueryDialect); } } } - diff --git a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisVectorDistanceMetric.java b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisVectorDistanceMetric.java index f7563b793c..06d1764319 100644 --- a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisVectorDistanceMetric.java +++ b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisVectorDistanceMetric.java @@ -1,9 +1,10 @@ +// Copyright (c) Microsoft. All rights reserved. package com.microsoft.semantickernel.connectors.memory.redis; /* - Supported distance metrics are {L2, IP, COSINE}. The default value is "COSINE". - - */ + Supported distance metrics are {L2, IP, COSINE}. The default value is "COSINE". + + */ public class RedisVectorDistanceMetric { /* Euclidean distance between two vectors */ diff --git a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisVectorType.java b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisVectorType.java index 5db1f3fbf6..9201468169 100644 --- a/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisVectorType.java +++ b/java/connectors/semantickernel-connectors-memory-redis/src/main/java/com/microsoft/semantickernel/connectors/memory/redis/RedisVectorType.java @@ -1,6 +1,7 @@ +// Copyright (c) Microsoft. All rights reserved. package com.microsoft.semantickernel.connectors.memory.redis; public class RedisVectorType { - public static final String FLOAT32 = "FLOAT32"; - public static final String FLOAT64 = "FLOAT64"; + public static final String FLOAT32 = "FLOAT32"; + public static final String FLOAT64 = "FLOAT64"; } diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example06_TemplateLanguage.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example06_TemplateLanguage.java index a37e900961..6f2ea76b3d 100644 --- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example06_TemplateLanguage.java +++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example06_TemplateLanguage.java @@ -9,6 +9,7 @@ import com.microsoft.semantickernel.coreskills.TimeSkill; import com.microsoft.semantickernel.exceptions.ConfigurationException; import com.microsoft.semantickernel.orchestration.SKContext; import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; +import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings; /** * Show how to invoke a Native Function written in Java @@ -26,11 +27,11 @@ public class Example06_TemplateLanguage { OpenAIAsyncClient client = SamplesConfig.getClient(); Kernel kernel = SKBuilders.kernel() - .withDefaultAIService(SKBuilders.textCompletion() - .withModelId("davinci-002") - .withOpenAIClient(client) - .build()) - .build(); + .withDefaultAIService(SKBuilders.textCompletion() + .withModelId("davinci-002") + .withOpenAIClient(client) + .build()) + .build(); // Load native skill into the kernel skill collection, sharing its functions // with prompt templates @@ -70,11 +71,11 @@ public class Example06_TemplateLanguage { .withPromptTemplate(functionDefinition) .withRequestSettings( SKBuilders.completionRequestSettings() + .maxTokens(256) .temperature(0) .topP(0) - .maxTokens(256) - .frequencyPenalty(0) .presencePenalty(0) + .frequencyPenalty(0) .build()) .build(); diff --git a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/AiServiceRegistryTest.java b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/AiServiceRegistryTest.java index 5f3e002911..c645228ac5 100644 --- a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/AiServiceRegistryTest.java +++ b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/AiServiceRegistryTest.java @@ -37,7 +37,7 @@ public class AiServiceRegistryTest { Assertions.assertSame(kernel.getService("a-service", TextCompletion.class), service); CompletionSKFunction function = - kernel.importSkillFromDirectory("FunSkill", "../../samples/skills") + kernel.importSkillFromDirectory("FunPlugin", "../../samples/plugins") .getFunction("joke", CompletionSKFunction.class); function.invokeAsync("time travel to dinosaur age").block(); diff --git a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/DefaultKernelTest.java b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/DefaultKernelTest.java index b14d5c54e6..73ca7fe3d9 100644 --- a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/DefaultKernelTest.java +++ b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/DefaultKernelTest.java @@ -95,7 +95,7 @@ public class DefaultKernelTest { Kernel kernel = buildKernel(model, client); CompletionSKFunction function = - kernel.importSkillFromDirectory("FunSkill", "../../samples/skills") + kernel.importSkillFromDirectory("FunPlugin", "../../samples/plugins") .getFunction("joke", CompletionSKFunction.class); Mono mono = function.invokeAsync("time travel to dinosaur age"); diff --git a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example04CombineLLMPromptsAndNativeCodeTest.java b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example04CombineLLMPromptsAndNativeCodeTest.java index f54ed7f884..c96a6ff336 100644 --- a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example04CombineLLMPromptsAndNativeCodeTest.java +++ b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example04CombineLLMPromptsAndNativeCodeTest.java @@ -40,7 +40,8 @@ public class Example04CombineLLMPromptsAndNativeCodeTest { .build(); kernel.importSkill(new SearchEngineSkill(), null); - kernel.importSkillFromDirectory("SummarizeSkill", "../../samples/skills", "SummarizeSkill"); + kernel.importSkillFromDirectory( + "SummarizeSkill", "../../samples/plugins", "SummarizePlugin"); // Run String ask = "What's the tallest building in South America?"; diff --git a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example05UsingThePlannerTest.java b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example05UsingThePlannerTest.java index b3e5d29714..2acd9efc09 100644 --- a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example05UsingThePlannerTest.java +++ b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example05UsingThePlannerTest.java @@ -14,8 +14,9 @@ import reactor.util.function.Tuples; public class Example05UsingThePlannerTest { public static SequentialPlanner getPlanner(Kernel kernel) { - kernel.importSkillFromDirectory("SummarizeSkill", "../../samples/skills", "SummarizeSkill"); - kernel.importSkillFromDirectory("WriterSkill", "../../samples/skills", "WriterSkill"); + kernel.importSkillFromDirectory( + "SummarizeSkill", "../../samples/plugins", "SummarizePlugin"); + kernel.importSkillFromDirectory("WriterSkill", "../../samples/plugins", "WriterPlugin"); return new SequentialPlanner(kernel, null, null); } diff --git a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example12SequentialPlannerTest.java b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example12SequentialPlannerTest.java index e904a97730..30911a5814 100644 --- a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example12SequentialPlannerTest.java +++ b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example12SequentialPlannerTest.java @@ -84,8 +84,9 @@ public class Example12SequentialPlannerTest { .build()) .build(); - kernel.importSkillFromDirectory("SummarizeSkill", "../../samples/skills", "SummarizeSkill"); - kernel.importSkillFromDirectory("WriterSkill", "../../samples/skills", "WriterSkill"); + kernel.importSkillFromDirectory( + "SummarizeSkill", "../../samples/plugins", "SummarizePlugin"); + kernel.importSkillFromDirectory("WriterSkill", "../../samples/plugins", "WriterPlugin"); kernel.importSkill(new TextSkill(), "TextSkill"); return kernel; } diff --git a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example28ActionPlannerTest.java b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example28ActionPlannerTest.java index d56b9f1129..dcf717b7b2 100644 --- a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example28ActionPlannerTest.java +++ b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/syntaxexamples/Example28ActionPlannerTest.java @@ -128,8 +128,9 @@ public class Example28ActionPlannerTest { .build()) .build(); - kernel.importSkillFromDirectory("SummarizeSkill", "../../samples/skills", "SummarizeSkill"); - kernel.importSkillFromDirectory("WriterSkill", "../../samples/skills", "WriterSkill"); + kernel.importSkillFromDirectory( + "SummarizeSkill", "../../samples/plugins", "SummarizePlugin"); + kernel.importSkillFromDirectory("WriterSkill", "../../samples/plugins", "WriterPlugin"); // Create an instance of ActionPlanner. // The ActionPlanner takes one goal and returns a single function to execute.