Files
012-kaopeilian/backend/app/api/v1/endpoints/recommendation.py
yuliang_guo 64f5d567fa
Some checks failed
continuous-integration/drone/push Build is failing
feat: 实现 KPL 系统功能改进计划
1. 课程学习进度追踪
   - 新增 UserCourseProgress 和 UserMaterialProgress 模型
   - 新增 /api/v1/progress/* 进度追踪 API
   - 更新 admin.py 使用真实课程完成率数据

2. 路由权限检查完善
   - 新增前端 permissionChecker.ts 权限检查工具
   - 更新 router/guard.ts 实现团队和课程权限验证
   - 新增后端 permission_service.py

3. AI 陪练音频转文本
   - 新增 speech_recognition.py 语音识别服务
   - 新增 /api/v1/speech/* API
   - 更新 ai-practice-coze.vue 支持语音输入

4. 双人对练报告生成
   - 更新 practice_room_service.py 添加报告生成功能
   - 新增 /rooms/{room_code}/report API
   - 更新 duo-practice-report.vue 调用真实 API

5. 学习提醒推送
   - 新增 notification_service.py 通知服务
   - 新增 scheduler_service.py 定时任务服务
   - 支持钉钉、企微、站内消息推送

6. 智能学习推荐
   - 新增 recommendation_service.py 推荐服务
   - 新增 /api/v1/recommendations/* API
   - 支持错题、能力、进度、热门多维度推荐

7. 安全问题修复
   - DEBUG 默认值改为 False
   - 添加 SECRET_KEY 安全警告
   - 新增 check_security_settings() 检查函数

8. 证书 PDF 生成
   - 更新 certificate_service.py 添加 PDF 生成
   - 添加 weasyprint、Pillow、qrcode 依赖
   - 更新下载 API 支持 PDF 和 PNG 格式
2026-01-30 14:22:35 +08:00

158 lines
4.3 KiB
Python

"""
智能学习推荐 API
"""
from typing import List, Optional
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel
from app.core.database import get_db
from app.api.deps import get_current_user
from app.models.user import User
from app.services.recommendation_service import RecommendationService
router = APIRouter()
# ============ Schemas ============
class CourseRecommendation(BaseModel):
"""课程推荐响应"""
course_id: int
course_name: str
category: Optional[str] = None
cover_image: Optional[str] = None
description: Optional[str] = None
progress_percent: Optional[float] = None
student_count: Optional[int] = None
source: Optional[str] = None
reason: Optional[str] = None
class KnowledgePointRecommendation(BaseModel):
"""知识点推荐响应"""
knowledge_point_id: int
name: str
description: Optional[str] = None
type: Optional[str] = None
course_id: int
mistake_count: Optional[int] = None
reason: Optional[str] = None
class RecommendationResponse(BaseModel):
"""推荐响应"""
code: int = 200
message: str = "success"
data: dict
# ============ API Endpoints ============
@router.get("/courses", response_model=RecommendationResponse)
async def get_course_recommendations(
limit: int = Query(10, ge=1, le=50, description="推荐数量"),
include_reasons: bool = Query(True, description="是否包含推荐理由"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""
获取个性化课程推荐
推荐策略:
- 基于错题分析推荐相关课程
- 基于能力评估推荐弱项课程
- 基于学习进度推荐未完成课程
- 基于热门程度推荐高人气课程
"""
service = RecommendationService(db)
recommendations = await service.get_recommendations(
user_id=current_user.id,
limit=limit,
include_reasons=include_reasons,
)
return RecommendationResponse(
code=200,
message="获取推荐成功",
data={
"recommendations": recommendations,
"total": len(recommendations),
}
)
@router.get("/knowledge-points", response_model=RecommendationResponse)
async def get_knowledge_point_recommendations(
limit: int = Query(5, ge=1, le=20, description="推荐数量"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""
获取知识点复习推荐
基于错题记录推荐需要重点复习的知识点
"""
service = RecommendationService(db)
recommendations = await service.get_knowledge_point_recommendations(
user_id=current_user.id,
limit=limit,
)
return RecommendationResponse(
code=200,
message="获取推荐成功",
data={
"recommendations": recommendations,
"total": len(recommendations),
}
)
@router.get("/summary")
async def get_recommendation_summary(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""
获取推荐摘要
返回各类推荐的概要信息
"""
service = RecommendationService(db)
# 获取各类推荐
all_recs = await service.get_recommendations(
user_id=current_user.id,
limit=20,
include_reasons=True,
)
# 按来源分类统计
source_counts = {}
for rec in all_recs:
source = rec.get("source", "other")
source_counts[source] = source_counts.get(source, 0) + 1
# 获取知识点推荐
kp_recs = await service.get_knowledge_point_recommendations(
user_id=current_user.id,
limit=5,
)
return {
"code": 200,
"message": "success",
"data": {
"total_recommendations": len(all_recs),
"source_breakdown": {
"mistake_based": source_counts.get("mistake", 0),
"ability_based": source_counts.get("ability", 0),
"progress_based": source_counts.get("progress", 0),
"popular": source_counts.get("popular", 0),
},
"weak_knowledge_points": len(kp_recs),
"top_recommendation": all_recs[0] if all_recs else None,
}
}