feature:加入功能,小朋友人脸识别与分类。
This commit is contained in:
305
db/kid_photo_redis.py
Normal file
305
db/kid_photo_redis.py
Normal file
@@ -0,0 +1,305 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from datetime import datetime
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
from typing import Dict, Optional, List, Any, Set
|
||||
|
||||
from db.connection import DBConnectionManager
|
||||
|
||||
|
||||
class KidPhotoRedisDB:
|
||||
"""小朋友照片提取功能Redis相关操作"""
|
||||
|
||||
def __init__(self, db_manager: DBConnectionManager):
|
||||
self.db_manager = db_manager
|
||||
self.prefix = "group:kid_photo:"
|
||||
self.logger = logging.getLogger("DB.KidPhotoRedis")
|
||||
|
||||
def get_redis_connection(self):
|
||||
"""获取Redis连接"""
|
||||
try:
|
||||
return self.db_manager.get_redis_connection()
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取Redis连接失败: {e}")
|
||||
return None
|
||||
|
||||
def save_last_analysis_time(self, group_id: str) -> bool:
|
||||
"""保存最后分析时间"""
|
||||
try:
|
||||
timestamp = int(datetime.now().timestamp())
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return False
|
||||
redis_client.set(f'{self.prefix}{group_id}:last_time', str(timestamp))
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"保存最后分析时间失败: {e}")
|
||||
return False
|
||||
|
||||
def get_last_analysis_time(self, group_id: str) -> Optional[int]:
|
||||
"""获取最后分析时间"""
|
||||
try:
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return None
|
||||
timestamp = redis_client.get(f'{self.prefix}{group_id}:last_time')
|
||||
if timestamp:
|
||||
if isinstance(timestamp, bytes):
|
||||
timestamp = timestamp.decode('utf-8')
|
||||
return int(timestamp)
|
||||
return None
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取最后分析时间失败: {e}")
|
||||
return None
|
||||
|
||||
def save_analysis_result(self, group_id: str, result: Dict) -> bool:
|
||||
"""保存分析结果"""
|
||||
try:
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return False
|
||||
redis_client.set(f'{self.prefix}{group_id}:results', json.dumps(result, ensure_ascii=False))
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"保存分析结果失败: {e}")
|
||||
return False
|
||||
|
||||
def get_last_analysis_result(self, group_id: str) -> Optional[Dict]:
|
||||
"""获取最后一次分析结果"""
|
||||
try:
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return None
|
||||
result = redis_client.get(f'{self.prefix}{group_id}:results')
|
||||
if result:
|
||||
if isinstance(result, bytes):
|
||||
result = result.decode('utf-8')
|
||||
return json.loads(result)
|
||||
return None
|
||||
except json.JSONDecodeError as e:
|
||||
self.logger.error(f"解析分析结果JSON失败: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取最后分析结果失败: {e}")
|
||||
return None
|
||||
|
||||
def save_processed_photo(self, group_id: str, photo_path: str) -> bool:
|
||||
"""保存已处理的照片路径"""
|
||||
try:
|
||||
if not photo_path:
|
||||
return False
|
||||
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return False
|
||||
redis_client.sadd(f'{self.prefix}{group_id}:processed_photos', photo_path)
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"保存已处理照片失败: {e}")
|
||||
return False
|
||||
|
||||
def save_processed_photos(self, group_id: str, photo_paths: List[str]) -> bool:
|
||||
"""批量保存已处理的照片路径"""
|
||||
try:
|
||||
if not photo_paths:
|
||||
return True
|
||||
|
||||
# 过滤空路径
|
||||
valid_paths = [path for path in photo_paths if path]
|
||||
if not valid_paths:
|
||||
return True
|
||||
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return False
|
||||
|
||||
# 使用管道批量操作提高性能
|
||||
pipeline = redis_client.pipeline()
|
||||
key = f'{self.prefix}{group_id}:processed_photos'
|
||||
|
||||
# 每次最多添加1000个元素,避免命令过长
|
||||
batch_size = 1000
|
||||
for i in range(0, len(valid_paths), batch_size):
|
||||
batch = valid_paths[i:i+batch_size]
|
||||
if batch:
|
||||
pipeline.sadd(key, *batch)
|
||||
|
||||
pipeline.execute()
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"批量保存已处理照片失败: {e}")
|
||||
return False
|
||||
|
||||
def get_processed_photos(self, group_id: str) -> Set[str]:
|
||||
"""获取所有已处理的照片路径"""
|
||||
photos = set()
|
||||
try:
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return photos
|
||||
|
||||
photo_paths = redis_client.smembers(f'{self.prefix}{group_id}:processed_photos')
|
||||
for path in photo_paths:
|
||||
if isinstance(path, bytes):
|
||||
path = path.decode('utf-8')
|
||||
photos.add(path)
|
||||
return photos
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取已处理照片失败: {e}")
|
||||
return set()
|
||||
|
||||
def is_photo_processed(self, group_id: str, photo_path: str) -> bool:
|
||||
"""检查照片是否已处理"""
|
||||
try:
|
||||
if not photo_path:
|
||||
return False
|
||||
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return False
|
||||
return redis_client.sismember(f'{self.prefix}{group_id}:processed_photos', photo_path)
|
||||
except Exception as e:
|
||||
self.logger.error(f"检查照片是否已处理失败: {e}")
|
||||
return False
|
||||
|
||||
def save_photo_mapping(self, group_id: str, kid_id: str, photo_path: str) -> bool:
|
||||
"""保存照片与小朋友的映射关系"""
|
||||
try:
|
||||
if not photo_path or not kid_id:
|
||||
return False
|
||||
|
||||
photo_name = os.path.basename(photo_path)
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return False
|
||||
|
||||
# 使用管道批量操作
|
||||
pipeline = redis_client.pipeline()
|
||||
# 保存小朋友的照片集合
|
||||
pipeline.sadd(f'{self.prefix}{group_id}:kid:{kid_id}:photos', photo_path)
|
||||
# 保存照片对应的小朋友ID
|
||||
pipeline.set(f'{self.prefix}{group_id}:photo:{photo_name}', kid_id)
|
||||
pipeline.execute()
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"保存照片映射关系失败: {e}")
|
||||
return False
|
||||
|
||||
def get_kid_photos(self, group_id: str, kid_id: str) -> List[str]:
|
||||
"""获取小朋友的所有照片"""
|
||||
photos = []
|
||||
try:
|
||||
if not kid_id:
|
||||
return photos
|
||||
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return photos
|
||||
|
||||
photo_paths = redis_client.smembers(f'{self.prefix}{group_id}:kid:{kid_id}:photos')
|
||||
for path in photo_paths:
|
||||
if isinstance(path, bytes):
|
||||
path = path.decode('utf-8')
|
||||
photos.append(path)
|
||||
return photos
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取小朋友照片失败: {e}")
|
||||
return []
|
||||
|
||||
def get_photo_kid(self, group_id: str, photo_name: str) -> Optional[str]:
|
||||
"""获取照片对应的小朋友ID"""
|
||||
try:
|
||||
if not photo_name:
|
||||
return None
|
||||
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return None
|
||||
|
||||
kid_id = redis_client.get(f'{self.prefix}{group_id}:photo:{photo_name}')
|
||||
if kid_id and isinstance(kid_id, bytes):
|
||||
kid_id = kid_id.decode('utf-8')
|
||||
return kid_id
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取照片对应的小朋友ID失败: {e}")
|
||||
return None
|
||||
|
||||
def save_last_process_time(self, group_id: str) -> bool:
|
||||
"""保存最后处理时间"""
|
||||
try:
|
||||
timestamp = int(datetime.now().timestamp())
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return False
|
||||
redis_client.set(f'{self.prefix}{group_id}:last_process_time', str(timestamp))
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"保存最后处理时间失败: {e}")
|
||||
return False
|
||||
|
||||
def get_last_process_time(self, group_id: str) -> Optional[int]:
|
||||
"""获取最后处理时间"""
|
||||
try:
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return None
|
||||
|
||||
timestamp = redis_client.get(f'{self.prefix}{group_id}:last_process_time')
|
||||
if timestamp:
|
||||
if isinstance(timestamp, bytes):
|
||||
timestamp = timestamp.decode('utf-8')
|
||||
return int(timestamp)
|
||||
return None
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取最后处理时间失败: {e}")
|
||||
return None
|
||||
|
||||
def clear_processed_photos(self, group_id: str) -> bool:
|
||||
"""清理已处理的照片记录"""
|
||||
try:
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return False
|
||||
redis_client.delete(f'{self.prefix}{group_id}:processed_photos')
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"清理已处理照片记录失败: {e}")
|
||||
return False
|
||||
|
||||
def clear_analysis_data(self, group_id: str) -> bool:
|
||||
"""清理分析数据"""
|
||||
try:
|
||||
with self.get_redis_connection() as redis_client:
|
||||
if not redis_client:
|
||||
return False
|
||||
|
||||
# 使用管道批量操作
|
||||
pipeline = redis_client.pipeline()
|
||||
|
||||
# 获取所有小朋友ID
|
||||
kid_keys = redis_client.keys(f'{self.prefix}{group_id}:kid:*')
|
||||
|
||||
# 删除小朋友照片映射
|
||||
if kid_keys:
|
||||
pipeline.delete(*kid_keys)
|
||||
|
||||
# 删除照片到小朋友的映射
|
||||
photo_keys = redis_client.keys(f'{self.prefix}{group_id}:photo:*')
|
||||
if photo_keys:
|
||||
pipeline.delete(*photo_keys)
|
||||
|
||||
# 删除其他数据
|
||||
keys_to_delete = [
|
||||
f'{self.prefix}{group_id}:last_time',
|
||||
f'{self.prefix}{group_id}:results',
|
||||
f'{self.prefix}{group_id}:processed_photos',
|
||||
f'{self.prefix}{group_id}:last_process_time'
|
||||
]
|
||||
pipeline.delete(*keys_to_delete)
|
||||
|
||||
pipeline.execute()
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"清理分析数据失败: {e}")
|
||||
return False
|
||||
Reference in New Issue
Block a user