feat: 初始化考培练系统项目
- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
This commit is contained in:
145
backend/app/api/v1/broadcast.py
Normal file
145
backend/app/api/v1/broadcast.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
播课功能 API 接口
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.deps import get_db, get_current_user, require_admin_or_manager
|
||||
from app.schemas.base import ResponseModel
|
||||
from app.models.course import Course
|
||||
from app.models.user import User
|
||||
from app.services.coze_broadcast_service import broadcast_service
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# Schema 定义
|
||||
class GenerateBroadcastResponse(BaseModel):
|
||||
"""生成播课响应"""
|
||||
message: str = Field(..., description="提示信息")
|
||||
|
||||
|
||||
class BroadcastInfo(BaseModel):
|
||||
"""播课信息"""
|
||||
has_broadcast: bool = Field(..., description="是否有播课")
|
||||
mp3_url: Optional[str] = Field(None, description="播课音频URL")
|
||||
generated_at: Optional[datetime] = Field(None, description="生成时间")
|
||||
|
||||
|
||||
@router.post("/courses/{course_id}/generate-broadcast", response_model=ResponseModel[GenerateBroadcastResponse])
|
||||
async def generate_broadcast(
|
||||
course_id: int,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(require_admin_or_manager)
|
||||
):
|
||||
"""
|
||||
触发播课音频生成(立即返回,Coze工作流会直接写数据库)
|
||||
|
||||
权限:manager、admin
|
||||
|
||||
Args:
|
||||
course_id: 课程ID
|
||||
db: 数据库会话
|
||||
current_user: 当前用户
|
||||
|
||||
Returns:
|
||||
启动提示信息
|
||||
|
||||
Raises:
|
||||
HTTPException 404: 课程不存在
|
||||
"""
|
||||
logger.info(
|
||||
f"请求生成播课",
|
||||
extra={"course_id": course_id, "user_id": current_user.id}
|
||||
)
|
||||
|
||||
# 查询课程
|
||||
result = await db.execute(
|
||||
select(Course)
|
||||
.where(Course.id == course_id)
|
||||
.where(Course.is_deleted == False)
|
||||
)
|
||||
course = result.scalar_one_or_none()
|
||||
|
||||
if not course:
|
||||
logger.warning(f"课程不存在", extra={"course_id": course_id})
|
||||
raise HTTPException(status_code=404, detail="课程不存在")
|
||||
|
||||
# 调用 Coze 工作流(不等待结果,工作流会直接写数据库)
|
||||
try:
|
||||
await broadcast_service.trigger_workflow(course_id)
|
||||
|
||||
logger.info(
|
||||
f"播课生成工作流已触发",
|
||||
extra={"course_id": course_id, "user_id": current_user.id}
|
||||
)
|
||||
|
||||
return ResponseModel(
|
||||
code=200,
|
||||
message="播课生成已启动",
|
||||
data=GenerateBroadcastResponse(
|
||||
message="播课生成工作流已启动,生成完成后将自动更新"
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"触发播课生成失败",
|
||||
extra={"course_id": course_id, "error": str(e)}
|
||||
)
|
||||
raise HTTPException(status_code=500, detail=f"触发播课生成失败: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/courses/{course_id}/broadcast", response_model=ResponseModel[BroadcastInfo])
|
||||
async def get_broadcast_info(
|
||||
course_id: int,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
获取播课信息
|
||||
|
||||
权限:所有登录用户
|
||||
|
||||
Args:
|
||||
course_id: 课程ID
|
||||
db: 数据库会话
|
||||
current_user: 当前用户
|
||||
|
||||
Returns:
|
||||
播课信息
|
||||
|
||||
Raises:
|
||||
HTTPException 404: 课程不存在
|
||||
"""
|
||||
# 查询课程
|
||||
result = await db.execute(
|
||||
select(Course)
|
||||
.where(Course.id == course_id)
|
||||
.where(Course.is_deleted == False)
|
||||
)
|
||||
course = result.scalar_one_or_none()
|
||||
|
||||
if not course:
|
||||
raise HTTPException(status_code=404, detail="课程不存在")
|
||||
|
||||
# 构建播课信息
|
||||
has_broadcast = bool(course.broadcast_audio_url)
|
||||
|
||||
return ResponseModel(
|
||||
code=200,
|
||||
message="success",
|
||||
data=BroadcastInfo(
|
||||
has_broadcast=has_broadcast,
|
||||
mp3_url=course.broadcast_audio_url if has_broadcast else None,
|
||||
generated_at=course.broadcast_generated_at if has_broadcast else None
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user