Spaces:
Sleeping
Sleeping
Upload minio_uploader.py
Browse files- minio_uploader.py +102 -0
minio_uploader.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# core/minio_uploader.py
|
| 2 |
+
import os
|
| 3 |
+
from minio import Minio
|
| 4 |
+
from minio.error import S3Error
|
| 5 |
+
|
| 6 |
+
# 从环境变量读取 MinIO 配置(推荐)
|
| 7 |
+
# 如果环境变量不存在,则使用默认值
|
| 8 |
+
MINIO_ENDPOINT = os.environ.get("MINIO_ENDPOINT", "minioapi.auton.one") # 不包含协议
|
| 9 |
+
MINIO_ROOT_USER = os.environ.get("MINIO_ROOT_USER", "arvin") # 管理员 Access Key
|
| 10 |
+
MINIO_ROOT_PASSWORD = os.environ.get("MINIO_ROOT_PASSWORD", "LinJia1996") # 管理员 Secret Key
|
| 11 |
+
BUCKET_NAME = os.environ.get("MINIO_BUCKET", "video-demo")
|
| 12 |
+
MINIO_SECURE = os.environ.get("MINIO_SECURE", "True").lower() == "true" # 是否使用 HTTPS
|
| 13 |
+
|
| 14 |
+
# 初始化 MinIO 客户端(使用管理员账户)
|
| 15 |
+
minio_client = Minio(
|
| 16 |
+
MINIO_ENDPOINT,
|
| 17 |
+
access_key=MINIO_ROOT_USER,
|
| 18 |
+
secret_key=MINIO_ROOT_PASSWORD,
|
| 19 |
+
secure=MINIO_SECURE # 根据配置使用 HTTP 或 HTTPS
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
# 确保存储桶存在
|
| 24 |
+
try:
|
| 25 |
+
if not minio_client.bucket_exists(BUCKET_NAME):
|
| 26 |
+
minio_client.make_bucket(BUCKET_NAME)
|
| 27 |
+
print(f"[MinIO] ✅ 创建存储桶: {BUCKET_NAME}")
|
| 28 |
+
else:
|
| 29 |
+
print(f"[MinIO] ℹ️ 存储桶已存在: {BUCKET_NAME}")
|
| 30 |
+
except S3Error as e:
|
| 31 |
+
print(f"[MinIO] ⚠️ 检查存储桶失败: {e.code} - {e.message}")
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def upload_video_to_minio(video_file_path: str):
|
| 35 |
+
"""
|
| 36 |
+
上传视频到 MinIO,返回 (video_path, public_url_or_error_message)
|
| 37 |
+
兼容 Gradio 输出格式:(video, link)
|
| 38 |
+
|
| 39 |
+
返回预签名 URL,有效期 7 天,供 Gemini API 访问
|
| 40 |
+
"""
|
| 41 |
+
if not video_file_path or not os.path.isfile(video_file_path):
|
| 42 |
+
return None, "❌ 视频文件无效或不存在"
|
| 43 |
+
|
| 44 |
+
try:
|
| 45 |
+
from datetime import timedelta
|
| 46 |
+
|
| 47 |
+
original_name = os.path.basename(video_file_path)
|
| 48 |
+
file_ext = os.path.splitext(original_name)[1].lower()
|
| 49 |
+
allowed_video_exts = {".mp4", ".mov", ".avi", ".mkv", ".flv", ".wmv"}
|
| 50 |
+
|
| 51 |
+
if file_ext not in allowed_video_exts:
|
| 52 |
+
return None, f"❌ 不支持的视频格式: {file_ext},仅支持: {', '.join(allowed_video_exts)}"
|
| 53 |
+
|
| 54 |
+
print(f"[MinIO] 开始上传: {original_name}")
|
| 55 |
+
|
| 56 |
+
# 根据文件扩展名确定正确的 MIME 类型
|
| 57 |
+
mime_types = {
|
| 58 |
+
".mp4": "video/mp4",
|
| 59 |
+
".mov": "video/quicktime",
|
| 60 |
+
".avi": "video/x-msvideo",
|
| 61 |
+
".mkv": "video/x-matroska",
|
| 62 |
+
".flv": "video/x-flv",
|
| 63 |
+
".wmv": "video/x-ms-wmv"
|
| 64 |
+
}
|
| 65 |
+
content_type = mime_types.get(file_ext, "video/mp4") # 默认使用 video/mp4
|
| 66 |
+
|
| 67 |
+
print(f"[MinIO] 设置 Content-Type: {content_type}")
|
| 68 |
+
|
| 69 |
+
# 上传到 MinIO,使用 metadata 明确指定 Content-Type
|
| 70 |
+
# MinIO Python 客户端需要通过 metadata 设置 Content-Type
|
| 71 |
+
minio_client.fput_object(
|
| 72 |
+
bucket_name=BUCKET_NAME,
|
| 73 |
+
object_name=original_name,
|
| 74 |
+
file_path=video_file_path,
|
| 75 |
+
content_type=content_type, # 直接指定 content_type
|
| 76 |
+
metadata={
|
| 77 |
+
"Content-Type": content_type # 也在 metadata 中设置
|
| 78 |
+
}
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
print(f"[MinIO] ✅ 上传成功: {original_name}")
|
| 82 |
+
print(f"[MinIO] ✅ Content-Type 已设置为: {content_type}")
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
# 生成直链(格式:协议://MINIO_ENDPOINT/MINIO_BUCKET/original_name)
|
| 87 |
+
# 注意:这要求 MinIO 对象必须是公开可访问的
|
| 88 |
+
protocol = "https" if MINIO_SECURE else "http"
|
| 89 |
+
public_url = f"{protocol}://{MINIO_ENDPOINT}/{BUCKET_NAME}/{original_name}"
|
| 90 |
+
|
| 91 |
+
print(f"[MinIO] 🔗 生成直链: {public_url}")
|
| 92 |
+
|
| 93 |
+
return video_file_path, public_url # ✅ 返回直链
|
| 94 |
+
|
| 95 |
+
except S3Error as e:
|
| 96 |
+
error_msg = f"❌ MinIO 上传失败: {e.code} - {e.message}"
|
| 97 |
+
print(f"[MinIO] {error_msg}")
|
| 98 |
+
return None, error_msg
|
| 99 |
+
except Exception as e:
|
| 100 |
+
error_msg = f"❌ 上传出错: {type(e).__name__} - {str(e)}"
|
| 101 |
+
print(f"[MinIO] {error_msg}")
|
| 102 |
+
return None, error_msg
|