oss_client.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. """
  2. 阿里云 OSS 客户端
  3. 用于上传和管理租户的知识库文档
  4. 采用"单 Bucket + 租户前缀"的方式
  5. """
  6. import oss2
  7. import os
  8. from typing import Optional, Tuple
  9. from datetime import datetime
  10. class OSSClient:
  11. def __init__(self):
  12. # 从环境变量读取阿里云 OSS 配置
  13. self.access_key_id = os.getenv("ALIYUN_OSS_ACCESS_KEY_ID")
  14. self.access_key_secret = os.getenv("ALIYUN_OSS_ACCESS_KEY_SECRET")
  15. self.endpoint = os.getenv("ALIYUN_OSS_ENDPOINT", "oss-cn-hangzhou.aliyuncs.com")
  16. self.bucket_name = os.getenv("ALIYUN_OSS_BUCKET", "chat-ai-knowledge")
  17. # 初始化 OSS 认证和 Bucket
  18. auth = oss2.Auth(self.access_key_id, self.access_key_secret)
  19. self.bucket = oss2.Bucket(auth, self.endpoint, self.bucket_name)
  20. def upload_file(self, tenant_id: str, file_content: bytes, filename: str) -> Tuple[bool, str]:
  21. """
  22. 上传文件到 OSS
  23. :param tenant_id: 租户ID (如 com.xiaoyouhui)
  24. :param file_content: 文件内容(字节)
  25. :param filename: 原始文件名
  26. :return: (是否成功, OSS路径或错误信息)
  27. """
  28. try:
  29. # 构造 OSS 路径: {tenant_id}/documents/{timestamp}_{filename}
  30. timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S")
  31. oss_path = f"{tenant_id}/documents/{timestamp}_{filename}"
  32. # 上传文件
  33. result = self.bucket.put_object(oss_path, file_content)
  34. if result.status == 200:
  35. return True, oss_path
  36. else:
  37. return False, f"上传失败,状态码: {result.status}"
  38. except Exception as e:
  39. return False, f"上传异常: {str(e)}"
  40. def download_file(self, oss_path: str) -> Optional[bytes]:
  41. """
  42. 从 OSS 下载文件
  43. :param oss_path: OSS 中的文件路径
  44. :return: 文件内容(字节)或 None
  45. """
  46. try:
  47. result = self.bucket.get_object(oss_path)
  48. return result.read()
  49. except Exception as e:
  50. print(f"下载文件失败: {str(e)}")
  51. return None
  52. def delete_file(self, oss_path: str) -> bool:
  53. """
  54. 删除 OSS 中的文件
  55. :param oss_path: OSS 中的文件路径
  56. :return: 是否成功
  57. """
  58. try:
  59. self.bucket.delete_object(oss_path)
  60. return True
  61. except Exception as e:
  62. print(f"删除文件失败: {str(e)}")
  63. return False
  64. def get_file_url(self, oss_path: str, expires: int = 3600) -> Optional[str]:
  65. """
  66. 生成文件的临时访问 URL
  67. :param oss_path: OSS 中的文件路径
  68. :param expires: 过期时间(秒),默认1小时
  69. :return: 临时访问URL
  70. """
  71. try:
  72. url = self.bucket.sign_url('GET', oss_path, expires)
  73. return url
  74. except Exception as e:
  75. print(f"生成URL失败: {str(e)}")
  76. return None
  77. # 全局单例
  78. _oss_client = None
  79. def get_oss_client() -> OSSClient:
  80. """获取 OSS 客户端单例"""
  81. global _oss_client
  82. if _oss_client is None:
  83. _oss_client = OSSClient()
  84. return _oss_client