新能源汽车推荐系统分享

新能源汽车推荐系统 - 亲手搭的全链路实践

写这套项目时,我想把"看车、选车、对比、收藏、点评"这一整条链路串起来,让它既能跑通功能,又方便大家落地和二次改造。下面按个人实际体验带大家过一遍。

项目概览

  • 前端:React + Vite + TypeScript + Tailwind。组件化拆分卡片、详情、对比、偏好引导、后台面板,样式轻量又易改。
  • 后端:Flask + SQLAlchemy + Flask-Migrate + MySQL,JWT 鉴权。(auth/users/vehicles/recommend/favorites/reviews/history/compare/admin/media),接口清晰。
  • 媒体:本地静态目录 car-backend/media + /media/<path> 路由,序列化时返回绝对 URL,前端拿来即用。
  • 推荐与行为:偏好驱动 + 热门/相似推荐;收藏、对比(限 4 辆)、评分/评论、浏览历史全链路打通。
  • 数据:车辆表支持 image_url + images 多图 banner。我抓了多品牌的实车风景图并写入数据库,详情页一进来就有大图氛围感。

推荐算法与应用

  • 热门推荐(未登录兜底):先给你看大家都在看的,排序参考浏览量 + 评分权重(示例:score = rating_avg * log(review_count + 1) + view_count),保证游客也有好内容。
  • 偏好驱动(登录态):你填了预算/品牌/车型/续航,我们就按"离你最近"的顺序给;如果你没填偏好,就回退热门,不会让页面空着。
  • 相似推荐(详情页):点进一辆车,右侧推和它"气质相近"的,主要看车型类型、价格差、续航差做相似度,方便横向对比。
  • 行为信号(可扩展):收藏/浏览/评分可以做协同过滤,目前先用规则 + 偏好,后续想接入 CF 也很容易(recommend 模块是独立的)。
  • 数据闭环:浏览会累计,评分/评论提升互动,收藏/对比沉淀偏好;后台能看到热门和评分分布,用来调权重、做 A/B 时很直观。

系统展示

  • 首页/推荐 :卡片列表 + 筛选区,展示品牌、价格、续航、评分、浏览量。可截图对比"未登录热门"与"登录后个性化"。

  • 车辆详情:多图 banner(含风景大图)、价格/续航/加速/时速/座位、评分、收藏、对比、评论、点赞。可截主图和缩略图条。

  • 对比页 :最多 4 辆车的参数并排,包括价格/续航/加速/电池/座位等,适合做横向对比截图。
  • 收藏与历史:列表/卡片式展示,能看到最近浏览和收藏的车。
  • 管理后台:概览数据(用户数/车辆数/评论数/浏览量)、热门车辆排行榜、评分分布、车型分布,车辆/用户/评论管理。适合截仪表盘和表格。

推荐系统核心代码

  • 后端媒体路由:本地 /media 直出,安全校验避免越权。
python 复制代码
# car-backend/app/blueprints/media.py
@bp.get("/media/<path:filename>")
def serve_media(filename: str):
    media_root = Path(current_app.config["MEDIA_ROOT"]).resolve()
    requested = (media_root / filename).resolve()
    if not requested.exists() or not requested.is_relative_to(media_root):
        abort(404)
    rel_path = requested.relative_to(media_root)
    return send_from_directory(str(media_root), rel_path.as_posix())
  • 推荐相似接口:按车型/价格/续航相似度排序。
python 复制代码
# car-backend/app/blueprints/recommend.py
@bp.get("/similar/<int:vehicle_id>")
def similar(vehicle_id: int):
    target = Vehicle.query.get_or_404(vehicle_id)
    candidates = Vehicle.query.filter(Vehicle.id != vehicle_id, Vehicle.status == "active")
    vehicles = sorted(
        candidates,
        key=lambda v: (
            0 if v.vehicle_type == target.vehicle_type else 1,
            abs(v.price - target.price),
            abs(v.range_km - target.range_km),
        ),
    )
    return success([vehicle_to_dict(v) for v in vehicles])
  • 推荐接口(热门 + 偏好):未登录按热门,登录后按预算/品牌/车型/续航综合打分。
python 复制代码
# car-backend/app/blueprints/recommend.py
@bp.get("/hot")
def hot():
    vehicles = Vehicle.query.filter_by(status="active")\
        .order_by(desc(Vehicle.view_count)).limit(8).all()
    return success([vehicle_to_dict(v) for v in vehicles])

@bp.get("/personal")
@jwt_required(optional=True)
def personal():
    ident = get_jwt_identity()
    user_id = int(ident) if ident else None
    query = Vehicle.query.filter_by(status="active")
    if not user_id:
        vehicles = query.order_by(desc(Vehicle.rating_avg * Vehicle.rating_count + Vehicle.view_count)).limit(6).all()
        return success([vehicle_to_dict(v) for v in vehicles])

    pref = UserPreference.query.filter_by(user_id=user_id).first()
    if not pref:
        vehicles = query.order_by(desc(Vehicle.rating_avg * Vehicle.rating_count + Vehicle.view_count)).limit(6).all()
        return success([vehicle_to_dict(v) for v in vehicles])

    scored = []
    for v in query.all():
        score = 0
        if pref.budget_min <= v.price <= pref.budget_max:
            score += 40
        else:
            diff = min(abs(v.price - pref.budget_min), abs(v.price - pref.budget_max))
            score += max(0, 40 - (diff / 50000) * 10)
        if pref.preferred_brands and v.brand in pref.preferred_brands:
            score += 20
        if pref.vehicle_types and v.vehicle_type in pref.vehicle_types:
            score += 20
        score += 15 if v.range_km >= pref.range_requirement else (v.range_km / pref.range_requirement) * 15
        score += (float(v.rating_avg) / 5 if v.rating_avg else 0) * 5
        scored.append((score, v))
    scored.sort(key=lambda x: x[0], reverse=True)
    return success([vehicle_to_dict(v) for _, v in scored[:6]])
  • 前端车辆详情多图:images 数组 + 缩略图/全屏浏览。
tsx 复制代码
// car-front/src/components/ImageGallery.tsx
<div className="relative aspect-[4/3] rounded-2xl overflow-hidden bg-gray-100 group">
  <img src={images[currentIndex]} onClick={() => setIsFullscreen(true)} className="w-full h-full object-cover" />
  {/* 左右箭头 + 计数 */}
</div>
{isFullscreen && (
  <div className="fixed inset-0 bg-black z-50 flex items-center justify-center">
    <img src={images[currentIndex]} className="max-w-full max-h-[90vh] object-contain" />
    {/* 缩略条 + 翻页按钮 */}
  </div>
)}

快速启动项目的脚本

bash 复制代码
# 1) 一键脚本(推荐)
./start.sh start
# 默认:后端 http://localhost:5555,前端 http://localhost:3000

# 2) 手动(如需)
cd car-backend && python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
flask db upgrade
FLASK_APP=run.py flask run --host=0.0.0.0 --port=5555

cd ../car-front && npm install && npm run dev -- --host --port 3000

实测下来,一键脚本就能把 venv、依赖、迁移、端口都搞定;如果你想分步调试,手动流程也很顺畅。

目录与重要文件

  • car-front/src:前端源代码(组件、样式、API 封装)。
  • car-backend/app:后端、模型、序列化、配置。
  • car-backend/media/vehicles:车辆图片存储(已含多张风景实拍图)。
  • start.sh:安装依赖 + 启动前后端的便捷脚本。

API 与数据约定

  • 路由前缀 /api,统一响应 { code, message, data }
  • 车辆字段:imageUrl(主封面),images(数组,含主封面 + 额外图),price 单位元,range km。
  • 媒体访问:直接使用后端返回的绝对 URL,或手动拼接 /media/vehicles/xxx.jpg

配置与扩展

  • 数据库:环境变量 DB_USER/DB_PASSWORD/DB_HOST/DB_PORT/DB_NAME
  • 媒体目录:MEDIA_ROOT 可改为挂载盘/CDN 同步目录;MEDIA_URL_PATH 可自定义前缀。
  • 安全:JWT 鉴权,管理员路由校验;生产建议收紧 CORS、加限流/反代静态。
  • 性能:车辆查询索引(品牌/车型/价格/续航/类型);热门/推荐可加短缓存;媒体可前置 CDN/Nginx。

写在最后

  • 这套代码更偏"能跑、易改、易扩展",你可以直接用,也可以把推荐/样式/数据源替换成自己的。
  • 有反馈或想法欢迎留言交流,大家一起把"看车选车"这件小事做得更顺手。
相关推荐
未来影子2 小时前
Java领域构建Agent新杀入一匹黑马(agentscope-java)
java·开发语言·python
管理大亨3 小时前
ELK的操作应用
开发语言·python·elk
倔强青铜三3 小时前
Django 6.0来袭!这些新特性,真的令人振奋!
人工智能·python·django
越甲八千3 小时前
ASGI和AWSIG区别
数据库·python·sqlite
Logic1013 小时前
一份系统化《Python爬虫教程》学习笔记:Python爬虫63个核心案例精讲(含反爬策略与源码剖析)
经验分享·爬虫·python·学习笔记·编程·软件开发
拉姆哥的小屋3 小时前
从原子到性能:机器学习如何重塑双金属催化剂的设计范式
人工智能·python·算法·机器学习
小黄编程快乐屋3 小时前
Python 期末复习知识点汇总
java·服务器·python
free-elcmacom3 小时前
机器学习进阶<10>分类器集成:集成学习算法
python·算法·机器学习·集成学习
全栈陈序员3 小时前
【Python】基础语法入门(十八)——函数式编程初探:用 `map`、`filter`、`reduce` 和 `lambda` 写出更简洁的代码
开发语言·人工智能·python·学习