197 lines
7.6 KiB
Python
197 lines
7.6 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""
|
|||
|
|
换装图片上传到阿里云 OSS 脚本(最终版 - 仅上传现有的 29 个图片)
|
|||
|
|
"""
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
from pathlib import Path
|
|||
|
|
import oss2
|
|||
|
|
from dotenv import load_dotenv
|
|||
|
|
|
|||
|
|
# 加载环境变量
|
|||
|
|
load_dotenv()
|
|||
|
|
|
|||
|
|
# OSS 配置
|
|||
|
|
ACCESS_KEY_ID = os.getenv('ALIYUN_OSS_ACCESS_KEY_ID')
|
|||
|
|
ACCESS_KEY_SECRET = os.getenv('ALIYUN_OSS_ACCESS_KEY_SECRET')
|
|||
|
|
BUCKET_NAME = os.getenv('ALIYUN_OSS_BUCKET_NAME')
|
|||
|
|
ENDPOINT = os.getenv('ALIYUN_OSS_ENDPOINT', 'https://oss-cn-hangzhou.aliyuncs.com')
|
|||
|
|
CDN_DOMAIN = os.getenv('ALIYUN_OSS_CDN_DOMAIN')
|
|||
|
|
|
|||
|
|
# 图片源目录
|
|||
|
|
SOURCE_DIR = Path('开发/2026年2月4日/Image')
|
|||
|
|
|
|||
|
|
# 文件映射(仅包含实际存在的 29 个文件)
|
|||
|
|
FILE_MAP = {
|
|||
|
|
# 上装 - 女性 (10个)
|
|||
|
|
"女性上衣白色T桖.png": "uploads/outfit/top/white_tshirt.png",
|
|||
|
|
"女性-上装-粉丝短袖.png": "uploads/outfit/top/pink_short_sleeve.png",
|
|||
|
|
"女性-上装-蓝色衬衫.png": "uploads/outfit/top/blue_shirt.png",
|
|||
|
|
"女性-上装-灰色卫衣.png": "uploads/outfit/top/gray_sweatshirt.png",
|
|||
|
|
"女性-上装-收费-蕾丝吊带上衣.png": "uploads/outfit/top/lace_strap.png",
|
|||
|
|
"女性-上装-收费-一字领露肩上衣.png": "uploads/outfit/top/off_shoulder.png",
|
|||
|
|
"女性-上装-收费-露脐短袖.png": "uploads/outfit/top/crop_top.png",
|
|||
|
|
"女性-上装-收费-针织开衫.png": "uploads/outfit/top/knit_cardigan.png",
|
|||
|
|
"女性-上装-收费-小香风外套.png": "uploads/outfit/top/tweed_jacket.png",
|
|||
|
|
"女性-上装-vlp专属-真丝衬衫.png": "uploads/outfit/top/silk_shirt.png",
|
|||
|
|
|
|||
|
|
# 下装 - 女性 (9个)
|
|||
|
|
"女性-下衣-蓝色牛仔裤.png": "uploads/outfit/bottom/blue_jeans.png",
|
|||
|
|
"女性-下衣-黑色短裙.png": "uploads/outfit/bottom/black_skirt.png",
|
|||
|
|
"女性-下衣-白色短裙.png": "uploads/outfit/bottom/white_shorts.png",
|
|||
|
|
"女性-下衣-灰色运动裤.png": "uploads/outfit/bottom/gray_sweatpants.png",
|
|||
|
|
"女性-下衣-A字半身裙.png": "uploads/outfit/bottom/a_line_skirt.png",
|
|||
|
|
"女性-下衣-高腰阔腿裤.png": "uploads/outfit/bottom/high_waist_pants.png",
|
|||
|
|
"女性-下衣-收费-百褶短裙.png": "uploads/outfit/bottom/pleated_skirt.png",
|
|||
|
|
"女性-下衣-收费-破洞牛仔裤.png": "uploads/outfit/bottom/ripped_jeans.png",
|
|||
|
|
"女性-下衣-收费-西装裤.png": "uploads/outfit/bottom/suit_pants.png",
|
|||
|
|
|
|||
|
|
# 连衣裙 - 女性 (10个)
|
|||
|
|
"女性-连衣裙-白色连衣裙.png": "uploads/outfit/dress/white_dress.png",
|
|||
|
|
"女性-连衣裙-碎花连衣裙.png": "uploads/outfit/dress/floral_dress.png",
|
|||
|
|
"女性-连衣裙-黑色小礼服.png": "uploads/outfit/dress/black_dress.png",
|
|||
|
|
"女性-连衣裙-优雅长裙.png": "uploads/outfit/dress/elegant_long_dress.png",
|
|||
|
|
"女性-连衣裙-吊带连衣裙.png": "uploads/outfit/dress/strapless_dress.png",
|
|||
|
|
"女性-连衣裙-JK制服.png": "uploads/outfit/dress/jk_uniform.png",
|
|||
|
|
"女性-连衣裙-汉服.png": "uploads/outfit/dress/hanfu.png",
|
|||
|
|
"女性-连衣裙-洛丽塔.png": "uploads/outfit/dress/lolita.png",
|
|||
|
|
"女性-连衣裙-圣诞服装.png": "uploads/outfit/dress/christmas_dress.png",
|
|||
|
|
"女性-连衣裙-高级定制婚纱.png": "uploads/outfit/dress/custom_wedding_dress.png",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
def upload_to_oss():
|
|||
|
|
"""上传图片到 OSS"""
|
|||
|
|
|
|||
|
|
# 检查配置
|
|||
|
|
if not all([ACCESS_KEY_ID, ACCESS_KEY_SECRET, BUCKET_NAME]):
|
|||
|
|
print("❌ 错误:OSS 配置不完整")
|
|||
|
|
print(f"ACCESS_KEY_ID: {'已配置' if ACCESS_KEY_ID else '未配置'}")
|
|||
|
|
print(f"ACCESS_KEY_SECRET: {'已配置' if ACCESS_KEY_SECRET else '未配置'}")
|
|||
|
|
print(f"BUCKET_NAME: {BUCKET_NAME or '未配置'}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
print("=" * 70)
|
|||
|
|
print(" 换装图片上传到阿里云 OSS(最终版)")
|
|||
|
|
print("=" * 70)
|
|||
|
|
print()
|
|||
|
|
print(f"📦 OSS Bucket: {BUCKET_NAME}")
|
|||
|
|
print(f"🌐 OSS Endpoint: {ENDPOINT}")
|
|||
|
|
print(f"🚀 CDN Domain: {CDN_DOMAIN or '未配置'}")
|
|||
|
|
print(f"📁 源目录: {SOURCE_DIR}")
|
|||
|
|
print(f"📊 待上传文件数: {len(FILE_MAP)}")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
# 初始化 OSS
|
|||
|
|
try:
|
|||
|
|
auth = oss2.Auth(ACCESS_KEY_ID, ACCESS_KEY_SECRET)
|
|||
|
|
# 去掉 endpoint 中的 https://
|
|||
|
|
endpoint_clean = ENDPOINT.replace('https://', '').replace('http://', '')
|
|||
|
|
bucket = oss2.Bucket(auth, endpoint_clean, BUCKET_NAME)
|
|||
|
|
|
|||
|
|
# 测试连接
|
|||
|
|
bucket.get_bucket_info()
|
|||
|
|
print("✓ OSS 连接成功")
|
|||
|
|
print()
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ OSS 连接失败: {e}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 检查源目录
|
|||
|
|
if not SOURCE_DIR.exists():
|
|||
|
|
print(f"❌ 错误:源目录不存在: {SOURCE_DIR}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 上传文件
|
|||
|
|
uploaded_count = 0
|
|||
|
|
failed_count = 0
|
|||
|
|
skipped_count = 0
|
|||
|
|
|
|||
|
|
print("开始上传图片...")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
for idx, (source_file, oss_object) in enumerate(FILE_MAP.items(), 1):
|
|||
|
|
source_path = SOURCE_DIR / source_file
|
|||
|
|
|
|||
|
|
if not source_path.exists():
|
|||
|
|
print(f"[{idx}/{len(FILE_MAP)}] ⚠️ 跳过(文件不存在): {source_file}")
|
|||
|
|
skipped_count += 1
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 读取文件
|
|||
|
|
with open(source_path, 'rb') as f:
|
|||
|
|
file_data = f.read()
|
|||
|
|
|
|||
|
|
file_size = len(file_data) / 1024 # KB
|
|||
|
|
|
|||
|
|
# 上传到 OSS
|
|||
|
|
bucket.put_object(oss_object, file_data)
|
|||
|
|
|
|||
|
|
# 生成访问 URL
|
|||
|
|
if CDN_DOMAIN:
|
|||
|
|
url = f"{CDN_DOMAIN.rstrip('/')}/{oss_object}"
|
|||
|
|
else:
|
|||
|
|
url = f"https://{BUCKET_NAME}.{endpoint_clean}/{oss_object}"
|
|||
|
|
|
|||
|
|
print(f"[{idx}/{len(FILE_MAP)}] ✓ 已上传: {source_file}")
|
|||
|
|
print(f" 大小: {file_size:.1f} KB")
|
|||
|
|
print(f" OSS: {oss_object}")
|
|||
|
|
print(f" URL: {url}")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
uploaded_count += 1
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"[{idx}/{len(FILE_MAP)}] ❌ 上传失败: {source_file}")
|
|||
|
|
print(f" 错误: {e}")
|
|||
|
|
print()
|
|||
|
|
failed_count += 1
|
|||
|
|
|
|||
|
|
# 统计结果
|
|||
|
|
print("=" * 70)
|
|||
|
|
print(" 上传完成")
|
|||
|
|
print("=" * 70)
|
|||
|
|
print()
|
|||
|
|
print(f"✓ 成功上传: {uploaded_count} 个文件")
|
|||
|
|
if failed_count > 0:
|
|||
|
|
print(f"✗ 上传失败: {failed_count} 个文件")
|
|||
|
|
if skipped_count > 0:
|
|||
|
|
print(f"⚠ 跳过文件: {skipped_count} 个文件")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
if uploaded_count > 0:
|
|||
|
|
print("=" * 70)
|
|||
|
|
print(" 下一步操作")
|
|||
|
|
print("=" * 70)
|
|||
|
|
print()
|
|||
|
|
print("1️⃣ 执行 SQL 文件导入数据库")
|
|||
|
|
print(" 📄 文件:开发/2026年2月4日/数据填充_换装种类_最终版.sql")
|
|||
|
|
print()
|
|||
|
|
print("2️⃣ 重启 Python 服务")
|
|||
|
|
print(" 💻 命令:python -m uvicorn lover.main:app --host 0.0.0.0 --port 30101 --reload")
|
|||
|
|
print()
|
|||
|
|
print("3️⃣ 测试前端换装功能")
|
|||
|
|
print(" 📱 打开前端应用 → 金币商店 → 查看服装列表")
|
|||
|
|
print()
|
|||
|
|
print("4️⃣ 验证图片访问")
|
|||
|
|
print(f" 🌐 示例:{CDN_DOMAIN or f'https://{BUCKET_NAME}.{endpoint_clean}'}/uploads/outfit/top/white_tshirt.png")
|
|||
|
|
print()
|
|||
|
|
|
|||
|
|
return uploaded_count > 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
try:
|
|||
|
|
success = upload_to_oss()
|
|||
|
|
sys.exit(0 if success else 1)
|
|||
|
|
except KeyboardInterrupt:
|
|||
|
|
print("\n\n⚠️ 用户中断")
|
|||
|
|
sys.exit(1)
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"\n❌ 发生错误: {e}")
|
|||
|
|
import traceback
|
|||
|
|
traceback.print_exc()
|
|||
|
|
sys.exit(1)
|