# -*- coding = utf-8 -*- # @Time : 2025/2/13 下午4:50 # @File : routes.py # @Software : PyCharm # @Author : xingc # @Desc : import hashlib import logging from io import BytesIO from pathlib import Path from typing import Literal from urllib.parse import urljoin from fastapi import APIRouter, UploadFile, File, status, HTTPException, Depends from PIL import Image from config import settings from core.base.schema import BaseResponse from core.routers.auth.schema import LoginUser from core.routers.auth.services import get_current_user from . import schema logger = logging.getLogger(__name__) file_router = APIRouter(prefix='/file', tags=['文件存储模块']) @file_router.post('/{upload_type}/upload', summary='图片上传', response_model=BaseResponse[schema.FileOut]) async def upload_file( upload_type: Literal['card', 'chat', 'avatar'], file: UploadFile = File(...), login_user: LoginUser = Depends(get_current_user) ): # 验证文件类型 if file.content_type not in settings.UPLOADED_ALLOWED_MIME_TYPES: raise HTTPException( status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, detail=f'Unsupported media type: {file.content_type}' ) # 验证文件大小 if file.size > settings.UPLOADED_MAX_FILE_SIZE: raise HTTPException( status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, detail=f'File exceeds maximum size' ) try: file_chunks = await file.read() file_hash = hashlib.sha256(file_chunks).hexdigest() file_name = f'{file_hash}.jpg' dirname_args = [upload_type.lower(), str(login_user.user_id), file_name] save_file_path: Path = settings.UPLOADED_FILES_DIR.joinpath(*dirname_args) if save_file_path.exists() is False: # 创建目录 save_file_path.parent.mkdir(parents=True, exist_ok=True) img = Image.open(BytesIO(file_chunks)) img = img.convert("RGB") img.save(save_file_path, format="JPEG") file_info = { 'filename': file_name, 'content_type': file.content_type, 'size': file.size, 'hash': file_hash, 'url': urljoin(settings.ASSETS_BASE_URL, '/'.join([settings.UPLOADED_FILES_DIR.name, *dirname_args])), } return {'data': file_info} except Exception as e: logger.error(f'Upload failed: {e}') logger.exception(e) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='Internal server error' )