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