Files
012-kaopeilian/backend/app/api/v1/broadcast.py
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

146 lines
4.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
播课功能 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
)
)