Files
life-echo/api/services/redis_service.py
penghanyuan dbbb924625 feat: 添加Redis支持和Celery任务处理
- 新增Redis服务模块用于会话状态存储和缓存
- 集成Celery用于后台任务处理
- 更新Docker Compose配置以支持开发环境
- 优化API以支持异步调用和Redis会话存储
- 更新文档以反映新的开发环境配置和使用方法
2026-01-21 23:06:47 +01:00

194 lines
5.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Redis 服务模块:用于会话状态存储和缓存
"""
import os
import json
import logging
from typing import Optional, List, Dict, Any
import redis.asyncio as aioredis
logger = logging.getLogger(__name__)
class RedisService:
"""Redis 服务,用于存储对话历史和状态"""
def __init__(self):
"""初始化 Redis 连接"""
self.redis_url = os.getenv("REDIS_URL", "redis://localhost:6379/0")
self._client: Optional[aioredis.Redis] = None
# 会话过期时间(默认 24 小时)
self.session_ttl = int(os.getenv("REDIS_SESSION_TTL", "86400"))
async def get_client(self) -> aioredis.Redis:
"""获取 Redis 客户端(延迟初始化)"""
if self._client is None:
try:
self._client = await aioredis.from_url(
self.redis_url,
encoding="utf-8",
decode_responses=True
)
# 测试连接
await self._client.ping()
logger.info(f"Redis 连接成功: {self.redis_url}")
except Exception as e:
logger.error(f"Redis 连接失败: {e}")
raise
return self._client
async def close(self):
"""关闭 Redis 连接"""
if self._client:
await self._client.close()
self._client = None
# ==================== 对话历史管理 ====================
def _conversation_key(self, conversation_id: str) -> str:
"""生成对话历史的 Redis key"""
return f"conversation:history:{conversation_id}"
async def get_conversation_history(self, conversation_id: str) -> List[Dict[str, Any]]:
"""
获取对话历史
Args:
conversation_id: 对话 ID
Returns:
消息列表 [{"role": "human/ai", "content": "..."}]
"""
try:
client = await self.get_client()
key = self._conversation_key(conversation_id)
data = await client.get(key)
if data:
return json.loads(data)
return []
except Exception as e:
logger.error(f"获取对话历史失败: {e}")
return []
async def add_message(
self,
conversation_id: str,
role: str,
content: str
) -> bool:
"""
添加消息到对话历史
Args:
conversation_id: 对话 ID
role: 角色 ("human""ai")
content: 消息内容
Returns:
是否成功
"""
try:
client = await self.get_client()
key = self._conversation_key(conversation_id)
# 获取现有历史
history = await self.get_conversation_history(conversation_id)
# 添加新消息
history.append({"role": role, "content": content})
# 保存回 Redis带过期时间
await client.setex(key, self.session_ttl, json.dumps(history, ensure_ascii=False))
return True
except Exception as e:
logger.error(f"添加消息失败: {e}")
return False
async def clear_conversation_history(self, conversation_id: str) -> bool:
"""
清除对话历史
Args:
conversation_id: 对话 ID
Returns:
是否成功
"""
try:
client = await self.get_client()
key = self._conversation_key(conversation_id)
await client.delete(key)
return True
except Exception as e:
logger.error(f"清除对话历史失败: {e}")
return False
async def extend_session_ttl(self, conversation_id: str) -> bool:
"""
延长会话过期时间
Args:
conversation_id: 对话 ID
Returns:
是否成功
"""
try:
client = await self.get_client()
key = self._conversation_key(conversation_id)
await client.expire(key, self.session_ttl)
return True
except Exception as e:
logger.error(f"延长会话TTL失败: {e}")
return False
# ==================== 通用缓存方法 ====================
async def set_cache(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
"""设置缓存"""
try:
client = await self.get_client()
data = json.dumps(value, ensure_ascii=False) if not isinstance(value, str) else value
if ttl:
await client.setex(key, ttl, data)
else:
await client.set(key, data)
return True
except Exception as e:
logger.error(f"设置缓存失败: {e}")
return False
async def get_cache(self, key: str) -> Optional[Any]:
"""获取缓存"""
try:
client = await self.get_client()
data = await client.get(key)
if data:
try:
return json.loads(data)
except json.JSONDecodeError:
return data
return None
except Exception as e:
logger.error(f"获取缓存失败: {e}")
return None
async def delete_cache(self, key: str) -> bool:
"""删除缓存"""
try:
client = await self.get_client()
await client.delete(key)
return True
except Exception as e:
logger.error(f"删除缓存失败: {e}")
return False
def is_available(self) -> bool:
"""检查 Redis 是否可用"""
return self._client is not None
# 创建全局实例
redis_service = RedisService()