合并腾讯 qcloud 相关代码

This commit is contained in:
aaron 2025-01-24 22:06:56 +08:00
parent fd28f612b4
commit f2891a17c0
4 changed files with 151 additions and 124 deletions

View File

@ -1,8 +1,6 @@
from fastapi import APIRouter, UploadFile, File, Depends from fastapi import APIRouter, UploadFile, File, Depends
from typing import List from typing import List
import uuid from app.core.qcloud import qcloud_manager
from datetime import datetime
from app.core.cos import cos_manager
from app.core.config import settings from app.core.config import settings
from app.models.upload import UploadResponse, MultiUploadResponse from app.models.upload import UploadResponse, MultiUploadResponse
from app.core.response import success_response, error_response, ResponseModel from app.core.response import success_response, error_response, ResponseModel
@ -11,24 +9,6 @@ from app.models.user import UserDB
router = APIRouter() router = APIRouter()
async def upload_to_cos(file: UploadFile) -> str:
"""上传文件到腾讯云COS"""
# 生成唯一文件名
ext = file.filename.split('.')[-1] if '.' in file.filename else ''
filename = f"{datetime.now().strftime('%Y%m%d')}/{uuid.uuid4()}.{ext}"
# 上传文件
cos_manager.put_object(
Bucket=settings.COS_BUCKET,
Body=await file.read(),
Key=filename,
ContentType=file.content_type,
ACL="public-read"
)
# 返回文件URL
return f"https://{settings.COS_BASE_URL}/{filename}"
@router.post("/image", response_model=ResponseModel) @router.post("/image", response_model=ResponseModel)
async def upload_image( async def upload_image(
file: UploadFile = File(...), file: UploadFile = File(...),
@ -39,7 +19,7 @@ async def upload_image(
return error_response(code=400, message="只能上传图片文件") return error_response(code=400, message="只能上传图片文件")
try: try:
url = await upload_to_cos(file) url = await qcloud_manager.upload_file(file)
return success_response(data=UploadResponse(url=url)) return success_response(data=UploadResponse(url=url))
except Exception as e: except Exception as e:
return error_response(code=500, message=f"上传失败: {str(e)}") return error_response(code=500, message=f"上传失败: {str(e)}")
@ -58,7 +38,7 @@ async def upload_images(
for file in files: for file in files:
if not file.content_type.startswith('image/'): if not file.content_type.startswith('image/'):
return error_response(code=400, message="只能上传图片文件") return error_response(code=400, message="只能上传图片文件")
url = await upload_to_cos(file) url = await qcloud_manager.upload_file(file)
urls.append(url) urls.append(url)
return success_response(data=MultiUploadResponse(urls=urls)) return success_response(data=MultiUploadResponse(urls=urls))
except Exception as e: except Exception as e:
@ -72,7 +52,7 @@ async def get_presigned_url(
"""获取预签名上传URL""" """获取预签名上传URL"""
key = f"uploads/{current_user.userid}/{filename}" key = f"uploads/{current_user.userid}/{filename}"
try: try:
url = cos_manager.get_upload_url(key) url = qcloud_manager.get_upload_url(key)
return success_response(data={ return success_response(data={
"url": url, "url": url,
"key": key "key": key

View File

@ -38,31 +38,10 @@ redis_client = redis.Redis(
async def send_verify_code(request: VerifyCodeRequest): async def send_verify_code(request: VerifyCodeRequest):
"""发送验证码""" """发送验证码"""
phone = request.phone phone = request.phone
code = ''.join(random.choices(string.digits, k=6))
try: try:
# 实例化认证对象 # 发送验证码
cred = credential.Credential( code, request_id = await qcloud_manager.send_sms_code(phone)
settings.TENCENT_SECRET_ID,
settings.TENCENT_SECRET_KEY
)
# 实例化短信客户端
client = sms_client.SmsClient(cred, "ap-guangzhou")
# 组装请求参数
req = models.SendSmsRequest()
req.SmsSdkAppId = settings.SMS_SDK_APP_ID
req.SignName = settings.SMS_SIGN_NAME
req.TemplateId = settings.SMS_TEMPLATE_ID
req.TemplateParamSet = [code]
req.PhoneNumberSet = [f"+86{phone}"]
# 发送短信
resp = client.SendSms(req)
if resp.SendStatusSet[0].Code != "Ok":
return error_response(message=f"短信发送失败: {resp.SendStatusSet[0].Message}")
# 存储验证码到 Redis # 存储验证码到 Redis
redis_client.setex( redis_client.setex(
@ -73,7 +52,7 @@ async def send_verify_code(request: VerifyCodeRequest):
return success_response(message="验证码已发送") return success_response(message="验证码已发送")
except TencentCloudSDKException as e: except Exception as e:
return error_response(message=f"发送验证码失败: {str(e)}") return error_response(message=f"发送验证码失败: {str(e)}")
@router.post("/login") @router.post("/login")

View File

@ -1,69 +0,0 @@
from qcloud_cos import CosConfig, CosS3Client
from app.core.config import settings
import sys
import logging
# 正常情况日志级别使用INFO需要定位时可以修改为DEBUG此时SDK会打印和服务端的通信信息
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
class COSManager:
def __init__(self):
config = CosConfig(
Region=settings.COS_REGION,
SecretId=settings.TENCENT_SECRET_ID,
SecretKey=settings.TENCENT_SECRET_KEY
)
self.client = CosS3Client(config)
def get_upload_url(self, key: str, expires: int = 3600) -> str:
"""
获取预签名上传URL
Args:
key: 对象键
expires: 签名有效期
Returns:
预签名URL
"""
try:
url = self.client.get_presigned_url(
Method='PUT',
Bucket=settings.COS_BUCKET,
Key=key,
Expired=expires
)
return url
except Exception as e:
logging.error(f"获取上传URL失败: {str(e)}")
raise
def get_download_url(self, key: str, expires: int = 3600) -> str:
"""
获取预签名下载URL
Args:
key: 对象键
expires: 签名有效期
Returns:
预签名URL
"""
try:
url = self.client.get_presigned_url(
Method='GET',
Bucket=settings.COS_BUCKET,
Key=key,
Expired=expires
)
return url
except Exception as e:
logging.error(f"获取下载URL失败: {str(e)}")
raise
def put_object(self, **kwargs):
"""上传对象的封装方法"""
return self.client.put_object(**kwargs)
# 创建全局 COS 客户端实例
cos_manager = COSManager()

View File

@ -3,8 +3,15 @@ from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.faceid.v20180301 import faceid_client, models from tencentcloud.faceid.v20180301 import faceid_client, models
from tencentcloud.sms.v20210111 import sms_client, models as sms_models
from qcloud_cos import CosConfig, CosS3Client
from app.core.config import settings from app.core.config import settings
import json import json
import random
import string
import uuid
from datetime import datetime
from fastapi import UploadFile
class QCloudManager: class QCloudManager:
"""腾讯云服务管理类""" """腾讯云服务管理类"""
@ -18,18 +25,87 @@ class QCloudManager:
# 配置 HTTP # 配置 HTTP
self.http_profile = HttpProfile() self.http_profile = HttpProfile()
self.http_profile.endpoint = "faceid.tencentcloudapi.com"
# 配置 Client # 配置 Client
self.client_profile = ClientProfile() self.client_profile = ClientProfile()
self.client_profile.httpProfile = self.http_profile self.client_profile.httpProfile = self.http_profile
# 初始化人脸识别客户端 # 初始化客户端
self.faceid_client = faceid_client.FaceidClient( self.sms_client = None
self.cred, self.faceid_client = None
settings.TENCENT_REGION, self.cos_client = None
self.client_profile
) def _init_faceid_client(self):
"""初始化人脸识别客户端"""
if not self.faceid_client:
self.http_profile.endpoint = "faceid.tencentcloudapi.com"
self.faceid_client = faceid_client.FaceidClient(
self.cred,
settings.TENCENT_REGION,
self.client_profile
)
def _init_sms_client(self):
"""初始化短信客户端"""
if not self.sms_client:
self.http_profile.endpoint = "sms.tencentcloudapi.com"
self.sms_client = sms_client.SmsClient(
self.cred,
settings.TENCENT_REGION
)
def _init_cos_client(self):
"""初始化 COS 客户端"""
if not self.cos_client:
config = CosConfig(
Region=settings.COS_REGION,
SecretId=settings.TENCENT_SECRET_ID,
SecretKey=settings.TENCENT_SECRET_KEY
)
self.cos_client = CosS3Client(config)
def generate_verify_code(self, length: int = 6) -> str:
"""生成验证码"""
return ''.join(random.choices(string.digits, k=length))
async def send_sms_code(self, phone: str) -> tuple[str, str]:
"""
发送短信验证码
Args:
phone: 手机号
Returns:
tuple: (验证码, 请求ID)
Raises:
Exception: 发送失败时抛出异常
"""
try:
self._init_sms_client()
# 生成验证码
code = self.generate_verify_code()
# 构建请求
req = sms_models.SendSmsRequest()
req.SmsSdkAppId = settings.SMS_SDK_APP_ID
req.SignName = settings.SMS_SIGN_NAME
req.TemplateId = settings.SMS_TEMPLATE_ID
req.TemplateParamSet = [code]
req.PhoneNumberSet = [f"+86{phone}"]
# 发送短信
response = self.sms_client.SendSms(req)
# 检查发送结果
if response.SendStatusSet[0].Code != "Ok":
raise Exception(response.SendStatusSet[0].Message)
return code, response.RequestId
except TencentCloudSDKException as e:
raise Exception(f"发送短信失败: {str(e)}")
async def verify_id_card(self, id_card: str, name: str) -> dict: async def verify_id_card(self, id_card: str, name: str) -> dict:
""" """
@ -50,6 +126,8 @@ class QCloudManager:
TencentCloudSDKException: 调用API失败 TencentCloudSDKException: 调用API失败
""" """
try: try:
self._init_faceid_client()
# 构建请求 # 构建请求
req = models.IdCardVerificationRequest() req = models.IdCardVerificationRequest()
params = { params = {
@ -73,5 +151,64 @@ class QCloudManager:
except TencentCloudSDKException as e: except TencentCloudSDKException as e:
raise Exception(f"身份证实名认证失败: {str(e)}") raise Exception(f"身份证实名认证失败: {str(e)}")
async def upload_file(self, file: UploadFile, folder: str = None) -> str:
"""
上传文件到 COS
Args:
file: 上传的文件
folder: 存储文件夹名称默认使用日期
Returns:
str: 文件访问URL
Raises:
Exception: 上传失败时抛出异常
"""
try:
self._init_cos_client()
# 生成存储路径
folder = folder or datetime.now().strftime('%Y%m%d')
ext = file.filename.split('.')[-1] if '.' in file.filename else ''
key = f"{folder}/{uuid.uuid4()}.{ext}"
# 上传文件
self.cos_client.put_object(
Bucket=settings.COS_BUCKET,
Body=await file.read(),
Key=key,
ContentType=file.content_type,
ACL="public-read"
)
# 返回文件URL
return f"https://{settings.COS_BASE_URL}/{key}"
except Exception as e:
raise Exception(f"文件上传失败: {str(e)}")
def get_upload_url(self, key: str, expire: int = 300) -> str:
"""
获取预签名上传URL
Args:
key: 文件路径
expire: 链接有效期()
Returns:
str: 预签名URL
"""
try:
self._init_cos_client()
return self.cos_client.get_presigned_url(
Method='PUT',
Bucket=settings.COS_BUCKET,
Key=key,
Expired=expire
)
except Exception as e:
raise Exception(f"获取上传URL失败: {str(e)}")
# 创建全局实例 # 创建全局实例
qcloud_manager = QCloudManager() qcloud_manager = QCloudManager()