All checks were successful
continuous-integration/drone/push Build is passing
- progress.py: get_db, get_current_user 从 app.core.deps 导入 - speech.py: 同上 - recommendation.py: 同上
157 lines
4.3 KiB
Python
157 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.deps import get_db, 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,
|
|
}
|
|
}
|