feat: 更新 MinIO 上传功能,支持指定存储桶并添加公共读取策略,修复文件上传bug
This commit is contained in:
parent
42b75979dd
commit
a0194b8e09
@ -603,7 +603,7 @@ async def upload_user_avatar(
|
|||||||
file_extension = file.filename.split(".")[-1].lower() if file.filename and "." in file.filename else "jpg"
|
file_extension = file.filename.split(".")[-1].lower() if file.filename and "." in file.filename else "jpg"
|
||||||
|
|
||||||
# 上传到MinIO
|
# 上传到MinIO
|
||||||
avatar_url = upload_image_to_minio(file_content, file_extension)
|
avatar_url = upload_image_to_minio("avatar", file_content, file_extension)
|
||||||
|
|
||||||
# 更新用户头像
|
# 更新用户头像
|
||||||
current_user.avatar = avatar_url
|
current_user.avatar = avatar_url
|
||||||
|
|||||||
@ -60,7 +60,7 @@ async def text_to_img_qwen(text: str) -> str:
|
|||||||
response = requests.get(image_url)
|
response = requests.get(image_url)
|
||||||
file_data = response.content
|
file_data = response.content
|
||||||
|
|
||||||
image_url = upload_image_to_minio(data=file_data, file_extension="jpg")
|
image_url = upload_image_to_minio(bucket_name="generated-images", data=file_data, file_extension="jpg")
|
||||||
logger.info(f"Image uploaded. URL: {image_url}")
|
logger.info(f"Image uploaded. URL: {image_url}")
|
||||||
return image_url
|
return image_url
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ MinIO 存储客户端
|
|||||||
简化的 MinIO 对象存储操作
|
简化的 MinIO 对象存储操作
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
@ -32,6 +33,8 @@ class MinIOClient:
|
|||||||
简化的 MinIO 客户端类
|
简化的 MinIO 客户端类
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PUBLIC_READ_BUCKETS = {"generated-images", "avatar"}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""初始化 MinIO 客户端"""
|
"""初始化 MinIO 客户端"""
|
||||||
self.endpoint = os.getenv("MINIO_URI", "http://milvus-minio:9000")
|
self.endpoint = os.getenv("MINIO_URI", "http://milvus-minio:9000")
|
||||||
@ -41,7 +44,12 @@ class MinIOClient:
|
|||||||
|
|
||||||
# 设置公开访问端点
|
# 设置公开访问端点
|
||||||
if os.getenv("RUNNING_IN_DOCKER"):
|
if os.getenv("RUNNING_IN_DOCKER"):
|
||||||
host_ip = os.getenv("HOST_IP", "localhost")
|
host_ip = (os.getenv("HOST_IP") or "").strip()
|
||||||
|
if not host_ip:
|
||||||
|
host_ip = "localhost"
|
||||||
|
if "://" in host_ip:
|
||||||
|
host_ip = host_ip.split("://")[-1]
|
||||||
|
host_ip = host_ip.rstrip("/")
|
||||||
self.public_endpoint = f"{host_ip}:9000"
|
self.public_endpoint = f"{host_ip}:9000"
|
||||||
else:
|
else:
|
||||||
self.public_endpoint = "localhost:9000"
|
self.public_endpoint = "localhost:9000"
|
||||||
@ -62,14 +70,23 @@ class MinIOClient:
|
|||||||
def ensure_bucket_exists(self, bucket_name: str) -> bool:
|
def ensure_bucket_exists(self, bucket_name: str) -> bool:
|
||||||
"""确保存储桶存在"""
|
"""确保存储桶存在"""
|
||||||
try:
|
try:
|
||||||
|
created = False
|
||||||
if not self.client.bucket_exists(bucket_name):
|
if not self.client.bucket_exists(bucket_name):
|
||||||
self.client.make_bucket(bucket_name)
|
self.client.make_bucket(bucket_name)
|
||||||
|
created = True
|
||||||
logger.info(f"存储桶 '{bucket_name}' 已创建")
|
logger.info(f"存储桶 '{bucket_name}' 已创建")
|
||||||
return True
|
|
||||||
|
self._ensure_public_read_access(bucket_name)
|
||||||
|
|
||||||
|
if created and bucket_name in self.PUBLIC_READ_BUCKETS:
|
||||||
|
logger.info(f"存储桶 '{bucket_name}' 已配置为公开可读")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except S3Error as e:
|
except S3Error as e:
|
||||||
logger.error(f"存储桶 '{bucket_name}' 错误: {e}")
|
logger.error(f"存储桶 '{bucket_name}' 错误: {e}")
|
||||||
raise StorageError(f"Error with bucket '{bucket_name}': {e}")
|
raise StorageError(f"Error with bucket '{bucket_name}': {e}")
|
||||||
|
except StorageError:
|
||||||
|
raise
|
||||||
|
|
||||||
def upload_file(
|
def upload_file(
|
||||||
self, bucket_name: str, object_name: str, data: bytes, content_type: str = "application/octet-stream"
|
self, bucket_name: str, object_name: str, data: bytes, content_type: str = "application/octet-stream"
|
||||||
@ -167,6 +184,35 @@ class MinIOClient:
|
|||||||
return False
|
return False
|
||||||
raise StorageError(f"检查文件存在性失败: {e}")
|
raise StorageError(f"检查文件存在性失败: {e}")
|
||||||
|
|
||||||
|
def _ensure_public_read_access(self, bucket_name: str) -> None:
|
||||||
|
"""设置存储桶策略,允许公开读取对象"""
|
||||||
|
if bucket_name not in self.PUBLIC_READ_BUCKETS:
|
||||||
|
return
|
||||||
|
|
||||||
|
policy = {
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": {"AWS": ["*"]},
|
||||||
|
"Action": ["s3:GetObject"],
|
||||||
|
"Resource": [f"arn:aws:s3:::{bucket_name}/*"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": {"AWS": ["*"]},
|
||||||
|
"Action": ["s3:ListBucket"],
|
||||||
|
"Resource": [f"arn:aws:s3:::{bucket_name}"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.client.set_bucket_policy(bucket_name, json.dumps(policy))
|
||||||
|
except S3Error as e:
|
||||||
|
logger.warning(f"设置存储桶 '{bucket_name}' 公共读取策略失败: {e}")
|
||||||
|
raise StorageError(f"无法设置存储桶公共访问策略: {e}")
|
||||||
|
|
||||||
|
|
||||||
# 全局客户端实例
|
# 全局客户端实例
|
||||||
_default_client = None
|
_default_client = None
|
||||||
@ -180,7 +226,7 @@ def get_minio_client() -> MinIOClient:
|
|||||||
return _default_client
|
return _default_client
|
||||||
|
|
||||||
|
|
||||||
def upload_image_to_minio(data: bytes, file_extension: str = "jpg") -> str:
|
def upload_image_to_minio(bucket_name: str, data: bytes, file_extension: str = "jpg") -> str:
|
||||||
"""
|
"""
|
||||||
上传图片到 MinIO(保持向后兼容)
|
上传图片到 MinIO(保持向后兼容)
|
||||||
|
|
||||||
@ -194,6 +240,6 @@ def upload_image_to_minio(data: bytes, file_extension: str = "jpg") -> str:
|
|||||||
client = get_minio_client()
|
client = get_minio_client()
|
||||||
file_name = f"{uuid.uuid4()}.{file_extension}"
|
file_name = f"{uuid.uuid4()}.{file_extension}"
|
||||||
result = client.upload_file(
|
result = client.upload_file(
|
||||||
bucket_name="generated-images", object_name=file_name, data=data, content_type=f"image/{file_extension}"
|
bucket_name=bucket_name, object_name=file_name, data=data, content_type=f"image/{file_extension}"
|
||||||
)
|
)
|
||||||
return result.url
|
return result.url
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user