You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

6.2 KiB

AI API 异常处理标准化

变更日期: 2026-02-11
变更类型: 重构 (Refactor)
影响范围: server/app/api/v1/ai.py
相关文档: API 响应格式标准化


📋 变更摘要

修复 ai.py 的异常处理不规范问题,删除所有手动 try-except 块,让 Service 层异常直接传播至 FastAPI 全局异常处理器。

核心问题

原代码存在 14 个路由,每个都包含冗余的异常捕获:

# ❌ 错误模式:手动捕获并重新抛出
try:
    result = await service.generate_image(...)
    return SuccessResponse(data=result)
except InsufficientCreditsError as e:
    raise InsufficientCreditsError(str(e))  # 冗余
except ValidationError as e:
    raise ValidationError(str(e))  # 冗余
except Exception as e:
    raise HTTPException(500, "服务器内部错误")  # 应由 Service 层处理

修复内容

1. 删除所有手动异常捕获

修改前(以 generate_image 为例):

@router.post("/generate-image")
async def generate_image(...):
    service = AIService(db)
    try:
        result = await service.generate_image(...)
        return SuccessResponse(data=result)
    except InsufficientCreditsError as e:
        raise InsufficientCreditsError(str(e))
    except ValidationError as e:
        raise ValidationError(str(e))
    except Exception as e:
        raise HTTPException(500, "服务器内部错误")

修改后

@router.post("/generate-image")
async def generate_image(...):
    """生成图片
    
    - **prompt**: 提示词(必填)
    - **model**: 模型名称(可选)
    """
    logger.info("收到图片生成请求: user_id=%s", current_user.user_id)
    service = AIService(db)
    
    result = await service.generate_image(
        user_id=str(current_user.user_id),
        prompt=request.prompt,
        model=request.model,
        # ...
    )
    logger.info("图片生成任务创建成功: job_id=%s", result['job_id'])
    return SuccessResponse(data=result, message="图片生成任务创建成功")

2. 清理冗余导入

删除

from fastapi import HTTPException, status  # ❌ 删除
from app.core.exceptions import ValidationError, NotFoundError, InsufficientCreditsError  # ❌ 删除

保留

from app.core.logging import get_logger  # ✅ 保留日志记录
from app.schemas.common import SuccessResponse  # ✅ 保留标准响应

🎯 技术规范

Service 层职责

  • AIService 负责抛出业务异常:
    • InsufficientCreditsError - 积分不足
    • ValidationError - 参数校验失败
    • NotFoundError - 任务不存在
    • NotImplementedError - 功能未实现
    • InternalServerError - 服务器内部错误

API 层职责

  • :接收请求、调用 Service、返回标准响应
  • :记录请求日志(info/warning/error)
  • 不做:捕获业务异常
  • 不做:手动转换异常类型

FastAPI 全局异常处理器

# app/core/exception_handlers.py (已有配置)
@app.exception_handler(InsufficientCreditsError)
async def insufficient_credits_handler(request, exc):
    return JSONResponse(
        status_code=exc.status_code,
        content={"code": 40302, "message": exc.detail}
    )

📦 影响的路由 (14 个)

路由 方法 说明
/ai/generate-image POST 生成图片
/ai/generate-video POST 生成视频
/ai/generate-sound POST 生成音效
/ai/generate-voice POST 生成配音
/ai/voices GET 获取音色列表
/ai/generate-subtitle POST 生成字幕
/ai/process-text POST 处理文本
/ai/jobs GET 批量查询任务
/ai/jobs/{job_id} GET 查询任务状态
/ai/jobs/{job_id}/cancel POST 取消任务
/ai/statistics GET 获取任务统计
/ai/usage/stats GET 获取使用统计
/ai/queue/status GET 获取队列状态
/ai/models GET 获取可用模型

🔍 代码质量提升

行数优化

  • 修改前: 430 行(含大量 try-except)
  • 修改后: 290 行
  • 减少: 140 行(-33%)

可读性提升

# ✅ 清晰的业务逻辑流(修改后)
async def generate_image(...):
    logger.info("收到图片生成请求")
    service = AIService(db)
    result = await service.generate_image(...)  # Service 层会抛异常
    logger.info("图片生成任务创建成功")
    return SuccessResponse(data=result)  # FastAPI 自动处理异常

🧪 验证方法

1. 积分不足场景

# 请求
POST /api/v1/ai/generate-image
{
  "prompt": "未来城市",
  "width": 2048,
  "height": 2048
}

# 响应(由 Service 层抛出,全局处理器捕获)
HTTP 403 Forbidden
{
  "code": 40302,
  "message": "积分不足,当前积分: 10,需要: 50",
  "timestamp": "2026-02-11T10:30:00Z"
}

2. 参数校验失败

# 请求
POST /api/v1/ai/generate-video
{
  "video_type": "text2video",
  "prompt": ""  # 空提示词
}

# 响应(由 Service 层抛出)
HTTP 422 Unprocessable Entity
{
  "code": 42201,
  "message": "prompt 不能为空",
  "timestamp": "2026-02-11T10:31:00Z"
}

3. 任务不存在

# 请求
GET /api/v1/ai/jobs/nonexistent-job-id

# 响应(由 Service 层抛出)
HTTP 404 Not Found
{
  "code": 40401,
  "message": "任务不存在",
  "timestamp": "2026-02-11T10:32:00Z"
}

🔗 相关链接


📌 注意事项

  1. 不影响现有功能:异常仍会被正确处理,只是处理位置从 API 层移至全局
  2. 日志保留:所有 logger.info/warning/error 调用均保留,用于追踪请求流程
  3. 向后兼容:响应格式完全不变,前端无需修改

变更人: Claude
审核人: 待定
部署状态: 已完成