一、项目简介
在线学习平台越来越强调"因材施教"。传统课程平台通常只提供固定课程列表,学习者需要自行判断下一步学什么,容易出现课程难度不匹配、重复学习、缺少阶段反馈等问题。本文实现一个 基于机器学习思想的个性化学习系统:用户注册后填写学习目标和偏好难度,系统记录课时完成情况和测验分数,并通过可解释的推荐评分为用户推荐最适合的课程。
本项目不是单纯讲推荐算法,而是一个完整的 Python 全栈项目,包含后端 API、SQLite 数据库、JWT 认证鉴权、Vue 3 前端页面、学习进度管理、课程推荐仪表盘和部署运行说明。
二、技术栈
- 后端:FastAPI、SQLAlchemy、Pydantic、SQLite
- 认证:密码哈希 Passlib + JWT Token
- 前端:Vue 3、Vite、Fetch API
- 数据库:SQLite,本地文件
learning.db - 推荐逻辑:用户画像特征 + 课程标签匹配 + 难度偏好 + 学习进度 + 测验分数加权排序
三、系统架构
系统采用前后端分离架构:
text
浏览器(Vue 3/Vite)
│ 1. 注册/登录,保存 token
│ 2. 携带 Authorization: Bearer <token>
▼
FastAPI 后端服务
│ 1. 校验 JWT
│ 2. 处理课程、进度、推荐接口
▼
SQLite 数据库
│
├─ users 用户表
├─ courses 课程表
├─ lessons 课时表
└─ learning_progress 学习进度表
核心业务流程:
- 用户注册,系统保存密码哈希、学习目标、偏好难度。
- 登录成功后返回 JWT token。
- 前端将 token 存入 localStorage,并在后续请求中放入请求头。
- 用户浏览课程并提交学习进度和测验分数。
- 后端根据用户画像和学习历史计算推荐分。
- 前端展示学习统计、课程列表、推荐结果。
四、功能模块
1. 用户认证模块
- 用户注册
- 用户登录
- 密码哈希存储
- JWT token 生成和校验
- 获取当前登录用户
- 退出登录和前端登录状态管理
2. 课程学习模块
- 课程列表
- 课程详情和课时列表
- 课时完成状态记录
- 测验分数保存
3. 个性化推荐模块
推荐模块使用可解释评分策略:
- 课程标签与用户学习目标匹配,匹配越多得分越高。
- 课程难度与用户偏好难度一致,增加权重。
- 用户已经完整学完的课程降低推荐权重,避免重复推荐。
- 用户平均分较高时,对中高级课程增加权重。
4. 前端交互模块
- 注册页
- 登录页
- 学习仪表盘
- 推荐课程区域
- 课程中心
- 课时完成与打分交互
五、数据库/数据模型设计
users 用户表
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| username | String | 用户名,唯一 |
| String | 邮箱,唯一 | |
| hashed_password | String | 哈希密码 |
| learning_goal | String | 学习目标 |
| preferred_level | String | 偏好难度 |
| is_active | Boolean | 是否启用 |
| created_at | DateTime | 创建时间 |
courses 课程表
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| title | String | 课程标题 |
| description | Text | 课程简介 |
| tags | String | 标签,逗号分隔 |
| level | String | 难度 |
| duration_minutes | Integer | 预计学习时长 |
lessons 课时表
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| course_id | Integer | 所属课程 |
| title | String | 课时标题 |
| content | Text | 课时内容 |
| order_no | Integer | 排序 |
learning_progress 学习进度表
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| user_id | Integer | 用户 ID |
| lesson_id | Integer | 课时 ID |
| completed | Boolean | 是否完成 |
| quiz_score | Float | 测验分数 |
| updated_at | DateTime | 更新时间 |
同一用户和同一课时设置唯一约束,避免重复插入。
六、后端接口设计
| 方法 | 路径 | 是否认证 | 说明 |
|---|---|---|---|
| GET | /api/health |
否 | 健康检查 |
| POST | /api/auth/register |
否 | 用户注册 |
| POST | /api/auth/login |
否 | 用户登录 |
| GET | /api/users/me |
是 | 当前用户信息 |
| GET | /api/courses |
是 | 获取课程与课时 |
| GET | /api/courses/{course_id} |
是 | 课程详情 |
| POST | /api/progress |
是 | 保存学习进度 |
| GET | /api/dashboard |
是 | 学习统计和推荐结果 |
鉴权方式:前端登录后把 token 放入请求头:
http
Authorization: Bearer <access_token>
七、前端页面设计
前端使用 Vue 3 + Vite,主要文件如下:
text
frontend/
package.json
index.html
src/
main.js
App.vue
api.js
style.css
页面结构:
- 顶部标题栏:展示系统名称和退出登录按钮。
- 未登录状态:展示登录表单和注册表单。
- 已登录状态:展示学习仪表盘、推荐课程、课程中心。
- 课程中心:每个课时提供"完成并打分"按钮。
前端请求统一封装在 src/api.js 中,自动读取 localStorage 中的 token,并添加认证请求头。
八、核心代码讲解
1. 数据库连接
backend/app/database.py:
python
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
SQLite 默认不允许跨线程访问连接,FastAPI 开发环境下需要设置 check_same_thread=False。
2. 用户注册与密码哈希
backend/app/main.py:
python
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def get_password_hash(password: str) -> str:
return pwd_context.hash(password)
@app.post("/api/auth/register", response_model=schemas.Token)
def register(data: schemas.UserCreate, db: Session = Depends(get_db)):
if crud.get_user_by_username(db, data.username):
raise HTTPException(status_code=400, detail="用户名已存在")
user = crud.create_user(db, data, get_password_hash(data.password))
token = create_access_token({"sub": user.username})
return {"access_token": token, "token_type": "bearer", "user": user}
后端不会保存明文密码,而是保存 bcrypt 哈希值。
3. JWT 鉴权依赖
python
def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
user = crud.get_user_by_username(db, username=username)
if user is None:
raise credentials_exception
return user
所有核心业务接口都通过 Depends(get_current_user) 保护,未登录用户无法访问课程、进度和推荐数据。
4. 学习进度保存
python
@app.post("/api/progress", response_model=schemas.ProgressOut)
def save_progress(data: schemas.ProgressIn, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user)):
lesson = db.query(models.Lesson).filter(models.Lesson.id == data.lesson_id).first()
if not lesson:
raise HTTPException(status_code=404, detail="课时不存在")
return crud.upsert_progress(db, current_user.id, data)
系统根据当前登录用户写入学习进度,避免用户伪造其他用户 ID。
5. 推荐评分逻辑
python
def recommendation_score(user, course, completed_lesson_ids, avg_score):
tags = set(course.tags.split(","))
goal_words = set(user.learning_goal.lower().replace(",", ",").replace(" ", ",").split(","))
tag_match = len(tags.intersection(goal_words)) * 25
level_match = 30 if course.level == user.preferred_level else 10
completion_penalty = 35 if lesson_ids and lesson_ids.issubset(completed_lesson_ids) else 0
score_boost = 15 if avg_score >= 80 and course.level in {"intermediate", "advanced"} else 5
score = max(0, min(100, 35 + tag_match + level_match + score_boost - completion_penalty))
return score, reason
这段逻辑虽然轻量,但体现了机器学习推荐系统中的关键思想:用户画像、特征工程、打分排序、推荐解释。
6. 前端认证请求封装
frontend/src/api.js:
javascript
export async function request(path, options = {}) {
const headers = { 'Content-Type': 'application/json', ...(options.headers || {}) }
const token = getToken()
if (token) headers.Authorization = `Bearer ${token}`
const response = await fetch(`${API_BASE}${path}`, { ...options, headers })
const data = await response.json().catch(() => ({}))
if (!response.ok) throw new Error(data.detail || '请求失败')
return data
}
前端所有接口调用都走统一封装,保证认证头和错误处理一致。
九、部署与运行步骤
1. 解压项目
bash
unzip 85_fullstack_project.zip
cd project
2. 运行后端
bash
cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
后端默认地址:http://127.0.0.1:8000。
3. 运行前端
另开终端:
bash
cd frontend
npm install
npm run dev
打开 Vite 提示的地址,一般为:http://127.0.0.1:5173。
4. 测试流程
- 注册账号:用户名
demo,密码demo123。 - 学习目标填写:
python,fastapi,机器学习。 - 登录后查看推荐课程。
- 点击课程课时完成按钮,输入测验分数。
- 刷新仪表盘,观察推荐分变化。
十、项目总结
本文完成了一个可运行的 Python 全栈项目:基于机器学习的个性化学习系统。项目具备完整的注册、登录、JWT 鉴权、课程管理、学习进度、推荐计算和 Vue 3 前端交互。相比只展示算法 Demo,本项目更贴近真实业务场景:数据需要落库,接口需要鉴权,前端需要维护登录状态,推荐结果需要和用户行为形成闭环。
后续可以继续扩展:
- 引入协同过滤,根据相似用户推荐课程。
- 增加课程搜索、收藏和评论。
- 增加后台课程管理端。
- 将 SQLite 替换为 PostgreSQL。
- 使用 ECharts 展示学习曲线。
- 将推荐算法封装成独立服务,支持 A/B 测试。
通过该项目,读者可以掌握 FastAPI + SQLite + Vue 3 的完整全栈开发流程,也能理解个性化推荐系统如何从用户画像和学习行为中产生实际业务价值。