diff --git a/.sdkmanrc b/.sdkmanrc
index 4e7acfe..95502c0 100644
--- a/.sdkmanrc
+++ b/.sdkmanrc
@@ -3,4 +3,4 @@
# See https://sdkman.io/usage#config
# A summary is to add the following to ~/.sdkman/etc/config
# sdkman_auto_env=true
-java=17.0.11-tem
+java=17.0.11-tem
\ No newline at end of file
diff --git a/langchain4j-qianfan-spring-boot-starter/pom.xml b/langchain4j-qianfan-spring-boot-starter/pom.xml
index 4e58a54..b59d121 100644
--- a/langchain4j-qianfan-spring-boot-starter/pom.xml
+++ b/langchain4j-qianfan-spring-boot-starter/pom.xml
@@ -6,7 +6,7 @@
dev.langchain4j
langchain4j-spring
- 0.30.0
+ 0.32.0-SNAPSHOT
../pom.xml
diff --git a/langchain4j-redis-spring-boot-starter/pom.xml b/langchain4j-redis-spring-boot-starter/pom.xml
new file mode 100644
index 0000000..7227a0e
--- /dev/null
+++ b/langchain4j-redis-spring-boot-starter/pom.xml
@@ -0,0 +1,91 @@
+
+
+ 4.0.0
+
+ dev.langchain4j
+ langchain4j-spring
+ 0.32.0-SNAPSHOT
+ ../pom.xml
+
+
+ langchain4j-redis-spring-boot-starter
+ LangChain4j Spring Boot starter for Redis
+ jar
+
+
+
+
+ dev.langchain4j
+ langchain4j-redis
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure-processor
+ true
+
+
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ dev.langchain4j
+ langchain4j-embeddings-all-minilm-l6-v2-q
+ test
+
+
+
+ dev.langchain4j
+ langchain4j-spring-boot-tests
+ ${project.version}
+ tests
+ test-jar
+ test
+
+
+
+ com.redis.testcontainers
+ testcontainers-redis
+ 1.6.4
+ test
+
+
+
+ org.tinylog
+ tinylog-impl
+ test
+
+
+
+ org.tinylog
+ slf4j-tinylog
+ test
+
+
+
+
+
\ No newline at end of file
diff --git a/langchain4j-redis-spring-boot-starter/src/main/java/dev/langchain4j/store/embedding/redis/spring/RedisEmbeddingStoreAutoConfiguration.java b/langchain4j-redis-spring-boot-starter/src/main/java/dev/langchain4j/store/embedding/redis/spring/RedisEmbeddingStoreAutoConfiguration.java
new file mode 100644
index 0000000..bff93ac
--- /dev/null
+++ b/langchain4j-redis-spring-boot-starter/src/main/java/dev/langchain4j/store/embedding/redis/spring/RedisEmbeddingStoreAutoConfiguration.java
@@ -0,0 +1,47 @@
+package dev.langchain4j.store.embedding.redis.spring;
+
+import dev.langchain4j.model.embedding.EmbeddingModel;
+import dev.langchain4j.store.embedding.redis.RedisEmbeddingStore;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.lang.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static dev.langchain4j.store.embedding.redis.spring.RedisEmbeddingStoreProperties.PREFIX;
+
+@AutoConfiguration
+@EnableConfigurationProperties(RedisEmbeddingStoreProperties.class)
+@ConditionalOnProperty(prefix = PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
+public class RedisEmbeddingStoreAutoConfiguration {
+
+ private static final String DEFAULT_HOST = "localhost";
+ private static final int DEFAULT_PORT = 6379;
+ private static final String DEFAULT_INDEX_NAME = "langchain4j-index";
+
+ @Bean
+ @ConditionalOnMissingBean
+ public RedisEmbeddingStore redisEmbeddingStore(RedisEmbeddingStoreProperties properties,
+ @Nullable EmbeddingModel embeddingModel) {
+ String host = Optional.ofNullable(properties.getHost()).orElse(DEFAULT_HOST);
+ int port = Optional.ofNullable(properties.getPort()).orElse(DEFAULT_PORT);
+ String indexName = Optional.ofNullable(properties.getIndexName()).orElse(DEFAULT_INDEX_NAME);
+ Integer dimension = Optional.ofNullable(properties.getDimension()).orElseGet(() -> embeddingModel == null ? null : embeddingModel.dimension());
+ List metadataKeys = Optional.ofNullable(properties.getMetadataKeys()).orElse(new ArrayList<>());
+
+ return RedisEmbeddingStore.builder()
+ .host(host)
+ .port(port)
+ .user(properties.getUser())
+ .password(properties.getPassword())
+ .indexName(indexName)
+ .dimension(dimension)
+ .metadataKeys(metadataKeys)
+ .build();
+ }
+}
diff --git a/langchain4j-redis-spring-boot-starter/src/main/java/dev/langchain4j/store/embedding/redis/spring/RedisEmbeddingStoreProperties.java b/langchain4j-redis-spring-boot-starter/src/main/java/dev/langchain4j/store/embedding/redis/spring/RedisEmbeddingStoreProperties.java
new file mode 100644
index 0000000..daf0796
--- /dev/null
+++ b/langchain4j-redis-spring-boot-starter/src/main/java/dev/langchain4j/store/embedding/redis/spring/RedisEmbeddingStoreProperties.java
@@ -0,0 +1,24 @@
+package dev.langchain4j.store.embedding.redis.spring;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@ConfigurationProperties(prefix = RedisEmbeddingStoreProperties.PREFIX)
+@Getter
+@Setter
+public class RedisEmbeddingStoreProperties {
+
+ static final String PREFIX = "langchain4j.redis";
+
+ private String host;
+ private Integer port;
+ private String user;
+ private String password;
+ private String indexName;
+ private Integer dimension;
+ private List metadataKeys;
+}
diff --git a/langchain4j-redis-spring-boot-starter/src/main/resources/META-INF/spring.factories b/langchain4j-redis-spring-boot-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..c03ec78
--- /dev/null
+++ b/langchain4j-redis-spring-boot-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=dev.langchain4j.store.embedding.redis.spring.RedisEmbeddingStoreAutoConfiguration
\ No newline at end of file
diff --git a/langchain4j-redis-spring-boot-starter/src/test/java/dev/langchain4j/store/embedding/redis/spring/RedisEmbeddingStoreAutoConfigurationIT.java b/langchain4j-redis-spring-boot-starter/src/test/java/dev/langchain4j/store/embedding/redis/spring/RedisEmbeddingStoreAutoConfigurationIT.java
new file mode 100644
index 0000000..aa05e4a
--- /dev/null
+++ b/langchain4j-redis-spring-boot-starter/src/test/java/dev/langchain4j/store/embedding/redis/spring/RedisEmbeddingStoreAutoConfigurationIT.java
@@ -0,0 +1,61 @@
+package dev.langchain4j.store.embedding.redis.spring;
+
+import com.redis.testcontainers.RedisContainer;
+import dev.langchain4j.data.segment.TextSegment;
+import dev.langchain4j.store.embedding.EmbeddingStore;
+import dev.langchain4j.store.embedding.redis.RedisEmbeddingStore;
+import dev.langchain4j.store.embedding.spring.EmbeddingStoreAutoConfigurationIT;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.testcontainers.containers.wait.strategy.Wait;
+import redis.clients.jedis.JedisPooled;
+
+import static com.redis.testcontainers.RedisStackContainer.DEFAULT_IMAGE_NAME;
+import static com.redis.testcontainers.RedisStackContainer.DEFAULT_TAG;
+
+class RedisEmbeddingStoreAutoConfigurationIT extends EmbeddingStoreAutoConfigurationIT {
+
+ static RedisContainer redis = new RedisContainer(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG))
+ .waitingFor(Wait.defaultWaitStrategy());
+
+ @BeforeAll
+ static void beforeAll() {
+ redis.start();
+ }
+
+ @AfterAll
+ static void afterAll() {
+ redis.stop();
+ }
+
+ @BeforeEach
+ void beforeEach() {
+ try (JedisPooled jedis = new JedisPooled(redis.getHost(), redis.getFirstMappedPort())) {
+ jedis.flushDB(); // TODO fix: why redis returns embeddings from different indexes?
+ }
+ }
+
+ @Override
+ protected Class> autoConfigurationClass() {
+ return RedisEmbeddingStoreAutoConfiguration.class;
+ }
+
+ @Override
+ protected Class extends EmbeddingStore> embeddingStoreClass() {
+ return RedisEmbeddingStore.class;
+ }
+
+ @Override
+ protected String[] properties() {
+ return new String[]{
+ "langchain4j.redis.host=" + redis.getHost(),
+ "langchain4j.redis.port=" + redis.getFirstMappedPort()
+ };
+ }
+
+ @Override
+ protected String dimensionPropertyKey() {
+ return "langchain4j.redis.dimension";
+ }
+}
diff --git a/pom.xml b/pom.xml
index 3fac0e7..b5df5ed 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,6 +24,7 @@
langchain4j-azure-open-ai-spring-boot-starter
langchain4j-vertex-ai-gemini-spring-boot-starter
langchian4j-elasticsearch-spring-boot-starter
+ langchain4j-redis-spring-boot-starter
langchain4j-qianfan-spring-boot-starter
@@ -31,6 +32,7 @@
17
17
UTF-8
+ 2.6.2
3.2.6
1.19.8
2.6.2