diff --git a/backend/app/routers/ocr.py b/backend/app/routers/ocr.py index 6a9eb29..b91a114 100644 --- a/backend/app/routers/ocr.py +++ b/backend/app/routers/ocr.py @@ -23,24 +23,52 @@ OSS_CONFIG = { "public_url": "https://jiachenlong-oss.oss-cn-hangzhou.aliyuncs.com" } -# 临时上传目录(用于OCR识别) +# 临时上传目录(用于OCR识别本地备选) UPLOAD_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "uploads", "temp") os.makedirs(UPLOAD_DIR, exist_ok=True) -def upload_to_oss(file_data, filename, bucket_name=None): +def get_oss_path(file_type: str, user_id: str = None, collection_id: str = None, filename: str = None): + """生成OSS路径 - 按年/月/日分类""" + from datetime import datetime + now = datetime.now() + year = now.strftime("%Y") + month = now.strftime("%m") + day = now.strftime("%d") + + if file_type == "temp": + # 临时文件: temp/{year}/{month}/{day}/{uuid}.{ext} + import uuid + unique_id = str(uuid.uuid4()) + ext = filename.split('.')[-1] if filename and '.' in filename else 'jpg' + return f"temp/{year}/{month}/{day}/{unique_id}.{ext}", unique_id + + elif file_type == "collection": + # 藏品文件: collections/{user_id}/{year}/{collection_id}/{filename} + if not user_id or not collection_id: + raise ValueError("user_id and collection_id required for collection") + return f"collections/{user_id}/{year}/{collection_id}/{filename}" + + elif file_type == "avatar": + # 头像: avatars/{user_id}/avatar.{ext} + if not user_id: + raise ValueError("user_id required for avatar") + ext = filename.split('.')[-1] if filename and '.' in filename else 'jpg' + return f"avatars/{user_id}/avatar.{ext}" + + return None + + +def upload_to_oss(file_data, oss_key): """上传文件到阿里云OSS""" import oss2 - bucket_name = bucket_name or OSS_CONFIG["bucket_name"] - auth = oss2.Auth(OSS_CONFIG["access_key_id"], OSS_CONFIG["access_key_secret"]) - bucket = oss2.Bucket(auth, OSS_CONFIG["endpoint"], bucket_name) + bucket = oss2.Bucket(auth, OSS_CONFIG["endpoint"], OSS_CONFIG["bucket_name"]) - # 上传文件 - result = bucket.put_object(filename, file_data) + result = bucket.put_object(oss_key, file_data) if result.status == 200: - return f"{OSS_CONFIG['public_url']}/{filename}" + return f"{OSS_CONFIG['public_url']}/{oss_key}" else: raise Exception(f"OSS上传失败: {result.status}") @@ -82,27 +110,25 @@ async def recognize_image( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): - """OCR 图片识别 - 识别后自动保存图片到临时目录""" + """OCR 图片识别 - 识别后自动保存图片到OSS临时目录""" try: # 读取图片数据 image_data = await image.read() image_base64 = base64.b64encode(image_data).decode('utf-8') - # 生成临时文件名(识别后保存到OSS) - temp_id = str(uuid.uuid4()) - ext = image.filename.split('.')[-1] if '.' in image.filename else 'jpg' - oss_key = f"temp/{temp_id}.{ext}" + # 生成OSS临时路径: temp/{year}/{month}/{day}/{uuid}.{ext} + oss_key, temp_id = get_oss_path("temp", filename=image.filename) # 上传到OSS try: image_url = upload_to_oss(image_data, oss_key) except Exception as oss_err: # OSS失败时保存到本地作为备选 - temp_filename = f"{temp_id}.{ext}" - temp_path = os.path.join(UPLOAD_DIR, temp_filename) + temp_path = os.path.join(UPLOAD_DIR, oss_key.split('/')[-1]) + os.makedirs(os.path.dirname(temp_path), exist_ok=True) with open(temp_path, 'wb') as f: f.write(image_data) - image_url = f"/uploads/temp/{temp_filename}" + image_url = f"/uploads/temp/{oss_key.split('/')[-1]}" headers = { "Authorization": f"Bearer {DASHSCOPE_API_KEY}", @@ -254,8 +280,9 @@ async def claim_temp_image( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): - """将临时图片移动到正式藏品目录""" + """将临时图片移动到正式藏品目录 - 按用户/年/藏品ID分类""" from app.models.models import Collection, CollectionImage + from datetime import datetime # 验证藏品是否存在 collection = db.query(Collection).filter( @@ -266,30 +293,40 @@ async def claim_temp_image( if not collection: raise HTTPException(status_code=404, detail="藏品不存在") - # 生成正式文件名 + # 生成正式文件名和OSS路径: collections/{user_id}/{year}/{collection_id}/{filename} code = collection.f01_02_code or "0000" prefix = collection.f02_10_prefix_serial or "" username = current_user.f01_01_name import time final_filename = f"{username}-{code}-{prefix}-{int(time.time())}.jpg" - oss_key = f"collections/{final_filename}" + oss_key = get_oss_path("collection", user_id=current_user.f99_90_id, collection_id=collection_id, filename=final_filename) - # 尝试从OSS获取临时图片 - 尝试多种扩展名 + # 尝试从OSS获取临时图片 - 尝试多种扩展名和日期路径 temp_extensions = ['jpg', 'jpeg', 'png', 'gif'] temp_content = None - found_ext = None + found_key = None - for ext in temp_extensions: - try: - temp_oss_key = f"temp/{temp_id}.{ext}" - import oss2 - auth = oss2.Auth(OSS_CONFIG["access_key_id"], OSS_CONFIG["access_key_secret"]) - bucket = oss2.Bucket(auth, OSS_CONFIG["endpoint"], OSS_CONFIG["bucket_name"]) - temp_content = bucket.get_object(temp_oss_key).read() - found_ext = ext + # 尝试最近7天的路径 + from datetime import timedelta + for i in range(7): + date = datetime.now() - timedelta(days=i) + year = date.strftime("%Y") + month = date.strftime("%m") + day = date.strftime("%d") + + for ext in temp_extensions: + try: + temp_oss_key = f"temp/{year}/{month}/{day}/{temp_id}.{ext}" + import oss2 + auth = oss2.Auth(OSS_CONFIG["access_key_id"], OSS_CONFIG["access_key_secret"]) + bucket = oss2.Bucket(auth, OSS_CONFIG["endpoint"], OSS_CONFIG["bucket_name"]) + temp_content = bucket.get_object(temp_oss_key).read() + found_key = temp_oss_key + break + except: + continue + if temp_content: break - except: - continue if temp_content: # 上传到正式目录 @@ -297,7 +334,7 @@ async def claim_temp_image( # 删除临时图片 try: - bucket.delete_object(f"temp/{temp_id}.{found_ext}") + bucket.delete_object(found_key) except: pass diff --git a/config/VERSION b/config/VERSION index e46e4c4..d04827c 100644 --- a/config/VERSION +++ b/config/VERSION @@ -2,7 +2,7 @@ # Version Configuration for Zodiac Collection Management System # 当前版本号 (语义化版本:主版本。次版本.修订版) -VERSION=1.1.6 +VERSION=1.1.7 # 版本代号 (可选) VERSION_CODENAME="新生"