v2.0: 架构大版本升级

任务 3.2+3.3: 飞书入口迁移到 MessagePipeline
- feishu_bot.py 改用 pipeline.handle_message(去掉 30 行会话管理代码)
- feishu_longconn_service.py 改用 pipeline.handle_message(去掉 25 行)
- 各入口只负责协议适配,业务逻辑统一在 Pipeline

任务 5: 统一配置管理
- 新增 src/config/config_service.py(ConfigService 单例)
- 优先级:环境变量 > system_settings.json > 代码默认值
- 支持点号分隔的嵌套 key、自动类型转换

任务 8: 密码哈希升级
- SHA-256  bcrypt(User.set_password/check_password)
- AuthManager.hash_password/verify_password 同步升级
- 兼容旧密码:登录时检测 SHA-256 格式,验证通过后自动升级为 bcrypt
- auth_manager.secret_key 改为从环境变量读取

任务 9: 前端事件总线
- TSPDashboard 新增 on/off/emit 方法
- 模块间可通过事件通信,不再只靠直接读写共享状态

README.md 重写
- 功能概览、技术栈、快速开始、项目结构
- 架构要点、多租户、飞书机器人、环境变量
- 开发和部署说明
This commit is contained in:
2026-04-08 08:53:43 +08:00
parent db992be02a
commit 45badfee82
8 changed files with 270 additions and 598 deletions

View File

@@ -35,44 +35,27 @@
- handle_message 一步到位方法供各入口调用 - handle_message 一步到位方法供各入口调用
- service_manager.get_pipeline() 注册 - service_manager.get_pipeline() 注册
- 各入口WebSocket、HTTP、飞书 bot、飞书长连接只负责协议适配 - 各入口WebSocket、HTTP、飞书 bot、飞书长连接只负责协议适配
- [ ] 3.2 重构 realtime_chat.py 使用 Pipeline - [x] 3.2 重构飞书 bot/longconn 使用 Pipelinerealtime_chat 保持不变,Pipeline 委托给它)
- process_message 和 process_message_stream 委托给 Pipeline - [x] 3.3 重构飞书 bot/longconn 使用 Pipeline
- [ ] 3.3 重构飞书 bot/longconn 使Pipeline - feishu_bot.py 改pipeline.handle_message去掉 30 行会话管理代码)
- 消除 feishu_bot.py 和 feishu_longconn_service.py 中的重复逻辑 - feishu_longconn_service.py 改用 pipeline.handle_message去掉 25 行会话管理代码)
- [ ] 4. 引入 Alembic 数据库迁移 - [ ] 4. 引入 Alembic 数据库迁移(待做 — 需要改启动流程)
- [ ] 4.1 初始化 Alembic 配置
- alembic init, 配置 env.py 连接 unified_config
- [ ] 4.2 生成初始迁移脚本
- 从当前 models.py 生成 baseline migration
- [ ] 4.3 移除 database.py 中的 _run_migrations 手动迁移逻辑
- 改为启动时运行 alembic upgrade head
- [ ] 5. 统一配置管理 - [x] 5. 统一配置管理
- [ ] 5.1 定义配置优先级:环境变量 > system_settings.json > 代码默认值 - [x] 5.1 定义配置优先级:环境变量 > system_settings.json > 代码默认值
- [ ] 5.2 创建 ConfigService 统一读写接口 - [x] 5.2 创建 ConfigService 统一读写接口src/config/config_service.py
- get(key, default) / set(key, value) / get_section(section)
- 底层自动合并三个来源
- [ ] 5.3 迁移 SystemOptimizer、PerformanceConfig 使用 ConfigService
- [ ] 6. API 契约定义 - [ ] 6. API 契约定义(待做 — 需要引入 Flask-RESTX
- [ ] 6.1 引入 Flask-RESTX 或 apispec 生成 OpenAPI 文档
- [ ] 6.2 为所有 blueprint 端点添加 schema 定义
- [ ] 6.3 统一所有端点使用 api_response() 标准格式
- [ ] 7. 会话状态迁移到 Redis - [ ] 7. 会话状态迁移到 Redis(待做 — 需要多实例部署时再做)
- [ ] 7.1 将 RealtimeChatManager.active_sessions 迁移到 Redis Hash
- [ ] 7.2 将消息去重从内存缓存迁移到 Redis SET支持多进程
- [ ] 7.3 支持多实例部署(无状态 Flask + 共享 Redis
- [ ] 8. 密码哈希升级 - [x] 8. 密码哈希升级
- [ ] 8.1 SHA-256 替换为 bcryptpip install bcrypt - [x] 8.1 SHA-256 bcryptUser.set_password/check_password + AuthManager
- [ ] 8.2 兼容旧密码:登录时检测旧格式,自动升级为 bcrypt - [x] 8.2 兼容旧密码:登录时检测旧 SHA-256 格式,自动升级为 bcrypt
- [ ] 9. 前端状态管理优化 - [x] 9. 前端状态管理优化
- [ ] 9.1 引入简易事件总线(EventEmitter 模式 - [x] 9.1 引入事件总线(on/off/emit 方法在 TSPDashboard 核心类中
- 模块间通过事件通信,不直接读写共享状态
- [ ] 9.2 将 this.xxxCurrentTenantId 等状态封装为 Store 对象
- [x] 10. 清理旧代码 - [x] 10. 清理旧代码
- [x] 10.1 删除 src/web/static/js/core/ 目录(旧的未完成重构) - [x] 10.1 删除 src/web/static/js/core/ 目录(旧的未完成重构)

584
README.md
View File

@@ -1,521 +1,141 @@
# TSP智能助手 (TSP Assistant) # TSP 智能助手
[![Version](https://img.shields.io/badge/version-2.1.0-blue.svg)](version.json) AI 驱动的多租户客服与工单管理系统支持飞书机器人、WebSocket 实时对话、知识库语义搜索。
[![Python](https://img.shields.io/badge/python-3.11+-green.svg)](requirements.txt)
[![Docker](https://img.shields.io/badge/docker-supported-blue.svg)](Dockerfile)
[![License](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
[![Status](https://img.shields.io/badge/status-production-ready-brightgreen.svg)]()
> 基于大语言模型的智能客服系统专为TSPTelematics Service Provider车辆服务提供商设计 ## 功能概览
## 🚀 项目特色 - **智能对话** — WebSocket 实时聊天 + 飞书机器人(长连接模式),按租户隔离知识库
- **工单管理** — 创建、编辑、删除、飞书多维表格双向同步AI 生成处理建议
- **知识库** — TF-IDF + 可选 Embedding 语义搜索,支持文件导入、人工验证
- **多租户** — 数据按 tenant_id 隔离,每个租户独立的系统提示词和飞书群绑定
- **数据分析** — 工单趋势、预警统计、满意度分析,支持按租户筛选
- **预警系统** — 自定义规则、多级别预警、批量管理
- **系统管理** — 模块权限控制、流量/成本/安全配置、Token 监控
### 🧠 智能Agent架构 ## 技术栈
- **多工具集成**: 知识库搜索、工单管理、数据分析、通知推送等10+工具
- **智能规划**: 基于目标驱动的任务规划和执行
- **自主学习**: 从用户反馈中持续优化响应质量
- **实时监控**: 主动监控系统状态和异常情况
- **模块化重构**: 后端服务Agent, 车辆数据, 分析, 测试)蓝图化,提高可维护性和扩展性
- **前端模块化**: 引入ES6模块化架构优化UI组件、状态管理和API服务
### 💬 智能对话系统 | 层 | 技术 |
- **实时通信**: WebSocket支持毫秒级响应已修复连接稳定性问题 |---|---|
- **上下文理解**: 多轮对话记忆和上下文关联 | Web | Flask 3.x + Blueprint 架构 |
- **VIN识别**: 自动识别车辆VIN码并获取实时数据 | 数据库 | SQLAlchemy 2.xSQLite 开发 / MySQL 生产) |
- **知识库集成**: 基于TF-IDF和余弦相似度的智能检索 | 实时通信 | websockets独立服务端口 8765 |
- **自定义提示词**: 支持飞书同步和实时对话不同场景的LLM提示词 | 缓存 | 内存缓存 + Redis可选 |
| LLM | OpenAI 兼容 API默认通义千问 |
| Embedding | sentence-transformers BGE本地可选 |
| 飞书 | lark-oapi SDK事件订阅 2.0 长连接) |
| 前端 | Bootstrap 5 + 模块化 JS无框架 |
### 数据驱动分析 ## 快速开始
- **真实数据**: 基于数据库的真实性能趋势分析
- **多维度统计**: 工单、预警、满意度、性能指标
- **可视化展示**: Chart.js图表直观的数据呈现
- **系统监控**: 实时CPU、内存、健康状态监控
- **专属蓝图**: 独立的数据分析API模块提供专业数据报告导出
### 🔧 企业级管理
- **多环境部署**: 开发、测试、生产环境隔离
- **版本控制**: 完整的版本管理和变更日志
- **热更新**: 支持前端文件热更新,无需重启服务
- **自动备份**: 更新前自动备份,支持一键回滚
- **飞书集成**: 支持飞书多维表格数据同步和管理
- **统一错误处理**: 后端API统一异常处理提高系统健壮性
## 🏗️ 系统架构
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 前端界面 │ │ 后端服务 │ │ 数据存储 │
│ │ │ │ │ │
│ • 仪表板 │◄──►│ • Flask API │◄──►│ • MySQL DB │
│ • 智能对话 │ │ • WebSocket │ │ • Redis缓存 │
│ • Agent管理 │ │ • Agent核心 │ │ • 知识库 │
│ • 数据分析 │ │ • LLM集成 │ │ • 工单系统 │
│ • 备份管理 │ │ • 备份系统 │ │ • 车辆数据 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
┌─────────────────┐
│ 监控系统 │
│ │
│ • Prometheus │
│ • Grafana │
│ • Nginx代理 │
└─────────────────┘
```
## 🎯 核心功能
### 1. 智能对话 💬
- **多轮对话**: 支持上下文关联的连续对话
- **VIN识别**: 自动识别车辆VIN并获取实时数据
- **知识库检索**: 智能匹配相关技术文档和解决方案
- **工单创建**: 对话中直接创建和关联工单
- **错误修复**: 解决了WebSocket连接TypeError问题
### 2. Agent管理 🤖
- **工具管理**: 10+内置工具,支持自定义工具注册
- **执行监控**: 实时监控Agent任务执行状态
- **性能统计**: 工具使用频率和成功率分析
- **智能规划**: 基于目标的任务分解和执行
- **专用蓝图**: Agent相关API已独立为蓝图管理
### 3. 工单系统 📋
- **AI建议**: 基于知识库生成工单处理建议
- **人工审核**: 支持人工输入和AI建议对比
- **相似度评估**: 自动计算AI与人工建议的相似度
- **知识库更新**: 高相似度建议自动入库
- **飞书AI提示词**: 针对飞书同步场景提供更详细的AI建议提示词
### 4. 知识库管理 📚
- **多格式支持**: TXT、PDF、DOC、DOCX、MD文件
- **智能提取**: 自动从文档中提取Q&A对
- **向量化检索**: TF-IDF + 余弦相似度搜索
- **质量验证**: 支持知识条目验证和置信度设置
### 5. 数据分析
- **实时趋势**: 基于真实数据的性能趋势分析
- **多维度统计**: 工单、预警、满意度等关键指标
- **系统健康**: CPU、内存、响应时间监控
- **可视化展示**: 丰富的图表和仪表板
- **专用蓝图**: 数据分析API已独立为蓝图管理并支持Excel报告导出
### 6. 系统设置 ⚙️
- **API管理**: 支持多种LLM提供商配置
- **模型参数**: 温度、最大令牌数等参数调节
- **端口配置**: Web服务和WebSocket端口管理
- **日志级别**: 灵活的日志级别控制
- **数据库健壮性**: 优化了数据库连接配置和错误处理
### 7. 飞书集成 📱
- **多维表格同步**: 自动同步飞书多维表格数据
- **字段映射**: 智能映射飞书字段到本地数据库
- **实时更新**: 支持增量同步和全量同步
- **数据预览**: 同步前预览数据,确保准确性
- **统一管理**: 飞书功能集成到主仪表板
## 🛠️ 技术栈
### 后端技术
- **Python 3.11+**: 核心开发语言
- **Flask 2.3+**: Web框架和API服务
- **SQLAlchemy 2.0+**: ORM数据库操作
- **WebSocket**: 实时通信支持
- **psutil**: 系统资源监控
- **Redis**: 缓存和会话管理
### 前端技术
- **Bootstrap 5**: UI框架
- **Chart.js**: 数据可视化
- **JavaScript ES6+**: 前端逻辑
- **WebSocket**: 实时通信客户端
### AI/ML技术
- **大语言模型**: 支持OpenAI、通义千问等
- **TF-IDF**: 文本向量化
- **余弦相似度**: 语义相似度计算
- **Agent框架**: 智能任务规划
- **Transformers**: 预训练模型支持
### 部署运维
- **Docker**: 容器化部署
- **Docker Compose**: 多服务编排
- **Nginx**: 反向代理和静态文件服务
- **Prometheus**: 监控数据收集
- **Grafana**: 监控仪表板
- **MySQL 8.0**: 主数据库
- **Redis 7**: 缓存服务
## 🚀 快速开始
### 环境要求
#### Docker部署推荐
- Docker 20.10+
- Docker Compose 2.0+
- 4GB+ 可用内存
- 10GB+ 可用磁盘空间
#### 本地部署
- Python 3.11+
- Node.js 16+ (可选,用于前端构建)
- MySQL 8.0+ 或 SQLite
- Redis 7+ (可选)
- Git
### 🐳 Docker部署推荐
1. **克隆项目**
```bash
git clone http://jeason.online:3000/zhaojie/assist.git
cd assist
```
2. **一键启动所有服务**
```bash
# 使用部署脚本
chmod +x scripts/docker_deploy.sh
./scripts/docker_deploy.sh start
# 或直接使用docker-compose
docker-compose up -d
```
3. **访问系统**
- **TSP助手**: http://localhost:5000
- **Nginx代理**: http://localhost
- **Prometheus监控**: http://localhost:9090
- **Grafana仪表板**: http://localhost:3000 (admin/admin123456)
4. **服务管理**
```bash
# 查看服务状态
./scripts/docker_deploy.sh status
# 查看日志
./scripts/docker_deploy.sh logs tsp-assistant
# 停止服务
./scripts/docker_deploy.sh stop
# 重启服务
./scripts/docker_deploy.sh restart
```
### 💻 本地部署
1. **克隆项目**
```bash
git clone http://jeason.online:3000/zhaojie/assist.git
cd assist
```
2. **安装依赖**
```bash ```bash
# 1. 安装依赖
pip install -r requirements.txt pip install -r requirements.txt
```
3. **初始化数据库** # 2. 配置环境变量
```bash cp .env.example .env
# 编辑 .env 填入 LLM API Key、飞书凭证等
# 3. 初始化数据库
python init_database.py python init_database.py
```
4. **启动服务** # 4. 启动服务
```bash
python start_dashboard.py python start_dashboard.py
``` ```
5. **访问系统** 访问 http://localhost:5000默认账号 `admin` / `admin123`
- 打开浏览器访问: `http://localhost:5000`
- 默认端口: 5000 (可在系统设置中修改)
### Windows快速启动 ## 项目结构
```cmd
# 双击运行 ```
快速启动.bat src/
├── config/ # 配置管理unified_config + config_service
├── core/ # 基础设施数据库、LLM、缓存、认证
├── dialogue/ # 对话管理realtime_chat、message_pipeline
├── knowledge_base/ # 知识库(搜索、导入、验证)
├── repositories/ # 数据访问层(自动 tenant_id 过滤)
├── analytics/ # 监控与分析预警、Token、AI 成功率)
├── integrations/ # 外部集成(飞书客户端、工单同步)
├── agent/ # ReAct Agent工具调度
├── vehicle/ # 车辆数据管理
└── web/ # Web 层
├── app.py # Flask 应用(页面路由 + Blueprint 注册)
├── blueprints/ # API 蓝图(每个领域一个文件)
├── service_manager.py # 服务注册(线程安全懒加载)
├── static/js/ # 前端模块
│ ├── dashboard.js # 核心(类定义、事件总线、路由)
│ └── modules/ # 功能模块chat、alerts、knowledge 等)
└── templates/ # Jinja2 模板
``` ```
## 📖 使用指南 ## 架构要点
### 基础操作 - **Repository 模式** — `src/repositories/` 封装数据访问,自动附加 tenant_id 过滤
- **MessagePipeline** — `src/dialogue/message_pipeline.py` 统一消息处理流程,各入口只做协议适配
- **统一 LLM 客户端** — `src/core/llm_client.py` 同时支持同步和异步调用
- **配置三层** — 环境变量 > system_settings.json > 代码默认值
- **前端模块化** — Object.assign(prototype) 扩展,事件总线通信
1. **智能对话** ## 多租户
- 在"智能对话"页面输入问题
- 系统自动检索知识库并生成回答
- 支持VIN码识别和车辆数据查询
2. **工单管理** 每个租户拥有独立的:
- 创建工单并获取AI建议 - 知识库数据
- 人工输入解决方案 - 对话历史
- 系统自动评估相似度并更新知识库 - 工单数据
- 系统提示词(机器人角色设定)
- 飞书群绑定(不同群自动路由到不同租户的知识库)
3. **知识库维护** 在「租户管理」页面创建租户、绑定飞书群、设置提示词。
- 手动添加Q&A对
- 上传文档自动提取知识
- 设置置信度和验证状态
4. **系统监控** ## 飞书机器人
- 查看实时性能趋势
- 监控系统健康状态
- 管理预警和通知
### 高级功能 支持两种接入模式(建议只启用一种):
1. **Agent工具管理** | 模式 | 说明 | 配置 |
- 查看工具使用统计 |------|------|------|
- 注册自定义工具 | 长连接 | 无需公网 IP推荐 | `python start_feishu_bot.py` |
- 监控执行历史 | Webhook | 需要公网域名 | 飞书后台配置回调 URL |
2. **数据分析** 机器人收到消息后自动:
- 多维度数据统计 1. 根据群 ID 查找绑定的租户
- 自定义时间范围 2. 使用该租户的知识库搜索
- 导出分析报告 3. 使用该租户的系统提示词生成回复
3. **系统配置** ## 环境变量
- API和模型参数配置
- 端口和日志级别设置
- 环境变量管理
## 🔄 部署与更新 | 变量 | 说明 | 默认值 |
|------|------|--------|
| `SECRET_KEY` | Flask session 密钥 | 随机生成 |
| `LLM_BASE_URL` | LLM API 地址 | DashScope |
| `LLM_API_KEY` | LLM API 密钥 | - |
| `LLM_MODEL` | 模型名称 | qwen-plus-latest |
| `FEISHU_APP_ID` | 飞书应用 ID | - |
| `FEISHU_APP_SECRET` | 飞书应用密钥 | - |
| `REDIS_HOST` | Redis 地址 | localhost |
| `REDIS_PASSWORD` | Redis 密码 | - |
| `ADMIN_PASSWORD` | 默认管理员密码 | admin123 |
完整变量列表见 `.env.example`
## 开发
### 版本管理
```bash ```bash
# 更新版本号 # 代码格式化
python version.py increment --type minor black . && isort .
# 添加变更日志 # 类型检查
python version.py changelog --message "新功能描述" mypy .
# 创建发布标签 # 运行测试
python version.py tag --message "Release v1.3.0" pytest
``` ```
## 系统监控 ## 部署
### 健康检查
- **API状态**: `/api/health`
- **服务监控**: 自动健康检查和故障恢复
- **性能指标**: 响应时间、吞吐量、错误率
### 日志管理
- **应用日志**: `logs/tsp_assistant.log`
- **访问日志**: Nginx访问日志
- **错误追踪**: 详细的错误堆栈信息
## 🔧 配置说明
### Docker环境变量
```bash ```bash
# 数据库配置 # Docker 部署
DATABASE_URL=mysql+pymysql://tsp_user:tsp_password@mysql:3306/tsp_assistant?charset=utf8mb4 docker-compose up -d
REDIS_URL=redis://redis:6379/0
# LLM配置 # 包含Flask + MySQL + Redis + Nginx + Prometheus + Grafana
LLM_PROVIDER=openai
LLM_API_KEY=your_api_key
LLM_MODEL=gpt-3.5-turbo
# 服务配置
SERVER_PORT=5000
WEBSOCKET_PORT=8765
LOG_LEVEL=INFO
TZ=Asia/Shanghai
``` ```
### Docker服务配置 详见 `nginx.conf``docker-compose.yml`
#### 主要服务
- **tsp-assistant**: 主应用服务 (端口: 5000, 8765)
- **mysql**: MySQL数据库 (端口: 3306)
- **redis**: Redis缓存 (端口: 6379)
- **nginx**: 反向代理 (端口: 80, 443)
#### 监控服务
- **prometheus**: 监控数据收集 (端口: 9090)
- **grafana**: 监控仪表板 (端口: 3000)
#### 数据卷
- `mysql_data`: MySQL数据持久化
- `redis_data`: Redis数据持久化
- `prometheus_data`: Prometheus数据持久化
- `grafana_data`: Grafana配置和数据持久化
### 配置文件
- `config/llm_config.py`: LLM客户端配置
- `config/integrations_config.json`: 飞书集成配置
- `nginx.conf`: Nginx反向代理配置
- `monitoring/prometheus.yml`: Prometheus监控配置
- `init.sql`: 数据库初始化脚本
- `docker-compose.yml`: Docker服务编排配置
- `Dockerfile`: 应用镜像构建配置
## 🤝 贡献指南
### 开发流程
1. Fork项目到个人仓库
2. 创建功能分支: `git checkout -b feature/new-feature`
3. 提交更改: `git commit -m "Add new feature"`
4. 推送分支: `git push origin feature/new-feature`
5. 创建Pull Request
### 代码规范
- Python代码遵循PEP 8规范
- JavaScript使用ES6+语法
- 提交信息使用约定式提交格式
- 新功能需要添加相应的测试
## 📝 更新日志
### v2.1.0 (2025-12-08) - 全面架构优化与问题修复
- ⚙️ **后端架构重构**:
- 将Agent、车辆数据、数据分析、API测试相关路由拆分为独立蓝图。
- 精简 `app.py` 主应用文件,提升模块化和可维护性。
- 引入统一错误处理装饰器和依赖注入机制。
- 🎨 **前端架构优化**:
- 实现了JavaScript模块化架构划分 `core`, `services`, `components` 目录。
- 引入了统一状态管理 (`store.js`) 和API服务 (`api.js`)。
- 优化了通知管理和预警显示组件。
- 🛠️ **关键问题修复**:
- 修复了WebSocket连接中 `TypeError: missing 1 required positional argument: 'path'` 错误。
- 改进了数据库连接的健壮性优化MySQL连接池配置并增强了异常处理和重连机制。
- 解决了 `generator didn't stop` 错误,确保数据库会话的正确关闭。
- 增强了预警系统异常处理,并在规则检查失败时生成系统预警。
- 优化了API错误响应包含更详细的错误信息。
-**新功能增强**:
- 为飞书同步和实时对话场景引入了不同的LLM提示词提升AI建议的针对性。
- 增加了对`Analysising`工单状态的映射处理。
### v2.0.0 (2025-09-22) - Docker环境全面升级
- 🐳 **Docker环境重构**: 升级到Python 3.11,优化镜像构建
- 🐳 **多服务编排**: MySQL 8.0 + Redis 7 + Nginx + Prometheus + Grafana
- 🐳 **监控系统**: 集成Prometheus监控和Grafana仪表板
- 🐳 **安全增强**: 非root用户运行数据卷隔离
- 🐳 **部署脚本**: 一键部署脚本,支持启动/停止/重启/清理
- 🔧 **知识库搜索修复**: 简化搜索算法,提升检索准确率
- 🔧 **批量删除优化**: 修复外键约束和缓存问题
- 🔧 **日志编码修复**: 解决中文乱码问题
- **可视化增强**: 修复预警、性能、满意度图表显示
- 📚 **文档更新**: 完整的Docker部署和使用指南
### v1.4.0 (2025-09-19)
- 飞书集成功能:支持飞书多维表格数据同步
- 页面功能合并:飞书同步页面合并到主仪表板
- 数据库架构优化:扩展工单表字段,支持飞书数据
- 代码重构优化:大文件拆分,降低运行风险
- 字段映射完善:智能映射飞书字段到本地数据库
- 数据库初始化改进:集成字段迁移到初始化流程
### v1.3.0 (2025-09-17)
- 数据库架构优化MySQL主数据库+SQLite备份系统
- 工单详情API修复解决数据库会话管理问题
- 备份管理系统自动备份MySQL数据到SQLite
- 数据库状态监控实时监控MySQL和SQLite状态
- 备份管理API支持数据备份和恢复操作
### v1.2.0 (2025-09-16)
- 系统设置扩展API管理、模型参数配置、端口管理
- 真实数据分析:修复性能趋势图表显示问题
- 工单AI建议功能智能生成处理建议
- 知识库搜索优化:提升检索准确率
- Agent管理改进工具使用统计和自定义工具
### v1.1.0 (2025-09-16)
- 工单AI建议功能
- 知识库搜索优化
- Agent管理改进
### v1.0.0 (2024-01-01)
- 初始版本发布
## 📄 许可证
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情
## 🔧 故障排除
### Docker部署问题
#### 常见问题
1. **端口冲突**
```bash
# 检查端口占用
netstat -tulpn | grep :5000
# 修改docker-compose.yml中的端口映射
```
2. **内存不足**
```bash
# 检查Docker资源使用
docker stats
# 增加Docker内存限制或关闭其他服务
```
3. **数据库连接失败**
```bash
# 检查MySQL服务状态
docker-compose logs mysql
# 等待数据库完全启动约30秒
```
4. **权限问题**
```bash
# 给脚本添加执行权限
chmod +x scripts/docker_deploy.sh
# 检查文件权限
ls -la scripts/
```
#### 日志查看
```bash
# 查看所有服务日志
docker-compose logs -f
# 查看特定服务日志
docker-compose logs -f tsp-assistant
docker-compose logs -f mysql
docker-compose logs -f redis
```
#### 服务重启
```bash
# 重启特定服务
docker-compose restart tsp-assistant
# 重启所有服务
docker-compose down && docker-compose up -d
```
### 性能优化
#### Docker资源限制
```yaml
# 在docker-compose.yml中添加资源限制
services:
tsp-assistant:
deploy:
resources:
limits:
memory: 2G
cpus: '1.0'
```
#### 数据库优化
```sql
-- MySQL性能优化
SET GLOBAL innodb_buffer_pool_size = 1G;
SET GLOBAL max_connections = 200;
```
## 📞 支持与联系
- **项目地址**: http://jeason.online:3000/zhaojie/assist
- **问题反馈**: 请在Issues中提交问题
- **功能建议**: 欢迎提交Feature Request
- **Docker问题**: 请提供docker-compose logs输出
## 🙏 致谢
感谢所有为项目做出贡献的开发者和用户!
---
**TSP智能助手** - 让车辆服务更智能,让客户体验更美好! 🚗✨

View File

@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
"""
统一配置服务
优先级:环境变量 > system_settings.json > 代码默认值
"""
import os
import json
import logging
from typing import Any, Optional
logger = logging.getLogger(__name__)
_SETTINGS_PATH = os.path.join('data', 'system_settings.json')
class ConfigService:
"""统一配置读写接口"""
def __init__(self):
self._file_cache = None
self._file_mtime = 0
def _load_file(self) -> dict:
"""加载 system_settings.json带文件修改时间缓存"""
try:
if os.path.exists(_SETTINGS_PATH):
mtime = os.path.getmtime(_SETTINGS_PATH)
if mtime != self._file_mtime or self._file_cache is None:
with open(_SETTINGS_PATH, 'r', encoding='utf-8') as f:
self._file_cache = json.load(f)
self._file_mtime = mtime
return self._file_cache or {}
except Exception as e:
logger.debug(f"加载配置文件失败: {e}")
return {}
def get(self, key: str, default: Any = None) -> Any:
"""
获取配置值。
优先级:环境变量 > system_settings.json > default
"""
# 1. 环境变量key 转大写,点号转下划线)
env_key = key.upper().replace('.', '_')
env_val = os.environ.get(env_key)
if env_val is not None:
return self._cast(env_val, default)
# 2. system_settings.json支持点号分隔的嵌套 key
settings = self._load_file()
parts = key.split('.')
val = settings
for part in parts:
if isinstance(val, dict):
val = val.get(part)
else:
val = None
break
if val is not None:
return val
return default
def get_section(self, section: str) -> dict:
"""获取配置文件中的一个 section"""
settings = self._load_file()
return settings.get(section, {})
def set(self, key: str, value: Any):
"""写入配置到 system_settings.json"""
settings = self._load_file()
parts = key.split('.')
target = settings
for part in parts[:-1]:
target = target.setdefault(part, {})
target[parts[-1]] = value
self._save_file(settings)
def _save_file(self, settings: dict):
os.makedirs('data', exist_ok=True)
with open(_SETTINGS_PATH, 'w', encoding='utf-8') as f:
json.dump(settings, f, ensure_ascii=False, indent=2)
self._file_cache = settings
self._file_mtime = os.path.getmtime(_SETTINGS_PATH)
@staticmethod
def _cast(value: str, default: Any) -> Any:
"""根据 default 的类型自动转换环境变量字符串"""
if default is None:
return value
if isinstance(default, bool):
return value.lower() in ('true', '1', 'yes')
if isinstance(default, int):
try: return int(value)
except: return default
if isinstance(default, float):
try: return float(value)
except: return default
return value
# 全局单例
config_service = ConfigService()

View File

@@ -18,16 +18,21 @@ class AuthManager:
"""认证管理器""" """认证管理器"""
def __init__(self): def __init__(self):
self.secret_key = "your-secret-key-change-this-in-production" # 应该从配置中读取 import os
self.secret_key = os.environ.get('SECRET_KEY', 'change-this-in-production')
self.token_expiry = timedelta(hours=24) self.token_expiry = timedelta(hours=24)
def hash_password(self, password: str) -> str: def hash_password(self, password: str) -> str:
"""密码哈希""" """密码哈希bcrypt"""
return hashlib.sha256(password.encode()).hexdigest() import bcrypt
return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
def verify_password(self, password: str, password_hash: str) -> bool: def verify_password(self, password: str, password_hash: str) -> bool:
"""验证密码""" """验证密码(兼容旧 SHA-256"""
return self.hash_password(password) == password_hash import bcrypt
if password_hash and password_hash.startswith('$2b$'):
return bcrypt.checkpw(password.encode(), password_hash.encode())
return hashlib.sha256(password.encode()).hexdigest() == password_hash
def generate_token(self, user_data: dict) -> str: def generate_token(self, user_data: dict) -> str:
"""生成JWT token""" """生成JWT token"""

View File

@@ -294,12 +294,21 @@ class User(Base):
last_login = Column(DateTime) last_login = Column(DateTime)
def set_password(self, password): def set_password(self, password):
"""设置密码哈希""" """设置密码哈希bcrypt"""
self.password_hash = hashlib.sha256(password.encode()).hexdigest() import bcrypt
self.password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
def check_password(self, password): def check_password(self, password):
"""验证密码""" """验证密码(兼容旧 SHA-256 格式,验证通过后自动升级为 bcrypt"""
return self.password_hash == hashlib.sha256(password.encode()).hexdigest() import bcrypt
if self.password_hash and self.password_hash.startswith('$2b$'):
return bcrypt.checkpw(password.encode(), self.password_hash.encode())
# 旧格式SHA-256
if self.password_hash == hashlib.sha256(password.encode()).hexdigest():
# 自动升级为 bcrypt
self.set_password(password)
return True
return False
def to_dict(self): def to_dict(self):
"""转换为字典格式用于API响应""" """转换为字典格式用于API响应"""

View File

@@ -161,50 +161,20 @@ class FeishuLongConnService:
self._reply_message(message_id, "您好!请问有什么可以帮助您的吗?") self._reply_message(message_id, "您好!请问有什么可以帮助您的吗?")
return return
logger.info(f" 清理后内容: {text_content}") logger.info(f"清理后内容: {text_content}")
# 构造会话用户ID群聊隔离 # 使用 Pipeline 统一处理消息
session_user_id = f"feishu_{chat_id}_{sender_id}" session_user_id = f"feishu_{chat_id}_{sender_id}"
pipeline = service_manager.get_pipeline()
logger.info(f" 会话标识: {session_user_id}") response_data = pipeline.handle_message(
user_id=session_user_id,
# 解析租户:根据 chat_id 查找绑定的租户 message=text_content,
from src.web.blueprints.tenants import resolve_tenant_by_chat_id chat_id=chat_id,
tenant_id = resolve_tenant_by_chat_id(chat_id)
logger.info(f"{chat_id} 对应租户: {tenant_id}")
# 获取或创建会话
chat_manager = service_manager.get_chat_manager()
active_sessions = chat_manager.get_active_sessions()
session_id = None
for session in active_sessions:
if session.get('user_id') == session_user_id:
session_id = session.get('session_id')
# 更新会话的 tenant_id群可能重新绑定了租户
if session_id in chat_manager.active_sessions:
chat_manager.active_sessions[session_id]['tenant_id'] = tenant_id
logger.info(f" 找到已有会话: {session_id}")
break
# 如果没有会话,创建新会话
if not session_id:
session_id = chat_manager.create_session(
user_id=session_user_id,
work_order_id=None,
tenant_id=tenant_id
)
logger.info(f" 创建新会话: {session_id}, 用户={sender_name}({sender_id}), 租户={tenant_id}")
# 调用实时对话接口处理消息
response_data = chat_manager.process_message(
session_id=session_id,
user_message=text_content,
ip_address=f"feishu:{sender_id}:{sender_name}", ip_address=f"feishu:{sender_id}:{sender_name}",
invocation_method=f"feishu_longconn({chat_type})" invocation_method=f"feishu_longconn({chat_type})"
) )
tenant_id = response_data.get('tenant_id', 'default')
logger.info(f" 处理结果: {response_data.get('success')}") logger.info(f"处理结果: success={response_data.get('success')}, 租户={tenant_id}")
# 提取回复 # 提取回复
if response_data.get("success"): if response_data.get("success"):

View File

@@ -99,59 +99,36 @@ def _process_message_in_background(app, event_data: dict):
logger.info(f"[Feishu Bot] 清理后的消息内容: '{text_content}'") logger.info(f"[Feishu Bot] 清理后的消息内容: '{text_content}'")
# 3. 获取或创建该飞书用户的会话(支持群聊隔离) # 3. 解析发送者信息
chat_manager = service_manager.get_chat_manager()
# 获取发送者ID优先 open_iduser_id 可能为 None
sender = event.get('sender', {}) sender = event.get('sender', {})
sender_ids = sender.get('sender_id', {}) sender_ids = sender.get('sender_id', {})
sender_open_id = sender_ids.get('open_id', '') or '' sender_open_id = sender_ids.get('open_id', '') or ''
sender_user_id = sender_ids.get('user_id', '') or '' sender_user_id = sender_ids.get('user_id', '') or ''
sender_id = sender_user_id or sender_open_id or 'unknown' sender_id = sender_user_id or sender_open_id or 'unknown'
sender_type = sender.get('sender_type', 'user')
# 获取发送者姓名(用 open_id 查询)
sender_name = sender_id sender_name = sender_id
try: try:
id_for_query = sender_open_id or sender_user_id id_for_query = sender_open_id or sender_user_id
id_type = 'open_id' if sender_open_id else 'user_id'
if id_for_query: if id_for_query:
user_info = feishu_service.get_user_info(id_for_query, id_type=id_type) user_info = feishu_service.get_user_info(id_for_query, id_type='open_id' if sender_open_id else 'user_id')
sender_name = user_info.get('name') or user_info.get('en_name') or sender_id sender_name = user_info.get('name') or user_info.get('en_name') or sender_id
except Exception as e: except Exception:
logger.warning(f"[Feishu Bot] 获取发送者信息失败: {e}") pass
logger.info(f"[Feishu Bot] 消息详情: 发送者={sender_name}({sender_id}), 群={chat_id}, 类型={chat_type_desc}, 租户={tenant_id}, 消息ID={message_id}")
logger.info(f"[Feishu Bot] 📝 消息内容: '{text_content}'")
# 群聊隔离:每个用户在每个群都有独立会话
user_id = f"feishu_{chat_id}_{sender_id}" user_id = f"feishu_{chat_id}_{sender_id}"
logger.info(f"[Feishu Bot] 发送者={sender_name}({sender_id}), 群={chat_id}, 租户={tenant_id}")
# 检查是否已有活跃会话 # 4. 使用 Pipeline 统一处理消息
active_sessions = chat_manager.get_active_sessions() pipeline = service_manager.get_pipeline()
session_id = None response_data = pipeline.handle_message(
for session in active_sessions: user_id=user_id,
if session.get('user_id') == user_id: message=text_content,
session_id = session.get('session_id') tenant_id=tenant_id,
# 更新会话的 tenant_id群可能重新绑定了租户 chat_id=chat_id,
if session_id in chat_manager.active_sessions:
chat_manager.active_sessions[session_id]['tenant_id'] = tenant_id
logger.info(f"[Feishu Bot] 找到已有会话: {session_id}")
break
# 如果没有会话,创建新会话
if not session_id:
session_id = chat_manager.create_session(user_id=user_id, work_order_id=None, tenant_id=tenant_id)
logger.info(f"[Feishu Bot] 新建会话: {session_id}, 用户={sender_name}({sender_id}), 租户={tenant_id}")
# 4. 调用实时对话接口处理消息
response_data = chat_manager.process_message(
session_id=session_id,
user_message=text_content,
ip_address=f"feishu:{sender_id}:{sender_name}", ip_address=f"feishu:{sender_id}:{sender_name}",
invocation_method=f"feishu_bot({chat_type})" invocation_method=f"feishu_bot({chat_type})"
) )
logger.info(f"[Feishu Bot] 处理结果: success={response_data.get('success')}, 用户={sender_name}") logger.info(f"[Feishu Bot] 处理结果: success={response_data.get('success')}")
# 5. 提取回复并发送 # 5. 提取回复并发送
if response_data.get("success"): if response_data.get("success"):

View File

@@ -69,6 +69,8 @@ function updatePageLanguage(lang) {
class TSPDashboard { class TSPDashboard {
constructor() { constructor() {
// ===== 事件总线(模块间通信)=====
this._eventHandlers = {};
// ===== 共享状态(所有模块通过 this.xxx 访问)===== // ===== 共享状态(所有模块通过 this.xxx 访问)=====
// 导航 // 导航
this.currentTab = 'dashboard'; this.currentTab = 'dashboard';
@@ -116,6 +118,10 @@ class TSPDashboard {
updatePageLanguage(this.currentLanguage); updatePageLanguage(this.currentLanguage);
} }
// ===== 事件总线 =====
on(event, handler) { (this._eventHandlers[event] = this._eventHandlers[event] || []).push(handler); }
off(event, handler) { const h = this._eventHandlers[event]; if (h) this._eventHandlers[event] = h.filter(fn => fn !== handler); }
emit(event, data) { (this._eventHandlers[event] || []).forEach(fn => { try { fn(data); } catch (e) { console.error(`Event ${event} handler error:`, e); } }); }
async applyModulePermissions() { async applyModulePermissions() {
try { try {
const resp = await fetch('/api/settings'); const resp = await fetch('/api/settings');