add cos
This commit is contained in:
@@ -19,7 +19,7 @@ class AuditLog(Base):
|
||||
request_data: Mapped[Optional[dict]] = mapped_column(MySQLJSON, comment="请求数据")
|
||||
response_data: Mapped[Optional[dict]] = mapped_column(MySQLJSON, comment="响应数据")
|
||||
token_usage: Mapped[Optional[dict]] = mapped_column(MySQLJSON, comment="消耗的token数量")
|
||||
cost: Mapped[Optional[float]] = mapped_column(Numeric(10, 5), comment="API调用成本")
|
||||
cost: Mapped[Optional[float]] = mapped_column(Numeric(10, 6), comment="API调用成本")
|
||||
duration: Mapped[Optional[float]] = mapped_column(Float, comment="调用耗时(秒)")
|
||||
status_code: Mapped[Optional[int]] = mapped_column(Integer, comment="HTTP状态码")
|
||||
image_id: Mapped[Optional[int]] = mapped_column(BigInteger, ForeignKey('image.id'), comment="关联的图片ID")
|
||||
|
||||
@@ -31,9 +31,10 @@ class AddFileParam(FileSchemaBase):
|
||||
pass
|
||||
|
||||
|
||||
class UpdateFileParam(FileSchemaBase):
|
||||
class UpdateFileParam(SchemaBase):
|
||||
"""更新文件参数"""
|
||||
pass
|
||||
storage_path: Optional[str] = None
|
||||
metadata_info: Optional[FileMetadata] = None
|
||||
|
||||
|
||||
class FileInfoSchema(FileSchemaBase):
|
||||
|
||||
@@ -135,7 +135,8 @@ class FileService:
|
||||
# 其他存储方式(包括COS),使用真实的文件ID保存文件
|
||||
storage_path = await storage_provider.save(
|
||||
file_id=file_id,
|
||||
content=content
|
||||
content=content,
|
||||
file_name=file.filename,
|
||||
)
|
||||
|
||||
# 更新数据库中的存储路径
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import hashlib
|
||||
import os
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
import aiofiles
|
||||
from fastapi import UploadFile
|
||||
|
||||
from qcloud_cos import CosConfig
|
||||
from qcloud_cos import CosS3Client
|
||||
|
||||
from backend.core.conf import settings
|
||||
from backend.core.path_conf import UPLOAD_DIR
|
||||
|
||||
|
||||
class StorageProvider(ABC):
|
||||
@@ -87,21 +84,26 @@ class CosStorage(StorageProvider):
|
||||
|
||||
def __init__(self):
|
||||
"""初始化COS客户端"""
|
||||
import logging
|
||||
# Reduce verbosity of COS client logging
|
||||
logging.getLogger('qcloud_cos').setLevel(logging.WARNING)
|
||||
|
||||
secret_id = settings.COS_SECRET_ID
|
||||
secret_key = settings.COS_SECRET_KEY
|
||||
region = settings.COS_REGION
|
||||
bucket = settings.COS_BUCKET
|
||||
config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key)
|
||||
self.basic_dir = settings.COS_BASIC_DIR
|
||||
self.client = CosS3Client(config)
|
||||
self.bucket = bucket
|
||||
|
||||
def _get_key(self, file_id: int) -> str:
|
||||
"""构建COS对象键"""
|
||||
return f"{self.bucket}/{file_id}"
|
||||
return f"{self.basic_dir}/{file_id}"
|
||||
|
||||
async def save(self, file_id: int, content: bytes) -> str:
|
||||
async def save(self, file_id: int, content: bytes, file_name: str) -> str:
|
||||
"""保存文件到COS"""
|
||||
key = self._get_key(file_id, file_name)
|
||||
key = self._get_key(file_id)
|
||||
|
||||
# 上传文件到COS
|
||||
response = self.client.put_object(
|
||||
@@ -115,7 +117,7 @@ class CosStorage(StorageProvider):
|
||||
# 返回存储路径(即对象键)
|
||||
return key
|
||||
|
||||
async def read(self, file_id: int) -> bytes:
|
||||
async def read(self, file_id: int, storage_path: str) -> bytes:
|
||||
"""从COS读取文件"""
|
||||
# 下载文件
|
||||
response = self.client.get_object(
|
||||
|
||||
@@ -89,6 +89,5 @@ class UpdateImageParam(ImageInfoSchemaBase):
|
||||
|
||||
class ProcessImageRequest(BaseModel):
|
||||
file_id: int
|
||||
cloud_id: str
|
||||
type: str = "word"
|
||||
dict_level: Optional[DictLevel] = Field(None, description="词典等级")
|
||||
@@ -414,7 +414,7 @@ class RecordingService:
|
||||
# }
|
||||
|
||||
# 计算成本 (假设每次调用固定成本)
|
||||
cost = 0.004 # 4元/千次
|
||||
cost = round(0.004, 6) # 4元/千次
|
||||
|
||||
# 构造请求数据
|
||||
request_data = {
|
||||
|
||||
@@ -52,6 +52,10 @@ def setup_logging() -> None:
|
||||
logging.getLogger(name).handlers = []
|
||||
if 'uvicorn.access' in name or 'watchfiles.main' in name:
|
||||
logging.getLogger(name).propagate = False
|
||||
elif 'qcloud_cos' in name or 'urllib3' in name or 'botocore' in name:
|
||||
# Suppress verbose logging from COS client and its dependencies
|
||||
logging.getLogger(name).setLevel(logging.WARNING)
|
||||
logging.getLogger(name).propagate = True
|
||||
else:
|
||||
logging.getLogger(name).propagate = True
|
||||
|
||||
|
||||
@@ -124,7 +124,6 @@ class CustomHTTPBearer(HTTPBearer):
|
||||
# Validate and attach user to request
|
||||
token = credentials.credentials
|
||||
user = await jwt_authentication(token)
|
||||
request.user = user
|
||||
return credentials
|
||||
except HTTPException as e:
|
||||
if e.status_code == 403 or e.status_code == 401:
|
||||
|
||||
@@ -56,6 +56,7 @@ class Settings(BaseSettings):
|
||||
COS_SECRET_KEY: str
|
||||
COS_REGION: str
|
||||
COS_BUCKET: str
|
||||
COS_BASIC_DIR: str
|
||||
YOUDAO_APP_ID: str
|
||||
YOUDAO_APP_SECRET: str
|
||||
|
||||
|
||||
@@ -411,7 +411,8 @@ class Qwen:
|
||||
elif api_type == "embedding":
|
||||
# 假设每张图片 $0.001
|
||||
cost = 0.01
|
||||
return cost
|
||||
# Round to 6 decimal places to prevent data truncation issues
|
||||
return round(cost, 6)
|
||||
|
||||
@staticmethod
|
||||
def _audit_log(api_type: str, params: CreateAuditLogParam):
|
||||
|
||||
@@ -427,7 +427,7 @@ class TencentCloud:
|
||||
},
|
||||
response_data=result,
|
||||
token_usage={},
|
||||
cost=(len(content) / 10000) * 2.4, # 2.4 全 / 1 万字
|
||||
cost=round((len(content) / 10000) * 2.4, 6), # 2.4 全 / 1 万字
|
||||
duration=duration,
|
||||
status_code=status_code,
|
||||
error_message=error_message,
|
||||
|
||||
Reference in New Issue
Block a user