Skip to content

Commit e75d16a

Browse files
committed
feat: modularize Redis components
Signed-off-by: Brian Sam-Bodden <[email protected]>
1 parent 50ea565 commit e75d16a

File tree

48 files changed

+7997
-789
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+7997
-789
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.ai</groupId>
7+
<artifactId>spring-ai-parent</artifactId>
8+
<version>1.0.0-SNAPSHOT</version>
9+
<relativePath>../../../../../pom.xml</relativePath>
10+
</parent>
11+
<artifactId>spring-ai-autoconfigure-model-chat-memory-redis</artifactId>
12+
<packaging>jar</packaging>
13+
<name>Spring AI Redis Chat Memory Auto Configuration</name>
14+
<description>Spring AI Redis Chat Memory Auto Configuration</description>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>org.springframework.boot</groupId>
19+
<artifactId>spring-boot-autoconfigure</artifactId>
20+
</dependency>
21+
22+
<dependency>
23+
<groupId>org.springframework.ai</groupId>
24+
<artifactId>spring-ai-model-chat-memory-redis</artifactId>
25+
<version>${project.version}</version>
26+
</dependency>
27+
28+
<dependency>
29+
<groupId>redis.clients</groupId>
30+
<artifactId>jedis</artifactId>
31+
</dependency>
32+
33+
<!-- Optional dependencies -->
34+
<dependency>
35+
<groupId>org.springframework.boot</groupId>
36+
<artifactId>spring-boot-configuration-processor</artifactId>
37+
<optional>true</optional>
38+
</dependency>
39+
40+
<!-- Test dependencies -->
41+
<dependency>
42+
<groupId>org.springframework.boot</groupId>
43+
<artifactId>spring-boot-starter-test</artifactId>
44+
<scope>test</scope>
45+
</dependency>
46+
47+
<dependency>
48+
<groupId>org.springframework.boot</groupId>
49+
<artifactId>spring-boot-starter-data-redis</artifactId>
50+
<scope>test</scope>
51+
</dependency>
52+
53+
<dependency>
54+
<groupId>org.springframework.boot</groupId>
55+
<artifactId>spring-boot-testcontainers</artifactId>
56+
<scope>test</scope>
57+
</dependency>
58+
59+
<dependency>
60+
<groupId>org.testcontainers</groupId>
61+
<artifactId>junit-jupiter</artifactId>
62+
<scope>test</scope>
63+
</dependency>
64+
65+
<dependency>
66+
<groupId>com.redis</groupId>
67+
<artifactId>testcontainers-redis</artifactId>
68+
<version>2.2.0</version>
69+
<scope>test</scope>
70+
</dependency>
71+
</dependencies>
72+
73+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2023-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.ai.model.chat.memory.redis.autoconfigure;
17+
18+
import org.springframework.ai.chat.memory.ChatMemory;
19+
import org.springframework.ai.chat.memory.ChatMemoryRepository;
20+
import org.springframework.ai.chat.memory.redis.RedisChatMemory;
21+
import org.springframework.boot.autoconfigure.AutoConfiguration;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
24+
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
25+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
26+
import org.springframework.context.annotation.Bean;
27+
import org.springframework.util.StringUtils;
28+
29+
import redis.clients.jedis.JedisPooled;
30+
31+
/**
32+
* Auto-configuration for Redis-based chat memory implementation.
33+
*
34+
* @author Brian Sam-Bodden
35+
*/
36+
@AutoConfiguration(after = RedisAutoConfiguration.class)
37+
@ConditionalOnClass({ RedisChatMemory.class, JedisPooled.class })
38+
@EnableConfigurationProperties(RedisChatMemoryProperties.class)
39+
public class RedisChatMemoryAutoConfiguration {
40+
41+
@Bean
42+
@ConditionalOnMissingBean
43+
public JedisPooled jedisClient(RedisChatMemoryProperties properties) {
44+
return new JedisPooled(properties.getHost(), properties.getPort());
45+
}
46+
47+
@Bean
48+
@ConditionalOnMissingBean({ RedisChatMemory.class, ChatMemory.class, ChatMemoryRepository.class })
49+
public RedisChatMemory redisChatMemory(JedisPooled jedisClient, RedisChatMemoryProperties properties) {
50+
RedisChatMemory.Builder builder = RedisChatMemory.builder().jedisClient(jedisClient);
51+
52+
// Apply configuration if provided
53+
if (StringUtils.hasText(properties.getIndexName())) {
54+
builder.indexName(properties.getIndexName());
55+
}
56+
57+
if (StringUtils.hasText(properties.getKeyPrefix())) {
58+
builder.keyPrefix(properties.getKeyPrefix());
59+
}
60+
61+
if (properties.getTimeToLive() != null && properties.getTimeToLive().toSeconds() > 0) {
62+
builder.timeToLive(properties.getTimeToLive());
63+
}
64+
65+
if (properties.getInitializeSchema() != null) {
66+
builder.initializeSchema(properties.getInitializeSchema());
67+
}
68+
69+
if (properties.getMaxConversationIds() != null) {
70+
builder.maxConversationIds(properties.getMaxConversationIds());
71+
}
72+
73+
if (properties.getMaxMessagesPerConversation() != null) {
74+
builder.maxMessagesPerConversation(properties.getMaxMessagesPerConversation());
75+
}
76+
77+
if (properties.getMetadataFields() != null && !properties.getMetadataFields().isEmpty()) {
78+
builder.metadataFields(properties.getMetadataFields());
79+
}
80+
81+
return builder.build();
82+
}
83+
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Copyright 2023-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.ai.model.chat.memory.redis.autoconfigure;
17+
18+
import java.time.Duration;
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
import org.springframework.boot.context.properties.ConfigurationProperties;
23+
import org.springframework.ai.chat.memory.redis.RedisChatMemoryConfig;
24+
25+
/**
26+
* Configuration properties for Redis-based chat memory.
27+
*
28+
* @author Brian Sam-Bodden
29+
*/
30+
@ConfigurationProperties(prefix = "spring.ai.chat.memory.redis")
31+
public class RedisChatMemoryProperties {
32+
33+
/**
34+
* Redis server host.
35+
*/
36+
private String host = "localhost";
37+
38+
/**
39+
* Redis server port.
40+
*/
41+
private int port = 6379;
42+
43+
/**
44+
* Name of the Redis search index.
45+
*/
46+
private String indexName = RedisChatMemoryConfig.DEFAULT_INDEX_NAME;
47+
48+
/**
49+
* Key prefix for Redis chat memory entries.
50+
*/
51+
private String keyPrefix = RedisChatMemoryConfig.DEFAULT_KEY_PREFIX;
52+
53+
/**
54+
* Time to live for chat memory entries. Default is no expiration.
55+
*/
56+
private Duration timeToLive;
57+
58+
/**
59+
* Whether to initialize the Redis schema. Default is true.
60+
*/
61+
private Boolean initializeSchema = true;
62+
63+
/**
64+
* Maximum number of conversation IDs to return (defaults to 1000).
65+
*/
66+
private Integer maxConversationIds = RedisChatMemoryConfig.DEFAULT_MAX_RESULTS;
67+
68+
/**
69+
* Maximum number of messages to return per conversation (defaults to 1000).
70+
*/
71+
private Integer maxMessagesPerConversation = RedisChatMemoryConfig.DEFAULT_MAX_RESULTS;
72+
73+
/**
74+
* Metadata field definitions for proper indexing. Compatible with RedisVL schema
75+
* format. Example: <pre>
76+
* spring.ai.chat.memory.redis.metadata-fields[0].name=priority
77+
* spring.ai.chat.memory.redis.metadata-fields[0].type=tag
78+
* spring.ai.chat.memory.redis.metadata-fields[1].name=score
79+
* spring.ai.chat.memory.redis.metadata-fields[1].type=numeric
80+
* </pre>
81+
*/
82+
private List<Map<String, String>> metadataFields;
83+
84+
public String getHost() {
85+
return host;
86+
}
87+
88+
public void setHost(String host) {
89+
this.host = host;
90+
}
91+
92+
public int getPort() {
93+
return port;
94+
}
95+
96+
public void setPort(int port) {
97+
this.port = port;
98+
}
99+
100+
public String getIndexName() {
101+
return indexName;
102+
}
103+
104+
public void setIndexName(String indexName) {
105+
this.indexName = indexName;
106+
}
107+
108+
public String getKeyPrefix() {
109+
return keyPrefix;
110+
}
111+
112+
public void setKeyPrefix(String keyPrefix) {
113+
this.keyPrefix = keyPrefix;
114+
}
115+
116+
public Duration getTimeToLive() {
117+
return timeToLive;
118+
}
119+
120+
public void setTimeToLive(Duration timeToLive) {
121+
this.timeToLive = timeToLive;
122+
}
123+
124+
public Boolean getInitializeSchema() {
125+
return initializeSchema;
126+
}
127+
128+
public void setInitializeSchema(Boolean initializeSchema) {
129+
this.initializeSchema = initializeSchema;
130+
}
131+
132+
public Integer getMaxConversationIds() {
133+
return maxConversationIds;
134+
}
135+
136+
public void setMaxConversationIds(Integer maxConversationIds) {
137+
this.maxConversationIds = maxConversationIds;
138+
}
139+
140+
public Integer getMaxMessagesPerConversation() {
141+
return maxMessagesPerConversation;
142+
}
143+
144+
public void setMaxMessagesPerConversation(Integer maxMessagesPerConversation) {
145+
this.maxMessagesPerConversation = maxMessagesPerConversation;
146+
}
147+
148+
public List<Map<String, String>> getMetadataFields() {
149+
return metadataFields;
150+
}
151+
152+
public void setMetadataFields(List<Map<String, String>> metadataFields) {
153+
this.metadataFields = metadataFields;
154+
}
155+
156+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.springframework.ai.model.chat.memory.redis.autoconfigure.RedisChatMemoryAutoConfiguration

0 commit comments

Comments
 (0)