#!/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日/Gift') # 文件映射(源文件名 -> OSS 对象名)- 仅包含实际存在的 29 个文件 FILE_MAP = { # 经济类礼物(10-50金币)- 10个 "玫瑰花.png": "uploads/gifts/rose.png", "棒棒糖.png": "uploads/gifts/lollipop.png", "咖啡.png": "uploads/gifts/coffee.png", "冰淇淋.png": "uploads/gifts/icecream.png", "小蛋糕.png": "uploads/gifts/cake.png", "巧克力.png": "uploads/gifts/chocolate.png", "奶茶.png": "uploads/gifts/milktea.png", "爱心气球.png": "uploads/gifts/heart_balloon.png", "小礼物盒.png": "uploads/gifts/gift_box.png", "彩虹.png": "uploads/gifts/rainbow.png", # 中档礼物(50-200金币)- 9个 "香槟.png": "uploads/gifts/champagne.png", "钻石.png": "uploads/gifts/diamond.png", "王冠.png": "uploads/gifts/crown.png", "爱心.png": "uploads/gifts/big_heart.png", "月亮.png": "uploads/gifts/moon.png", "烟花.png": "uploads/gifts/fireworks.png", "水晶球.png": "uploads/gifts/crystal_ball.png", "玫瑰花束.png": "uploads/gifts/rose_bouquet.png", "星星项链.png": "uploads/gifts/star_necklace.png", # 高级礼物(200-500金币)- 4个 "跑车.png": "uploads/gifts/sports_car.png", "飞机.png": "uploads/gifts/airplane.png", "游艇.png": "uploads/gifts/yacht.png", "城堡.png": "uploads/gifts/castle.png", # 特殊礼物(500+金币)- 2个 "宇宙飞船.png": "uploads/gifts/spaceship.png", "魔法棒.png": "uploads/gifts/magic_wand.png", # 节日限定礼物 - 4个 "圣诞树.png": "uploads/gifts/christmas_tree.png", "情人节巧克力.png": "uploads/gifts/valentine_chocolate.png", "生日蛋糕.png": "uploads/gifts/birthday_cake.png", "万圣节南瓜.png": "uploads/gifts/halloween_pumpkin.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/gifts/rose.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)