Skip to content

Repository files navigation

SentimentPlatform

中文评论情感分析与洞察平台(云析智研)

模型推理只是其中一环。评论进来、分析落库、低置信度交人工复核、有效标注沉淀成数据集、
攒够阈值触发重训、新模型注册激活——这条闭环才是本项目要解决的问题。

CI License: MIT Django Vue Tests

关键决策 · 业务闭环 · 系统架构 · 能力边界 · 快速开始

SentimentPlatform 产品入口页

公开版首页。不含真实业务数据、账号、模型权重或训练资产。

落地场景

面向产品反馈分析、服务评价监测、电商评论归因、客服工单洞察这类中文文本分析场景。这类场景的共同特征决定了系统形态:

场景约束 对系统的要求
模型对真实语料一定会判错 必须有人工复核通道,且修正结果要能回流训练
标注成本高,但线上样本源源不断 高置信度样本自动采信,低置信度才占用人力
训练是长任务,报告生成是短任务 两类任务不能挤同一个队列
模型会迭代多个版本 注册、激活、回退要能在后台完成,不靠改配置重启
三类使用者职责不同 权限要在前端路由与后端接口两侧同时约束

要评估设计的人看关键决策能力边界;要跑起来的人直接跳快速开始

关键决策

决策 选择 代价
有效标注的判定 置信度 ≥ 0.70 自动采信;低于阈值必须分析师复核过才入池 阈值是经验值,调高会拖慢数据沉淀、调低会引入噪声标注
训练任务队列 独立 training 队列 + 独立 worker,与默认队列物理隔离 要多起一个 worker 进程;本地开发也得跑两个
重训触发 攒满阈值(默认 5000 条)自动建训练任务,另有 signal 模式只记提醒 自动模式下管理员是事后知情,不是事前批准
refresh token HttpOnly cookie,不进响应体 前端拿不到 refresh token,跨域部署要额外配 cookie 域
模型激活 后台注册 + 激活,运行时按文件系统特征探测产物类型 产物目录结构成了隐式契约,缺一个文件就识别不出来
训练产物浏览 强制落在 TRAINING_WORKSPACE_ROOT 白名单内 想看工作区外的产物得改配置,不能临时传路径
任务可靠性 acks_late + reject_on_worker_lost 任务可能重复执行,幂等性得由任务自己保证

几条值得展开的:

为什么置信度阈值配人工复核,而不是全量复核或全量自动采信。 全量复核的话,标注人力会成为吞吐上限,线上样本再多也沉淀不下来;全量自动采信的话,模型判错的样本会作为「正确标注」回流,下一轮训练把错误固化。0.70 这条线把人力集中在模型自己也不确定的样本上 —— 这批样本的标注收益最高。

为什么训练必须独占队列。 训练是分钟到小时级的任务,报告生成是秒级。共用队列时,一个训练任务会把后面排队的报告请求全部堵住,而用户侧看到的现象是「报告一直在生成中」,排查方向会指向报告模块,和真正的原因隔了一层。

为什么 refresh token 不进响应体。 进了响应体,前端就得自己存 —— 存 localStorage 会被 XSS 直接读走,存内存则刷新页面即丢失登录态。放 HttpOnly cookie 后 JS 读不到,代价是跨域部署时要额外配 cookie 域和 SameSite,这个代价比 XSS 泄漏长效凭证小。

业务闭环

用户提交评论 / 上传文件
        ↓  文本校验 · 文件解析 · 批量行数限制(默认 1000)
    模型推理 + 关键词归一化
        ↓
   评论与分析结果入库
        ↓
   ┌────────────────┬─────────────────┐
   置信度 ≥ 0.70      置信度 < 0.70
   自动视为有效标注    分析师复核修正后才算
   └────────┬───────┴─────────────────┘
            ↓  攒满阈值(默认 5000 条)
    保存为 HuggingFace Dataset 批次
            ↓  auto 模式建训练任务 / signal 模式只记提醒
      训练队列异步执行 → 评估 → 注册 → 激活
            ↓
        新模型接管推理

分析结果会记录分析渠道、分析会话、来源名称、模型原始情感、人工修正情感、审核人、审核时间和自动训练数据集引用 —— 最后一个字段是防重复入池的关键:已进批次的结果不会被下一轮再统计一次。

系统架构

%%{init: {'theme': 'base', 'themeVariables': { 'edgeLabelBackground': '#ffffff', 'mainBkg': '#ffffff', 'lineColor': '#64748b' }}}%%
flowchart TB
    classDef client fill:#ffffff,stroke:#3b82f6,stroke-width:1.5px,color:#1e40af,rx:5px,ry:5px;
    classDef edge fill:#ffffff,stroke:#2563eb,stroke-width:1.5px,color:#1d4ed8,rx:5px,ry:5px;
    classDef app fill:#ffffff,stroke:#334155,stroke-width:1.5px,color:#0f172a,rx:5px,ry:5px;
    classDef training fill:#ffffff,stroke:#ef4444,stroke-width:1.5px,color:#b91c1c,rx:5px,ry:5px;
    classDef ml fill:#ffffff,stroke:#8b5cf6,stroke-width:1.5px,color:#6d28d9,rx:5px,ry:5px;
    classDef mq fill:#ffffff,stroke:#f59e0b,stroke-width:1.5px,color:#b45309,rx:5px,ry:5px;
    classDef db fill:#ffffff,stroke:#64748b,stroke-width:1.5px,color:#334155,rx:5px,ry:5px;

    %% 统一入口
    U["多角色用户 (普通用户 · 分析师 · 管理员)"]:::client
    FE["Vue 3.5 前端单页应用 (三角色路由守卫 · DOMPurify)"]:::edge
    API["Django 6 REST API (JWT 鉴权 · HttpOnly Refresh)"]:::app

    %% 线上推理链路 (左路)
    ANA["文本分析与人工复核<br/>(apps/analysis · 置信度分流)"]:::app
    ML_INF["模型工作区 (运行时特征探测)<br/>Transformer · 传统 ML · 神经基线"]:::ml
    Q_DEF["Celery 默认队列 (短任务)<br/>PDF/Excel 报告生成 · 状态审计"]:::mq

    %% 自动化重训闭环 (右路)
    ADM["模型管理与审计中心<br/>(apps/admin_panel · 自动重训判定)"]:::app
    Q_TRN["Celery training 队列 (长任务)<br/>独占 Worker 进程 · 微调/超参搜索"]:::training
    ML_REG["新模型产物交付<br/>自动评估 · 注册登记 · 一键激活"]:::ml

    %% 数据基础设施
    DB[("MySQL 8.0 持久库<br/>(8 张核心业务表 · RBAC · 审计)")]:::db
    RD[("Redis 7.0 缓存中间件<br/>(Celery Broker · Backend · 缓存)")]:::db

    %% 顶层流转
    U --> FE --> API

    %% 核心业务与计算分流 (左路与右路)
    API -->|"单条 / 批量分析"| ANA
    ANA -->|"加载产物推理"| ML_INF
    ANA -->|"异步生成报告"| Q_DEF
    ANA --> DB

    API -->|"阈值触发 / 管理"| ADM
    ADM -->|"下发重训任务"| Q_TRN
    Q_TRN -->|"训练产物产出"| ML_REG
    ML_REG -.->|"激活新模型生效"| ML_INF
    ADM --> DB

    %% 异步到 Redis
    Q_DEF & Q_TRN --> RD
Loading

运行时模型探测:激活的模型路径按文件系统特征判定产物类型 —— .joblib 文件识别为传统模型,.pt 且同目录有 vocab.jsonconfig_snapshot.json 识别为神经基线,目录内同时有 config.jsonmodel.safetensorstokenizer_config.json 识别为 Transformer。三者都不匹配则返回空类型,接口据此向前端报告能力缺失,而不是在推理时抛异常。

模型路径另有一道校验:必须落在 MODEL_WORKSPACE_DIR 之内,否则拒绝加载并记日志。

技术栈

组件
前端 Vue 3.5 · Vite 8 · Pinia · Vue Router 5 · Element Plus · Tailwind CSS 4 · ECharts
前端安全 DOMPurify —— 验证码以 SVG 下发,SVG 能携带脚本,渲染前必须净化
API Django 6 · Django REST Framework · Simple JWT · drf-spectacular
业务 apps/users · apps/analysis · apps/reports · apps/admin_panel
存储 MySQL 8 · Redis
异步 Celery 5.6 · Celery Beat
模型 PyTorch · Transformers · scikit-learn · jieba · datasets · safetensors
报告 ReportLab · openpyxl · CSV / TXT / XLSX
质量 pytest · ruff · ESLint · Prettier · vue-tsc · GitHub Actions

角色与权限

角色 前端路径 权限范围 典型操作
普通用户 /user/* 仅本人分析历史与报告 单条分析、批量上传、查看历史、生成报告、维护资料
分析师 /analyst/* 全局分析结果与统计报表 评论复核、情感修正、重点标注、报表查看与导出
管理员 /admin/* 系统级资源 用户管理、模型切换、训练编排、数据集导出、日志与备份

登录成功后按角色跳转对应首页。权限在两侧同时约束:前端路由守卫决定看得见什么,后端接口权限决定拿得到什么 —— 只做前端守卫的话,直接调接口就能越权。

统一用户认证(JWT + 图形验证码) 角色注册与申领(RBAC + 邮箱验证码)
登录页面 注册页面

核心能力

能力域 说明
账号与权限 图形验证码、邮箱验证码、注册登录、JWT access token、HttpOnly refresh cookie、三角色 RBAC
评论分析 单条分析、TXT/XLSX 批量分析、批量模板下载、运行时模型能力检测、分析历史与详情
分析师复核 全局评论检索、情感修正、审核备注、重点关注、趋势统计、报表导出
报告中心 PDF / Excel / CSV 报告生成,异步入队,状态追踪,安全下载
管理后台 用户管理、数据集沉淀与导出、模型注册与激活、训练中心、日志审计、数据库备份
模型训练 Transformer 微调、Transformer 超参搜索、传统模型对比、TextCNN / BiLSTM 基线训练
自动重训 按高置信度与人工审核样本构建批次,达阈值触发训练或记录提醒
运维治理 Celery Beat 定时任务、日志保留策略、异常训练任务清理、路径安全校验
数据模型 · 8 张核心表
表名 Django 模型 说明
users users.User 自定义用户表,支持 user / analyst / admin 三类角色
email_verification_codes users.EmailVerificationCode 邮箱验证码、用途、失败次数与过期控制
comments analysis.Comment 评论正文、项目名、评分、类别、来源、评论时间
analysis_results analysis.AnalysisResult 情感类别、置信度、关键词、分析渠道、人工修正、审核信息、自动训练数据集引用
models analysis.Model 模型注册、版本、指标、路径、激活状态、运行时兼容性
training_runs admin_panel.TrainingRun 训练任务、数据集引用、配置快照、指标、产物与日志路径
reports reports.Report 报告类型、格式、状态、文件路径、摘要与入队信息
operation_logs admin_panel.OperationLog 登录、分析、导入导出、训练、模型切换等审计日志
API 概览与异步任务
前缀 说明
/api/healthz/ 服务健康检查
/api/auth/ 验证码、注册、登录、刷新、退出、资料、密码
/api/analyze/ 单条 / 批量分析、模板、历史、详情、分析师视图、报表导出
/api/report/ 报告生成、报告列表、报告下载
/api/admin/ 用户、日志、仪表盘、备份、数据集、自动重训状态、模型、训练中心
/swagger//redoc/ OpenAPI 文档,需 SWAGGER_ENABLED=True 且管理员访问
队列 / 定时任务 用途
celery 默认队列 报告生成、验证码清理、日志清理等通用任务
training 队列 模型训练、训练后处理、训练产物登记
Beat */5 * * * * 清理异常停留在 running 的训练任务
Beat 每小时第 15 分 自动重训阈值检查
Beat 每 6 小时第 10 分 操作日志清理(保留期默认 180 天)
Beat 每天 03:30 过期验证码清理

公开版本说明

本仓库是 SentimentPlatform 的公开源码版本,只发布系统源码、自动化测试、文档、前端品牌资源和开发脚本。以下资产不在公开范围:

类型 公开策略
.env、真实密钥、本地账号 不发布
训练数据集、Arrow 文件、数据切分结果 不发布
模型权重、.joblib.pt.safetensors 训练产物 不发布
本地数据库、日志、上传文件、报告导出、备份文件 不发布

因此克隆后无法直接跑通真实分析、训练或模型激活 —— 这三条路径都依赖上面的资产。要跑通需按 模型与数据资产说明 在本地准备模型、数据集与配置。

界面截图同理只提供不含业务数据的首页与认证页面;分析、复核、训练中心等页面的截图需要真实数据与模型权重才能呈现,不随公开版发布。

能力边界

已实现并验证:

  • 三角色 RBAC 在前端路由与后端接口两侧同时约束
  • 高低置信度分流的复核机制,修正结果回流训练数据池
  • 训练与常规任务队列物理隔离,长任务不阻塞报告生成
  • 三类模型产物(Transformer / 传统 ML / 神经基线)运行时按文件特征探测
  • 训练产物与数据集路径强制落在白名单根目录内
  • 122 个后端测试覆盖认证、分析、报告、训练与权限路径

明确的限制:

  • 单机部署。Celery Beat 未做选主,多实例会重复触发定时任务
  • 自动重训是「事后知情」auto 模式下达阈值直接建任务,管理员事后在训练中心看到;需要事前批准应切 signal 模式
  • 置信度阈值 0.70 是经验值,没有做过阈值扫描实验来定这条线
  • acks_late 意味着任务可能重复执行,幂等性由各任务自行保证,没有统一的去重中间层
  • 批量分析上限 1000 行MAX_BATCH_RECORDS),更大的文件需要分批
  • 无模型 A/B 与灰度。激活是全量切换,回退靠重新激活旧模型

工程验证

规模
后端 Python 304 个文件 / 27,877 行
后端测试 15 个文件 / 122 个测试
前端 40 个 .vue:23 个页面 + 13 个组件 + 3 个布局,三角色路由
数据表 8 张核心业务表
Celery 2 个队列 + 4 类 Beat 定时任务

最近一次本地全量检查:

cd sentiment_server
$env:DJANGO_SETTINGS_MODULE = "sentiment_server.settings.local"
python manage.py check
python manage.py makemigrations --check --dry-run
python -m ruff check .
python -m pytest -q

cd ..\sentiment_webapp
npm run check
npm run build

结果:系统检查通过、迁移无遗漏、ruff 通过、后端 122 passed;前端 lint、Prettier、vue-tsc 与生产构建均通过。

CI(.github/workflows/ci.yml)跑 manage.py checkruff checkpytest、前端 checkbuild

lint 规则集显式声明在 [tool.ruff.lint]select,不吃 ruff 的默认集 —— 默认集从 0.15 的 59 条涨到 0.16 的 413 条,曾导致不改一行代码 CI 自己变红。选定的是 E4/E7/E9/F(ruff 自身默认,代码库本来就对着它干净)加三样:I 导入排序(纯机械、可自动修)、DTZ 时区(它抓出过一个真缺陷,见下)、UP 语法跟上 requires-python。再放宽是独立决定:全开 E 会引入 522 条行超长,全开 RUF 会引入 205 条全角标点告警 —— 后者是本项目在面向用户的文案里刻意用的。

已知缺口:makemigrations --check 只在本地清单里,未进 CI —— 它拦的是「模型改了但没生成迁移」,这类问题在已有库的开发机上不报错,换台机器从零建库才暴露。

修过的真实缺陷

缺陷 后果 修法
训练记录时间戳一半 aware、一半 naive --start-time 筛训练记录时抛 can't compare offset-naive and offset-aware;排序路径不崩,但改用 .timestamp() 后 naive 被按本地时区解释,结果随机器漂移 两条来源统一为 aware,无偏移输入按 UTC 解释;DTZ 规则守着
lint 规则集吃 ruff 默认值 默认集 0.15→0.16 从 59 条涨到 413 条,不改一行代码 CI 自己变红,284 处告警无一是缺陷 select 显式声明,门禁与工具版本解耦

时间戳那条的具体位置:_record_timestamp 在 payload 里找到 ISO 字符串时返回 aware,找不到就回落到 datetime.fromtimestamp(mtime) 返回 naive。trends.filter_experiment_records 拿它和 CLI 传入的 aware 时间直接比较,于是「payload 里没有时间字段的记录」+「指定了时间范围」这个组合必崩。三个文件里同一个函数各有一份副本,都改了。

快速开始

环境要求:Python 3.12+ · Node.js 22.18+ 或 24.11+ · MySQL 8+(127.0.0.1:3306)· Redis(127.0.0.1:6379/0)· PowerShell 7.0+(一键脚本用)

后端

cd sentiment_server
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -e ".[training,testing]"
Copy-Item .env.example .env

编辑 .env,至少填 SECRET_KEYJWT_SIGNING_KEY 与数据库连接。然后:

$env:DJANGO_SETTINGS_MODULE = "sentiment_server.settings.local"
python manage.py migrate
python manage.py check
python -m pytest -q
python manage.py runserver 127.0.0.1:8000

前端

cd sentiment_webapp
npm install
npm run check
npm run build
npm run dev

Vite 开发服务默认 http://127.0.0.1:5173/,通过代理访问后端 /api

一键启停

.\start-dev.ps1                              # 全部服务
.\start-dev.ps1 -Services backend,frontend   # 只起部分
.\stop-dev.ps1

一键启动会先检查后端 .env 必填密钥、MySQL 与 Redis 连接,再依次拉起 Django、Celery 默认 worker、Celery training worker、Celery Beat 和 Vite。健康检查地址 http://127.0.0.1:8000/api/healthz/

注意这里会起两个 Celery worker —— 默认队列和 training 队列各一个。只起一个的话,训练任务会一直排队不执行,而界面上看起来只是「训练中」。

项目结构

SentimentPlatform/
├── sentiment_server/     Django REST API、Celery、模型推理与训练工作区
│   ├── apps/             users / analysis / reports / admin_panel
│   ├── core/             跨应用的公共设施
│   ├── ml_assets/        模型工作区(权重与数据集不公开)
│   └── tests/            后端测试
├── sentiment_webapp/     Vue 3 + Vite 单页应用
│   ├── src/pages/        23 个页面,按 auth / user / analyst / admin 分组
│   ├── src/components/   13 个复用组件
│   ├── src/layouts/      3 个布局(按角色)
│   ├── src/stores/       Pinia 状态
│   └── src/api/          接口封装
├── docs/                 公开发布、模型与数据资产说明
├── start-dev.ps1         一键启动后端、两个 Celery worker、Beat、前端
├── stop-dev.ps1          一键停止
└── dev-services.ps1      本地服务定义与复用函数

公开版采用 monorepo 组织,后端与前端在同一仓库,便于统一管理 issue、CI、版本与文档。

文档

公开发布说明 · 模型与数据资产 · 后端说明 · 前端说明 · 前端设计规范 · 手工测试素材

许可证

MIT License

About

One of the projects I keep around while learning from text, signals, and product feedback.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages