This commit is contained in:
felix
2025-11-26 16:12:03 +08:00
parent 50a2c20482
commit 4e27370bf7
11 changed files with 24 additions and 16 deletions

View File

@@ -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")

View File

@@ -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):

View File

@@ -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,
)
# 更新数据库中的存储路径

View File

@@ -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(

View File

@@ -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="词典等级")

View File

@@ -414,7 +414,7 @@ class RecordingService:
# }
# 计算成本 (假设每次调用固定成本)
cost = 0.004 # 4元/千次
cost = round(0.004, 6) # 4元/千次
# 构造请求数据
request_data = {

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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):

View File

@@ -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,