|
@@ -2,6 +2,8 @@ import os
|
|
|
import uuid
|
|
import uuid
|
|
|
import json
|
|
import json
|
|
|
import requests
|
|
import requests
|
|
|
|
|
+import io
|
|
|
|
|
+from app.core.minio_client import minio_client
|
|
|
from typing import Optional, Dict, Any
|
|
from typing import Optional, Dict, Any
|
|
|
from fastapi import APIRouter, File, UploadFile, Depends, HTTPException, Form, Path
|
|
from fastapi import APIRouter, File, UploadFile, Depends, HTTPException, Form, Path
|
|
|
from fastapi.concurrency import run_in_threadpool
|
|
from fastapi.concurrency import run_in_threadpool
|
|
@@ -45,13 +47,22 @@ async def upload_image_for_card(
|
|
|
|
|
|
|
|
file_extension = os.path.splitext(image.filename)[1]
|
|
file_extension = os.path.splitext(image.filename)[1]
|
|
|
unique_filename = f"{uuid.uuid4()}{file_extension}"
|
|
unique_filename = f"{uuid.uuid4()}{file_extension}"
|
|
|
- image_path = settings.DATA_DIR / unique_filename
|
|
|
|
|
- relative_path = f"/{image_path.parent.name}/{image_path.name}"
|
|
|
|
|
|
|
+
|
|
|
|
|
+ relative_path = f"/Data/{unique_filename}"
|
|
|
|
|
+ object_name = f"{settings.MINIO_BASE_PREFIX}{relative_path}"
|
|
|
|
|
+
|
|
|
try:
|
|
try:
|
|
|
- with open(image_path, "wb") as buffer:
|
|
|
|
|
- buffer.write(await image.read())
|
|
|
|
|
|
|
+ # 写入 MinIO 存储
|
|
|
|
|
+ file_bytes = await image.read()
|
|
|
|
|
+ minio_client.put_object(
|
|
|
|
|
+ settings.MINIO_BUCKET,
|
|
|
|
|
+ object_name,
|
|
|
|
|
+ io.BytesIO(file_bytes),
|
|
|
|
|
+ len(file_bytes),
|
|
|
|
|
+ content_type=image.content_type or "image/jpeg"
|
|
|
|
|
+ )
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
- logger.error(f"保存图片失败: {e}")
|
|
|
|
|
|
|
+ logger.error(f"保存图片到MinIO失败: {e}")
|
|
|
raise HTTPException(status_code=500, detail="无法保存图片文件。")
|
|
raise HTTPException(status_code=500, detail="无法保存图片文件。")
|
|
|
|
|
|
|
|
cursor = None
|
|
cursor = None
|
|
@@ -84,18 +95,34 @@ async def upload_image_for_card(
|
|
|
cursor.execute(f"SELECT * FROM {settings.DB_IMAGE_TABLE_NAME} WHERE id = %s", (new_id,))
|
|
cursor.execute(f"SELECT * FROM {settings.DB_IMAGE_TABLE_NAME} WHERE id = %s", (new_id,))
|
|
|
new_image_data = cursor.fetchone()
|
|
new_image_data = cursor.fetchone()
|
|
|
columns = [desc[0] for desc in cursor.description]
|
|
columns = [desc[0] for desc in cursor.description]
|
|
|
|
|
+ row_dict = dict(zip(columns, new_image_data))
|
|
|
|
|
+
|
|
|
|
|
+ # 返回完整url
|
|
|
|
|
+ row_dict['image_path'] = settings.get_full_url(row_dict.get('image_path'))
|
|
|
|
|
+ row_dict['detection_image_path'] = settings.get_full_url(row_dict.get('detection_image_path'))
|
|
|
|
|
+ row_dict['modified_image_path'] = settings.get_full_url(row_dict.get('modified_image_path'))
|
|
|
return CardImageResponse.model_validate(dict(zip(columns, new_image_data)))
|
|
return CardImageResponse.model_validate(dict(zip(columns, new_image_data)))
|
|
|
|
|
|
|
|
|
|
+
|
|
|
except IntegrityError as e:
|
|
except IntegrityError as e:
|
|
|
db_conn.rollback()
|
|
db_conn.rollback()
|
|
|
- if os.path.exists(image_path): os.remove(image_path)
|
|
|
|
|
|
|
+ # 清理已上传到 MinIO 的文件
|
|
|
|
|
+ try:
|
|
|
|
|
+ minio_client.remove_object(settings.MINIO_BUCKET, object_name)
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
if e.errno == 1062:
|
|
if e.errno == 1062:
|
|
|
- raise HTTPException(status_code=409, detail=f"卡牌ID {card_id} 已存在类型为 '{image_type.value}' 的图片。")
|
|
|
|
|
|
|
+ raise HTTPException(status_code=409, detail=f"卡牌ID {card_id} 已存在...")
|
|
|
|
|
+
|
|
|
raise HTTPException(status_code=500, detail="数据库操作失败。")
|
|
raise HTTPException(status_code=500, detail="数据库操作失败。")
|
|
|
|
|
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
db_conn.rollback()
|
|
db_conn.rollback()
|
|
|
- if os.path.exists(image_path): os.remove(image_path)
|
|
|
|
|
|
|
+ try:
|
|
|
|
|
+ minio_client.remove_object(settings.MINIO_BUCKET, object_name)
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
logger.error(f"关联图片到卡牌失败: {e}")
|
|
logger.error(f"关联图片到卡牌失败: {e}")
|
|
|
if isinstance(e, HTTPException): raise e
|
|
if isinstance(e, HTTPException): raise e
|
|
|
raise HTTPException(status_code=500, detail="数据库操作失败。")
|
|
raise HTTPException(status_code=500, detail="数据库操作失败。")
|
|
@@ -121,14 +148,22 @@ async def upload_gray_image_for_card(
|
|
|
# 1. 保存文件
|
|
# 1. 保存文件
|
|
|
file_extension = os.path.splitext(image.filename)[1]
|
|
file_extension = os.path.splitext(image.filename)[1]
|
|
|
unique_filename = f"gray_{uuid.uuid4()}{file_extension}" # 加个前缀区分
|
|
unique_filename = f"gray_{uuid.uuid4()}{file_extension}" # 加个前缀区分
|
|
|
- image_path = settings.DATA_DIR / unique_filename
|
|
|
|
|
- relative_path = f"/{image_path.parent.name}/{image_path.name}"
|
|
|
|
|
|
|
+
|
|
|
|
|
+ relative_path = f"/Data/{unique_filename}"
|
|
|
|
|
+ object_name = f"{settings.MINIO_BASE_PREFIX}{relative_path}"
|
|
|
|
|
|
|
|
try:
|
|
try:
|
|
|
- with open(image_path, "wb") as buffer:
|
|
|
|
|
- buffer.write(await image.read())
|
|
|
|
|
|
|
+ # 写入 MinIO 存储
|
|
|
|
|
+ file_bytes = await image.read()
|
|
|
|
|
+ minio_client.put_object(
|
|
|
|
|
+ settings.MINIO_BUCKET,
|
|
|
|
|
+ object_name,
|
|
|
|
|
+ io.BytesIO(file_bytes),
|
|
|
|
|
+ len(file_bytes),
|
|
|
|
|
+ content_type=image.content_type or "image/jpeg"
|
|
|
|
|
+ )
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
- logger.error(f"保存灰度图片失败: {e}")
|
|
|
|
|
|
|
+ logger.error(f"保存图片到MinIO失败: {e}")
|
|
|
raise HTTPException(status_code=500, detail="无法保存图片文件。")
|
|
raise HTTPException(status_code=500, detail="无法保存图片文件。")
|
|
|
|
|
|
|
|
cursor = None
|
|
cursor = None
|
|
@@ -163,6 +198,7 @@ async def upload_gray_image_for_card(
|
|
|
from app.crud.crud_card import EMPTY_DETECTION_JSON
|
|
from app.crud.crud_card import EMPTY_DETECTION_JSON
|
|
|
response_dict = {
|
|
response_dict = {
|
|
|
**row_dict,
|
|
**row_dict,
|
|
|
|
|
+ "image_path": settings.get_full_url(row_dict.get('image_path')),
|
|
|
"detection_json": EMPTY_DETECTION_JSON, # 默认死值
|
|
"detection_json": EMPTY_DETECTION_JSON, # 默认死值
|
|
|
"modified_json": None, # 刚上传还没有 modified
|
|
"modified_json": None, # 刚上传还没有 modified
|
|
|
"image_name": None,
|
|
"image_name": None,
|
|
@@ -173,17 +209,25 @@ async def upload_gray_image_for_card(
|
|
|
|
|
|
|
|
return CardImageResponse.model_validate(response_dict)
|
|
return CardImageResponse.model_validate(response_dict)
|
|
|
|
|
|
|
|
|
|
+
|
|
|
except IntegrityError as e:
|
|
except IntegrityError as e:
|
|
|
db_conn.rollback()
|
|
db_conn.rollback()
|
|
|
- if os.path.exists(image_path): os.remove(image_path)
|
|
|
|
|
|
|
+ # 清理已上传到 MinIO 的文件
|
|
|
|
|
+ try:
|
|
|
|
|
+ minio_client.remove_object(settings.MINIO_BUCKET, object_name)
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
if e.errno == 1062:
|
|
if e.errno == 1062:
|
|
|
- raise HTTPException(status_code=409, detail=f"卡牌ID {card_id} 已存在类型为 '{image_type.value}' 的图片。")
|
|
|
|
|
|
|
+ raise HTTPException(status_code=409, detail=f"卡牌ID {card_id} 已存在...")
|
|
|
raise HTTPException(status_code=500, detail="数据库操作失败。")
|
|
raise HTTPException(status_code=500, detail="数据库操作失败。")
|
|
|
|
|
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
db_conn.rollback()
|
|
db_conn.rollback()
|
|
|
- if os.path.exists(image_path): os.remove(image_path)
|
|
|
|
|
- logger.error(f"灰度图上传失败: {e}")
|
|
|
|
|
|
|
+ try:
|
|
|
|
|
+ minio_client.remove_object(settings.MINIO_BUCKET, object_name)
|
|
|
|
|
+ except:
|
|
|
|
|
+ pass
|
|
|
|
|
+ logger.error(f"关联图片到卡牌失败: {e}")
|
|
|
if isinstance(e, HTTPException): raise e
|
|
if isinstance(e, HTTPException): raise e
|
|
|
raise HTTPException(status_code=500, detail="数据库操作失败。")
|
|
raise HTTPException(status_code=500, detail="数据库操作失败。")
|
|
|
finally:
|
|
finally:
|