feature:加入功能,小朋友人脸识别与分类。

This commit is contained in:
liuwei
2025-04-14 11:12:47 +08:00
parent c59dacb36b
commit 2f2e0a8113
9 changed files with 1473 additions and 7 deletions

305
db/kid_photo_redis.py Normal file
View 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