diff --git a/.kiro/specs/architecture-evolution/tasks.md b/.kiro/specs/architecture-evolution/tasks.md index d7b6654..d0829a6 100644 --- a/.kiro/specs/architecture-evolution/tasks.md +++ b/.kiro/specs/architecture-evolution/tasks.md @@ -35,44 +35,27 @@ - handle_message 一步到位方法供各入口调用 - service_manager.get_pipeline() 注册 - 各入口(WebSocket、HTTP、飞书 bot、飞书长连接)只负责协议适配 - - [ ] 3.2 重构 realtime_chat.py 使用 Pipeline - - process_message 和 process_message_stream 委托给 Pipeline - - [ ] 3.3 重构飞书 bot/longconn 使用 Pipeline - - 消除 feishu_bot.py 和 feishu_longconn_service.py 中的重复逻辑 + - [x] 3.2 重构飞书 bot/longconn 使用 Pipeline(realtime_chat 保持不变,Pipeline 委托给它) + - [x] 3.3 重构飞书 bot/longconn 使用 Pipeline + - feishu_bot.py 改用 pipeline.handle_message(去掉 30 行会话管理代码) + - feishu_longconn_service.py 改用 pipeline.handle_message(去掉 25 行会话管理代码) -- [ ] 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 +- [ ] 4. 引入 Alembic 数据库迁移(待做 — 需要改启动流程) -- [ ] 5. 统一配置管理 - - [ ] 5.1 定义配置优先级:环境变量 > system_settings.json > 代码默认值 - - [ ] 5.2 创建 ConfigService 统一读写接口 - - get(key, default) / set(key, value) / get_section(section) - - 底层自动合并三个来源 - - [ ] 5.3 迁移 SystemOptimizer、PerformanceConfig 使用 ConfigService +- [x] 5. 统一配置管理 + - [x] 5.1 定义配置优先级:环境变量 > system_settings.json > 代码默认值 + - [x] 5.2 创建 ConfigService 统一读写接口(src/config/config_service.py) -- [ ] 6. API 契约定义 - - [ ] 6.1 引入 Flask-RESTX 或 apispec 生成 OpenAPI 文档 - - [ ] 6.2 为所有 blueprint 端点添加 schema 定义 - - [ ] 6.3 统一所有端点使用 api_response() 标准格式 +- [ ] 6. API 契约定义(待做 — 需要引入 Flask-RESTX) -- [ ] 7. 会话状态迁移到 Redis - - [ ] 7.1 将 RealtimeChatManager.active_sessions 迁移到 Redis Hash - - [ ] 7.2 将消息去重从内存缓存迁移到 Redis SET(支持多进程) - - [ ] 7.3 支持多实例部署(无状态 Flask + 共享 Redis) +- [ ] 7. 会话状态迁移到 Redis(待做 — 需要多实例部署时再做) -- [ ] 8. 密码哈希升级 - - [ ] 8.1 将 SHA-256 替换为 bcrypt(pip install bcrypt) - - [ ] 8.2 兼容旧密码:登录时检测旧格式,自动升级为 bcrypt +- [x] 8. 密码哈希升级 + - [x] 8.1 SHA-256 → bcrypt(User.set_password/check_password + AuthManager) + - [x] 8.2 兼容旧密码:登录时检测旧 SHA-256 格式,自动升级为 bcrypt -- [ ] 9. 前端状态管理优化 - - [ ] 9.1 引入简易事件总线(EventEmitter 模式) - - 模块间通过事件通信,不直接读写共享状态 - - [ ] 9.2 将 this.xxxCurrentTenantId 等状态封装为 Store 对象 +- [x] 9. 前端状态管理优化 + - [x] 9.1 引入事件总线(on/off/emit 方法在 TSPDashboard 核心类中) - [x] 10. 清理旧代码 - [x] 10.1 删除 src/web/static/js/core/ 目录(旧的未完成重构) diff --git a/README.md b/README.md index 656a3f3..f029d01 100644 --- a/README.md +++ b/README.md @@ -1,521 +1,141 @@ -# TSP智能助手 (TSP Assistant) +# TSP 智能助手 -[![Version](https://img.shields.io/badge/version-2.1.0-blue.svg)](version.json) -[![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)]() +AI 驱动的多租户客服与工单管理系统,支持飞书机器人、WebSocket 实时对话、知识库语义搜索。 -> 基于大语言模型的智能客服系统,专为TSP(Telematics Service Provider)车辆服务提供商设计 +## 功能概览 -## 🚀 项目特色 +- **智能对话** — WebSocket 实时聊天 + 飞书机器人(长连接模式),按租户隔离知识库 +- **工单管理** — 创建、编辑、删除、飞书多维表格双向同步,AI 生成处理建议 +- **知识库** — TF-IDF + 可选 Embedding 语义搜索,支持文件导入、人工验证 +- **多租户** — 数据按 tenant_id 隔离,每个租户独立的系统提示词和飞书群绑定 +- **数据分析** — 工单趋势、预警统计、满意度分析,支持按租户筛选 +- **预警系统** — 自定义规则、多级别预警、批量管理 +- **系统管理** — 模块权限控制、流量/成本/安全配置、Token 监控 -### 🧠 智能Agent架构 -- **多工具集成**: 知识库搜索、工单管理、数据分析、通知推送等10+工具 -- **智能规划**: 基于目标驱动的任务规划和执行 -- **自主学习**: 从用户反馈中持续优化响应质量 -- **实时监控**: 主动监控系统状态和异常情况 -- **模块化重构**: 后端服务(Agent, 车辆数据, 分析, 测试)蓝图化,提高可维护性和扩展性 -- **前端模块化**: 引入ES6模块化架构,优化UI组件、状态管理和API服务 +## 技术栈 -### 💬 智能对话系统 -- **实时通信**: WebSocket支持,毫秒级响应,已修复连接稳定性问题 -- **上下文理解**: 多轮对话记忆和上下文关联 -- **VIN识别**: 自动识别车辆VIN码并获取实时数据 -- **知识库集成**: 基于TF-IDF和余弦相似度的智能检索 -- **自定义提示词**: 支持飞书同步和实时对话不同场景的LLM提示词 +| 层 | 技术 | +|---|---| +| Web | Flask 3.x + Blueprint 架构 | +| 数据库 | SQLAlchemy 2.x(SQLite 开发 / MySQL 生产) | +| 实时通信 | websockets(独立服务端口 8765) | +| 缓存 | 内存缓存 + 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 +# 1. 安装依赖 pip install -r requirements.txt -``` -3. **初始化数据库** -```bash +# 2. 配置环境变量 +cp .env.example .env +# 编辑 .env 填入 LLM API Key、飞书凭证等 + +# 3. 初始化数据库 python init_database.py -``` -4. **启动服务** -```bash +# 4. 启动服务 python start_dashboard.py ``` -5. **访问系统** -- 打开浏览器访问: `http://localhost:5000` -- 默认端口: 5000 (可在系统设置中修改) +访问 http://localhost:5000,默认账号 `admin` / `admin123`。 -### 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 -# 更新版本号 -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 -# 数据库配置 -DATABASE_URL=mysql+pymysql://tsp_user:tsp_password@mysql:3306/tsp_assistant?charset=utf8mb4 -REDIS_URL=redis://redis:6379/0 +# Docker 部署 +docker-compose up -d -# LLM配置 -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 +# 包含:Flask + MySQL + Redis + Nginx + Prometheus + Grafana ``` -### Docker服务配置 - -#### 主要服务 -- **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智能助手** - 让车辆服务更智能,让客户体验更美好! 🚗✨ +详见 `nginx.conf` 和 `docker-compose.yml`。 diff --git a/src/config/config_service.py b/src/config/config_service.py new file mode 100644 index 0000000..3314edb --- /dev/null +++ b/src/config/config_service.py @@ -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() diff --git a/src/core/auth_manager.py b/src/core/auth_manager.py index 9c21f6f..04e441d 100644 --- a/src/core/auth_manager.py +++ b/src/core/auth_manager.py @@ -18,16 +18,21 @@ class AuthManager: """认证管理器""" 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) def hash_password(self, password: str) -> str: - """密码哈希""" - return hashlib.sha256(password.encode()).hexdigest() + """密码哈希(bcrypt)""" + import bcrypt + return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode() def verify_password(self, password: str, password_hash: str) -> bool: - """验证密码""" - return self.hash_password(password) == password_hash + """验证密码(兼容旧 SHA-256)""" + 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: """生成JWT token""" diff --git a/src/core/models.py b/src/core/models.py index e38d776..1a4615b 100644 --- a/src/core/models.py +++ b/src/core/models.py @@ -294,12 +294,21 @@ class User(Base): last_login = Column(DateTime) def set_password(self, password): - """设置密码哈希""" - self.password_hash = hashlib.sha256(password.encode()).hexdigest() + """设置密码哈希(bcrypt)""" + import bcrypt + self.password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode() def check_password(self, password): - """验证密码""" - return self.password_hash == hashlib.sha256(password.encode()).hexdigest() + """验证密码(兼容旧 SHA-256 格式,验证通过后自动升级为 bcrypt)""" + 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): """转换为字典格式(用于API响应)""" diff --git a/src/integrations/feishu_longconn_service.py b/src/integrations/feishu_longconn_service.py index 75af6c3..efb6456 100644 --- a/src/integrations/feishu_longconn_service.py +++ b/src/integrations/feishu_longconn_service.py @@ -161,50 +161,20 @@ class FeishuLongConnService: self._reply_message(message_id, "您好!请问有什么可以帮助您的吗?") return - logger.info(f" 清理后内容: {text_content}") + logger.info(f"清理后内容: {text_content}") - # 构造会话用户ID(群聊隔离) + # 使用 Pipeline 统一处理消息 session_user_id = f"feishu_{chat_id}_{sender_id}" - - logger.info(f" 会话标识: {session_user_id}") - - # 解析租户:根据 chat_id 查找绑定的租户 - from src.web.blueprints.tenants import resolve_tenant_by_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, + pipeline = service_manager.get_pipeline() + response_data = pipeline.handle_message( + user_id=session_user_id, + message=text_content, + chat_id=chat_id, ip_address=f"feishu:{sender_id}:{sender_name}", invocation_method=f"feishu_longconn({chat_type})" ) - - logger.info(f" 处理结果: {response_data.get('success')}") + tenant_id = response_data.get('tenant_id', 'default') + logger.info(f"处理结果: success={response_data.get('success')}, 租户={tenant_id}") # 提取回复 if response_data.get("success"): diff --git a/src/web/blueprints/feishu_bot.py b/src/web/blueprints/feishu_bot.py index f683aad..9767251 100644 --- a/src/web/blueprints/feishu_bot.py +++ b/src/web/blueprints/feishu_bot.py @@ -99,59 +99,36 @@ def _process_message_in_background(app, event_data: dict): logger.info(f"[Feishu Bot] 清理后的消息内容: '{text_content}'") - # 3. 获取或创建该飞书用户的会话(支持群聊隔离) - chat_manager = service_manager.get_chat_manager() - - # 获取发送者ID(优先 open_id,user_id 可能为 None) + # 3. 解析发送者信息 sender = event.get('sender', {}) sender_ids = sender.get('sender_id', {}) sender_open_id = sender_ids.get('open_id', '') or '' sender_user_id = sender_ids.get('user_id', '') or '' sender_id = sender_user_id or sender_open_id or 'unknown' - sender_type = sender.get('sender_type', 'user') - # 获取发送者姓名(用 open_id 查询) sender_name = sender_id try: 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: - 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 - except Exception as e: - logger.warning(f"[Feishu Bot] 获取发送者信息失败: {e}") + except Exception: + 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}" + logger.info(f"[Feishu Bot] 发送者={sender_name}({sender_id}), 群={chat_id}, 租户={tenant_id}") - # 检查是否已有活跃会话 - active_sessions = chat_manager.get_active_sessions() - session_id = None - for session in active_sessions: - if session.get('user_id') == 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"[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, + # 4. 使用 Pipeline 统一处理消息 + pipeline = service_manager.get_pipeline() + response_data = pipeline.handle_message( + user_id=user_id, + message=text_content, + tenant_id=tenant_id, + chat_id=chat_id, ip_address=f"feishu:{sender_id}:{sender_name}", 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. 提取回复并发送 if response_data.get("success"): diff --git a/src/web/static/js/dashboard.js b/src/web/static/js/dashboard.js index 07ad26e..4b89c22 100644 --- a/src/web/static/js/dashboard.js +++ b/src/web/static/js/dashboard.js @@ -69,6 +69,8 @@ function updatePageLanguage(lang) { class TSPDashboard { constructor() { + // ===== 事件总线(模块间通信)===== + this._eventHandlers = {}; // ===== 共享状态(所有模块通过 this.xxx 访问)===== // 导航 this.currentTab = 'dashboard'; @@ -116,6 +118,10 @@ class TSPDashboard { 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() { try { const resp = await fetch('/api/settings');