upload.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import requests
  2. import os
  3. import sys
  4. import uuid
  5. import hmac
  6. import time
  7. import hashlib
  8. import base64
  9. from collections import OrderedDict
  10. from dotenv import load_dotenv
  11. # 加载环境变量(AK/SK)
  12. load_dotenv()
  13. # ========== 核心配置(替换成你的信息) ==========
  14. LIBLIBAI_AK = os.getenv("LIBLIBAI_ACCESS_KEY") # 从.env读取或直接写死
  15. LIBLIBAI_SK = os.getenv("LIBLIBAI_SECRET_KEY")
  16. LOCAL_IMAGE_PATH = r"C:\Users\11304\gitlab\cybertogether\tool_agent\control_reference.png" # 你的本地图片路径
  17. LIBLIBAI_DOMAIN = "https://openapi.liblibai.cloud"
  18. # ========== 核心工具函数 ==========
  19. def generate_auth_url(uri, ak, sk):
  20. """生成带签名的请求URL(仅用于获取OSS签名)"""
  21. ts = str(int(time.time() * 1000))
  22. nonce = uuid.uuid4().hex
  23. sign_str = f"{uri}&{ts}&{nonce}"
  24. # 生成签名
  25. dig = hmac.new(sk.encode(), sign_str.encode(), hashlib.sha1).digest()
  26. sig = base64.urlsafe_b64encode(dig).rstrip(b"=").decode()
  27. # 拼接URL
  28. return f"{LIBLIBAI_DOMAIN}{uri}?AccessKey={ak}&Timestamp={ts}&SignatureNonce={nonce}&Signature={sig}"
  29. def get_oss_upload_signature(file_name, ak, sk):
  30. """获取OSS上传签名"""
  31. # 1. 提取文件扩展名
  32. ext = os.path.splitext(file_name)[1].lstrip('.').lower()
  33. if ext not in ['jpg', 'jpeg', 'png']:
  34. print(f"❌ 不支持的文件格式: {ext},仅支持jpg/png/jpeg")
  35. return None
  36. # 2. 调用签名接口
  37. uri = "/api/generate/upload/signature"
  38. auth_url = generate_auth_url(uri, ak, sk)
  39. headers = {'Content-Type': 'application/json'}
  40. payload = {
  41. "name": file_name, # 完整文件名(含扩展名)
  42. "extension": ext
  43. }
  44. try:
  45. print(f"📡 正在请求OSS签名... URL: {auth_url[:100]}...")
  46. resp = requests.post(auth_url, headers=headers, json=payload, timeout=10)
  47. resp.raise_for_status()
  48. result = resp.json()
  49. if result.get("code") != 0:
  50. print(f"❌ 获取签名失败: {result.get('msg')}")
  51. return None
  52. sig_data = result.get("data")
  53. print(f"✅ 获取签名成功!")
  54. print(f" - postUrl: {sig_data['postUrl']}")
  55. print(f" - key: {sig_data['key']}")
  56. return sig_data
  57. except Exception as e:
  58. print(f"❌ 请求签名接口异常: {str(e)}")
  59. return None
  60. def upload_to_oss(sig_data, local_file_path):
  61. """上传本地文件到OSS"""
  62. # 1. 校验文件
  63. if not os.path.exists(local_file_path):
  64. print(f"❌ 本地文件不存在: {local_file_path}")
  65. return None
  66. file_name = os.path.basename(local_file_path)
  67. ext = os.path.splitext(local_file_path)[1].lower()
  68. content_type = 'image/jpeg' if ext in ['.jpg', '.jpeg'] else 'image/png'
  69. # 2. 构造表单参数(必须用OrderedDict保证顺序,file放最后)
  70. form_data = OrderedDict([
  71. ('key', sig_data['key']),
  72. ('policy', sig_data['policy']),
  73. ('x-oss-date', sig_data['xOssDate']),
  74. ('x-oss-expires', str(sig_data['xOssExpires'])),
  75. ('x-oss-signature', sig_data['xOssSignature']),
  76. ('x-oss-credential', sig_data['xOssCredential']),
  77. ('x-oss-signature-version', sig_data['xOssSignatureVersion'])
  78. ])
  79. # 3. 读取文件并上传
  80. try:
  81. print(f"📤 正在上传文件到OSS...")
  82. print(f" - 本地文件: {local_file_path}")
  83. print(f" - OSS地址: {sig_data['postUrl']}")
  84. with open(local_file_path, 'rb') as f:
  85. files = {
  86. 'file': (file_name, f, content_type) # file必须是最后一个字段
  87. }
  88. # 发送上传请求
  89. resp = requests.post(
  90. sig_data['postUrl'],
  91. data=form_data,
  92. files=files,
  93. timeout=30,
  94. headers={'User-Agent': 'Mozilla/5.0'}
  95. )
  96. # 4. 输出上传结果
  97. print(f"\n📋 上传响应信息:")
  98. print(f" - 状态码: {resp.status_code}")
  99. print(f" - 响应头: {dict(resp.headers)}")
  100. print(f" - 响应体: {resp.text[:500] if resp.text else '空'}")
  101. if resp.status_code in [200, 204]:
  102. # 拼接最终的OSS URL(仅用于LiblibAI API调用,浏览器访问会403)
  103. oss_url = f"{sig_data['postUrl']}/{sig_data['key']}"
  104. print(f"\n✅ 上传成功!OSS URL: {oss_url}")
  105. print(f"⚠️ 注意:该URL仅能用于LiblibAI API调用,浏览器直接访问会返回403(私有读权限)")
  106. return oss_url
  107. else:
  108. print(f"\n❌ 上传失败!状态码: {resp.status_code}")
  109. return None
  110. except Exception as e:
  111. print(f"\n❌ 上传过程异常: {str(e)}")
  112. return None
  113. # ========== 主执行逻辑 ==========
  114. if __name__ == "__main__":
  115. # 1. 基础校验
  116. if not LIBLIBAI_AK or not LIBLIBAI_SK:
  117. print("❌ 请先配置LIBLIBAI_ACCESS_KEY和LIBLIBAI_SECRET_KEY(.env文件或直接写死)")
  118. sys.exit(1)
  119. if not os.path.exists(LOCAL_IMAGE_PATH):
  120. print(f"❌ 本地图片不存在: {LOCAL_IMAGE_PATH}")
  121. sys.exit(1)
  122. # 2. 获取OSS签名
  123. file_name = os.path.basename(LOCAL_IMAGE_PATH)
  124. sig_data = get_oss_upload_signature(file_name, LIBLIBAI_AK, LIBLIBAI_SK)
  125. if not sig_data:
  126. sys.exit(1)
  127. # 3. 上传图片到OSS
  128. upload_to_oss(sig_data, LOCAL_IMAGE_PATH)