Files
Enterprise-Knowledge-Base/internal/application/service/llmcontext/redis_storage.go
T
wizardchen 266b9a5943 feat: Enhance chat and knowledge base functionalities with multi-KB support
- Updated agentChat API to accept optional knowledge_base_ids and agent_enabled parameters.
- Introduced getSession API to retrieve session details.
- Modified useStream to validate knowledge_base_ids for agent-chat requests and prepare POST body accordingly.
- Enhanced createKnowledgeBase API to include additional configuration options.
- Refactored chat routing to remove knowledge base ID from the chat path, allowing for dynamic knowledge base selection.
- Improved session management by preventing duplicate session entries in the menu store.
- Updated UI components for better session handling and display.
- Added context management for agent conversations to improve state persistence across sessions.
2025-11-06 21:12:26 +08:00

113 lines
3.3 KiB
Go

package llmcontext
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/Tencent/WeKnora/internal/logger"
"github.com/Tencent/WeKnora/internal/models/chat"
"github.com/redis/go-redis/v9"
)
// redisStorage implements ContextStorage using Redis
type redisStorage struct {
client *redis.Client
ttl time.Duration
prefix string
}
// NewRedisStorage creates a new Redis-based storage
func NewRedisStorage(client *redis.Client, ttl time.Duration, prefix string) (ContextStorage, error) {
// Validate connection
_, err := client.Ping(context.Background()).Result()
if err != nil {
return nil, fmt.Errorf("failed to connect to Redis: %w", err)
}
if ttl == 0 {
ttl = 24 * time.Hour // Default TTL 24 hours
}
if prefix == "" {
prefix = "context:" // Default prefix
}
return &redisStorage{
client: client,
ttl: ttl,
prefix: prefix,
}, nil
}
// buildKey builds the Redis key for a session
func (rs *redisStorage) buildKey(sessionID string) string {
return fmt.Sprintf("%s%s", rs.prefix, sessionID)
}
// Save saves messages for a session to Redis
func (rs *redisStorage) Save(ctx context.Context, sessionID string, messages []chat.Message) error {
key := rs.buildKey(sessionID)
// Marshal messages to JSON
data, err := json.Marshal(messages)
if err != nil {
logger.Errorf(ctx, "[RedisStorage][Session-%s] Failed to marshal messages: %v", sessionID, err)
return fmt.Errorf("failed to marshal messages: %w", err)
}
// Save to Redis with TTL
err = rs.client.Set(ctx, key, data, rs.ttl).Err()
if err != nil {
logger.Errorf(ctx, "[RedisStorage][Session-%s] Failed to save to Redis: %v", sessionID, err)
return fmt.Errorf("failed to save to Redis: %w", err)
}
logger.Debugf(ctx, "[RedisStorage][Session-%s] Saved %d messages to Redis (TTL: %s)",
sessionID, len(messages), rs.ttl)
return nil
}
// Load loads messages for a session from Redis
func (rs *redisStorage) Load(ctx context.Context, sessionID string) ([]chat.Message, error) {
key := rs.buildKey(sessionID)
// Get from Redis
data, err := rs.client.Get(ctx, key).Bytes()
if err != nil {
if err == redis.Nil {
// No context exists yet, return empty slice
logger.Debugf(ctx, "[RedisStorage][Session-%s] No context found in Redis", sessionID)
return []chat.Message{}, nil
}
logger.Errorf(ctx, "[RedisStorage][Session-%s] Failed to get from Redis: %v", sessionID, err)
return nil, fmt.Errorf("failed to get from Redis: %w", err)
}
// Unmarshal messages
var messages []chat.Message
err = json.Unmarshal(data, &messages)
if err != nil {
logger.Errorf(ctx, "[RedisStorage][Session-%s] Failed to unmarshal messages: %v", sessionID, err)
return nil, fmt.Errorf("failed to unmarshal messages: %w", err)
}
logger.Debugf(ctx, "[RedisStorage][Session-%s] Loaded %d messages from Redis", sessionID, len(messages))
return messages, nil
}
// Delete deletes all messages for a session from Redis
func (rs *redisStorage) Delete(ctx context.Context, sessionID string) error {
key := rs.buildKey(sessionID)
err := rs.client.Del(ctx, key).Err()
if err != nil {
logger.Errorf(ctx, "[RedisStorage][Session-%s] Failed to delete from Redis: %v", sessionID, err)
return fmt.Errorf("failed to delete from Redis: %w", err)
}
logger.Debugf(ctx, "[RedisStorage][Session-%s] Deleted context from Redis", sessionID)
return nil
}