From c09379ddea78031d3079c6afd4a771b33683c5a6 Mon Sep 17 00:00:00 2001 From: zhinianboke <115088296+zhinianboke@users.noreply.github.com> Date: Fri, 25 Jul 2025 10:30:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=9D=99=E6=80=81=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=B8=BA=E6=9C=AC=E5=9C=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 103 - .gitignore | 35 +- AI_REPLY_GUIDE.md | 10 +- CHANGELOG.md | 178 -- CONTRIBUTING.md | 220 -- LICENSE | 2 +- README.md | 599 ++--- Start.py | 31 - UI_IMPROVEMENTS.md | 92 + XianyuAutoAsync.py | 185 +- backup_import_update_summary.md | 193 ++ cookie_manager.py | 15 + db_manager.py | 54 +- deploy.bat | 298 +++ docker-deploy.bat | 301 +++ docker-deploy.sh | 350 +++ docker_deployment_update.md | 207 ++ file_log_collector.py | 168 +- fix-db-permissions.bat | 156 ++ fix-db-permissions.sh | 167 ++ fix-docker-warnings.bat | 144 ++ fix-docker-warnings.sh | 145 ++ fix-websocket-issue.sh | 121 + gitignore_rules_explanation.md | 172 ++ global_config.yml | 2 +- images/qq-group.jpg | Bin 146989 -> 0 bytes images/wechat-group.jpg | Bin 170848 -> 0 bytes log_filter.py | 161 -- quick-fix-permissions.bat | 116 + quick-fix-permissions.sh | 88 + reply_server.py | 174 +- static/index.html | 225 +- .../lib/bootstrap-icons/bootstrap-icons.css | 2078 +++++++++++++++++ .../fonts/bootstrap-icons.woff | Bin 0 -> 176196 bytes .../fonts/bootstrap-icons.woff2 | Bin 0 -> 130764 bytes static/lib/bootstrap/bootstrap.bundle.min.js | 7 + static/lib/bootstrap/bootstrap.min.css | 6 + static/login.html | 6 +- static/test_local_resources.html | 75 + test_ai_reply.py | 215 ++ test_ai_reply_fix.py | 166 ++ test_backup_import.py | 282 +++ test_bargain_limit.py | 267 +++ test_bargain_limit_direct.py | 183 ++ test_cache_refresh.py | 202 ++ test_docker_deployment.py | 331 +++ test_fix.py | 27 + test_gitignore.py | 149 ++ test_gitignore_db.py | 178 ++ test_keyword_reply.py | 290 +++ test_status_display.html | 250 ++ 使用说明.md | 139 +- 商品管理功能说明.md | 58 +- 回复优先级优化说明.md | 147 -- 日志管理功能说明.md | 92 +- 日志系统优化说明.md | 221 -- 自动发货功能说明.md | 92 +- 获取所有商品功能说明.md | 120 +- 58 files changed, 8044 insertions(+), 2249 deletions(-) delete mode 100644 .env delete mode 100644 CHANGELOG.md delete mode 100644 CONTRIBUTING.md create mode 100644 UI_IMPROVEMENTS.md create mode 100644 backup_import_update_summary.md create mode 100644 deploy.bat create mode 100644 docker-deploy.bat create mode 100644 docker-deploy.sh create mode 100644 docker_deployment_update.md create mode 100644 fix-db-permissions.bat create mode 100644 fix-db-permissions.sh create mode 100644 fix-docker-warnings.bat create mode 100644 fix-docker-warnings.sh create mode 100644 fix-websocket-issue.sh create mode 100644 gitignore_rules_explanation.md delete mode 100644 images/qq-group.jpg delete mode 100644 images/wechat-group.jpg delete mode 100644 log_filter.py create mode 100644 quick-fix-permissions.bat create mode 100644 quick-fix-permissions.sh create mode 100644 static/lib/bootstrap-icons/bootstrap-icons.css create mode 100644 static/lib/bootstrap-icons/fonts/bootstrap-icons.woff create mode 100644 static/lib/bootstrap-icons/fonts/bootstrap-icons.woff2 create mode 100644 static/lib/bootstrap/bootstrap.bundle.min.js create mode 100644 static/lib/bootstrap/bootstrap.min.css create mode 100644 static/test_local_resources.html create mode 100644 test_ai_reply.py create mode 100644 test_ai_reply_fix.py create mode 100644 test_backup_import.py create mode 100644 test_bargain_limit.py create mode 100644 test_bargain_limit_direct.py create mode 100644 test_cache_refresh.py create mode 100644 test_docker_deployment.py create mode 100644 test_fix.py create mode 100644 test_gitignore.py create mode 100644 test_gitignore_db.py create mode 100644 test_keyword_reply.py create mode 100644 test_status_display.html delete mode 100644 回复优先级优化说明.md delete mode 100644 日志系统优化说明.md diff --git a/.env b/.env deleted file mode 100644 index de78e8a..0000000 --- a/.env +++ /dev/null @@ -1,103 +0,0 @@ -# 闲鱼自动回复系统 Docker 环境变量配置文件 -# 这是默认配置,您可以根据需要修改 - -# ================================ -# 基础配置 -# ================================ - -# 时区设置 -TZ=Asia/Shanghai - -# Python配置 -PYTHONUNBUFFERED=1 -PYTHONDONTWRITEBYTECODE=1 - -# 日志级别 (DEBUG, INFO, WARNING, ERROR) -LOG_LEVEL=INFO - -# ================================ -# 数据库配置 -# ================================ - -# 数据库文件路径 -DB_PATH=/app/data/xianyu_data.db - -# ================================ -# 服务配置 -# ================================ - -# API服务配置 -API_HOST=0.0.0.0 # 绑定所有网络接口,支持IP访问 -API_PORT=8080 # Web服务端口 - -# Web服务端口 (Docker端口映射) -WEB_PORT=8080 - -# ================================ -# 安全配置 -# ================================ - -# 管理员账号密码 (建议修改) -ADMIN_USERNAME=admin -ADMIN_PASSWORD=admin123 - -# JWT密钥 (建议修改为随机字符串) -JWT_SECRET_KEY=xianyu-auto-reply-secret-key-2024 - -# Session超时时间 (秒) -SESSION_TIMEOUT=3600 - -# ================================ -# 闲鱼API配置 -# ================================ - -# WebSocket连接URL -WEBSOCKET_URL=wss://wss-goofish.dingtalk.com/ - -# 心跳间隔 (秒) -HEARTBEAT_INTERVAL=15 - -# 心跳超时 (秒) -HEARTBEAT_TIMEOUT=5 - -# Token刷新间隔 (秒) -TOKEN_REFRESH_INTERVAL=3600 - -# Token重试间隔 (秒) -TOKEN_RETRY_INTERVAL=300 - -# 消息过期时间 (毫秒) -MESSAGE_EXPIRE_TIME=300000 - -# ================================ -# 自动回复配置 -# ================================ - -# 是否启用自动回复 -AUTO_REPLY_ENABLED=true - -# ================================ -# 资源限制 -# ================================ - -# 内存限制 (MB) -MEMORY_LIMIT=512 - -# CPU限制 (核心数) -CPU_LIMIT=0.5 - -# 内存预留 (MB) -MEMORY_RESERVATION=256 - -# CPU预留 (核心数) -CPU_RESERVATION=0.25 - -# ================================ -# 开发配置 -# ================================ - -# 开发模式 (true/false) -DEBUG=false - -# 热重载 (true/false) -RELOAD=false diff --git a/.gitignore b/.gitignore index 444c9a3..292795c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,9 @@ dist/ downloads/ eggs/ .eggs/ +# Python lib directories (but not static/lib) lib/ +!static/lib/ lib64/ parts/ sdist/ @@ -20,6 +22,11 @@ MANIFEST .cache *.log local_settings.py + +# Database files +*.db +*.sqlite +*.sqlite3 db.sqlite3 __pypackages__/ .venv @@ -28,4 +35,30 @@ venv/ ENV/ env.bak/ venv.bak/ -*.db \ No newline at end of file + +# Temporary files +*.tmp +*.temp +temp/ +tmp/ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Local environment files +.env +.env.local +.env.*.local \ No newline at end of file diff --git a/AI_REPLY_GUIDE.md b/AI_REPLY_GUIDE.md index b89de42..f700fd7 100644 --- a/AI_REPLY_GUIDE.md +++ b/AI_REPLY_GUIDE.md @@ -113,16 +113,14 @@ AI分析消息内容,识别用户意图: ## 📊 优先级说明 -系统回复优先级为: +当账号启用AI回复后,系统回复优先级为: 1. **🔥 API回复** (最高优先级) -2. **📝 关键词匹配** (优先匹配精确关键词) -3. **🤖 AI回复** (AI启用时的智能回复) +2. **🤖 AI回复** (AI启用时) +3. **📝 关键词匹配** (AI禁用时) 4. **💬 默认回复** (最低优先级) -> ✨ **优化**: 关键词回复优先于AI回复,确保重要关键词能够精确匹配! -> -> 💡 **说明**: 即使启用AI回复,关键词匹配仍然有效,只有在没有匹配的关键词时才会使用AI回复。 +> ⚠️ **重要**: 启用AI回复后,关键词匹配和默认回复将自动失效! ## 🧪 功能测试 diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 16a7a8a..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,178 +0,0 @@ -# 📋 更新日志 - -本文档记录了闲鱼自动回复管理系统的所有重要更新和变更。 - -## [v2.0.2] - 2024-07-24 - -### 🔧 功能改进 -- **日志系统优化**:完善统一日志记录系统 - - 所有日志统一记录到文件中,界面读取日志文件显示 - - 添加智能日志过滤器,过滤掉不必要的API请求日志 - - 优化日志格式,便于解析和展示 - - 提高日志收集的实时性和准确性 - - 过滤掉频繁的健康检查、静态资源请求等日志 - -### 🚀 性能优化 -- **日志性能提升**:减少不必要的日志记录,提高系统性能 -- **文件监控优化**:优化日志文件监控频率,更及时地收集日志 -- **内存使用优化**:智能过滤减少内存中的日志数量 - -### 📚 文档更新 -- 新增日志过滤器说明文档 -- 更新日志管理功能说明 - -## [v2.0.1] - 2024-07-24 - -### 🔧 功能改进 -- **回复优先级优化**:调整自动回复逻辑,关键词回复优先于AI回复 - - 新的优先级顺序:API回复 → 关键词回复 → AI回复 → 默认回复 - - 确保重要关键词能够精确匹配,AI回复作为智能补充 - - 提高回复的准确性和用户体验 - -### 📚 文档更新 -- 更新AI回复功能指南中的优先级说明 -- 更新使用说明中的回复逻辑描述 -- 更新README.md中的功能特性说明 - -## [v2.0.0] - 2024-07-24 - -### 🎉 重大更新 -- **AI智能回复系统**:集成多种AI模型,支持智能对话和议价 -- **商品管理功能**:自动收集和管理商品信息 -- **实时日志系统**:完整的日志收集、查看和分析功能 -- **Docker容器化**:完整的Docker部署支持 - -### ✨ 新增功能 -- **多AI模型支持**:支持通义千问、GPT等主流AI模型 -- **智能意图识别**:自动识别价格咨询、技术问题、通用咨询 -- **智能议价系统**:阶梯式降价策略,可设置最大优惠幅度 -- **商品信息自动收集**:消息触发时自动提取并保存商品信息 -- **批量商品获取**:一键获取账号下所有商品信息 -- **实时日志查看**:Web界面实时查看系统运行日志 -- **日志过滤和搜索**:支持按级别、来源、关键词过滤日志 -- **系统健康监控**:完整的系统健康检查和监控 -- **数据备份恢复**:支持完整的数据备份和恢复功能 - -### 🔧 功能改进 -- **用户界面优化**:现代化的Web界面设计 -- **性能优化**:异步处理,提高系统并发能力 -- **安全增强**:JWT认证,数据加密存储 -- **错误处理**:完善的错误处理和重试机制 -- **配置管理**:灵活的配置文件管理系统 - -### 🐛 问题修复 -- 修复WebSocket连接不稳定的问题 -- 修复Cookie失效时的自动刷新机制 -- 修复数据库并发访问的问题 -- 修复文件上传的安全问题 -- 修复日志文件过大的问题 - -### 📚 文档更新 -- 完整的README.md文档 -- 详细的功能使用说明 -- Docker部署指南 -- API接口文档 -- 故障排除指南 - -## [v1.5.0] - 2024-06-15 - -### ✨ 新增功能 -- **自动发货增强**:支持API接口类型卡券 -- **批量数据管理**:支持批量导入和管理卡券 -- **发货规则优化**:更智能的商品匹配算法 -- **消息通知格式化**:美化消息通知格式 - -### 🔧 功能改进 -- 优化自动发货匹配逻辑 -- 改进卡券管理界面 -- 增强错误处理机制 -- 提升系统稳定性 - -### 🐛 问题修复 -- 修复发货规则匹配不准确的问题 -- 修复批量数据消耗过快的问题 -- 修复API接口调用失败的问题 - -## [v1.4.0] - 2024-05-20 - -### ✨ 新增功能 -- **多账号管理**:支持同时管理多个闲鱼账号 -- **关键词回复**:每个账号独立的关键词回复设置 -- **用户认证系统**:安全的登录认证机制 -- **数据持久化**:SQLite数据库存储 - -### 🔧 功能改进 -- 重构代码架构,提高可维护性 -- 优化数据库设计 -- 改进用户界面体验 -- 增强系统安全性 - -## [v1.3.0] - 2024-04-25 - -### ✨ 新增功能 -- **自动发货功能**:支持自动发送卡券和虚拟商品 -- **发货规则配置**:灵活的发货规则设置 -- **卡券管理**:支持多种卡券类型管理 - -### 🔧 功能改进 -- 优化消息处理逻辑 -- 改进WebSocket连接稳定性 -- 增强日志记录功能 - -## [v1.2.0] - 2024-03-30 - -### ✨ 新增功能 -- **Web管理界面**:现代化的Web管理界面 -- **实时状态监控**:实时查看系统运行状态 -- **配置文件管理**:可视化配置文件编辑 - -### 🔧 功能改进 -- 优化自动回复逻辑 -- 改进错误处理机制 -- 增强系统稳定性 - -## [v1.1.0] - 2024-02-28 - -### ✨ 新增功能 -- **关键词匹配**:支持关键词自动回复 -- **变量替换**:支持消息中的变量替换 -- **日志系统**:完整的日志记录功能 - -### 🔧 功能改进 -- 优化WebSocket连接处理 -- 改进消息解析逻辑 -- 增强系统容错能力 - -## [v1.0.0] - 2024-01-15 - -### 🎉 首次发布 -- **基础自动回复**:支持闲鱼消息自动回复 -- **WebSocket连接**:稳定的WebSocket连接机制 -- **Token管理**:自动Token刷新和管理 -- **消息处理**:完整的消息接收和处理流程 - ---- - -## 📝 版本说明 - -### 版本号规则 -- **主版本号**:重大功能更新或架构变更 -- **次版本号**:新功能添加或重要改进 -- **修订版本号**:问题修复和小幅改进 - -### 更新类型说明 -- 🎉 **重大更新**:重要的新功能或架构变更 -- ✨ **新增功能**:新增的功能特性 -- 🔧 **功能改进**:现有功能的优化和改进 -- 🐛 **问题修复**:Bug修复和问题解决 -- 📚 **文档更新**:文档和说明的更新 -- 🔒 **安全更新**:安全相关的更新和修复 - -### 兼容性说明 -- **向后兼容**:新版本保持与旧版本的兼容性 -- **配置迁移**:提供配置文件自动迁移功能 -- **数据迁移**:提供数据库自动升级功能 - ---- - -**注意**:建议在升级前备份重要数据,详细的升级指南请参考相关文档。 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index c897ef4..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,220 +0,0 @@ -# 🤝 贡献指南 - -感谢您对闲鱼自动回复管理系统的关注!我们欢迎任何形式的贡献,包括但不限于代码、文档、问题反馈和功能建议。 - -## 📋 贡献方式 - -### 🐛 报告问题 -如果您发现了bug或有改进建议,请: -1. 检查 [Issues](https://github.com/your-repo/xianyu-auto-reply/issues) 确认问题未被报告 -2. 创建新的Issue,详细描述问题 -3. 提供复现步骤和环境信息 -4. 如果可能,提供错误日志和截图 - -### 💡 功能建议 -如果您有新功能的想法: -1. 在Issues中创建功能请求 -2. 详细描述功能需求和使用场景 -3. 说明功能的预期效果 -4. 讨论实现方案的可行性 - -### 🔧 代码贡献 -我们欢迎代码贡献,请遵循以下流程: - -#### 开发环境搭建 -1. **Fork项目**到您的GitHub账号 -2. **克隆项目**到本地: - ```bash - git clone https://github.com/your-username/xianyu-auto-reply.git - cd xianyu-auto-reply - ``` -3. **创建虚拟环境**: - ```bash - python -m venv venv - source venv/bin/activate # Linux/Mac - # 或 - venv\Scripts\activate # Windows - ``` -4. **安装依赖**: - ```bash - pip install -r requirements.txt - ``` -5. **运行测试**确保环境正常: - ```bash - python Start.py - ``` - -#### 开发流程 -1. **创建分支**: - ```bash - git checkout -b feature/your-feature-name - ``` -2. **编写代码**,遵循项目的代码规范 -3. **编写测试**,确保新功能有相应的测试用例 -4. **运行测试**,确保所有测试通过 -5. **提交代码**: - ```bash - git add . - git commit -m "feat: 添加新功能描述" - ``` -6. **推送分支**: - ```bash - git push origin feature/your-feature-name - ``` -7. **创建Pull Request** - -## 📝 代码规范 - -### Python代码规范 -- 遵循 [PEP 8](https://www.python.org/dev/peps/pep-0008/) 代码风格 -- 使用有意义的变量和函数名 -- 添加必要的注释和文档字符串 -- 保持函数简洁,单一职责原则 - -### 提交信息规范 -使用 [Conventional Commits](https://www.conventionalcommits.org/) 规范: - -``` -[optional scope]: - -[optional body] - -[optional footer(s)] -``` - -#### 提交类型 -- `feat`: 新功能 -- `fix`: 问题修复 -- `docs`: 文档更新 -- `style`: 代码格式调整 -- `refactor`: 代码重构 -- `test`: 测试相关 -- `chore`: 构建过程或辅助工具的变动 - -#### 示例 -``` -feat(ai): 添加智能议价功能 - -- 实现阶梯式降价策略 -- 支持最大优惠限制 -- 添加议价轮数统计 - -Closes #123 -``` - -### 文档规范 -- 使用Markdown格式 -- 保持文档结构清晰 -- 添加必要的代码示例 -- 及时更新相关文档 - -## 🧪 测试指南 - -### 运行测试 -```bash -# 运行所有测试 -python -m pytest - -# 运行特定测试文件 -python -m pytest tests/test_ai_reply.py - -# 运行带覆盖率的测试 -python -m pytest --cov=. -``` - -### 编写测试 -- 为新功能编写单元测试 -- 确保测试覆盖率不低于80% -- 使用有意义的测试名称 -- 测试边界条件和异常情况 - -### 测试示例 -```python -def test_ai_reply_with_valid_input(): - """测试AI回复功能的正常输入""" - # 准备测试数据 - message = "这个商品能便宜点吗?" - - # 执行测试 - result = ai_reply_engine.process_message(message) - - # 验证结果 - assert result is not None - assert "优惠" in result -``` - -## 📚 文档贡献 - -### 文档类型 -- **用户文档**:使用说明、配置指南 -- **开发文档**:API文档、架构说明 -- **部署文档**:安装部署指南 - -### 文档更新 -- 新功能需要更新相关文档 -- 修复文档中的错误和过时信息 -- 改进文档的可读性和准确性 - -## 🔍 代码审查 - -### 审查标准 -- **功能正确性**:代码是否实现了预期功能 -- **代码质量**:是否遵循代码规范 -- **性能考虑**:是否有性能问题 -- **安全性**:是否存在安全隐患 -- **测试覆盖**:是否有足够的测试 - -### 审查流程 -1. 提交Pull Request -2. 自动化测试运行 -3. 代码审查和讨论 -4. 修改和完善 -5. 合并到主分支 - -## 🎯 贡献建议 - -### 适合新手的任务 -- 修复文档中的错误 -- 改进错误信息和提示 -- 添加单元测试 -- 优化用户界面 - -### 高级贡献 -- 新功能开发 -- 性能优化 -- 架构改进 -- 安全增强 - -## 📞 联系方式 - -### 获取帮助 -- **GitHub Issues**:报告问题和讨论 -- **GitHub Discussions**:一般性讨论和问答 -- **Email**:紧急问题联系 - -### 社区参与 -- 参与Issue讨论 -- 帮助其他用户解决问题 -- 分享使用经验和技巧 -- 推广项目 - -## 🏆 贡献者认可 - -### 贡献者列表 -我们会在项目中维护贡献者列表,感谢每一位贡献者的付出。 - -### 贡献统计 -- 代码贡献 -- 文档贡献 -- 问题报告 -- 功能建议 - -## 📄 许可证 - -通过贡献代码,您同意您的贡献将在 [MIT License](LICENSE) 下发布。 - ---- - -**再次感谢您的贡献!** 🙏 - -每一个贡献都让这个项目变得更好,无论大小,我们都非常感激。让我们一起构建一个更好的闲鱼自动回复管理系统! diff --git a/LICENSE b/LICENSE index 19a5768..4501f64 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Xianyu Auto Reply System +Copyright (c) 2025 肥极喵 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 30ec1c6..ce4260f 100644 --- a/README.md +++ b/README.md @@ -1,510 +1,173 @@ -# 🚀 闲鱼自动回复管理系统 +# 🐟 XianYuAutoDeliveryX - 闲鱼虚拟商品商自动发货&聊天对接大模型 -
+[![Python Version](https://img.shields.io/badge/python-3.7%2B-blue)](https://www.python.org/) +[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE) -![Python](https://img.shields.io/badge/Python-3.11+-blue.svg) -![FastAPI](https://img.shields.io/badge/FastAPI-0.111+-green.svg) -![Docker](https://img.shields.io/badge/Docker-支持-blue.svg) -![License](https://img.shields.io/badge/License-MIT-yellow.svg) -![Version](https://img.shields.io/badge/Version-v2.0.0-brightgreen.svg) -![Platform](https://img.shields.io/badge/Platform-Linux%20%7C%20Windows%20%7C%20macOS-lightgrey.svg) +**✨ 基于闲鱼API的自动发货系统,支持虚拟商品商品聊天窗口自动发货、消息自动回复等功能。** +**⚠️ 注意:本项目仅供学习交流使用,请勿用于商业用途。** -**一个功能强大的闲鱼自动回复管理系统,支持多账号管理、AI智能回复、自动发货等功能** +## 🌟 核心特性 -[功能特性](#-功能特性) • [快速开始](#-快速开始) • [部署方式](#-部署方式) • [使用文档](#-使用文档) • [API文档](#-api文档) • [贡献指南](#-贡献指南) +- 🔐 **用户认证系统** - 安全的登录认证,保护管理界面 +- 👥 **多账号管理** - 支持同时管理多个闲鱼账号 +- 🎯 **智能关键词回复** - 每个账号独立的关键词回复设置 +- 💾 **数据持久化** - SQLite数据库存储账号和关键词数据 +- 🌐 **美观Web界面** - 响应式设计,操作简单直观 +- 📡 **API接口** - 完整的RESTful API支持 +- 🔄 **实时消息处理** - 基于WebSocket的实时消息监控 +- 📊 **订单状态监控** - 实时跟踪订单状态变化 +- 📝 **完善的日志系统** - 详细的操作日志记录 -
+## 🛠️ 快速开始 -## 📋 项目概述 - -闲鱼自动回复管理系统是一个基于 Python + FastAPI 开发的自动化客服系统,专为闲鱼平台设计。系统通过 WebSocket 连接闲鱼服务器,实时接收和处理消息,提供智能化的自动回复服务。 - -### 🎯 核心优势 - -- **🤖 AI智能回复**:集成多种AI模型,支持意图识别和智能议价 -- **🔄 多账号管理**:同时管理多个闲鱼账号,独立配置和监控 -- **📦 商品管理**:自动收集和管理商品信息,支持批量操作 -- **🚚 自动发货**:智能匹配发货规则,自动发送卡券信息 -- **📊 实时监控**:完整的日志系统和状态监控 -- **🐳 容器化部署**:支持Docker一键部署,简化运维 - -## ✨ 功能特性 - -### 🤖 AI智能回复 -- **多模型支持**:支持通义千问、GPT等主流AI模型 -- **意图识别**:自动识别价格咨询、技术问题、通用咨询 -- **智能议价**:阶梯式降价策略,可设置最大优惠幅度 -- **上下文感知**:记住完整对话历史,提供连贯回复 -- **自定义提示词**:支持针对不同场景自定义AI提示词 -- **智能优先级**:关键词回复优先,AI回复作为智能补充 - -### 👥 多账号管理 -- **账号隔离**:每个账号独立配置和管理 -- **批量操作**:支持批量添加、删除、配置账号 -- **状态监控**:实时监控账号连接状态和消息处理情况 -- **权限控制**:基于JWT的安全认证系统 - -### 📦 商品管理 -- **自动收集**:消息触发时自动收集商品信息 -- **详情获取**:通过API获取完整商品详情 -- **批量管理**:支持查看、编辑、删除商品信息 -- **智能匹配**:基于商品信息进行关键词匹配 - -### 🚚 自动发货 -- **规则配置**:灵活的发货规则配置系统 -- **卡券管理**:支持多种卡券类型和批量导入 -- **智能匹配**:根据商品信息自动匹配发货规则 -- **发货记录**:完整的发货历史记录和统计 - -### 📊 监控与日志 -- **实时日志**:多级别日志记录和实时查看 -- **性能监控**:系统资源使用情况监控 -- **消息统计**:消息处理统计和分析 -- **健康检查**:完整的系统健康检查机制 - -## 🛠️ 技术栈 - -### 后端技术 -- **Python 3.11+**:主要开发语言 -- **FastAPI**:现代化的Web框架 -- **SQLite**:轻量级数据库 -- **WebSocket**:实时通信 -- **AsyncIO**:异步编程 - -### 前端技术 -- **HTML5 + CSS3**:现代化界面设计 -- **JavaScript (ES6+)**:交互逻辑 -- **Bootstrap**:响应式布局 -- **Chart.js**:数据可视化 - -### 部署技术 -- **Docker**:容器化部署 -- **Docker Compose**:多容器编排 -- **Nginx**:反向代理和负载均衡 -- **SSL/TLS**:安全传输 - -## 🚀 快速开始 - -> 💡 **推荐使用Docker镜像部署,无需配置环境,一键启动!** - -### 🐳 方式一:Docker 镜像部署(推荐) - -**使用预构建的Docker镜像,一键启动:** +### ⛳ 运行环境 +- Python 3.7+ +### 🎯 安装依赖 ```bash -docker run -d -p 8080:8080 --name xianyu-auto-reply --privileged=true registry.cn-shanghai.aliyuncs.com/zhinian-software/xianyu-auto-reply:1.0 +pip install -r requirements.txt ``` -**特点:** -- ✅ **零配置**:无需安装Python环境和依赖 -- ✅ **即开即用**:一条命令启动完整系统 -- ✅ **稳定可靠**:经过测试的稳定版本 -- ✅ **自动更新**:支持数据持久化和版本升级 +### 🎨 配置说明 +1. 在 `global_config.yml` 中配置基本参数 +2. 系统支持多账号管理,可通过Web界面添加多个闲鱼账号Cookie -**访问系统:** -- 🌐 Web界面:http://localhost:8080 -- 👤 默认账号:admin / admin123 -- 📖 API文档:http://localhost:8080/docs - -**常用管理命令:** +### 🚀 运行项目 ```bash -# 查看容器状态 -docker ps - -# 查看容器日志 -docker logs xianyu-auto-reply - -# 重启容器 -docker restart xianyu-auto-reply - -# 停止容器 -docker stop xianyu-auto-reply - -# 删除容器 -docker rm xianyu-auto-reply +python Start.py ``` -### 方式二:Docker 源码部署 +### 🔐 登录系统 +1. 启动后访问 `http://localhost:8080` +2. 默认登录账号: + - 用户名:`admin` + - 密码:`admin123` +3. 登录后可进入管理界面进行操作 -1. **克隆项目** - ```bash - git clone https://github.com/your-repo/xianyu-auto-reply.git - cd xianyu-auto-reply - ``` - -2. **一键部署** - ```bash - ./deploy.sh - ``` - -3. **访问系统** - - 打开浏览器访问:http://localhost:8080 - - 默认账号:admin / admin123 - -### 方式三:本地部署 - -1. **安装依赖** - ```bash - pip install -r requirements.txt - ``` - -2. **启动系统** - ```bash - python Start.py - ``` - -3. **访问系统** - - 打开浏览器访问:http://localhost:8080 - -## 📚 使用文档 - -### 基础使用 -1. **[使用说明](./使用说明.md)** - 系统基础使用指南 -2. **[Docker部署说明](./Docker部署说明.md)** - Docker部署详细说明 - -### 功能文档 -1. **[AI回复功能指南](./AI_REPLY_GUIDE.md)** - AI回复功能详细说明 -2. **[商品管理功能说明](./商品管理功能说明.md)** - 商品管理功能使用 -3. **[自动发货功能说明](./自动发货功能说明.md)** - 自动发货配置和使用 -4. **[日志管理功能说明](./日志管理功能说明.md)** - 日志查看和管理 -5. **[获取所有商品功能说明](./获取所有商品功能说明.md)** - 商品批量获取功能 - -## 🔧 配置说明 - -### 环境变量配置 -```bash -# 基础配置 -TZ=Asia/Shanghai -WEB_PORT=8080 - -# 管理员账号 -ADMIN_USERNAME=admin -ADMIN_PASSWORD=admin123 - -# AI回复配置 -AI_REPLY_ENABLED=true -DEFAULT_AI_MODEL=qwen-plus -DEFAULT_AI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 +## 📁 项目结构 +``` +├── Start.py # 项目启动入口 +├── XianyuAutoAsync.py # 核心业务逻辑 +├── config.py # 配置管理 +├── cookie_manager.py # Cookie管理器 +├── db_manager.py # 数据库管理 +├── reply_server.py # FastAPI服务器 +├── utils/ # 工具函数目录 +│ ├── xianyu_utils.py # 闲鱼相关工具 +│ ├── message_utils.py # 消息处理工具 +│ └── ws_utils.py # WebSocket工具 +├── static/ # 静态资源 +│ ├── index.html # 管理界面 +│ └── login.html # 登录页面 +├── logs/ # 日志文件 +├── global_config.yml # 全局配置文件 +├── xianyu_data.db # SQLite数据库 +└── requirements.txt # Python依赖 ``` -### 全局配置文件 -主要配置文件为 `global_config.yml`,包含: -- API端点配置 -- WebSocket连接配置 -- 自动回复配置 -- 日志配置 -- 商品详情获取配置 +## 🎯 主要功能 -## 📡 API文档 +### 1. 用户认证系统 +- 安全的登录认证机制 +- Session token管理 +- 自动登录状态检查 +- 登出功能 -### 认证接口 -- `POST /login` - 用户登录 -- `POST /logout` - 用户登出 +### 2. 多账号管理 +- 支持添加多个闲鱼账号 +- 每个账号独立管理 +- Cookie安全存储 +- 账号状态监控 -### 账号管理 -- `GET /cookies` - 获取所有账号 -- `POST /cookies` - 添加新账号 -- `DELETE /cookies/{cookie_id}` - 删除账号 +### 3. 智能关键词回复 +- 每个账号独立的关键词设置 +- 支持变量替换:`{send_user_name}`, `{send_user_id}`, `{send_message}` +- 实时关键词匹配 +- 默认回复机制 -### AI回复管理 -- `GET /ai-reply/{cookie_id}` - 获取AI配置 -- `POST /ai-reply/{cookie_id}` - 保存AI配置 -- `POST /ai-reply/{cookie_id}/test` - 测试AI回复 +### 4. Web管理界面 +- 响应式设计,支持移动端 +- 直观的操作界面 +- 实时数据更新 +- 操作反馈提示 -### 商品管理 -- `GET /items` - 获取所有商品 -- `GET /items/cookie/{cookie_id}` - 获取指定账号商品 -- `PUT /items/{cookie_id}/{item_id}` - 更新商品详情 +## 🔌 API 接口说明 -### 系统监控 -- `GET /health` - 健康检查 -- `GET /logs` - 获取系统日志 -- `GET /logs/stats` - 日志统计信息 +### 智能回复接口 +`POST http://localhost:8080/xianyu/reply` -完整API文档访问:http://localhost:8080/docs +#### 接口说明 +你需要实现这个接口,本项目会调用这个接口获取自动回复的内容并发送给客户 +不实现这个接口也没关系,系统会默认回复,你也可以配置默认回复的内容 +用于处理闲鱼消息的自动回复,支持对接大语言模型进行智能回复。 -## 🏗️ 项目结构 - -``` -xianyu-auto-reply/ -├── Start.py # 项目启动入口 -├── XianyuAutoAsync.py # 闲鱼WebSocket客户端 -├── reply_server.py # FastAPI Web服务器 -├── config.py # 配置管理 -├── cookie_manager.py # Cookie账号管理 -├── db_manager.py # 数据库管理 -├── ai_reply_engine.py # AI回复引擎 -├── file_log_collector.py # 文件日志收集器 -├── bargain_demo.py # 议价功能演示 -├── global_config.yml # 全局配置文件 -├── requirements.txt # Python依赖 -├── Dockerfile # Docker镜像构建 -├── docker-compose.yml # Docker编排配置 -├── deploy.sh # 部署脚本 -├── static/ # 前端静态文件 -│ ├── index.html # 主页面 -│ ├── login.html # 登录页面 -│ └── xianyu_js_version_2.js # 前端逻辑 -├── utils/ # 工具模块 -│ ├── xianyu_utils.py # 闲鱼工具函数 -│ ├── message_utils.py # 消息处理工具 -│ └── ws_utils.py # WebSocket工具 -├── nginx/ # Nginx配置 -├── docs/ # 文档目录 -└── backups/ # 备份目录 +**通过这个接口可以检测到用户是否已付款,然后回复虚拟资料内容即可** +#### 请求参数 +```json +{ + "msg_time": "消息时间", + "user_url": "用户主页URL", + "send_user_id": "发送者ID", + "send_user_name": "发送者昵称", + "item_id": "商品ID", + "send_message": "发送的消息内容", + "chat_id": "会话ID" +} ``` -## 🤝 贡献指南 - -我们欢迎任何形式的贡献!请查看 [CONTRIBUTING.md](CONTRIBUTING.md) 了解详细的贡献指南。 - -### 快速开始贡献 -1. **Fork** 项目到你的GitHub账号 -2. **克隆**项目到本地开发环境 -3. **创建分支**进行功能开发或问题修复 -4. **提交代码**并创建Pull Request - -### 贡献类型 -- 🐛 **问题报告**:发现bug或提出改进建议 -- 💡 **功能建议**:提出新功能想法 -- 🔧 **代码贡献**:修复问题或开发新功能 -- 📚 **文档改进**:完善文档和说明 -- 🧪 **测试用例**:添加或改进测试 - -详细信息请参考:[贡献指南](CONTRIBUTING.md) - -## 💬 社区交流 - -### 加入我们的交流群 - -
- -| 微信交流群 | QQ交流群 | -|:---:|:---:| -| 微信群二维码 | QQ群二维码 | -| 扫码加入微信群 | 扫码加入QQ群 | - -
- -### 交流内容 -- 💡 **功能讨论**:新功能建议和讨论 -- 🐛 **问题求助**:使用过程中遇到的问题 -- 📚 **经验分享**:使用技巧和最佳实践 -- 🔄 **版本更新**:最新版本发布通知 -- 🤝 **合作交流**:开发合作和技术交流 - -### 群规说明 -- 请保持友善和尊重的交流氛围 -- 优先使用搜索功能查找已有答案 -- 提问时请提供详细的问题描述和环境信息 -- 欢迎分享使用经验和改进建议 - -## 📄 许可证 - -本项目采用 MIT 许可证,详情请查看 [LICENSE](LICENSE) 文件。 - -## 📋 更新日志 - -查看 [CHANGELOG.md](CHANGELOG.md) 了解详细的版本更新历史。 - -## 🙏 致谢 - -感谢所有为这个项目做出贡献的开发者和用户! - -### 特别感谢 -- 所有提交代码的贡献者 -- 提供问题反馈的用户 -- 完善文档的志愿者 -- 推广项目的支持者 - -### 技术支持 -- [FastAPI](https://fastapi.tiangolo.com/) - 现代化的Web框架 -- [SQLite](https://www.sqlite.org/) - 轻量级数据库 -- [Docker](https://www.docker.com/) - 容器化技术 -- [Loguru](https://github.com/Delgan/loguru) - 优秀的日志库 - ---- - -
- -**如果这个项目对你有帮助,请给个 ⭐ Star 支持一下!** - -[📋 报告问题](https://github.com/your-repo/xianyu-auto-reply/issues) • [💡 功能建议](https://github.com/your-repo/xianyu-auto-reply/issues) • [🤝 参与贡献](https://github.com/your-repo/xianyu-auto-reply/pulls) • [📖 查看文档](https://github.com/your-repo/xianyu-auto-reply/wiki) - -**让我们一起构建更好的闲鱼自动化工具!** 🚀 - -
- -## 🔧 核心模块说明 - -### Start.py - 项目启动入口 -- 初始化文件日志收集器 -- 创建和管理 CookieManager -- 启动 FastAPI Web服务器 -- 加载配置文件和环境变量中的账号 - -### XianyuAutoAsync.py - 闲鱼WebSocket客户端 -- 维持与闲鱼服务器的WebSocket连接 -- 处理消息接收和发送 -- 自动刷新token和维持心跳 -- 商品信息获取和处理 -- 自动回复逻辑处理 - -### reply_server.py - FastAPI Web服务器 -- 提供Web管理界面 -- RESTful API接口 -- 用户认证和权限控制 -- 文件上传和下载 -- 健康检查和监控 - -### ai_reply_engine.py - AI回复引擎 -- 多AI模型支持(通义千问、GPT等) -- 意图识别和分类 -- 智能议价逻辑 -- 对话历史管理 -- 自定义提示词处理 - -### db_manager.py - 数据库管理 -- SQLite数据库操作 -- 数据表结构管理 -- 数据备份和恢复 -- 事务处理和连接池 - -## 🎮 使用场景 - -### 个人卖家 -- **自动客服**:24小时自动回复买家咨询 -- **智能议价**:自动处理价格谈判,提高成交率 -- **快速发货**:自动发送卡券和虚拟商品 - -### 商家店铺 -- **多账号管理**:统一管理多个闲鱼账号 -- **批量操作**:批量设置关键词和回复规则 -- **数据分析**:查看消息统计和销售数据 - -### 代运营服务 -- **客户隔离**:为不同客户提供独立的账号管理 -- **定制化配置**:根据客户需求定制回复策略 -- **监控报告**:提供详细的运营数据报告 - -## 🔒 安全特性 - -### 数据安全 -- **本地存储**:所有数据存储在本地,不上传到第三方 -- **加密传输**:支持HTTPS和WSS加密传输 -- **权限控制**:基于JWT的用户认证系统 - -### 隐私保护 -- **Cookie加密**:敏感信息加密存储 -- **日志脱敏**:自动过滤敏感信息 -- **访问控制**:IP白名单和访问频率限制 - -## 📈 性能优化 - -### 系统性能 -- **异步处理**:全异步架构,高并发处理能力 -- **连接池**:数据库连接池,提高数据库操作效率 -- **缓存机制**:智能缓存,减少重复请求 - -### 资源优化 -- **内存管理**:自动清理过期数据和缓存 -- **日志轮转**:自动清理过期日志文件 -- **资源限制**:Docker资源限制,防止资源滥用 - -## 🚨 故障排除 - -### 常见问题 - -**Q: 系统启动失败?** -A: 检查以下项目: -- Python版本是否为3.11+ -- 依赖包是否正确安装 -- 端口8080是否被占用 -- 配置文件是否存在 - -**Q: WebSocket连接失败?** -A: 检查以下方面: -- 网络连接是否正常 -- Cookie是否有效 -- 防火墙设置 -- 代理配置 - -**Q: AI回复不工作?** -A: 检查以下配置: -- AI API密钥是否正确 -- API地址是否可访问 -- 账户余额是否充足 -- 网络连接是否稳定 - -### 日志查看 -```bash -# 查看实时日志 -docker-compose logs -f - -# 查看特定服务日志 -docker-compose logs xianyu-app - -# 查看系统日志文件 -tail -f logs/xianyu_$(date +%Y-%m-%d).log +#### 响应格式 +```json +{ + "code": 200, + "data": { + "send_msg": "回复的消息内容" + } +} ``` -## 🤝 贡献指南 +#### 配置示例 +```yaml +AUTO_REPLY: + api: + enabled: true # 是否启用API回复 + timeout: 10 # 超时时间(秒) + url: http://localhost:8080/xianyu/reply +``` -我们欢迎任何形式的贡献!请查看 [CONTRIBUTING.md](CONTRIBUTING.md) 了解详细的贡献指南。 +#### 使用场景 +- 当收到买家消息时,系统会自动调用此接口 +- 支持接入 ChatGPT、文心一言等大语言模型 +- 支持自定义回复规则和模板 +- 支持消息变量替换(如 `{send_user_name}`) -### 快速开始贡献 -1. **Fork** 项目到你的GitHub账号 -2. **克隆**项目到本地开发环境 -3. **创建分支**进行功能开发或问题修复 -4. **提交代码**并创建Pull Request +#### 注意事项 +- 接口需要返回正确的状态码(200)和消息内容 +- 建议实现错误重试机制 +- 注意处理超时情况(默认10秒) +- 可以根据需要扩展更多的参数和功能 -### 贡献类型 -- 🐛 **问题报告**:发现bug或提出改进建议 -- 💡 **功能建议**:提出新功能想法 -- 🔧 **代码贡献**:修复问题或开发新功能 -- 📚 **文档改进**:完善文档和说明 -- 🧪 **测试用例**:添加或改进测试 +## 🗝️ 注意事项 +- 请确保闲鱼账号已登录并获取有效的 Cookie +- 建议在正式环境使用前先在测试环境验证 +- 定期检查日志文件,及时处理异常情况 +- 使用大模型时注意 API 调用频率和成本控制 -### 开发规范 -- 遵循 [PEP 8](https://www.python.org/dev/peps/pep-0008/) 代码风格 -- 使用 [Conventional Commits](https://www.conventionalcommits.org/) 提交规范 -- 为新功能添加相应的测试用例 -- 更新相关文档和说明 +## 📝 效果 -详细信息请参考:[贡献指南](CONTRIBUTING.md) -## 📄 许可证 +![image-20250611004531745](https://typeropic.oss-cn-beijing.aliyuncs.com/cp/image-20250611004531745.png) -本项目采用 MIT 许可证,详情请查看 [LICENSE](LICENSE) 文件。 +![image-20250611004549662](https://typeropic.oss-cn-beijing.aliyuncs.com/cp/image-20250611004549662.png) -## � 更新日志 +## 🧸特别鸣谢 -查看 [CHANGELOG.md](CHANGELOG.md) 了解详细的版本更新历史。 +本项目参考了以下开源项目: https://github.com/cv-cat/XianYuApis -## �🙏 致谢 +感谢[@CVcat](https://github.com/cv-cat)的技术支持 -感谢所有为这个项目做出贡献的开发者和用户! +## 📞 联系方式 +如有问题或建议,欢迎提交 Issue 或 Pull Request。 -### 特别感谢 -- 所有提交代码的贡献者 -- 提供问题反馈的用户 -- 完善文档的志愿者 -- 推广项目的支持者 +## 技术交流 -### 技术支持 -- [FastAPI](https://fastapi.tiangolo.com/) - 现代化的Web框架 -- [SQLite](https://www.sqlite.org/) - 轻量级数据库 -- [Docker](https://www.docker.com/) - 容器化技术 -- [Loguru](https://github.com/Delgan/loguru) - 优秀的日志库 - ---- - -
- -**如果这个项目对你有帮助,请给个 ⭐ Star 支持一下!** - -[📋 报告问题](https://github.com/your-repo/xianyu-auto-reply/issues) • [💡 功能建议](https://github.com/your-repo/xianyu-auto-reply/issues) • [🤝 参与贡献](https://github.com/your-repo/xianyu-auto-reply/pulls) • [📖 查看文档](https://github.com/your-repo/xianyu-auto-reply/wiki) - -**让我们一起构建更好的闲鱼自动化工具!** 🚀 - -
+![image-20250611004141387](https://typeropic.oss-cn-beijing.aliyuncs.com/cp/image-20250611004141387.png) diff --git a/Start.py b/Start.py index aa8652d..228cd42 100644 --- a/Start.py +++ b/Start.py @@ -9,7 +9,6 @@ import os import asyncio import threading import uvicorn -import time from urllib.parse import urlparse from pathlib import Path from loguru import logger @@ -19,36 +18,6 @@ import cookie_manager as cm from db_manager import db_manager from file_log_collector import setup_file_logging -# 配置统一的日志系统 -log_dir = 'logs' -os.makedirs(log_dir, exist_ok=True) -log_path = os.path.join(log_dir, f"xianyu_{time.strftime('%Y-%m-%d')}.log") - -# 移除默认的日志处理器 -logger.remove() - -# 导入日志过滤器 -try: - from log_filter import filter_log_record -except ImportError: - # 如果过滤器不可用,使用默认过滤器 - def filter_log_record(record): - return True - -# 添加文件日志处理器,使用统一格式,并应用过滤器 -logger.add( - log_path, - rotation="1 day", - retention="7 days", - compression="zip", - level="INFO", - format='{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {name}:{function}:{line} - {message}', - encoding='utf-8', - enqueue=False, # 立即写入 - buffering=1, # 行缓冲 - filter=filter_log_record # 应用日志过滤器 -) - def _start_api_server(): """后台线程启动 FastAPI 服务""" diff --git a/UI_IMPROVEMENTS.md b/UI_IMPROVEMENTS.md new file mode 100644 index 0000000..1ac59fc --- /dev/null +++ b/UI_IMPROVEMENTS.md @@ -0,0 +1,92 @@ +# 🎨 界面优化总结 + +## ✨ 主要改进 + +### 1. 🎯 Cookie显示优化 +- **❌ 修改前**: Cookie值被隐藏为星号 (`****`) +- **✅ 修改后**: 显示完整的Cookie内容,便于查看和调试 + +### 2. 🎨 视觉设计升级 +- **现代化配色方案**: 使用更现代的紫色主题 (`#4f46e5`) +- **渐变背景**: 美丽的渐变背景和卡片效果 +- **毛玻璃效果**: 卡片使用 `backdrop-filter: blur()` 实现毛玻璃效果 +- **阴影和动画**: 悬停时的阴影和位移动画效果 + +### 3. 🔧 功能增强 +- **一键复制Cookie**: 点击Cookie值或复制按钮即可复制到剪贴板 +- **改进的按钮组**: 更紧凑的按钮布局,包含复制功能 +- **更好的空状态**: 当没有账号时显示更友好的提示 + +### 4. 📱 响应式设计 +- **移动端优化**: 在小屏幕上按钮垂直排列 +- **自适应布局**: 表格和卡片在不同屏幕尺寸下的自适应 + +## 🛠️ 技术改进 + +### 新增API接口 +```javascript +GET /cookies/details +``` +返回包含Cookie ID和完整值的详细信息,而不仅仅是ID列表。 + +### CSS样式优化 +- **CSS变量**: 统一的颜色管理 +- **现代字体**: 使用 Inter 字体提升可读性 +- **代码字体**: Cookie值使用等宽字体 (JetBrains Mono) +- **流畅动画**: 所有交互都有平滑的过渡效果 + +### JavaScript功能增强 +- **复制功能**: 支持现代浏览器的 Clipboard API +- **降级方案**: 对于不支持的浏览器提供传统复制方法 +- **用户反馈**: 复制成功/失败的Toast提示 + +## 🎯 用户体验提升 + +### 1. Cookie管理 +- **完整显示**: 不再隐藏Cookie内容,便于调试 +- **一键复制**: 快速复制Cookie值到剪贴板 +- **格式化显示**: 使用等宽字体和适当的行高 + +### 2. 视觉反馈 +- **悬停效果**: 所有可交互元素都有悬停反馈 +- **状态指示**: 清晰的按钮状态和颜色区分 +- **加载动画**: 优雅的加载状态显示 + +### 3. 操作便利性 +- **按钮分组**: 相关操作按钮紧凑排列 +- **图标提示**: 每个按钮都有清晰的图标和提示 +- **确认对话框**: 危险操作有确认提示 + +## 📊 界面对比 + +| 功能 | 修改前 | 修改后 | +|------|--------|--------| +| Cookie显示 | 隐藏为星号 | 完整显示 | +| 复制功能 | 无 | 一键复制 | +| 视觉效果 | 基础Bootstrap | 现代化渐变设计 | +| 响应式 | 基本支持 | 完全优化 | +| 用户反馈 | 基础提示 | 丰富的Toast反馈 | + +## 🚀 使用说明 + +### 访问界面 +1. 启动系统: `python Start.py` +2. 打开浏览器: `http://localhost:8080` +3. 登录: `admin` / `admin123` + +### 主要功能 +- **添加账号**: 在顶部表单中输入账号ID和Cookie值 +- **查看Cookie**: 完整的Cookie值显示在表格中 +- **复制Cookie**: 点击Cookie值或复制按钮 +- **管理关键词**: 点击关键词按钮设置自动回复 +- **删除账号**: 点击删除按钮(有确认提示) + +## 🎉 总结 + +这次界面优化大幅提升了用户体验: +- ✅ **Cookie不再隐藏**,便于查看和调试 +- ✅ **现代化设计**,视觉效果更佳 +- ✅ **功能增强**,操作更便利 +- ✅ **响应式优化**,支持各种设备 + +界面现在更加美观、实用和用户友好!🎨✨ diff --git a/XianyuAutoAsync.py b/XianyuAutoAsync.py index ede8e00..ede6a00 100644 --- a/XianyuAutoAsync.py +++ b/XianyuAutoAsync.py @@ -20,34 +20,26 @@ from utils.ws_utils import WebSocketClient import sys import aiohttp -# 日志配置 - 统一日志文件 +# 日志配置 log_dir = 'logs' os.makedirs(log_dir, exist_ok=True) log_path = os.path.join(log_dir, f"xianyu_{time.strftime('%Y-%m-%d')}.log") - -# 移除所有现有的日志处理器 logger.remove() - -# 导入日志过滤器 -try: - from log_filter import filter_log_record -except ImportError: - # 如果过滤器不可用,使用默认过滤器 - def filter_log_record(record): - return True - -# 只添加文件日志处理器,使用统一格式便于解析,并应用过滤器 logger.add( log_path, rotation=LOG_CONFIG.get('rotation', '1 day'), retention=LOG_CONFIG.get('retention', '7 days'), compression=LOG_CONFIG.get('compression', 'zip'), level=LOG_CONFIG.get('level', 'INFO'), - format='{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {name}:{function}:{line} - {message}', + format=LOG_CONFIG.get('format', '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}'), encoding='utf-8', - enqueue=False, # 改为False,确保立即写入 - buffering=1, # 行缓冲,立即刷新到文件 - filter=filter_log_record # 应用日志过滤器 + enqueue=True +) +logger.add( + sys.stdout, + level=LOG_CONFIG.get('level', 'INFO'), + format=LOG_CONFIG.get('format', '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}'), + enqueue=True ) class XianyuLive: @@ -205,10 +197,14 @@ class XianyuLive: return new_token logger.error(f"Token刷新失败: {res_json}") + # 发送Token刷新失败通知 + await self.send_token_refresh_notification(f"Token刷新失败: {res_json}") return None - + except Exception as e: logger.error(f"Token刷新异常: {self._safe_str(e)}") + # 发送Token刷新异常通知 + await self.send_token_refresh_notification(f"Token刷新异常: {str(e)}") return None async def update_config_cookies(self): @@ -223,11 +219,17 @@ class XianyuLive: logger.debug(f"已更新Cookie到数据库: {self.cookie_id}") except Exception as e: logger.error(f"更新数据库Cookie失败: {self._safe_str(e)}") + # 发送数据库更新失败通知 + await self.send_token_refresh_notification(f"数据库Cookie更新失败: {str(e)}") else: logger.warning("Cookie ID不存在,无法更新数据库") + # 发送Cookie ID缺失通知 + await self.send_token_refresh_notification("Cookie ID不存在,无法更新数据库") except Exception as e: logger.error(f"更新Cookie失败: {self._safe_str(e)}") + # 发送Cookie更新失败通知 + await self.send_token_refresh_notification(f"Cookie更新失败: {str(e)}") async def save_item_info_to_db(self, item_id: str, item_detail: str = None): """保存商品信息到数据库 @@ -711,11 +713,11 @@ class XianyuLive: send_message=send_message ) logger.info(f"使用默认回复: {formatted_reply}") - return f"[默认回复] {formatted_reply}" + return formatted_reply except Exception as format_error: logger.error(f"默认回复变量替换失败: {self._safe_str(format_error)}") # 如果变量替换失败,返回原始内容 - return f"[默认回复] {reply_content}" + return reply_content except Exception as e: logger.error(f"获取默认回复失败: {self._safe_str(e)}") @@ -744,11 +746,11 @@ class XianyuLive: send_message=send_message ) logger.info(f"关键词匹配成功: '{keyword}' -> {formatted_reply}") - return f"[关键词回复] {formatted_reply}" + return formatted_reply except Exception as format_error: logger.error(f"关键词回复变量替换失败: {self._safe_str(format_error)}") # 如果变量替换失败,返回原始内容 - return f"[关键词回复] {reply}" + return reply logger.debug(f"未找到匹配的关键词: {send_message}") return None @@ -799,7 +801,7 @@ class XianyuLive: if reply: logger.info(f"AI回复生成成功: {reply}") - return f"[AI回复] {reply}" + return reply else: logger.debug(f"AI回复生成失败") return None @@ -893,6 +895,49 @@ class XianyuLive: except Exception as e: logger.error(f"发送QQ通知异常: {self._safe_str(e)}") + async def send_token_refresh_notification(self, error_message: str): + """发送Token刷新异常通知""" + try: + from db_manager import db_manager + + # 获取当前账号的通知配置 + notifications = db_manager.get_account_notifications(self.cookie_id) + + if not notifications: + logger.debug("未配置消息通知,跳过Token刷新通知") + return + + # 构造通知消息 + notification_msg = f"""🔴 闲鱼账号Token刷新异常 + +账号ID: {self.cookie_id} +异常时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} +异常信息: {error_message} + +请检查账号Cookie是否过期,如有需要请及时更新Cookie配置。""" + + logger.info(f"准备发送Token刷新异常通知: {self.cookie_id}") + + # 发送通知到各个渠道 + for notification in notifications: + if not notification.get('enabled', True): + continue + + channel_type = notification.get('channel_type') + channel_config = notification.get('channel_config') + + try: + if channel_type == 'qq': + await self._send_qq_notification(channel_config, notification_msg) + else: + logger.warning(f"不支持的通知渠道类型: {channel_type}") + + except Exception as notify_error: + logger.error(f"发送Token刷新通知失败 ({notification.get('channel_name', 'Unknown')}): {self._safe_str(notify_error)}") + + except Exception as e: + logger.error(f"处理Token刷新通知失败: {self._safe_str(e)}") + async def send_delivery_failure_notification(self, send_user_name: str, send_user_id: str, item_id: str, error_message: str): """发送自动发货失败通知""" try: @@ -1188,6 +1233,8 @@ class XianyuLive: break else: logger.error("Token刷新失败,将在{}分钟后重试".format(self.token_retry_interval // 60)) + # 发送Token刷新失败通知 + await self.send_token_refresh_notification("Token定时刷新失败,将自动重试") await asyncio.sleep(self.token_retry_interval) continue await asyncio.sleep(60) @@ -1272,6 +1319,8 @@ class XianyuLive: if not self.current_token: logger.error("无法获取有效token,初始化失败") + # 发送Token获取失败通知 + await self.send_token_refresh_notification("初始化时无法获取有效Token") raise Exception("Token获取失败") msg = { @@ -1826,19 +1875,19 @@ class XianyuLive: # 记录回复来源 reply_source = 'API' # 默认假设是API回复 - # 如果API回复失败或未启用API,按优先级尝试其他回复方式 + # 如果API回复失败或未启用API,按新的优先级顺序处理 if not reply: - # 优先尝试关键词匹配回复 + # 1. 首先尝试关键词匹配 reply = await self.get_keyword_reply(send_user_name, send_user_id, send_message) if reply: reply_source = '关键词' # 标记为关键词回复 else: - # 如果关键词匹配失败,尝试AI回复 + # 2. 关键词匹配失败,如果AI开关打开,尝试AI回复 reply = await self.get_ai_reply(send_user_name, send_user_id, send_message, item_id, chat_id) if reply: reply_source = 'AI' # 标记为AI回复 else: - # 最后尝试使用默认回复 + # 3. 最后使用默认回复 reply = await self.get_default_reply(send_user_name, send_user_id, send_message) reply_source = '默认' # 标记为默认回复 @@ -1908,8 +1957,14 @@ class XianyuLive: finally: await self.close_session() # 确保关闭session - async def get_item_list_info(self, retry_count=0): - """获取商品信息,自动处理token失效的情况""" + async def get_item_list_info(self, page_number=1, page_size=20, retry_count=0): + """获取商品信息,自动处理token失效的情况 + + Args: + page_number (int): 页码,从1开始 + page_size (int): 每页数量,默认20 + retry_count (int): 重试次数,内部使用 + """ if retry_count >= 3: # 最多重试3次 logger.error("获取商品信息失败,重试次数过多") return {"error": "获取商品信息失败,重试次数过多"} @@ -1952,8 +2007,8 @@ class XianyuLive: data = { 'needGroupInfo': False, - 'pageNumber': 1, - 'pageSize': 20, + 'pageNumber': page_number, + 'pageSize': page_size, 'groupName': '在售', 'groupId': '58877261', 'defaultGroup': True, @@ -2017,7 +2072,7 @@ class XianyuLive: # 打印商品详细信息到控制台 print("\n" + "="*80) - print(f"📦 账号 {self.myid} 的商品列表 ({len(items_list)} 个商品)") + print(f"📦 账号 {self.myid} 的商品列表 (第{page_number}页,{len(items_list)} 个商品)") print("="*80) for i, item in enumerate(items_list, 1): @@ -2046,7 +2101,9 @@ class XianyuLive: return { "success": True, - "total_count": len(items_list), + "page_number": page_number, + "page_size": page_size, + "current_count": len(items_list), "items": items_list, "saved_count": saved_count if items_list else 0, "raw_data": items_data # 保留原始数据以备调试 @@ -2057,7 +2114,7 @@ class XianyuLive: if 'FAIL_SYS_TOKEN_EXOIRED' in error_msg or 'token' in error_msg.lower(): logger.warning(f"Token失效,准备重试: {error_msg}") await asyncio.sleep(0.5) - return await self.get_item_list_info(retry_count + 1) + return await self.get_item_list_info(page_number, page_size, retry_count + 1) else: logger.error(f"获取商品信息失败: {res_json}") return {"error": f"获取商品信息失败: {error_msg}"} @@ -2065,7 +2122,65 @@ class XianyuLive: except Exception as e: logger.error(f"商品信息API请求异常: {self._safe_str(e)}") await asyncio.sleep(0.5) - return await self.get_item_list_info(retry_count + 1) + return await self.get_item_list_info(page_number, page_size, retry_count + 1) + + async def get_all_items(self, page_size=20, max_pages=None): + """获取所有商品信息(自动分页) + + Args: + page_size (int): 每页数量,默认20 + max_pages (int): 最大页数限制,None表示无限制 + + Returns: + dict: 包含所有商品信息的字典 + """ + all_items = [] + page_number = 1 + total_saved = 0 + + logger.info(f"开始获取所有商品信息,每页{page_size}条") + + while True: + if max_pages and page_number > max_pages: + logger.info(f"达到最大页数限制 {max_pages},停止获取") + break + + logger.info(f"正在获取第 {page_number} 页...") + result = await self.get_item_list_info(page_number, page_size) + + if not result.get("success"): + logger.error(f"获取第 {page_number} 页失败: {result}") + break + + current_items = result.get("items", []) + if not current_items: + logger.info(f"第 {page_number} 页没有数据,获取完成") + break + + all_items.extend(current_items) + total_saved += result.get("saved_count", 0) + + logger.info(f"第 {page_number} 页获取到 {len(current_items)} 个商品") + + # 如果当前页商品数量少于页面大小,说明已经是最后一页 + if len(current_items) < page_size: + logger.info(f"第 {page_number} 页商品数量({len(current_items)})少于页面大小({page_size}),获取完成") + break + + page_number += 1 + + # 添加延迟避免请求过快 + await asyncio.sleep(1) + + logger.info(f"所有商品获取完成,共 {len(all_items)} 个商品,保存了 {total_saved} 个") + + return { + "success": True, + "total_pages": page_number, + "total_count": len(all_items), + "total_saved": total_saved, + "items": all_items + } if __name__ == '__main__': cookies_str = os.getenv('COOKIES_STR') diff --git a/backup_import_update_summary.md b/backup_import_update_summary.md new file mode 100644 index 0000000..710ae24 --- /dev/null +++ b/backup_import_update_summary.md @@ -0,0 +1,193 @@ +# 备份和导入功能更新总结 + +## 📋 更新概述 + +由于系统新增了多个AI相关的数据表,备份和导入功能需要更新以确保所有数据都能正确备份和恢复。 + +## 🔧 更新内容 + +### 1. **新增的表** + +在原有的10个表基础上,新增了3个AI相关表: + +#### 新增表列表: +- `ai_reply_settings` - AI回复配置表 +- `ai_conversations` - AI对话历史表 +- `ai_item_cache` - AI商品信息缓存表 + +### 2. **更新的备份表列表** + +#### 更新前(10个表): +```python +tables = [ + 'cookies', 'keywords', 'cookie_status', 'cards', + 'delivery_rules', 'default_replies', 'notification_channels', + 'message_notifications', 'system_settings', 'item_info' +] +``` + +#### 更新后(13个表): +```python +tables = [ + 'cookies', 'keywords', 'cookie_status', 'cards', + 'delivery_rules', 'default_replies', 'notification_channels', + 'message_notifications', 'system_settings', 'item_info', + 'ai_reply_settings', 'ai_conversations', 'ai_item_cache' +] +``` + +### 3. **更新的删除顺序** + +考虑到外键依赖关系,更新了导入时的表删除顺序: + +#### 更新前: +```python +tables = [ + 'message_notifications', 'notification_channels', 'default_replies', + 'delivery_rules', 'cards', 'item_info', 'cookie_status', 'keywords', 'cookies' +] +``` + +#### 更新后: +```python +tables = [ + 'message_notifications', 'notification_channels', 'default_replies', + 'delivery_rules', 'cards', 'item_info', 'cookie_status', 'keywords', + 'ai_conversations', 'ai_reply_settings', 'ai_item_cache', 'cookies' +] +``` + +### 4. **更新的验证列表** + +导入功能中的表验证列表也相应更新,确保新增的AI表能够正确导入。 + +## ✅ 测试验证结果 + +### 测试环境 +- 数据库表总数:13个 +- 测试数据:包含所有表类型的数据 +- 测试场景:导出、导入、文件操作 + +### 测试结果 +``` +🎉 所有测试通过!备份和导入功能正常! + +✅ 功能验证: + • 所有13个表都包含在备份中 + • 备份导出功能正常 + • 备份导入功能正常 + • 数据完整性保持 + • 文件操作正常 +``` + +### 数据完整性验证 +所有13个表的数据在备份和导入过程中保持完整: + +| 表名 | 数据一致性 | 说明 | +|------|------------|------| +| ai_conversations | ✅ 一致 | AI对话历史 | +| ai_item_cache | ✅ 一致 | AI商品缓存 | +| ai_reply_settings | ✅ 一致 | AI回复配置 | +| cards | ✅ 一致 | 卡券信息 | +| cookie_status | ✅ 一致 | 账号状态 | +| cookies | ✅ 一致 | 账号信息 | +| default_replies | ✅ 一致 | 默认回复 | +| delivery_rules | ✅ 一致 | 发货规则 | +| item_info | ✅ 一致 | 商品信息 | +| keywords | ✅ 一致 | 关键词 | +| message_notifications | ✅ 一致 | 消息通知 | +| notification_channels | ✅ 一致 | 通知渠道 | +| system_settings | ✅ 一致 | 系统设置 | + +## 🎯 功能特性 + +### 1. **完整性保证** +- 包含所有13个数据表 +- 保持外键依赖关系 +- 数据完整性验证 + +### 2. **安全性** +- 事务性操作,确保数据一致性 +- 管理员密码保护(不会被覆盖) +- 错误回滚机制 + +### 3. **兼容性** +- 向后兼容旧版本备份文件 +- 自动跳过不存在的表 +- 版本标识和时间戳 + +### 4. **易用性** +- 一键导出所有数据 +- 一键导入恢复数据 +- 详细的操作日志 + +## 📊 使用方法 + +### 导出备份 +```python +from db_manager import db_manager + +# 导出备份数据 +backup_data = db_manager.export_backup() + +# 保存到文件 +import json +with open('backup.json', 'w', encoding='utf-8') as f: + json.dump(backup_data, f, indent=2, ensure_ascii=False) +``` + +### 导入备份 +```python +from db_manager import db_manager +import json + +# 从文件读取备份 +with open('backup.json', 'r', encoding='utf-8') as f: + backup_data = json.load(f) + +# 导入备份数据 +success = db_manager.import_backup(backup_data) +``` + +## 🔄 升级说明 + +### 对现有用户的影响 +- ✅ **无影响**:现有备份文件仍然可以正常导入 +- ✅ **自动兼容**:系统会自动跳过不存在的新表 +- ✅ **数据安全**:不会丢失任何现有数据 + +### 新功能优势 +- ✅ **AI数据备份**:AI回复配置和对话历史得到保护 +- ✅ **完整备份**:所有功能数据都包含在备份中 +- ✅ **快速恢复**:可以完整恢复所有AI功能设置 + +## 💡 建议 + +### 1. **定期备份** +建议用户定期进行数据备份,特别是在: +- 重要配置更改后 +- 系统升级前 +- 大量数据操作前 + +### 2. **备份验证** +建议在重要操作前验证备份文件的完整性: +- 检查文件大小 +- 验证JSON格式 +- 确认包含所需表 + +### 3. **多重备份** +建议保留多个备份版本: +- 每日自动备份 +- 重要节点手动备份 +- 异地备份存储 + +## 🎉 总结 + +备份和导入功能已成功更新,现在能够: + +1. ✅ **完整备份**所有13个数据表 +2. ✅ **安全导入**保持数据完整性 +3. ✅ **向后兼容**旧版本备份文件 +4. ✅ **AI数据保护**包含所有AI功能数据 + +用户可以放心使用备份和导入功能,所有数据都得到了完整的保护! diff --git a/cookie_manager.py b/cookie_manager.py index f58c011..e742e6c 100644 --- a/cookie_manager.py +++ b/cookie_manager.py @@ -35,6 +35,21 @@ class CookieManager: except Exception as e: logger.error(f"从数据库加载数据失败: {e}") + def reload_from_db(self): + """重新从数据库加载所有数据(用于备份导入后刷新)""" + logger.info("重新从数据库加载数据...") + old_cookies_count = len(self.cookies) + old_keywords_count = len(self.keywords) + + # 重新加载数据 + self._load_from_db() + + new_cookies_count = len(self.cookies) + new_keywords_count = len(self.keywords) + + logger.info(f"数据重新加载完成: Cookie {old_cookies_count} -> {new_cookies_count}, 关键字组 {old_keywords_count} -> {new_keywords_count}") + return True + # ------------------------ 内部协程 ------------------------ async def _run_xianyu(self, cookie_id: str, cookie_value: str): """在事件循环中启动 XianyuLive.main""" diff --git a/db_manager.py b/db_manager.py index 2e39fbe..ac4de85 100644 --- a/db_manager.py +++ b/db_manager.py @@ -51,12 +51,39 @@ class DBManager: self.conn = sqlite3.connect(self.db_path, check_same_thread=False) cursor = self.conn.cursor() - # 创建cookies表 + # 创建用户表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + email TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + # 创建邮箱验证码表 + cursor.execute(''' + CREATE TABLE IF NOT EXISTS email_verifications ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + email TEXT NOT NULL, + code TEXT NOT NULL, + expires_at TIMESTAMP NOT NULL, + used BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + + # 创建cookies表(添加user_id字段) cursor.execute(''' CREATE TABLE IF NOT EXISTS cookies ( id TEXT PRIMARY KEY, value TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + user_id INTEGER NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ''') @@ -234,6 +261,29 @@ class DBManager: ('theme_color', 'blue', '主题颜色') ''', (hashlib.sha256("admin123".encode()).hexdigest(),)) + # 创建默认admin用户 + cursor.execute(''' + INSERT OR IGNORE INTO users (username, email, password_hash) VALUES + ('admin', 'admin@localhost', ?) + ''', (hashlib.sha256("admin123".encode()).hexdigest(),)) + + # 获取admin用户ID,用于历史数据绑定 + cursor.execute("SELECT id FROM users WHERE username = 'admin'") + admin_user = cursor.fetchone() + if admin_user: + admin_user_id = admin_user[0] + + # 将历史cookies数据绑定到admin用户(如果user_id列不存在) + try: + cursor.execute("SELECT user_id FROM cookies LIMIT 1") + except sqlite3.OperationalError: + # user_id列不存在,需要添加并更新历史数据 + cursor.execute("ALTER TABLE cookies ADD COLUMN user_id INTEGER") + cursor.execute("UPDATE cookies SET user_id = ? WHERE user_id IS NULL", (admin_user_id,)) + else: + # user_id列存在,更新NULL值 + cursor.execute("UPDATE cookies SET user_id = ? WHERE user_id IS NULL", (admin_user_id,)) + self.conn.commit() logger.info(f"数据库初始化成功: {self.db_path}") except Exception as e: diff --git a/deploy.bat b/deploy.bat new file mode 100644 index 0000000..c10fd9d --- /dev/null +++ b/deploy.bat @@ -0,0 +1,298 @@ +@echo off +chcp 65001 >nul +setlocal enabledelayedexpansion + +:: 闲鱼自动回复系统 Docker 部署脚本 (Windows版本) +:: 作者: Xianyu Auto Reply System +:: 版本: 1.0.0 + +title 闲鱼自动回复系统 Docker 部署 + +:: 颜色定义 +set "RED=[91m" +set "GREEN=[92m" +set "YELLOW=[93m" +set "BLUE=[94m" +set "NC=[0m" + +:: 打印带颜色的消息 +:print_info +echo %BLUE%[INFO]%NC% %~1 +goto :eof + +:print_success +echo %GREEN%[SUCCESS]%NC% %~1 +goto :eof + +:print_warning +echo %YELLOW%[WARNING]%NC% %~1 +goto :eof + +:print_error +echo %RED%[ERROR]%NC% %~1 +goto :eof + +:: 检查Docker是否安装 +:check_docker +call :print_info "检查 Docker 环境..." + +docker --version >nul 2>&1 +if errorlevel 1 ( + call :print_error "Docker 未安装,请先安装 Docker Desktop" + echo. + echo 下载地址: https://www.docker.com/products/docker-desktop + pause + exit /b 1 +) + +docker-compose --version >nul 2>&1 +if errorlevel 1 ( + call :print_error "Docker Compose 未安装,请先安装 Docker Compose" + pause + exit /b 1 +) + +call :print_success "Docker 环境检查通过" +goto :eof + +:: 创建必要的目录 +:create_directories +call :print_info "创建必要的目录..." + +if not exist "data" mkdir data +if not exist "logs" mkdir logs +if not exist "backups" mkdir backups +if not exist "nginx" mkdir nginx +if not exist "nginx\ssl" mkdir nginx\ssl + +REM 检查目录是否创建成功 +if not exist "data" ( + call :print_error "data目录创建失败" + pause + exit /b 1 +) + +if not exist "logs" ( + call :print_error "logs目录创建失败" + pause + exit /b 1 +) + +call :print_success "目录创建完成" +goto :eof + +:: 生成默认配置文件 +:generate_config +REM 生成.env文件 +if not exist ".env" ( + if exist ".env.example" ( + call :print_info "从模板生成 .env 文件..." + copy ".env.example" ".env" >nul + call :print_success ".env 文件已生成" + ) else ( + call :print_warning ".env.example 文件不存在,跳过 .env 文件生成" + ) +) else ( + call :print_info ".env 文件已存在,跳过生成" +) + +REM 生成global_config.yml文件 +if exist "global_config.yml" ( + call :print_info "配置文件已存在,跳过生成" + goto :eof +) + +call :print_info "生成默认配置文件..." + +( +echo # 闲鱼自动回复系统配置文件 +echo API_ENDPOINTS: +echo login_check: https://passport.goofish.com/newlogin/hasLogin.do +echo message_headinfo: https://h5api.m.goofish.com/h5/mtop.idle.trade.pc.message.headinfo/1.0/ +echo token: https://h5api.m.goofish.com/h5/mtop.taobao.idlemessage.pc.login.token/1.0/ +echo. +echo APP_CONFIG: +echo api_version: '1.0' +echo app_key: 444e9908a51d1cb236a27862abc769c9 +echo app_version: '1.0' +echo platform: web +echo. +echo AUTO_REPLY: +echo enabled: true +echo default_message: '亲爱的"{send_user_name}" 老板你好!所有宝贝都可以拍,秒发货的哈~不满意的话可以直接申请退款哈~' +echo max_retry: 3 +echo retry_interval: 5 +echo api: +echo enabled: false +echo host: 0.0.0.0 # 绑定所有网络接口,支持IP访问 +echo port: 8080 # Web服务端口 +echo url: http://0.0.0.0:8080/xianyu/reply +echo timeout: 10 +echo. +echo COOKIES: +echo last_update_time: '' +echo value: '' +echo. +echo DEFAULT_HEADERS: +echo accept: application/json +echo accept-language: zh-CN,zh;q=0.9 +echo cache-control: no-cache +echo origin: https://www.goofish.com +echo pragma: no-cache +echo referer: https://www.goofish.com/ +echo user-agent: Mozilla/5.0 ^(Windows NT 10.0; Win64; x64^) AppleWebKit/537.36 ^(KHTML, like Gecko^) Chrome/119.0.0.0 Safari/537.36 +echo. +echo WEBSOCKET_URL: wss://wss-goofish.dingtalk.com/ +echo HEARTBEAT_INTERVAL: 15 +echo HEARTBEAT_TIMEOUT: 5 +echo TOKEN_REFRESH_INTERVAL: 3600 +echo TOKEN_RETRY_INTERVAL: 300 +echo MESSAGE_EXPIRE_TIME: 300000 +echo. +echo LOG_CONFIG: +echo level: INFO +echo format: '{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {name}:{function}:{line} - {message}' +echo rotation: '1 day' +echo retention: '7 days' +) > global_config.yml + +call :print_success "默认配置文件已生成" +goto :eof + +:: 构建Docker镜像 +:build_image +call :print_info "构建 Docker 镜像..." + +docker build -t xianyu-auto-reply:latest . +if errorlevel 1 ( + call :print_error "Docker 镜像构建失败" + pause + exit /b 1 +) + +call :print_success "Docker 镜像构建完成" +goto :eof + +:: 启动服务 +:start_services +call :print_info "启动服务..." + +if "%~1"=="--with-nginx" ( + call :print_info "启动服务(包含 Nginx)..." + docker-compose --profile with-nginx up -d +) else ( + call :print_info "启动服务(不包含 Nginx)..." + docker-compose up -d +) + +if errorlevel 1 ( + call :print_error "服务启动失败" + pause + exit /b 1 +) + +call :print_success "服务启动完成" +goto :eof + +:: 显示服务状态 +:show_status +call :print_info "服务状态:" +docker-compose ps + +echo. +call :print_info "服务日志(最近10行):" +docker-compose logs --tail=10 +goto :eof + +:: 显示访问信息 +:show_access_info +call :print_success "部署完成!" +echo. +call :print_info "访问信息:" +echo Web界面: http://localhost:8080 +echo 默认账号: admin +echo 默认密码: admin123 +echo. +call :print_info "常用命令:" +echo 查看日志: docker-compose logs -f +echo 重启服务: docker-compose restart +echo 停止服务: docker-compose down +echo 更新服务: deploy.bat update +echo. +call :print_info "数据目录:" +echo 数据库: .\data\xianyu_data.db +echo 日志: .\logs\ +echo 配置: .\global_config.yml +echo. +goto :eof + +:: 更新服务 +:update_services +call :print_info "更新服务..." + +docker-compose down +call :build_image +call :start_services %~1 + +call :print_success "服务更新完成" +goto :eof + +:: 清理资源 +:cleanup +call :print_warning "清理 Docker 资源..." + +docker-compose down --volumes --remove-orphans +docker rmi xianyu-auto-reply:latest 2>nul + +call :print_success "清理完成" +goto :eof + +:: 显示帮助 +:show_help +echo 使用方法: +echo %~nx0 # 首次部署 +echo %~nx0 with-nginx # 部署并启动 Nginx +echo %~nx0 update # 更新服务 +echo %~nx0 update with-nginx # 更新服务并启动 Nginx +echo %~nx0 status # 查看服务状态 +echo %~nx0 cleanup # 清理所有资源 +echo %~nx0 help # 显示帮助 +goto :eof + +:: 主函数 +:main +echo ======================================== +echo 闲鱼自动回复系统 Docker 部署脚本 +echo ======================================== +echo. + +if "%~1"=="update" ( + call :print_info "更新模式" + call :check_docker + call :update_services %~2 + call :show_status + call :show_access_info +) else if "%~1"=="cleanup" ( + call :print_warning "清理模式" + call :cleanup +) else if "%~1"=="status" ( + call :show_status +) else if "%~1"=="help" ( + call :show_help +) else ( + call :print_info "首次部署模式" + call :check_docker + call :create_directories + call :generate_config + call :build_image + call :start_services %~1 + call :show_status + call :show_access_info +) + +echo. +pause +goto :eof + +:: 执行主函数 +call :main %* diff --git a/docker-deploy.bat b/docker-deploy.bat new file mode 100644 index 0000000..671acb9 --- /dev/null +++ b/docker-deploy.bat @@ -0,0 +1,301 @@ +@echo off +chcp 65001 >nul +setlocal enabledelayedexpansion + +:: 闲鱼自动回复系统 Docker 部署脚本 (Windows版本) +:: 支持快速部署和管理 + +set PROJECT_NAME=xianyu-auto-reply +set COMPOSE_FILE=docker-compose.yml +set ENV_FILE=.env + +:: 颜色定义 (Windows 10+ 支持ANSI颜色) +set "RED=[31m" +set "GREEN=[32m" +set "YELLOW=[33m" +set "BLUE=[34m" +set "NC=[0m" + +:: 打印带颜色的消息 +:print_info +echo %BLUE%ℹ️ %~1%NC% +goto :eof + +:print_success +echo %GREEN%✅ %~1%NC% +goto :eof + +:print_warning +echo %YELLOW%⚠️ %~1%NC% +goto :eof + +:print_error +echo %RED%❌ %~1%NC% +goto :eof + +:: 检查依赖 +:check_dependencies +call :print_info "检查系统依赖..." + +docker --version >nul 2>&1 +if errorlevel 1 ( + call :print_error "Docker 未安装,请先安装 Docker Desktop" + exit /b 1 +) + +docker-compose --version >nul 2>&1 +if errorlevel 1 ( + call :print_error "Docker Compose 未安装,请先安装 Docker Compose" + exit /b 1 +) + +call :print_success "系统依赖检查通过" +goto :eof + +:: 初始化配置 +:init_config +call :print_info "初始化配置文件..." + +if not exist "%ENV_FILE%" ( + if exist ".env.example" ( + copy ".env.example" "%ENV_FILE%" >nul + call :print_success "已创建 %ENV_FILE% 配置文件" + ) else ( + call :print_error ".env.example 文件不存在" + exit /b 1 + ) +) else ( + call :print_warning "%ENV_FILE% 已存在,跳过创建" +) + +:: 创建必要的目录 +if not exist "data" mkdir data +if not exist "logs" mkdir logs +if not exist "backups" mkdir backups +call :print_success "已创建必要的目录" +goto :eof + +:: 构建镜像 +:build_image +call :print_info "构建 Docker 镜像..." +docker-compose build --no-cache +if errorlevel 1 ( + call :print_error "镜像构建失败" + exit /b 1 +) +call :print_success "镜像构建完成" +goto :eof + +:: 启动服务 +:start_services +set "profile=" +if "%~1"=="with-nginx" ( + set "profile=--profile with-nginx" + call :print_info "启动服务(包含 Nginx)..." +) else ( + call :print_info "启动基础服务..." +) + +docker-compose %profile% up -d +if errorlevel 1 ( + call :print_error "服务启动失败" + exit /b 1 +) +call :print_success "服务启动完成" + +:: 等待服务就绪 +call :print_info "等待服务就绪..." +timeout /t 10 /nobreak >nul + +:: 检查服务状态 +docker-compose ps | findstr "Up" >nul +if errorlevel 1 ( + call :print_error "服务启动失败" + docker-compose logs + exit /b 1 +) else ( + call :print_success "服务运行正常" + call :show_access_info "%~1" +) +goto :eof + +:: 停止服务 +:stop_services +call :print_info "停止服务..." +docker-compose down +call :print_success "服务已停止" +goto :eof + +:: 重启服务 +:restart_services +call :print_info "重启服务..." +docker-compose restart +call :print_success "服务已重启" +goto :eof + +:: 查看日志 +:show_logs +if "%~1"=="" ( + docker-compose logs -f +) else ( + docker-compose logs -f "%~1" +) +goto :eof + +:: 查看状态 +:show_status +call :print_info "服务状态:" +docker-compose ps + +call :print_info "资源使用:" +for /f "tokens=*" %%i in ('docker-compose ps -q') do ( + docker stats --no-stream %%i +) +goto :eof + +:: 显示访问信息 +:show_access_info +echo. +call :print_success "🎉 部署完成!" +echo. + +if "%~1"=="with-nginx" ( + echo 📱 访问地址: + echo HTTP: http://localhost + echo HTTPS: https://localhost ^(如果配置了SSL^) +) else ( + echo 📱 访问地址: + echo HTTP: http://localhost:8080 +) + +echo. +echo 🔐 默认登录信息: +echo 用户名: admin +echo 密码: admin123 +echo. +echo 📊 管理命令: +echo 查看状态: %~nx0 status +echo 查看日志: %~nx0 logs +echo 重启服务: %~nx0 restart +echo 停止服务: %~nx0 stop +echo. +goto :eof + +:: 健康检查 +:health_check +call :print_info "执行健康检查..." + +set "url=http://localhost:8080/health" +set "max_attempts=30" +set "attempt=1" + +:health_loop +curl -f -s "%url%" >nul 2>&1 +if not errorlevel 1 ( + call :print_success "健康检查通过" + goto :eof +) + +call :print_info "等待服务就绪... (!attempt!/%max_attempts%)" +timeout /t 2 /nobreak >nul +set /a attempt+=1 + +if !attempt! leq %max_attempts% goto health_loop + +call :print_error "健康检查失败" +exit /b 1 + +:: 备份数据 +:backup_data +call :print_info "备份数据..." + +for /f "tokens=2 delims==" %%i in ('wmic OS Get localdatetime /value') do set datetime=%%i +set backup_dir=backups\%datetime:~0,8%_%datetime:~8,6% +mkdir "%backup_dir%" 2>nul + +:: 备份数据库 +if exist "data\xianyu_data.db" ( + copy "data\xianyu_data.db" "%backup_dir%\" >nul + call :print_success "数据库备份完成" +) + +:: 备份配置 +copy "%ENV_FILE%" "%backup_dir%\" >nul +copy "global_config.yml" "%backup_dir%\" >nul 2>&1 + +call :print_success "数据备份完成: %backup_dir%" +goto :eof + +:: 显示帮助信息 +:show_help +echo 闲鱼自动回复系统 Docker 部署脚本 ^(Windows版本^) +echo. +echo 用法: %~nx0 [命令] [选项] +echo. +echo 命令: +echo init 初始化配置文件 +echo build 构建 Docker 镜像 +echo start [with-nginx] 启动服务^(可选包含 Nginx^) +echo stop 停止服务 +echo restart 重启服务 +echo status 查看服务状态 +echo logs [service] 查看日志 +echo health 健康检查 +echo backup 备份数据 +echo help 显示帮助信息 +echo. +echo 示例: +echo %~nx0 init # 初始化配置 +echo %~nx0 start # 启动基础服务 +echo %~nx0 start with-nginx # 启动包含 Nginx 的服务 +echo %~nx0 logs xianyu-app # 查看应用日志 +echo. +goto :eof + +:: 主函数 +:main +if "%~1"=="init" ( + call :check_dependencies + call :init_config +) else if "%~1"=="build" ( + call :check_dependencies + call :build_image +) else if "%~1"=="start" ( + call :check_dependencies + call :init_config + call :build_image + call :start_services "%~2" +) else if "%~1"=="stop" ( + call :stop_services +) else if "%~1"=="restart" ( + call :restart_services +) else if "%~1"=="status" ( + call :show_status +) else if "%~1"=="logs" ( + call :show_logs "%~2" +) else if "%~1"=="health" ( + call :health_check +) else if "%~1"=="backup" ( + call :backup_data +) else if "%~1"=="help" ( + call :show_help +) else if "%~1"=="-h" ( + call :show_help +) else if "%~1"=="--help" ( + call :show_help +) else if "%~1"=="" ( + call :print_info "快速部署模式" + call :check_dependencies + call :init_config + call :build_image + call :start_services +) else ( + call :print_error "未知命令: %~1" + call :show_help + exit /b 1 +) + +goto :eof + +:: 执行主函数 +call :main %* diff --git a/docker-deploy.sh b/docker-deploy.sh new file mode 100644 index 0000000..c79458a --- /dev/null +++ b/docker-deploy.sh @@ -0,0 +1,350 @@ +#!/bin/bash + +# 闲鱼自动回复系统 Docker 部署脚本 +# 支持快速部署和管理 + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 项目配置 +PROJECT_NAME="xianyu-auto-reply" +COMPOSE_FILE="docker-compose.yml" +ENV_FILE=".env" + +# 打印带颜色的消息 +print_info() { + echo -e "${BLUE}ℹ️ $1${NC}" +} + +print_success() { + echo -e "${GREEN}✅ $1${NC}" +} + +print_warning() { + echo -e "${YELLOW}⚠️ $1${NC}" +} + +print_error() { + echo -e "${RED}❌ $1${NC}" +} + +# 检查依赖 +check_dependencies() { + print_info "检查系统依赖..." + + if ! command -v docker &> /dev/null; then + print_error "Docker 未安装,请先安装 Docker" + exit 1 + fi + + if ! command -v docker-compose &> /dev/null; then + print_error "Docker Compose 未安装,请先安装 Docker Compose" + exit 1 + fi + + print_success "系统依赖检查通过" +} + +# 初始化配置 +init_config() { + print_info "初始化配置文件..." + + if [ ! -f "$ENV_FILE" ]; then + if [ -f ".env.example" ]; then + cp .env.example "$ENV_FILE" + print_success "已创建 $ENV_FILE 配置文件" + else + print_error ".env.example 文件不存在" + exit 1 + fi + else + print_warning "$ENV_FILE 已存在,跳过创建" + fi + + # 创建必要的目录 + mkdir -p data logs backups + print_success "已创建必要的目录" +} + +# 构建镜像 +build_image() { + print_info "构建 Docker 镜像..." + docker-compose build --no-cache + print_success "镜像构建完成" +} + +# 启动服务 +start_services() { + local profile="" + if [ "$1" = "with-nginx" ]; then + profile="--profile with-nginx" + print_info "启动服务(包含 Nginx)..." + else + print_info "启动基础服务..." + fi + + docker-compose $profile up -d + print_success "服务启动完成" + + # 等待服务就绪 + print_info "等待服务就绪..." + sleep 10 + + # 检查服务状态 + if docker-compose ps | grep -q "Up"; then + print_success "服务运行正常" + show_access_info "$1" + else + print_error "服务启动失败" + docker-compose logs + exit 1 + fi +} + +# 停止服务 +stop_services() { + print_info "停止服务..." + docker-compose down + print_success "服务已停止" +} + +# 重启服务 +restart_services() { + print_info "重启服务..." + docker-compose restart + print_success "服务已重启" +} + +# 查看日志 +show_logs() { + local service="$1" + if [ -z "$service" ]; then + docker-compose logs -f + else + docker-compose logs -f "$service" + fi +} + +# 查看状态 +show_status() { + print_info "服务状态:" + docker-compose ps + + print_info "资源使用:" + docker stats --no-stream $(docker-compose ps -q) +} + +# 显示访问信息 +show_access_info() { + local with_nginx="$1" + + echo "" + print_success "🎉 部署完成!" + echo "" + + if [ "$with_nginx" = "with-nginx" ]; then + echo "📱 访问地址:" + echo " HTTP: http://localhost" + echo " HTTPS: https://localhost (如果配置了SSL)" + else + echo "📱 访问地址:" + echo " HTTP: http://localhost:8080" + fi + + echo "" + echo "🔐 默认登录信息:" + echo " 用户名: admin" + echo " 密码: admin123" + echo "" + echo "📊 管理命令:" + echo " 查看状态: $0 status" + echo " 查看日志: $0 logs" + echo " 重启服务: $0 restart" + echo " 停止服务: $0 stop" + echo "" +} + +# 健康检查 +health_check() { + print_info "执行健康检查..." + + local url="http://localhost:8080/health" + local max_attempts=30 + local attempt=1 + + while [ $attempt -le $max_attempts ]; do + if curl -f -s "$url" > /dev/null 2>&1; then + print_success "健康检查通过" + return 0 + fi + + print_info "等待服务就绪... ($attempt/$max_attempts)" + sleep 2 + ((attempt++)) + done + + print_error "健康检查失败" + return 1 +} + +# 备份数据 +backup_data() { + print_info "备份数据..." + + local backup_dir="backups/$(date +%Y%m%d_%H%M%S)" + mkdir -p "$backup_dir" + + # 备份数据库 + if [ -f "data/xianyu_data.db" ]; then + cp data/xianyu_data.db "$backup_dir/" + print_success "数据库备份完成" + fi + + # 备份配置 + cp "$ENV_FILE" "$backup_dir/" + cp global_config.yml "$backup_dir/" 2>/dev/null || true + + print_success "数据备份完成: $backup_dir" +} + +# 更新部署 +update_deployment() { + print_info "更新部署..." + + # 备份数据 + backup_data + + # 停止服务 + stop_services + + # 拉取最新代码(如果是git仓库) + if [ -d ".git" ]; then + print_info "拉取最新代码..." + git pull + fi + + # 重新构建 + build_image + + # 启动服务 + start_services + + print_success "更新完成" +} + +# 清理环境 +cleanup() { + print_warning "这将删除所有容器、镜像和数据,确定要继续吗?(y/N)" + read -r response + + if [[ "$response" =~ ^[Yy]$ ]]; then + print_info "清理环境..." + + # 停止并删除容器 + docker-compose down -v --rmi all + + # 删除数据目录 + rm -rf data logs backups + + print_success "环境清理完成" + else + print_info "取消清理操作" + fi +} + +# 显示帮助信息 +show_help() { + echo "闲鱼自动回复系统 Docker 部署脚本" + echo "" + echo "用法: $0 [命令] [选项]" + echo "" + echo "命令:" + echo " init 初始化配置文件" + echo " build 构建 Docker 镜像" + echo " start [with-nginx] 启动服务(可选包含 Nginx)" + echo " stop 停止服务" + echo " restart 重启服务" + echo " status 查看服务状态" + echo " logs [service] 查看日志" + echo " health 健康检查" + echo " backup 备份数据" + echo " update 更新部署" + echo " cleanup 清理环境" + echo " help 显示帮助信息" + echo "" + echo "示例:" + echo " $0 init # 初始化配置" + echo " $0 start # 启动基础服务" + echo " $0 start with-nginx # 启动包含 Nginx 的服务" + echo " $0 logs xianyu-app # 查看应用日志" + echo "" +} + +# 主函数 +main() { + case "$1" in + "init") + check_dependencies + init_config + ;; + "build") + check_dependencies + build_image + ;; + "start") + check_dependencies + init_config + build_image + start_services "$2" + ;; + "stop") + stop_services + ;; + "restart") + restart_services + ;; + "status") + show_status + ;; + "logs") + show_logs "$2" + ;; + "health") + health_check + ;; + "backup") + backup_data + ;; + "update") + check_dependencies + update_deployment + ;; + "cleanup") + cleanup + ;; + "help"|"--help"|"-h") + show_help + ;; + "") + print_info "快速部署模式" + check_dependencies + init_config + build_image + start_services + ;; + *) + print_error "未知命令: $1" + show_help + exit 1 + ;; + esac +} + +# 执行主函数 +main "$@" diff --git a/docker_deployment_update.md b/docker_deployment_update.md new file mode 100644 index 0000000..b68877b --- /dev/null +++ b/docker_deployment_update.md @@ -0,0 +1,207 @@ +# Docker部署更新检查报告 + +## 📋 检查概述 + +对Docker部署配置进行了全面检查,评估是否需要更新以支持新增的AI回复功能和其他改进。 + +## ✅ 当前状态评估 + +### 🎯 **结论:Docker部署配置已经完善,无需重大更新** + +所有新增功能都已经在现有的Docker配置中得到支持。 + +## 📊 详细检查结果 + +### 1. **依赖包检查** ✅ +#### requirements.txt 状态:**完整** +``` +✅ openai>=1.65.5 # AI回复功能 +✅ python-dotenv>=1.0.1 # 环境变量支持 +✅ python-multipart>=0.0.6 # 文件上传支持 +✅ fastapi>=0.111 # Web框架 +✅ uvicorn[standard]>=0.29 # ASGI服务器 +✅ 其他所有必要依赖 +``` + +### 2. **环境变量配置** ✅ +#### .env.example 状态:**完整** +``` +✅ AI_REPLY_ENABLED=false +✅ DEFAULT_AI_MODEL=qwen-plus +✅ DEFAULT_AI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 +✅ AI_REQUEST_TIMEOUT=30 +✅ AI_MAX_TOKENS=100 +✅ 所有基础配置变量 +``` + +### 3. **Docker Compose配置** ✅ +#### docker-compose.yml 状态:**完整** +``` +✅ AI回复相关环境变量映射 +✅ 数据持久化配置 (/app/data, /app/logs, /app/backups) +✅ 健康检查配置 +✅ 资源限制配置 +✅ 网络配置 +✅ Nginx反向代理支持 +``` + +### 4. **Dockerfile配置** ✅ +#### Dockerfile 状态:**完整** +``` +✅ Python 3.11基础镜像 +✅ 所有系统依赖安装 +✅ 应用依赖安装 +✅ 工作目录配置 +✅ 端口暴露配置 +✅ 启动命令配置 +``` + +### 5. **数据持久化** ✅ +#### 挂载点配置:**完整** +``` +✅ ./data:/app/data:rw # 数据库文件 +✅ ./logs:/app/logs:rw # 日志文件 +✅ ./backups:/app/backups:rw # 备份文件 +✅ ./global_config.yml:/app/global_config.yml:ro # 配置文件 +``` + +### 6. **健康检查** ✅ +#### 健康检查配置:**完整** +``` +✅ HTTP健康检查端点 (/health) +✅ 检查间隔:30秒 +✅ 超时时间:10秒 +✅ 重试次数:3次 +✅ 启动等待:40秒 +``` + +## 🔍 新功能支持验证 + +### AI回复功能 ✅ +- **依赖支持**:openai库已包含 +- **配置支持**:所有AI相关环境变量已配置 +- **数据支持**:AI数据表会自动创建 +- **API支持**:FastAPI框架支持所有新接口 + +### 备份功能增强 ✅ +- **存储支持**:备份目录已挂载 +- **数据支持**:所有新表都包含在备份中 +- **权限支持**:容器有读写权限 + +### 商品管理功能 ✅ +- **文件上传**:python-multipart依赖已包含 +- **数据存储**:数据库挂载支持新表 +- **API支持**:FastAPI支持文件上传接口 + +## 💡 可选优化建议 + +虽然当前配置已经完善,但可以考虑以下优化: + +### 1. **添加AI服务健康检查** +```yaml +# 可选:添加AI服务连通性检查 +healthcheck: + test: ["CMD", "python", "-c", "import requests; requests.get('http://localhost:8080/api/ai/health', timeout=5)"] +``` + +### 2. **添加更多监控指标** +```yaml +# 可选:添加Prometheus监控 +environment: + - ENABLE_METRICS=true + - METRICS_PORT=9090 +``` + +### 3. **添加AI配置验证** +```yaml +# 可选:启动时验证AI配置 +environment: + - VALIDATE_AI_CONFIG=true +``` + +## 🚀 部署建议 + +### 生产环境部署 +1. **使用强密码** + ```bash + ADMIN_PASSWORD=$(openssl rand -base64 32) + JWT_SECRET_KEY=$(openssl rand -base64 32) + ``` + +2. **配置AI服务** + ```bash + AI_REPLY_ENABLED=true + # 配置真实的API密钥 + ``` + +3. **启用HTTPS** + ```bash + docker-compose --profile with-nginx up -d + ``` + +4. **配置资源限制** + ```bash + MEMORY_LIMIT=1024 # 如果使用AI功能,建议增加内存 + CPU_LIMIT=1.0 + ``` + +### 开发环境部署 +```bash +# 克隆项目 +git clone +cd xianyuapis + +# 复制环境变量 +cp .env.example .env + +# 启动服务 +docker-compose up -d + +# 查看日志 +docker-compose logs -f +``` + +## 📋 部署检查清单 + +### 部署前检查 ✅ +- [x] Docker和Docker Compose已安装 +- [x] 端口8080未被占用 +- [x] 有足够的磁盘空间(建议>2GB) +- [x] 网络连接正常 + +### 配置检查 ✅ +- [x] .env文件已配置 +- [x] global_config.yml文件存在 +- [x] data、logs、backups目录权限正确 +- [x] AI API密钥已配置(如果使用AI功能) + +### 功能验证 ✅ +- [x] Web界面可访问 +- [x] 账号管理功能正常 +- [x] 自动回复功能正常 +- [x] AI回复功能正常(如果启用) +- [x] 备份功能正常 + +## 🎉 总结 + +### ✅ **Docker部署配置完全就绪** + +1. **无需更新**:当前配置已支持所有新功能 +2. **开箱即用**:可直接部署使用 +3. **功能完整**:支持AI回复、备份、商品管理等所有功能 +4. **生产就绪**:包含安全、监控、资源限制等配置 + +### 🚀 **立即可用的部署命令** + +```bash +# 快速部署 +git clone +cd xianyuapis +cp .env.example .env +docker-compose up -d + +# 访问系统 +open http://localhost:8080 +``` + +**Docker部署配置已经完善,支持所有新功能,可以直接使用!** 🎉 diff --git a/file_log_collector.py b/file_log_collector.py index 854b8ab..7dd51e7 100644 --- a/file_log_collector.py +++ b/file_log_collector.py @@ -29,167 +29,119 @@ class FileLogCollector: def setup_file_monitoring(self): """设置文件监控""" - # 使用统一的日志文件路径 - import time - log_dir = 'logs' - os.makedirs(log_dir, exist_ok=True) - - # 使用与其他模块相同的日志文件命名规则 - today_log = os.path.join(log_dir, f"xianyu_{time.strftime('%Y-%m-%d')}.log") - - # 查找日志文件,优先使用今天的日志文件 + # 查找日志文件 possible_files = [ - today_log, - "logs/xianyu.log", "xianyu.log", - "app.log", + "app.log", "system.log", + "logs/xianyu.log", "logs/app.log" ] - + for file_path in possible_files: if os.path.exists(file_path): self.log_file = file_path break - + if not self.log_file: - # 如果没有找到现有文件,使用今天的日志文件 - self.log_file = today_log - - print(f"日志收集器监控文件: {self.log_file}") - + # 如果没有找到现有文件,创建一个新的 + self.log_file = "realtime.log" + + # 设置loguru输出到文件 + self.setup_loguru_file_output() + # 启动文件监控线程 self.monitor_thread = threading.Thread(target=self.monitor_file, daemon=True) self.monitor_thread.start() - + def setup_loguru_file_output(self): + """设置loguru输出到文件""" + try: + from loguru import logger + + # 添加文件输出 + logger.add( + self.log_file, + format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {name}:{function}:{line} - {message}", + level="DEBUG", + rotation="10 MB", + retention="7 days", + enqueue=False, # 改为False,避免队列延迟 + buffering=1 # 行缓冲,立即写入 + ) + + logger.info("文件日志收集器已启动") + + except ImportError: + pass def monitor_file(self): """监控日志文件变化""" - print(f"开始监控日志文件: {self.log_file}") - while True: try: if os.path.exists(self.log_file): # 获取文件大小 file_size = os.path.getsize(self.log_file) - + if file_size > self.last_position: # 读取新增内容 - try: - with open(self.log_file, 'r', encoding='utf-8', errors='ignore') as f: - f.seek(self.last_position) - new_lines = f.readlines() - self.last_position = f.tell() - - # 解析新增的日志行 - for line in new_lines: - line = line.strip() - if line: # 只处理非空行 - self.parse_log_line(line) - except Exception as read_error: - print(f"读取日志文件失败: {read_error}") - elif file_size < self.last_position: - # 文件被截断或重新创建,重置位置 - self.last_position = 0 - print(f"检测到日志文件被重置: {self.log_file}") - else: - # 文件不存在,重置位置等待文件创建 - self.last_position = 0 - - time.sleep(0.2) # 每0.2秒检查一次,更及时 - + with open(self.log_file, 'r', encoding='utf-8') as f: + f.seek(self.last_position) + new_lines = f.readlines() + self.last_position = f.tell() + + # 解析新增的日志行 + for line in new_lines: + self.parse_log_line(line.strip()) + + time.sleep(0.5) # 每0.5秒检查一次 + except Exception as e: - print(f"监控日志文件异常: {e}") time.sleep(1) # 出错时等待1秒 def parse_log_line(self, line: str): """解析日志行""" if not line: return - + try: - # 解析统一格式的日志 - # 格式: 2024-07-24 15:46:03.430 | INFO | module_name:function_name:123 - 消息内容 + # 解析loguru格式的日志 + # 格式: 2025-07-23 15:46:03.430 | INFO | __main__:debug_collector:70 - 消息 pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) \| (\w+) \| ([^:]+):([^:]+):(\d+) - (.*)' match = re.match(pattern, line) - + if match: timestamp_str, level, source, function, line_num, message = match.groups() - + # 转换时间格式 try: timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S.%f') except: timestamp = datetime.now() - - # 清理source名称,移除路径和扩展名 - if '\\' in source or '/' in source: - source = os.path.basename(source) - if source.endswith('.py'): - source = source[:-3] - + log_entry = { "timestamp": timestamp.isoformat(), - "level": level.strip(), - "source": source.strip(), - "function": function.strip(), + "level": level, + "source": source, + "function": function, "line": int(line_num), - "message": message.strip() + "message": message } - + with self.lock: self.logs.append(log_entry) - - else: - # 尝试解析其他可能的格式 - # 简单格式: [时间] [级别] 消息 - simple_pattern = r'\[([^\]]+)\] \[(\w+)\] (.*)' - simple_match = re.match(simple_pattern, line) - - if simple_match: - timestamp_str, level, message = simple_match.groups() - try: - timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S') - except: - timestamp = datetime.now() - - log_entry = { - "timestamp": timestamp.isoformat(), - "level": level.strip(), - "source": "system", - "function": "unknown", - "line": 0, - "message": message.strip() - } - - with self.lock: - self.logs.append(log_entry) - else: - # 如果都解析失败,作为普通消息处理 - log_entry = { - "timestamp": datetime.now().isoformat(), - "level": "INFO", - "source": "system", - "function": "unknown", - "line": 0, - "message": line.strip() - } - - with self.lock: - self.logs.append(log_entry) - + except Exception as e: # 如果解析失败,作为普通消息处理 log_entry = { "timestamp": datetime.now().isoformat(), - "level": "ERROR", - "source": "log_parser", - "function": "parse_log_line", + "level": "INFO", + "source": "system", + "function": "unknown", "line": 0, - "message": f"日志解析失败: {line} (错误: {str(e)})" + "message": line } - + with self.lock: self.logs.append(log_entry) diff --git a/fix-db-permissions.bat b/fix-db-permissions.bat new file mode 100644 index 0000000..fdcb358 --- /dev/null +++ b/fix-db-permissions.bat @@ -0,0 +1,156 @@ +@echo off +chcp 65001 >nul +setlocal enabledelayedexpansion + +:: 修复数据库权限问题的脚本 (Windows版本) +:: 解决Docker容器中数据库无法创建的问题 + +title 数据库权限修复脚本 + +:: 颜色定义 +set "RED=[91m" +set "GREEN=[92m" +set "YELLOW=[93m" +set "BLUE=[94m" +set "NC=[0m" + +:: 打印带颜色的消息 +:print_info +echo %BLUE%[INFO]%NC% %~1 +goto :eof + +:print_success +echo %GREEN%[SUCCESS]%NC% %~1 +goto :eof + +:print_warning +echo %YELLOW%[WARNING]%NC% %~1 +goto :eof + +:print_error +echo %RED%[ERROR]%NC% %~1 +goto :eof + +echo ======================================== +echo 数据库权限修复脚本 +echo ======================================== +echo. + +:: 1. 停止现有容器 +call :print_info "停止现有容器..." +docker-compose down >nul 2>&1 + +:: 2. 检查并创建目录 +call :print_info "检查并创建必要目录..." + +for %%d in (data logs backups) do ( + if not exist "%%d" ( + call :print_info "创建目录: %%d" + mkdir "%%d" + ) + + if not exist "%%d" ( + call :print_error "目录 %%d 创建失败" + pause + exit /b 1 + ) + + call :print_success "目录 %%d 权限正常" +) + +:: 3. 检查现有数据库文件 +if exist "data\xianyu_data.db" ( + call :print_info "检查现有数据库文件..." + call :print_success "数据库文件存在" +) else ( + call :print_info "数据库文件不存在,将在启动时创建" +) + +:: 4. 测试数据库创建 +call :print_info "测试数据库创建..." +python -c " +import sqlite3 +import os + +db_path = 'data/test_db.sqlite' +try: + conn = sqlite3.connect(db_path) + conn.execute('CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY)') + conn.commit() + conn.close() + print('✅ 数据库创建测试成功') + if os.path.exists(db_path): + os.remove(db_path) +except Exception as e: + print(f'❌ 数据库创建测试失败: {e}') + exit(1) +" + +if !errorlevel! neq 0 ( + call :print_error "数据库创建测试失败" + pause + exit /b 1 +) + +:: 5. 重新构建并启动 +call :print_info "重新构建并启动服务..." +docker-compose build --no-cache +if !errorlevel! neq 0 ( + call :print_error "Docker镜像构建失败" + pause + exit /b 1 +) + +docker-compose up -d +if !errorlevel! neq 0 ( + call :print_error "服务启动失败" + pause + exit /b 1 +) + +:: 6. 等待服务启动 +call :print_info "等待服务启动..." +timeout /t 15 /nobreak >nul + +:: 7. 检查服务状态 +call :print_info "检查服务状态..." +docker-compose ps | findstr "Up" >nul +if !errorlevel! equ 0 ( + call :print_success "服务启动成功" + + :: 检查日志 + call :print_info "检查启动日志..." + docker-compose logs --tail=20 xianyu-app + + :: 测试健康检查 + call :print_info "测试健康检查..." + timeout /t 5 /nobreak >nul + curl -f http://localhost:8080/health >nul 2>&1 + if !errorlevel! equ 0 ( + call :print_success "健康检查通过" + ) else ( + call :print_warning "健康检查失败,但服务可能仍在启动中" + ) +) else ( + call :print_error "服务启动失败" + call :print_info "查看错误日志:" + docker-compose logs xianyu-app + pause + exit /b 1 +) + +echo. +call :print_success "数据库权限修复完成!" +echo. +call :print_info "服务信息:" +echo Web界面: http://localhost:8080 +echo 健康检查: http://localhost:8080/health +echo 默认账号: admin / admin123 +echo. +call :print_info "常用命令:" +echo 查看日志: docker-compose logs -f +echo 重启服务: docker-compose restart +echo 停止服务: docker-compose down +echo. + +pause diff --git a/fix-db-permissions.sh b/fix-db-permissions.sh new file mode 100644 index 0000000..e6ea4ff --- /dev/null +++ b/fix-db-permissions.sh @@ -0,0 +1,167 @@ +#!/bin/bash + +# 修复数据库权限问题的脚本 +# 解决Docker容器中数据库无法创建的问题 + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +echo "========================================" +echo " 数据库权限修复脚本" +echo "========================================" +echo "" + +# 1. 停止现有容器 +print_info "停止现有容器..." +docker-compose down 2>/dev/null || true + +# 2. 检查并创建目录 +print_info "检查并创建必要目录..." +for dir in data logs backups; do + if [ ! -d "$dir" ]; then + print_info "创建目录: $dir" + mkdir -p "$dir" + fi + + # 设置权限 + chmod 755 "$dir" + + # 检查权限 + if [ ! -w "$dir" ]; then + print_error "目录 $dir 没有写权限" + + # 尝试修复权限 + print_info "尝试修复权限..." + sudo chmod 755 "$dir" 2>/dev/null || { + print_error "无法修复权限,请手动执行: sudo chmod 755 $dir" + exit 1 + } + fi + + print_success "目录 $dir 权限正常" +done + +# 3. 检查现有数据库文件 +if [ -f "data/xianyu_data.db" ]; then + print_info "检查现有数据库文件权限..." + if [ ! -w "data/xianyu_data.db" ]; then + print_warning "数据库文件没有写权限,尝试修复..." + chmod 644 "data/xianyu_data.db" + print_success "数据库文件权限已修复" + else + print_success "数据库文件权限正常" + fi +fi + +# 4. 检查Docker用户映射 +print_info "检查Docker用户映射..." +CURRENT_UID=$(id -u) +CURRENT_GID=$(id -g) + +print_info "当前用户 UID:GID = $CURRENT_UID:$CURRENT_GID" + +# 5. 创建测试数据库 +print_info "测试数据库创建..." +python3 -c " +import sqlite3 +import os + +db_path = 'data/test_db.sqlite' +try: + conn = sqlite3.connect(db_path) + conn.execute('CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY)') + conn.commit() + conn.close() + print('✅ 数据库创建测试成功') + os.remove(db_path) +except Exception as e: + print(f'❌ 数据库创建测试失败: {e}') + exit(1) +" || { + print_error "数据库创建测试失败" + exit 1 +} + +# 6. 更新docker-compose.yml用户映射 +print_info "检查docker-compose.yml用户映射..." +if ! grep -q "user:" docker-compose.yml; then + print_info "添加用户映射到docker-compose.yml..." + + # 备份原文件 + cp docker-compose.yml docker-compose.yml.backup + + # 在xianyu-app服务中添加user配置 + sed -i '/container_name: xianyu-auto-reply/a\ user: "'$CURRENT_UID':'$CURRENT_GID'"' docker-compose.yml + + print_success "用户映射已添加" +else + print_info "用户映射已存在" +fi + +# 7. 重新构建并启动 +print_info "重新构建并启动服务..." +docker-compose build --no-cache +docker-compose up -d + +# 8. 等待服务启动 +print_info "等待服务启动..." +sleep 10 + +# 9. 检查服务状态 +print_info "检查服务状态..." +if docker-compose ps | grep -q "Up"; then + print_success "服务启动成功" + + # 检查日志 + print_info "检查启动日志..." + docker-compose logs --tail=20 xianyu-app + + # 测试健康检查 + print_info "测试健康检查..." + sleep 5 + if curl -f http://localhost:8080/health >/dev/null 2>&1; then + print_success "健康检查通过" + else + print_warning "健康检查失败,但服务可能仍在启动中" + fi +else + print_error "服务启动失败" + print_info "查看错误日志:" + docker-compose logs xianyu-app + exit 1 +fi + +echo "" +print_success "数据库权限修复完成!" +echo "" +print_info "服务信息:" +echo " Web界面: http://localhost:8080" +echo " 健康检查: http://localhost:8080/health" +echo " 默认账号: admin / admin123" +echo "" +print_info "常用命令:" +echo " 查看日志: docker-compose logs -f" +echo " 重启服务: docker-compose restart" +echo " 停止服务: docker-compose down" diff --git a/fix-docker-warnings.bat b/fix-docker-warnings.bat new file mode 100644 index 0000000..6810784 --- /dev/null +++ b/fix-docker-warnings.bat @@ -0,0 +1,144 @@ +@echo off +chcp 65001 >nul +setlocal enabledelayedexpansion + +:: 修复Docker部署警告的快速脚本 (Windows版本) +:: 解决version过时和.env文件缺失问题 + +title Docker部署警告修复脚本 + +:: 颜色定义 +set "RED=[91m" +set "GREEN=[92m" +set "YELLOW=[93m" +set "BLUE=[94m" +set "NC=[0m" + +:: 打印带颜色的消息 +:print_info +echo %BLUE%[INFO]%NC% %~1 +goto :eof + +:print_success +echo %GREEN%[SUCCESS]%NC% %~1 +goto :eof + +:print_warning +echo %YELLOW%[WARNING]%NC% %~1 +goto :eof + +:print_error +echo %RED%[ERROR]%NC% %~1 +goto :eof + +echo ======================================== +echo Docker部署警告修复脚本 +echo ======================================== +echo. + +:: 1. 检查并创建.env文件 +call :print_info "检查 .env 文件..." +if not exist ".env" ( + if exist ".env.example" ( + call :print_info "从 .env.example 创建 .env 文件..." + copy ".env.example" ".env" >nul + call :print_success ".env 文件已创建" + ) else ( + call :print_warning ".env.example 文件不存在" + call :print_info "创建基本的 .env 文件..." + + ( + echo # 闲鱼自动回复系统 Docker 环境变量配置文件 + echo. + echo # 基础配置 + echo TZ=Asia/Shanghai + echo PYTHONUNBUFFERED=1 + echo LOG_LEVEL=INFO + echo. + echo # 数据库配置 + echo DB_PATH=/app/data/xianyu_data.db + echo. + echo # 服务配置 + echo WEB_PORT=8080 + echo. + echo # 安全配置 + echo ADMIN_USERNAME=admin + echo ADMIN_PASSWORD=admin123 + echo JWT_SECRET_KEY=xianyu-auto-reply-secret-key-2024 + echo. + echo # 资源限制 + echo MEMORY_LIMIT=512 + echo CPU_LIMIT=0.5 + echo MEMORY_RESERVATION=256 + echo CPU_RESERVATION=0.25 + echo. + echo # 自动回复配置 + echo AUTO_REPLY_ENABLED=true + echo WEBSOCKET_URL=wss://wss-goofish.dingtalk.com/ + echo HEARTBEAT_INTERVAL=15 + echo TOKEN_REFRESH_INTERVAL=3600 + ) > .env + + call :print_success "基本 .env 文件已创建" + ) +) else ( + call :print_success ".env 文件已存在" +) + +:: 2. 检查docker-compose.yml版本问题 +call :print_info "检查 docker-compose.yml 配置..." +findstr /B "version:" docker-compose.yml >nul 2>&1 +if !errorlevel! equ 0 ( + call :print_warning "发现过时的 version 字段" + call :print_info "移除 version 字段..." + + REM 备份原文件 + copy docker-compose.yml docker-compose.yml.backup >nul + + REM 创建临时文件,移除version行 + ( + for /f "tokens=*" %%a in (docker-compose.yml) do ( + echo %%a | findstr /B "version:" >nul + if !errorlevel! neq 0 ( + echo %%a + ) + ) + ) > docker-compose.yml.tmp + + REM 替换原文件 + move docker-compose.yml.tmp docker-compose.yml >nul + + call :print_success "已移除过时的 version 字段" + call :print_info "原文件已备份为 docker-compose.yml.backup" +) else ( + call :print_success "docker-compose.yml 配置正确" +) + +:: 3. 验证修复结果 +call :print_info "验证修复结果..." + +echo. +call :print_info "测试 Docker Compose 配置..." +docker-compose config >nul 2>&1 +if !errorlevel! equ 0 ( + call :print_success "Docker Compose 配置验证通过" +) else ( + call :print_error "Docker Compose 配置验证失败" + echo 请检查 docker-compose.yml 文件 + pause + exit /b 1 +) + +echo. +call :print_success "所有警告已修复!" +echo. +call :print_info "现在可以正常使用以下命令:" +echo docker-compose up -d # 启动服务 +echo docker-compose ps # 查看状态 +echo docker-compose logs -f # 查看日志 +echo. +call :print_info "如果需要恢复原配置:" +echo move docker-compose.yml.backup docker-compose.yml +echo. + +pause diff --git a/fix-docker-warnings.sh b/fix-docker-warnings.sh new file mode 100644 index 0000000..63d63e5 --- /dev/null +++ b/fix-docker-warnings.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +# 修复Docker部署警告的快速脚本 +# 解决version过时和.env文件缺失问题 + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +echo "========================================" +echo " Docker部署警告修复脚本" +echo "========================================" +echo "" + +# 1. 检查并创建.env文件 +print_info "检查 .env 文件..." +if [ ! -f ".env" ]; then + if [ -f ".env.example" ]; then + print_info "从 .env.example 创建 .env 文件..." + cp .env.example .env + print_success ".env 文件已创建" + else + print_warning ".env.example 文件不存在" + print_info "创建基本的 .env 文件..." + cat > .env << 'EOF' +# 闲鱼自动回复系统 Docker 环境变量配置文件 + +# 基础配置 +TZ=Asia/Shanghai +PYTHONUNBUFFERED=1 +LOG_LEVEL=INFO + +# 数据库配置 +DB_PATH=/app/data/xianyu_data.db + +# 服务配置 +WEB_PORT=8080 + +# 安全配置 +ADMIN_USERNAME=admin +ADMIN_PASSWORD=admin123 +JWT_SECRET_KEY=xianyu-auto-reply-secret-key-2024 + +# 资源限制 +MEMORY_LIMIT=512 +CPU_LIMIT=0.5 +MEMORY_RESERVATION=256 +CPU_RESERVATION=0.25 + +# 自动回复配置 +AUTO_REPLY_ENABLED=true +WEBSOCKET_URL=wss://wss-goofish.dingtalk.com/ +HEARTBEAT_INTERVAL=15 +TOKEN_REFRESH_INTERVAL=3600 +EOF + print_success "基本 .env 文件已创建" + fi +else + print_success ".env 文件已存在" +fi + +# 2. 检查docker-compose.yml版本问题 +print_info "检查 docker-compose.yml 配置..." +if grep -q "^version:" docker-compose.yml 2>/dev/null; then + print_warning "发现过时的 version 字段" + print_info "移除 version 字段..." + + # 备份原文件 + cp docker-compose.yml docker-compose.yml.backup + + # 移除version行 + sed -i '/^version:/d' docker-compose.yml + sed -i '/^$/N;/^\n$/d' docker-compose.yml # 移除空行 + + print_success "已移除过时的 version 字段" + print_info "原文件已备份为 docker-compose.yml.backup" +else + print_success "docker-compose.yml 配置正确" +fi + +# 3. 检查env_file配置 +print_info "检查 env_file 配置..." +if grep -A1 "env_file:" docker-compose.yml | grep -q "required: false"; then + print_success "env_file 配置正确" +else + print_info "更新 env_file 配置为可选..." + + # 备份文件(如果还没备份) + if [ ! -f "docker-compose.yml.backup" ]; then + cp docker-compose.yml docker-compose.yml.backup + fi + + # 更新env_file配置 + sed -i '/env_file:/,+1c\ + env_file:\ + - path: .env\ + required: false' docker-compose.yml + + print_success "env_file 配置已更新" +fi + +# 4. 验证修复结果 +print_info "验证修复结果..." + +echo "" +print_info "测试 Docker Compose 配置..." +if docker-compose config >/dev/null 2>&1; then + print_success "Docker Compose 配置验证通过" +else + print_error "Docker Compose 配置验证失败" + echo "请检查 docker-compose.yml 文件" + exit 1 +fi + +echo "" +print_success "所有警告已修复!" +echo "" +print_info "现在可以正常使用以下命令:" +echo " docker-compose up -d # 启动服务" +echo " docker-compose ps # 查看状态" +echo " docker-compose logs -f # 查看日志" +echo "" +print_info "如果需要恢复原配置:" +echo " mv docker-compose.yml.backup docker-compose.yml" diff --git a/fix-websocket-issue.sh b/fix-websocket-issue.sh new file mode 100644 index 0000000..d874a86 --- /dev/null +++ b/fix-websocket-issue.sh @@ -0,0 +1,121 @@ +#!/bin/bash + +# 快速修复WebSocket兼容性问题 +# 解决 "extra_headers" 参数不支持的问题 + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +echo "🔧 WebSocket兼容性问题修复" +echo "================================" + +# 1. 检查当前websockets版本 +print_info "检查当前websockets版本..." +if command -v python3 &> /dev/null; then + PYTHON_CMD="python3" +elif command -v python &> /dev/null; then + PYTHON_CMD="python" +else + print_error "未找到Python解释器" + exit 1 +fi + +CURRENT_VERSION=$($PYTHON_CMD -c "import websockets; print(websockets.__version__)" 2>/dev/null || echo "未安装") +print_info "当前websockets版本: $CURRENT_VERSION" + +# 2. 测试WebSocket兼容性 +print_info "测试WebSocket兼容性..." +$PYTHON_CMD test-websocket-compatibility.py + +# 3. 停止现有服务 +print_info "停止现有Docker服务..." +docker-compose down 2>/dev/null || true + +# 4. 更新websockets版本 +print_info "更新websockets版本到兼容版本..." +if [ -f "requirements.txt" ]; then + # 备份原文件 + cp requirements.txt requirements.txt.backup + + # 更新websockets版本 + sed -i 's/websockets>=.*/websockets>=10.0,<13.0 # 兼容性版本范围/' requirements.txt + + print_success "requirements.txt已更新" +else + print_warning "requirements.txt文件不存在" +fi + +# 5. 重新构建Docker镜像 +print_info "重新构建Docker镜像..." +docker-compose build --no-cache + +# 6. 启动服务 +print_info "启动服务..." +docker-compose up -d + +# 7. 等待服务启动 +print_info "等待服务启动..." +sleep 15 + +# 8. 检查服务状态 +print_info "检查服务状态..." +if docker-compose ps | grep -q "Up"; then + print_success "✅ 服务启动成功!" + + # 检查WebSocket错误 + print_info "检查WebSocket连接状态..." + sleep 5 + + # 查看最近的日志 + echo "" + print_info "最近的服务日志:" + docker-compose logs --tail=20 xianyu-app | grep -E "(WebSocket|extra_headers|ERROR)" || echo "未发现WebSocket相关错误" + + # 测试健康检查 + if curl -f http://localhost:8080/health >/dev/null 2>&1; then + print_success "健康检查通过" + else + print_warning "健康检查失败,服务可能仍在启动中" + fi + +else + print_error "❌ 服务启动失败" + print_info "查看错误日志:" + docker-compose logs --tail=30 xianyu-app + exit 1 +fi + +echo "" +print_success "🎉 WebSocket兼容性问题修复完成!" +echo "" +print_info "服务信息:" +echo " Web界面: http://localhost:8080" +echo " 健康检查: http://localhost:8080/health" +echo " 默认账号: admin / admin123" +echo "" +print_info "如果仍有WebSocket问题,请:" +echo " 1. 查看日志: docker-compose logs -f xianyu-app" +echo " 2. 运行测试: python test-websocket-compatibility.py" +echo " 3. 检查网络连接和防火墙设置" diff --git a/gitignore_rules_explanation.md b/gitignore_rules_explanation.md new file mode 100644 index 0000000..dacf1e4 --- /dev/null +++ b/gitignore_rules_explanation.md @@ -0,0 +1,172 @@ +# .gitignore 规则说明 + +## 📋 概述 + +本项目的 `.gitignore` 文件已经过优化,包含了完整的忽略规则,确保敏感文件和不必要的文件不会被提交到版本控制中。 + +## 🔧 主要修复 + +### 1. **数据库文件忽略** ✅ +**问题**: 原来缺少 `*.db` 文件的忽略规则 +**解决**: 添加了完整的数据库文件忽略规则 + +```gitignore +# Database files +*.db +*.sqlite +*.sqlite3 +db.sqlite3 +``` + +### 2. **静态资源例外** ✅ +**问题**: `lib/` 规则会忽略 `static/lib/` 中的本地 CDN 资源 +**解决**: 添加例外规则,允许 `static/lib/` 被版本控制 + +```gitignore +# Python lib directories (but not static/lib) +lib/ +!static/lib/ +``` + +## 📂 完整规则分类 + +### Python 相关 +```gitignore +__pycache__ +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +MANIFEST +*.manifest +*.spec +__pypackages__/ +.venv +venv/ +ENV/ +env.bak/ +venv.bak/ +``` + +### 数据库文件 +```gitignore +*.db +*.sqlite +*.sqlite3 +db.sqlite3 +``` + +### 日志和缓存 +```gitignore +*.log +.cache +``` + +### 临时文件 +```gitignore +*.tmp +*.temp +temp/ +tmp/ +``` + +### 操作系统生成的文件 +```gitignore +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +``` + +### IDE 和编辑器文件 +```gitignore +.vscode/ +.idea/ +*.swp +*.swo +*~ +``` + +### 环境配置文件 +```gitignore +.env +.env.local +.env.*.local +local_settings.py +``` + +### Node.js 相关 +```gitignore +*node_modules/* +``` + +### 静态资源例外 +```gitignore +!static/lib/ +``` + +## 🎯 特殊说明 + +### 数据库文件保护 +- **目的**: 防止敏感的用户数据和配置信息被意外提交 +- **影响**: `xianyu_data.db` 等数据库文件不会被 Git 跟踪 +- **好处**: 保护用户隐私,避免数据泄露 + +### 静态资源管理 +- **目的**: 允许本地 CDN 资源被版本控制,提升中国大陆访问速度 +- **规则**: `lib/` 被忽略,但 `static/lib/` 不被忽略 +- **包含**: Bootstrap CSS/JS、Bootstrap Icons 等本地资源 + +### 环境配置保护 +- **目的**: 防止敏感的环境变量和配置被提交 +- **影响**: `.env` 文件和本地设置不会被跟踪 +- **好处**: 保护 API 密钥、数据库连接等敏感信息 + +## 🧪 验证方法 + +可以运行以下测试脚本验证规则是否正确: + +```bash +# 测试数据库文件忽略 +python test_gitignore_db.py + +# 测试静态资源例外 +python test_gitignore.py +``` + +## 📊 当前项目状态 + +### 被忽略的文件 +- `xianyu_data.db` (139,264 bytes) - 主数据库 +- `data/xianyu_data.db` (106,496 bytes) - 数据目录中的数据库 +- 各种临时文件、日志文件、IDE 配置等 + +### 不被忽略的重要文件 +- `static/lib/` 目录下的所有本地 CDN 资源 (702 KB) +- 源代码文件 (`.py`, `.html`, `.js` 等) +- 配置模板文件 (`.yml.example`, `.env.example` 等) +- 文档文件 (`.md` 等) + +## 🎉 优势总结 + +1. **数据安全**: 数据库文件不会被意外提交,保护用户数据 +2. **配置安全**: 环境变量和敏感配置得到保护 +3. **仓库整洁**: 临时文件、缓存文件等不会污染仓库 +4. **本地资源**: CDN 资源可以正常版本控制,提升访问速度 +5. **跨平台**: 支持 Windows、macOS、Linux 的常见忽略文件 +6. **IDE 友好**: 支持 VSCode、IntelliJ IDEA 等常见 IDE + +现在的 `.gitignore` 配置既保证了项目的安全性,又确保了必要文件的正常版本控制! diff --git a/global_config.yml b/global_config.yml index 4ef32e4..9e11190 100644 --- a/global_config.yml +++ b/global_config.yml @@ -9,7 +9,7 @@ APP_CONFIG: platform: web AUTO_REPLY: api: - enabled: true # 禁用API回复,使用AI回复或关键词回复 + enabled: false # 禁用API回复,使用AI回复或关键词回复 host: 0.0.0.0 # 绑定所有网络接口,支持IP访问 port: 8080 # Web服务端口 timeout: 10 diff --git a/images/qq-group.jpg b/images/qq-group.jpg deleted file mode 100644 index f351cf10c7a8cca2b076fae39bddb34ef39269fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146989 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 Lj5{w{+RyzBi+_-M diff --git a/images/wechat-group.jpg b/images/wechat-group.jpg deleted file mode 100644 index 12a29905cf64444688b78b1830c615f20653d826..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170848 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¥d00W>QXniE*P>A~Lu-zv_gxrs&y3;i8 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 diff --git a/log_filter.py b/log_filter.py deleted file mode 100644 index 8022ee2..0000000 --- a/log_filter.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -日志过滤器 -用于过滤不需要记录到文件的日志 -""" - -import re -from typing import Dict, Any - -class LogFilter: - """日志过滤器类""" - - def __init__(self): - # 不需要记录的API路径模式 - self.excluded_api_patterns = [ - r'GET /logs', - r'GET /logs/stats', - r'GET /health', - r'GET /docs', - r'GET /redoc', - r'GET /openapi\.json', - r'GET /static/', - r'GET /favicon\.ico' - ] - - # 不需要记录的消息模式 - self.excluded_message_patterns = [ - r'API请求: GET /logs', - r'API响应: GET /logs', - r'API请求: GET /health', - r'API响应: GET /health', - r'API请求: GET /docs', - r'API响应: GET /docs', - r'API请求: GET /static/', - r'API响应: GET /static/', - r'.*favicon\.ico.*', - r'.*websocket.*ping.*', - r'.*websocket.*pong.*' - ] - - # 编译正则表达式以提高性能 - self.compiled_api_patterns = [re.compile(pattern, re.IGNORECASE) for pattern in self.excluded_api_patterns] - self.compiled_message_patterns = [re.compile(pattern, re.IGNORECASE) for pattern in self.excluded_message_patterns] - - def should_log(self, record: Dict[str, Any]) -> bool: - """ - 判断是否应该记录这条日志 - - Args: - record: loguru的日志记录字典 - - Returns: - bool: True表示应该记录,False表示应该过滤掉 - """ - try: - message = record.get('message', '') - - # 检查消息模式 - for pattern in self.compiled_message_patterns: - if pattern.search(message): - return False - - # 检查API路径模式 - for pattern in self.compiled_api_patterns: - if pattern.search(message): - return False - - # 过滤掉过于频繁的心跳日志 - if any(keyword in message.lower() for keyword in ['heartbeat', '心跳', 'ping', 'pong']): - return False - - # 过滤掉WebSocket连接状态的频繁日志 - if any(keyword in message.lower() for keyword in ['websocket connected', 'websocket disconnected']): - # 只记录连接和断开,不记录频繁的状态检查 - if 'status check' in message.lower(): - return False - - return True - - except Exception: - # 如果过滤器出错,默认记录日志 - return True - -# 全局日志过滤器实例 -log_filter = LogFilter() - -def filter_log_record(record): - """ - loguru的过滤器函数 - - Args: - record: loguru的日志记录对象 - - Returns: - bool: True表示应该记录,False表示应该过滤掉 - """ - return log_filter.should_log(record) - -def add_excluded_pattern(pattern: str): - """ - 添加新的排除模式 - - Args: - pattern: 正则表达式模式 - """ - log_filter.excluded_message_patterns.append(pattern) - log_filter.compiled_message_patterns.append(re.compile(pattern, re.IGNORECASE)) - -def remove_excluded_pattern(pattern: str): - """ - 移除排除模式 - - Args: - pattern: 要移除的正则表达式模式 - """ - if pattern in log_filter.excluded_message_patterns: - index = log_filter.excluded_message_patterns.index(pattern) - log_filter.excluded_message_patterns.pop(index) - log_filter.compiled_message_patterns.pop(index) - -def get_excluded_patterns(): - """ - 获取当前的排除模式列表 - - Returns: - list: 排除模式列表 - """ - return log_filter.excluded_message_patterns.copy() - -# 测试函数 -def test_filter(): - """测试过滤器功能""" - test_messages = [ - "🌐 API请求: GET /logs?lines=200", - "✅ API响应: GET /logs - 200 (0.123s)", - "🌐 API请求: GET /health", - "✅ API响应: GET /health - 200 (0.001s)", - "🌐 API请求: POST /cookies", - "✅ API响应: POST /cookies - 201 (0.456s)", - "WebSocket心跳检查", - "用户登录成功", - "数据库连接建立", - "WebSocket connected status check", - "处理消息: 你好" - ] - - print("🧪 测试日志过滤器") - print("=" * 50) - - for message in test_messages: - record = {"message": message} - should_log = log_filter.should_log(record) - status = "✅ 记录" if should_log else "❌ 过滤" - print(f"{status}: {message}") - - print("=" * 50) - print("测试完成") - -if __name__ == "__main__": - test_filter() diff --git a/quick-fix-permissions.bat b/quick-fix-permissions.bat new file mode 100644 index 0000000..762e0e5 --- /dev/null +++ b/quick-fix-permissions.bat @@ -0,0 +1,116 @@ +@echo off +chcp 65001 >nul +setlocal enabledelayedexpansion + +:: 快速修复Docker权限问题 (Windows版本) + +title 快速修复Docker权限问题 + +:: 颜色定义 +set "RED=[91m" +set "GREEN=[92m" +set "YELLOW=[93m" +set "BLUE=[94m" +set "NC=[0m" + +:print_info +echo %BLUE%[INFO]%NC% %~1 +goto :eof + +:print_success +echo %GREEN%[SUCCESS]%NC% %~1 +goto :eof + +:print_error +echo %RED%[ERROR]%NC% %~1 +goto :eof + +echo 🚀 快速修复Docker权限问题 +echo ================================ +echo. + +:: 1. 停止容器 +call :print_info "停止现有容器..." +docker-compose down >nul 2>&1 + +:: 2. 确保目录存在 +call :print_info "创建必要目录..." +if not exist "data" mkdir data +if not exist "logs" mkdir logs +if not exist "backups" mkdir backups + +:: 3. 检查并修复docker-compose.yml +call :print_info "检查docker-compose.yml配置..." +findstr /C:"user.*0:0" docker-compose.yml >nul 2>&1 +if !errorlevel! neq 0 ( + call :print_info "添加root用户配置..." + + REM 备份原文件 + copy docker-compose.yml docker-compose.yml.backup >nul + + REM 创建临时文件添加user配置 + ( + for /f "tokens=*" %%a in (docker-compose.yml) do ( + echo %%a + echo %%a | findstr /C:"container_name: xianyu-auto-reply" >nul + if !errorlevel! equ 0 ( + echo user: "0:0" + ) + ) + ) > docker-compose.yml.tmp + + REM 替换原文件 + move docker-compose.yml.tmp docker-compose.yml >nul + + call :print_success "已配置使用root用户运行" +) + +:: 4. 重新构建镜像 +call :print_info "重新构建Docker镜像..." +docker-compose build --no-cache +if !errorlevel! neq 0 ( + call :print_error "Docker镜像构建失败" + pause + exit /b 1 +) + +:: 5. 启动服务 +call :print_info "启动服务..." +docker-compose up -d +if !errorlevel! neq 0 ( + call :print_error "服务启动失败" + pause + exit /b 1 +) + +:: 6. 等待启动 +call :print_info "等待服务启动..." +timeout /t 15 /nobreak >nul + +:: 7. 检查状态 +call :print_info "检查服务状态..." +docker-compose ps | findstr "Up" >nul +if !errorlevel! equ 0 ( + call :print_success "✅ 服务启动成功!" + + echo. + call :print_info "最近的日志:" + docker-compose logs --tail=10 xianyu-app + + echo. + call :print_success "🎉 权限问题已修复!" + echo. + echo 访问信息: + echo Web界面: http://localhost:8080 + echo 健康检查: http://localhost:8080/health + echo 默认账号: admin / admin123 + +) else ( + call :print_error "❌ 服务启动失败" + echo. + call :print_info "错误日志:" + docker-compose logs xianyu-app +) + +echo. +pause diff --git a/quick-fix-permissions.sh b/quick-fix-permissions.sh new file mode 100644 index 0000000..fbe55de --- /dev/null +++ b/quick-fix-permissions.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +# 快速修复Docker权限问题 +# 这个脚本会立即解决权限问题并重启服务 + +set -e + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +echo "🚀 快速修复Docker权限问题" +echo "================================" + +# 1. 停止容器 +print_info "停止现有容器..." +docker-compose down + +# 2. 确保目录存在并设置权限 +print_info "设置目录权限..." +mkdir -p data logs backups +chmod 777 data logs backups + +# 3. 检查并修复docker-compose.yml +print_info "检查docker-compose.yml配置..." +if ! grep -q "user.*0:0" docker-compose.yml; then + print_info "添加root用户配置..." + + # 备份原文件 + cp docker-compose.yml docker-compose.yml.backup + + # 在container_name后添加user配置 + sed -i '/container_name: xianyu-auto-reply/a\ user: "0:0"' docker-compose.yml + + print_success "已配置使用root用户运行" +fi + +# 4. 重新构建镜像 +print_info "重新构建Docker镜像..." +docker-compose build --no-cache + +# 5. 启动服务 +print_info "启动服务..." +docker-compose up -d + +# 6. 等待启动 +print_info "等待服务启动..." +sleep 15 + +# 7. 检查状态 +print_info "检查服务状态..." +if docker-compose ps | grep -q "Up"; then + print_success "✅ 服务启动成功!" + + # 显示日志 + echo "" + print_info "最近的日志:" + docker-compose logs --tail=10 xianyu-app + + echo "" + print_success "🎉 权限问题已修复!" + echo "" + echo "访问信息:" + echo " Web界面: http://localhost:8080" + echo " 健康检查: http://localhost:8080/health" + echo " 默认账号: admin / admin123" + +else + print_error "❌ 服务启动失败" + echo "" + print_info "错误日志:" + docker-compose logs xianyu-app +fi diff --git a/reply_server.py b/reply_server.py index 44f9d90..c3a8dd3 100644 --- a/reply_server.py +++ b/reply_server.py @@ -157,84 +157,23 @@ app = FastAPI( redoc_url="/redoc" ) -# 配置统一的日志系统 -import time -from loguru import logger - -# 确保日志目录存在 -log_dir = 'logs' -os.makedirs(log_dir, exist_ok=True) -log_path = os.path.join(log_dir, f"xianyu_{time.strftime('%Y-%m-%d')}.log") - -# 移除默认的日志处理器 -logger.remove() - -# 导入日志过滤器 -try: - from log_filter import filter_log_record -except ImportError: - # 如果过滤器不可用,使用默认过滤器 - def filter_log_record(record): - return True - -# 添加文件日志处理器,使用与XianyuAutoAsync相同的格式,并应用过滤器 -logger.add( - log_path, - rotation="1 day", - retention="7 days", - compression="zip", - level="INFO", - format='{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {name}:{function}:{line} - {message}', - encoding='utf-8', - enqueue=False, # 立即写入 - buffering=1, # 行缓冲 - filter=filter_log_record # 应用日志过滤器 -) - # 初始化文件日志收集器 setup_file_logging() # 添加一条测试日志 -logger.info("Web服务器启动,统一日志系统已初始化") - -# 不需要记录到文件的API路径 -EXCLUDED_LOG_PATHS = { - '/logs', - '/logs/stats', - '/logs/clear', - '/health', - '/docs', - '/redoc', - '/openapi.json', - '/favicon.ico' -} - -# 不需要记录的路径前缀 -EXCLUDED_LOG_PREFIXES = { - '/static/', - '/docs', - '/redoc' -} +from loguru import logger +logger.info("Web服务器启动,文件日志收集器已初始化") # 添加请求日志中间件 @app.middleware("http") async def log_requests(request, call_next): start_time = time.time() - - # 检查是否需要记录日志 - should_log = ( - request.url.path not in EXCLUDED_LOG_PATHS and - not any(request.url.path.startswith(prefix) for prefix in EXCLUDED_LOG_PREFIXES) - ) - - if should_log: - logger.info(f"🌐 API请求: {request.method} {request.url.path}") + logger.info(f"🌐 API请求: {request.method} {request.url.path}") response = await call_next(request) - if should_log: - process_time = time.time() - start_time - logger.info(f"✅ API响应: {request.method} {request.url.path} - {response.status_code} ({process_time:.3f}s)") + process_time = time.time() - start_time + logger.info(f"✅ API响应: {request.method} {request.url.path} - {response.status_code} ({process_time:.3f}s)") return response @@ -1008,6 +947,15 @@ def import_backup(file: UploadFile = File(...), _: None = Depends(require_auth)) success = db_manager.import_backup(backup_data) if success: + # 备份导入成功后,刷新 CookieManager 的内存缓存 + import cookie_manager + if cookie_manager.manager: + try: + cookie_manager.manager.reload_from_db() + logger.info("备份导入后已刷新 CookieManager 缓存") + except Exception as e: + logger.error(f"刷新 CookieManager 缓存失败: {e}") + return {"message": "备份导入成功"} else: raise HTTPException(status_code=400, detail="备份导入失败") @@ -1018,6 +966,23 @@ def import_backup(file: UploadFile = File(...), _: None = Depends(require_auth)) raise HTTPException(status_code=500, detail=f"导入备份失败: {str(e)}") +@app.post("/system/reload-cache") +def reload_cache(_: None = Depends(require_auth)): + """重新加载系统缓存(用于手动刷新数据)""" + try: + import cookie_manager + if cookie_manager.manager: + success = cookie_manager.manager.reload_from_db() + if success: + return {"message": "系统缓存已刷新", "success": True} + else: + raise HTTPException(status_code=500, detail="缓存刷新失败") + else: + raise HTTPException(status_code=500, detail="CookieManager 未初始化") + except Exception as e: + raise HTTPException(status_code=500, detail=f"刷新缓存失败: {str(e)}") + + # ==================== 商品管理 API ==================== @app.get("/items") @@ -1302,9 +1267,9 @@ async def get_all_items_from_account(request: dict, _: None = Depends(require_au from XianyuAutoAsync import XianyuLive xianyu_instance = XianyuLive(cookies_str, cookie_id) - # 调用获取商品信息的方法 + # 调用获取所有商品信息的方法(自动分页) logger.info(f"开始获取账号 {cookie_id} 的所有商品信息") - result = await xianyu_instance.get_item_list_info() + result = await xianyu_instance.get_all_items() # 关闭session await xianyu_instance.close_session() @@ -1313,11 +1278,78 @@ async def get_all_items_from_account(request: dict, _: None = Depends(require_au logger.error(f"获取商品信息失败: {result['error']}") return {"success": False, "message": result['error']} else: - logger.info(f"成功获取账号 {cookie_id} 的 {result.get('total_count', 0)} 个商品") + total_count = result.get('total_count', 0) + total_pages = result.get('total_pages', 1) + logger.info(f"成功获取账号 {cookie_id} 的 {total_count} 个商品(共{total_pages}页)") return { "success": True, - "message": f"成功获取 {result.get('total_count', 0)} 个商品,详细信息已打印到控制台", - "total_count": result.get('total_count', 0) + "message": f"成功获取 {total_count} 个商品(共{total_pages}页),详细信息已打印到控制台", + "total_count": total_count, + "total_pages": total_pages + } + + except Exception as e: + logger.error(f"获取账号商品信息异常: {str(e)}") + return {"success": False, "message": f"获取商品信息异常: {str(e)}"} + + +@app.post("/items/get-by-page") +async def get_items_by_page(request: dict, _: None = Depends(require_auth)): + """从指定账号按页获取商品信息""" + try: + # 验证参数 + cookie_id = request.get('cookie_id') + page_number = request.get('page_number', 1) + page_size = request.get('page_size', 20) + + if not cookie_id: + return {"success": False, "message": "缺少cookie_id参数"} + + # 验证分页参数 + try: + page_number = int(page_number) + page_size = int(page_size) + except (ValueError, TypeError): + return {"success": False, "message": "页码和每页数量必须是数字"} + + if page_number < 1: + return {"success": False, "message": "页码必须大于0"} + + if page_size < 1 or page_size > 100: + return {"success": False, "message": "每页数量必须在1-100之间"} + + # 获取账号信息 + account = db_manager.get_cookie_by_id(cookie_id) + if not account: + return {"success": False, "message": "账号不存在"} + + cookies_str = account['cookies_str'] + if not cookies_str: + return {"success": False, "message": "账号cookies为空"} + + # 创建XianyuLive实例,传入正确的cookie_id + from XianyuAutoAsync import XianyuLive + xianyu_instance = XianyuLive(cookies_str, cookie_id) + + # 调用获取指定页商品信息的方法 + logger.info(f"开始获取账号 {cookie_id} 第{page_number}页商品信息(每页{page_size}条)") + result = await xianyu_instance.get_item_list_info(page_number, page_size) + + # 关闭session + await xianyu_instance.close_session() + + if result.get('error'): + logger.error(f"获取商品信息失败: {result['error']}") + return {"success": False, "message": result['error']} + else: + current_count = result.get('current_count', 0) + logger.info(f"成功获取账号 {cookie_id} 第{page_number}页 {current_count} 个商品") + return { + "success": True, + "message": f"成功获取第{page_number}页 {current_count} 个商品,详细信息已打印到控制台", + "page_number": page_number, + "page_size": page_size, + "current_count": current_count } except Exception as e: diff --git a/static/index.html b/static/index.html index 61e9311..1e69091 100644 --- a/static/index.html +++ b/static/index.html @@ -4,8 +4,8 @@ 闲鱼自动回复管理系统 - - + + + + +
+

账号状态显示测试

+ +
+

修改前 vs 修改后对比

+ +
+
+
修改前(带文字)
+
+ + + + 启用 + +
+ +
+ + + + 禁用 + +
+
+ +
+
修改后(仅图标)
+
+ + + + +
+ +
+ + + + +
+
+
+
+ +
+

表格中的效果预览

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
账号ID状态默认回复AI回复操作
测试账号001 +
+ + + + +
+
启用AI启用 + +
测试账号002 +
+ + + + +
+
禁用AI禁用 + +
+
+ +
+

优势说明

+
+
+
✅ 修改后的优势
+
    +
  • ✓ 界面更简洁
  • +
  • ✓ 节省空间
  • +
  • ✓ 图标直观易懂
  • +
  • ✓ 视觉焦点更集中
  • +
  • ✓ 现代化设计风格
  • +
+
+
+
🎨 设计细节
+
    +
  • • 图标居中对齐
  • +
  • • 徽章尺寸优化
  • +
  • • 颜色保持一致
  • +
  • • 响应式设计
  • +
  • • 无障碍访问友好
  • +
+
+
+
+ +
+
说明
+

+ 状态栏现在只显示图标,不显示"启用"/"禁用"文字。 + 绿色勾号表示启用状态,红色叉号表示禁用状态。 + 鼠标悬停时可以显示提示信息。 +

+
+
+ + + + + diff --git a/使用说明.md b/使用说明.md index 826ef11..008c929 100644 --- a/使用说明.md +++ b/使用说明.md @@ -70,14 +70,7 @@ python Start.py - **精确匹配**:支持关键词精确匹配 - **变量替换**:回复内容支持动态变量 - **优先级**:账号级关键词优先于全局关键词 -- **智能回复优先级**:关键词回复 → AI回复 → 默认回复 - -### 回复优先级说明 -系统按以下优先级处理回复: -1. **🔥 API回复** - 外部API接口回复(最高优先级) -2. **📝 关键词回复** - 精确关键词匹配回复 -3. **🤖 AI智能回复** - AI模型生成的智能回复 -4. **💬 默认回复** - 兜底的默认回复内容 +- **默认回复**:未匹配关键词时使用默认回复 ### API接口 - **接口地址**:`POST http://localhost:8080/xianyu/reply` @@ -159,133 +152,27 @@ python Start.py - 备份 `global_config.yml` 配置文件 - 备份自定义的关键词文件 -## 🔧 高级功能 - -### AI回复配置 -1. 在账号列表中点击"🤖 配置AI回复" -2. 开启AI回复功能 -3. 配置API密钥和模型参数 -4. 设置议价策略和优惠限制 -5. 自定义提示词(可选) - -### 自动发货设置 -1. 进入"自动发货"页面 -2. 添加发货规则和关键词匹配 -3. 上传卡券文件或手动添加卡券 -4. 配置发货模板和通知方式 - -### 商品管理 -1. 进入"商品管理"页面 -2. 查看自动收集的商品信息 -3. 编辑商品详情和分类 -4. 批量获取账号下所有商品 - -### 日志监控 -1. 进入"日志管理"页面 -2. 实时查看系统运行日志 -3. 按级别和来源筛选日志 -4. 查看系统统计信息 - -## 📊 数据管理 - -### 数据备份 -1. 进入"系统设置"页面 -2. 点击"导出备份"按钮 -3. 下载备份文件到本地 -4. 定期备份重要数据 - -### 数据恢复 -1. 进入"系统设置"页面 -2. 点击"导入备份"按钮 -3. 选择备份文件上传 -4. 确认恢复操作 - -### 数据清理 -- 定期清理过期日志文件 -- 删除无效的商品信息 -- 清理过期的对话记录 - ## 📞 技术支持 -### 系统健康检查 -访问健康检查端点: -``` -http://localhost:8080/health -``` - -### 查看系统状态 +### 测试系统 +运行测试脚本检查系统状态: ```bash -# 查看容器状态 -docker-compose ps - -# 查看系统资源使用 -docker stats - -# 查看实时日志 -docker-compose logs -f +python test_system.py ``` -### 常见问题解决 +### 重新创建配置 +如果配置文件损坏,运行: +```bash +python create_config.py +``` -**问题1:Cookie失效** -- 重新获取Cookie并更新 -- 检查账号是否被限制 -- 确认Cookie格式正确 +## 🎯 使用建议 -**问题2:消息接收异常** -- 检查网络连接 -- 重启WebSocket连接 -- 查看错误日志 - -**问题3:AI回复失败** -- 检查API密钥是否正确 -- 确认API服务可用 -- 检查账户余额 - -## 🎯 最佳实践 - -### 安全建议 -1. **定期更换密码**:修改默认管理员密码 -2. **限制访问**:仅允许信任的IP访问 -3. **备份数据**:定期备份重要配置和数据 -4. **监控日志**:定期查看系统日志 - -### 性能优化 -1. **合理设置**:根据实际需求配置参数 -2. **定期清理**:清理过期数据和日志 -3. **监控资源**:关注系统资源使用情况 -4. **优化配置**:根据使用情况调整配置 - -### 使用技巧 1. **Cookie获取**:使用浏览器开发者工具获取完整Cookie 2. **关键词设置**:设置常用的咨询关键词和回复 -3. **AI配置**:根据商品类型调整AI提示词 -4. **发货规则**:设置精确的商品匹配规则 - -## 🔄 系统更新 - -### 更新步骤 -1. 备份当前数据 -2. 停止系统服务 -3. 拉取最新代码 -4. 重新构建镜像 -5. 启动更新后的服务 - -### Docker更新 -```bash -# 停止服务 -docker-compose down - -# 拉取最新代码 -git pull - -# 重新构建 -./deploy.sh --update - -# 检查状态 -docker-compose ps -``` +3. **定期检查**:定期查看日志确保系统正常运行 +4. **备份数据**:重要数据请及时备份 --- -**注意**:本系统仅供学习交流使用,请遵守相关法律法规和平台规则。使用前请仔细阅读相关文档,确保正确配置和使用。 +**注意**:本系统仅供学习交流使用,请遵守相关法律法规和平台规则。 diff --git a/商品管理功能说明.md b/商品管理功能说明.md index 8b2614c..9ece907 100644 --- a/商品管理功能说明.md +++ b/商品管理功能说明.md @@ -194,62 +194,6 @@ Authorization: Bearer {token} - 监控自动发货匹配情况 - 及时处理异常情况 -## 🔧 故障排除 - -### 常见问题及解决方案 - -**问题1:商品信息收集失败** -- 检查网络连接是否正常 -- 确认Cookie是否有效 -- 验证商品ID格式是否正确 -- 查看详细错误日志 - -**问题2:商品详情获取失败** -- 检查API服务是否可用 -- 确认商品是否存在 -- 验证请求参数是否正确 -- 检查API配置 - -**问题3:数据库操作失败** -- 检查数据库文件权限 -- 确认磁盘空间是否充足 -- 验证数据格式是否正确 -- 查看数据库错误日志 - -### 性能优化建议 -1. **定期清理**:清理无效的商品信息 -2. **索引优化**:为常用查询字段建立索引 -3. **批量操作**:使用批量操作提高效率 -4. **缓存机制**:缓存常用的商品信息 - -## 📊 数据统计 - -### 商品统计信息 -- **总商品数量**:系统中所有商品的总数 -- **有效商品数**:包含完整信息的商品数量 -- **账号分布**:各账号的商品数量分布 -- **分类统计**:不同分类的商品数量 - -### 使用统计 -- **收集成功率**:商品信息收集的成功率 -- **API调用次数**:商品详情API的调用统计 -- **匹配成功率**:自动发货匹配的成功率 -- **处理速度**:商品信息处理的平均速度 - -## 🚀 未来规划 - -### 即将推出的功能 -1. **商品分析**:基于商品数据的深度分析 -2. **价格监控**:监控商品价格变化趋势 -3. **库存管理**:集成库存管理功能 -4. **销量统计**:统计商品销售数据 - -### 长期发展方向 -1. **智能推荐**:基于商品数据的智能推荐 -2. **自动定价**:根据市场数据自动调整价格 -3. **竞品分析**:分析同类商品的竞争情况 -4. **数据挖掘**:深度挖掘商品数据价值 - --- -🎉 **商品管理功能为您的闲鱼自动发货提供了强大的数据支持,让自动化运营更加智能和精准!通过持续优化和功能扩展,将为您带来更好的使用体验。** +🎉 **商品管理功能让您的闲鱼自动发货更加智能和准确!** diff --git a/回复优先级优化说明.md b/回复优先级优化说明.md deleted file mode 100644 index 1258b70..0000000 --- a/回复优先级优化说明.md +++ /dev/null @@ -1,147 +0,0 @@ -# 🔄 回复优先级优化说明 - -## 📋 优化概述 - -本次更新对自动回复系统的优先级逻辑进行了重要调整,确保关键词回复优先于AI回复,提高回复的准确性和用户体验。 - -## 🔧 优化内容 - -### 原有逻辑(v2.0.0之前) -``` -API回复 → AI回复 → 关键词回复 → 默认回复 -``` - -**问题**: -- AI回复可能覆盖重要的关键词回复 -- 精确的关键词匹配被AI的通用回复替代 -- 用户设置的关键词回复优先级过低 - -### 新的逻辑(v2.0.1) -``` -API回复 → 关键词回复 → AI回复 → 默认回复 -``` - -**优势**: -- ✅ 关键词回复优先级提升,确保精确匹配 -- ✅ AI回复作为智能补充,处理无关键词匹配的情况 -- ✅ 保持API回复的最高优先级 -- ✅ 默认回复作为最后的兜底方案 - -## 🎯 使用场景 - -### 场景1:价格咨询 -**用户消息**:`"请问这个商品的价格是多少?"` - -**处理流程**: -1. 检查API回复 → 无 -2. 检查关键词匹配 → 匹配"价格"关键词 ✅ -3. 返回:`"这个商品价格是100元"` - -**结果**:精确的价格信息,而不是AI的通用回复 - -### 场景2:通用咨询 -**用户消息**:`"这个东西怎么样?质量好吗?"` - -**处理流程**: -1. 检查API回复 → 无 -2. 检查关键词匹配 → 无匹配 -3. 使用AI回复 ✅ -4. 返回:`"AI智能回复:根据您的问题,我建议..."` - -**结果**:AI提供智能化的个性回复 - -### 场景3:兜底回复 -**用户消息**:`"随便说点什么"` - -**处理流程**: -1. 检查API回复 → 无 -2. 检查关键词匹配 → 无匹配 -3. 检查AI回复 → 失败或未启用 -4. 使用默认回复 ✅ -5. 返回:`"您好,感谢咨询!"` - -**结果**:确保总是有回复内容 - -## 📊 优化效果 - -### 回复准确性提升 -- **关键词匹配率**:100%(优先级最高) -- **重要信息覆盖**:避免AI回复覆盖重要关键词 -- **用户体验**:精确回复 + 智能补充 - -### 系统稳定性 -- **回复成功率**:保持100%(多层备选机制) -- **响应速度**:关键词匹配更快 -- **资源使用**:减少不必要的AI调用 - -## 🔧 技术实现 - -### 代码修改位置 -**文件**:`XianyuAutoAsync.py` -**行数**:1821-1835 - -### 修改前代码 -```python -# 如果API回复失败或未启用API,尝试使用AI回复 -if not reply: - reply = await self.get_ai_reply(send_user_name, send_user_id, send_message, item_id, chat_id) - if reply: - reply_source = 'AI' - else: - # 如果AI回复也失败,尝试关键词匹配 - reply = await self.get_keyword_reply(send_user_name, send_user_id, send_message) - if reply: - reply_source = '关键词' - else: - # 最后尝试使用默认回复 - reply = await self.get_default_reply(send_user_name, send_user_id, send_message) - reply_source = '默认' -``` - -### 修改后代码 -```python -# 如果API回复失败或未启用API,按优先级尝试其他回复方式 -if not reply: - # 优先尝试关键词匹配回复 - reply = await self.get_keyword_reply(send_user_name, send_user_id, send_message) - if reply: - reply_source = '关键词' - else: - # 如果关键词匹配失败,尝试AI回复 - reply = await self.get_ai_reply(send_user_name, send_user_id, send_message, item_id, chat_id) - if reply: - reply_source = 'AI' - else: - # 最后尝试使用默认回复 - reply = await self.get_default_reply(send_user_name, send_user_id, send_message) - reply_source = '默认' -``` - -## 📚 相关文档更新 - -### 更新的文档 -1. **AI_REPLY_GUIDE.md** - 更新优先级说明 -2. **使用说明.md** - 添加回复优先级说明 -3. **README.md** - 更新功能特性描述 -4. **CHANGELOG.md** - 记录版本更新 - -### 新增说明 -- 关键词回复优先于AI回复的原因 -- 各种回复方式的适用场景 -- 优化后的用户体验改进 - -## 🎉 总结 - -这次优化确保了: -- **精确性**:重要关键词得到精确回复 -- **智能性**:AI回复作为智能补充 -- **稳定性**:多层备选确保回复成功 -- **用户体验**:更准确、更贴心的自动回复 - -通过合理的优先级设计,系统既保持了智能化特性,又确保了关键信息的准确传达,为用户提供更好的自动回复体验。 - ---- - -**版本**:v2.0.1 -**更新时间**:2024-07-24 -**影响范围**:自动回复逻辑核心功能 diff --git a/日志管理功能说明.md b/日志管理功能说明.md index 185aba3..5ed5981 100644 --- a/日志管理功能说明.md +++ b/日志管理功能说明.md @@ -280,91 +280,17 @@ ## 🎯 使用建议 ### 适用场景 -- ✅ **开发调试**:实时查看程序运行状态和调试信息 -- ✅ **问题排查**:快速定位错误和异常,分析问题原因 -- ✅ **性能监控**:监控系统运行情况和性能指标 -- ✅ **用户支持**:协助用户解决问题,提供技术支持 -- ✅ **运维监控**:生产环境的实时监控和告警 -- ✅ **安全审计**:监控系统安全事件和异常行为 +- ✅ **开发调试**:实时查看程序运行状态 +- ✅ **问题排查**:快速定位错误和异常 +- ✅ **性能监控**:监控系统运行情况 +- ✅ **用户支持**:协助用户解决问题 ### 最佳实践 -1. **开启自动刷新**:实时监控系统状态,及时发现问题 -2. **合理使用过滤器**:根据需要过滤特定级别或来源的日志 -3. **定期查看统计信息**:了解系统整体运行状况和趋势 -4. **适时清空内存日志**:避免内存占用过多,保持系统性能 -5. **结合文件日志**:重要日志同时查看文件日志进行备份 -6. **设置告警规则**:对ERROR级别日志设置告警通知 - -### 日志级别使用指南 -- **DEBUG**:详细的调试信息,开发阶段使用 -- **INFO**:一般信息,记录程序正常运行状态 -- **WARNING**:警告信息,需要注意但不影响运行 -- **ERROR**:错误信息,需要立即处理的问题 -- **CRITICAL**:严重错误,可能导致程序崩溃 - -## 🔧 高级功能 - -### 日志导出 -1. **实时导出**:将当前显示的日志导出为文件 -2. **批量导出**:导出指定时间范围的日志 -3. **格式选择**:支持TXT、JSON、CSV等格式 -4. **自动压缩**:大文件自动压缩处理 - -### 日志分析 -1. **趋势分析**:分析日志数量和级别的时间趋势 -2. **异常检测**:自动检测异常日志模式 -3. **性能分析**:分析系统性能相关日志 -4. **报表生成**:生成日志分析报表 - -### 告警配置 -1. **级别告警**:ERROR级别日志自动告警 -2. **频率告警**:异常日志频率过高时告警 -3. **关键词告警**:包含特定关键词的日志告警 -4. **通知方式**:支持邮件、短信、webhook等通知 - -## 🚨 故障排除 - -### 常见问题 -**Q: 日志不更新?** -A: 检查以下项目: -- 自动刷新是否开启 -- 网络连接是否正常 -- 服务器是否正常运行 -- 浏览器是否支持WebSocket - -**Q: 日志显示不完整?** -A: 可能原因: -- 内存缓冲区已满,旧日志被清理 -- 过滤器设置过于严格 -- 日志级别设置不当 - -**Q: 性能影响?** -A: 优化建议: -- 适当调整刷新频率 -- 使用过滤器减少显示数量 -- 定期清空内存日志 -- 关闭不必要的DEBUG日志 - -### 性能优化 -1. **合理设置缓冲区大小**:根据系统内存调整 -2. **优化刷新频率**:平衡实时性和性能 -3. **使用过滤器**:减少不必要的日志传输 -4. **定期清理**:避免内存泄漏 - -## 📊 监控指标 - -### 系统指标 -- **日志生成速率**:每秒生成的日志数量 -- **内存使用量**:日志缓冲区内存占用 -- **处理延迟**:日志从生成到显示的延迟 -- **错误率**:ERROR级别日志的比例 - -### 业务指标 -- **消息处理量**:处理的消息数量统计 -- **API调用次数**:各API接口的调用统计 -- **用户活动**:用户操作和访问统计 -- **系统健康度**:基于日志的系统健康评分 +1. **开启自动刷新**:实时监控系统状态 +2. **使用过滤器**:快速找到关注的日志 +3. **查看统计信息**:了解系统整体状况 +4. **定期清空**:避免内存占用过多 --- -🎉 **实时日志管理功能提供了完整的日志查看、分析和监控能力,是系统运维和问题排查的重要工具!** +🎉 **实时日志管理功能已完成,提供了真正的实时日志查看、过滤和分析能力!** diff --git a/日志系统优化说明.md b/日志系统优化说明.md deleted file mode 100644 index 774b4da..0000000 --- a/日志系统优化说明.md +++ /dev/null @@ -1,221 +0,0 @@ -# 📋 日志系统优化说明 - -## 🎯 优化目标 - -本次优化的主要目标是: -1. **统一日志记录**:所有日志都记录到文件中 -2. **界面读取文件**:Web界面从日志文件读取并显示 -3. **智能过滤**:过滤掉不必要的API请求日志 -4. **提高性能**:减少日志噪音,提高系统性能 - -## 🔧 优化内容 - -### 1. 统一日志配置 - -#### 修改前的问题 -- 不同模块的日志配置不一致 -- 部分日志只输出到控制台,不记录到文件 -- 日志格式不统一,难以解析 - -#### 修改后的改进 -- **统一日志文件**:所有模块都使用相同的日志文件 -- **统一格式**:使用标准格式便于解析 -- **文件优先**:移除控制台输出,只记录到文件 - -```python -# 统一的日志配置格式 -format='{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {name}:{function}:{line} - {message}' -``` - -### 2. 智能日志过滤 - -#### 过滤的日志类型 -- **API请求日志**:`GET /logs`, `GET /health`, `GET /docs` 等 -- **静态资源请求**:`GET /static/`, `favicon.ico` 等 -- **心跳检查**:WebSocket心跳、健康检查等 -- **频繁状态检查**:连接状态检查等 - -#### 过滤器实现 -```python -# log_filter.py -class LogFilter: - def __init__(self): - self.excluded_patterns = [ - r'GET /logs', - r'GET /health', - r'.*favicon\.ico.*', - r'.*websocket.*ping.*' - ] - - def should_log(self, record): - # 智能判断是否应该记录日志 - return not self._matches_excluded_pattern(record['message']) -``` - -### 3. 文件监控优化 - -#### 监控改进 -- **实时监控**:从0.5秒优化到0.2秒检查频率 -- **错误处理**:增强文件读取的错误处理 -- **编码支持**:支持UTF-8编码,忽略编码错误 -- **文件重置检测**:检测日志文件被截断或重新创建 - -#### 解析优化 -- **多格式支持**:支持多种日志格式解析 -- **容错处理**:解析失败时的优雅降级 -- **性能优化**:预编译正则表达式提高解析速度 - -## 📊 优化效果 - -### 性能提升 -- **日志数量减少**:过滤掉约60%的无用日志 -- **文件大小减少**:日志文件大小减少约50% -- **界面响应更快**:减少不必要的日志传输 - -### 用户体验改善 -- **日志更清晰**:只显示有价值的日志信息 -- **加载更快**:减少日志数量,界面加载更快 -- **查找更容易**:减少噪音,更容易找到关键信息 - -### 系统稳定性 -- **内存使用优化**:减少内存中的日志缓存 -- **磁盘空间节省**:减少日志文件占用空间 -- **网络传输优化**:减少API传输的数据量 - -## 🔍 技术实现 - -### 1. 模块级配置 - -#### XianyuAutoAsync.py -```python -# 导入日志过滤器 -from log_filter import filter_log_record - -# 配置文件日志处理器 -logger.add( - log_path, - format='{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {name}:{function}:{line} - {message}', - filter=filter_log_record # 应用过滤器 -) -``` - -#### reply_server.py -```python -# 排除不需要记录的API路径 -EXCLUDED_LOG_PATHS = { - '/logs', '/logs/stats', '/health', '/docs' -} - -# 中间件级别的过滤 -@app.middleware("http") -async def log_requests(request, call_next): - should_log = request.url.path not in EXCLUDED_LOG_PATHS - if should_log: - logger.info(f"API请求: {request.method} {request.url.path}") -``` - -### 2. 文件监控系统 - -#### FileLogCollector优化 -```python -def monitor_file(self): - while True: - if os.path.exists(self.log_file): - file_size = os.path.getsize(self.log_file) - if file_size > self.last_position: - # 读取新增内容 - with open(self.log_file, 'r', encoding='utf-8', errors='ignore') as f: - f.seek(self.last_position) - new_lines = f.readlines() - self.last_position = f.tell() - - # 解析新增日志 - for line in new_lines: - if line.strip(): - self.parse_log_line(line.strip()) - - time.sleep(0.2) # 更频繁的检查 -``` - -### 3. 日志解析增强 - -#### 多格式支持 -```python -def parse_log_line(self, line): - # 主格式:统一格式 - pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) \| (\w+) \| ([^:]+):([^:]+):(\d+) - (.*)' - - # 备用格式:简单格式 - simple_pattern = r'\[([^\]]+)\] \[(\w+)\] (.*)' - - # 容错处理:解析失败时的处理 - if not match: - # 作为普通消息处理 - log_entry = { - "timestamp": datetime.now().isoformat(), - "level": "INFO", - "source": "system", - "message": line.strip() - } -``` - -## 📈 使用指南 - -### 1. 查看日志 -- **Web界面**:访问 http://localhost:8080,点击"日志管理" -- **实时更新**:日志会实时显示,无需手动刷新 -- **过滤功能**:可按级别、来源、关键词过滤 - -### 2. 日志文件位置 -``` -logs/ -└── xianyu_2024-07-24.log # 按日期命名的日志文件 -``` - -### 3. 自定义过滤规则 -```python -# 添加新的过滤规则 -from log_filter import add_excluded_pattern -add_excluded_pattern(r'自定义过滤模式') - -# 查看当前过滤规则 -from log_filter import get_excluded_patterns -patterns = get_excluded_patterns() -``` - -## 🚨 注意事项 - -### 1. 日志文件管理 -- **自动轮转**:日志文件按天轮转,自动压缩 -- **保留期限**:默认保留7天的日志文件 -- **磁盘空间**:注意监控磁盘空间使用情况 - -### 2. 性能考虑 -- **过滤器性能**:过滤器使用预编译正则表达式,性能较好 -- **文件监控**:监控频率为0.2秒,平衡实时性和性能 -- **内存使用**:日志缓存限制为2000条,避免内存溢出 - -### 3. 故障排除 -- **日志不显示**:检查日志文件是否存在和权限 -- **过滤过度**:检查过滤规则是否过于严格 -- **性能问题**:可以调整监控频率和缓存大小 - -## 🔮 未来规划 - -### 即将推出 -1. **日志分析**:基于日志的系统分析和报告 -2. **告警系统**:基于日志的智能告警 -3. **日志搜索**:全文搜索和高级查询 -4. **性能监控**:基于日志的性能指标 - -### 长期规划 -1. **分布式日志**:支持多实例的日志聚合 -2. **日志可视化**:图表和仪表板展示 -3. **机器学习**:基于日志的异常检测 -4. **API开放**:提供日志查询API - ---- - -**版本**:v2.0.2 -**更新时间**:2024-07-24 -**影响范围**:日志系统核心功能 diff --git a/自动发货功能说明.md b/自动发货功能说明.md index f48c3ad..059cdcb 100644 --- a/自动发货功能说明.md +++ b/自动发货功能说明.md @@ -254,92 +254,12 @@ python test-item-info-delivery.py ## 💡 最佳实践 -### 规则设计原则 -1. **关键字精确性**:关键字要具体明确,避免过于宽泛 -2. **优先级设置**:重要商品设置更长的关键字,提高匹配优先级 -3. **分类管理**:按商品类型分组管理发货规则 -4. **定期更新**:根据商品变化及时更新匹配规则 - -### 库存管理策略 -1. **实时监控**:定期检查批量数据库存状态 -2. **预警机制**:设置库存低于阈值时的告警 -3. **自动补充**:配置自动补充机制或定期手动补充 -4. **分批管理**:将卡券分批次管理,避免一次性消耗完 - -### 质量控制措施 -1. **测试验证**:新规则上线前在测试环境充分测试 -2. **灰度发布**:新规则先在部分商品上试运行 -3. **监控告警**:设置发货失败率告警,及时处理异常 -4. **人工审核**:重要商品可设置人工审核环节 - -### 数据分析优化 -1. **日志分析**:定期分析发货日志,识别问题模式 -2. **成功率统计**:监控各规则的匹配成功率 -3. **用户反馈**:收集买家反馈,优化发货内容 -4. **性能监控**:监控发货响应时间,优化处理流程 - -## 🔧 故障排除 - -### 常见问题及解决方案 - -**问题1:发货规则不匹配** -- 检查关键字是否正确 -- 确认商品信息是否完整 -- 验证匹配逻辑是否合理 -- 查看详细的匹配日志 - -**问题2:API接口调用失败** -- 检查API地址是否正确 -- 验证请求参数和格式 -- 确认网络连接状态 -- 查看API服务状态 - -**问题3:批量数据消耗过快** -- 检查匹配规则是否过于宽泛 -- 确认是否有重复发货 -- 调整匹配策略 -- 增加库存补充频率 - -**问题4:发货消息发送失败** -- 检查账号连接状态 -- 验证消息格式是否正确 -- 确认网络连接稳定 -- 查看WebSocket连接日志 - -### 调试技巧 -1. **开启详细日志**:在配置中开启DEBUG级别日志 -2. **单步测试**:使用测试功能验证单个规则 -3. **模拟环境**:在测试环境模拟真实场景 -4. **监控面板**:使用系统监控面板查看实时状态 - -## 📈 性能优化 - -### 系统性能优化 -1. **缓存机制**:缓存商品信息,减少API调用 -2. **异步处理**:使用异步处理提高并发能力 -3. **连接池**:优化数据库连接池配置 -4. **资源限制**:合理设置系统资源限制 - -### 业务流程优化 -1. **规则优化**:优化匹配算法,提高匹配效率 -2. **批量处理**:支持批量发货操作 -3. **智能调度**:根据系统负载智能调度任务 -4. **预处理**:预处理商品信息,提高匹配速度 - -## 🔐 安全考虑 - -### 数据安全 -1. **敏感信息加密**:卡券内容加密存储 -2. **访问控制**:严格的权限控制机制 -3. **审计日志**:完整的操作审计日志 -4. **备份恢复**:定期备份重要数据 - -### 业务安全 -1. **防重复发货**:严格的重复发货检测 -2. **异常监控**:实时监控异常发货行为 -3. **人工干预**:支持紧急情况下的人工干预 -4. **风险控制**:设置发货频率和数量限制 +1. **规则设计**:关键字要具体明确,避免过于宽泛 +2. **库存管理**:定期检查批量数据库存,及时补充 +3. **监控告警**:设置发货失败告警,及时处理异常 +4. **测试验证**:新规则上线前充分测试 +5. **日志分析**:定期分析发货日志,优化匹配规则 --- -🎉 **自动发货功能让您的闲鱼店铺实现真正的自动化运营!通过合理配置和优化,可以大大提高运营效率和用户体验。** +🎉 **自动发货功能让您的闲鱼店铺实现真正的自动化运营!** diff --git a/获取所有商品功能说明.md b/获取所有商品功能说明.md index ecf4dce..ca70f87 100644 --- a/获取所有商品功能说明.md +++ b/获取所有商品功能说明.md @@ -181,120 +181,22 @@ async def get_item_list_info(self, retry_count=0): - 错误信息记录 - 便于问题排查 -## 🚀 高级功能 +## 🚀 扩展可能 ### 1. 批量操作 -- **多账号批量获取**:一次性获取所有账号的商品信息 -- **定时自动获取**:设置定时任务自动更新商品信息 -- **增量更新**:只获取新增或变更的商品信息 -- **并发处理**:支持多账号并发获取,提高效率 +- 支持多个账号批量获取 +- 导出商品信息到文件 +- 商品信息对比分析 -### 2. 数据处理与分析 -- **商品信息入库**:自动将获取的商品信息存储到数据库 -- **商品状态监控**:监控商品上下架状态变化 -- **价格变化追踪**:跟踪商品价格变化趋势 -- **销量统计**:统计商品浏览量和销售数据 -- **数据导出**:支持导出为Excel、CSV等格式 +### 2. 数据处理 +- 商品信息入库存储 +- 商品状态监控 +- 价格变化追踪 ### 3. 界面优化 -- **商品信息表格**:以表格形式展示商品详细信息 -- **商品图片预览**:显示商品主图和详情图 -- **高级筛选**:按价格、分类、状态等条件筛选 -- **搜索功能**:支持商品标题、描述的全文搜索 -- **排序功能**:按时间、价格、浏览量等排序 - -### 4. 智能分析 -- **商品分类统计**:自动分析商品分类分布 -- **价格区间分析**:分析不同价格区间的商品数量 -- **热门商品识别**:基于浏览量识别热门商品 -- **库存预警**:监控商品库存状态,及时预警 - -## 📊 数据统计 - -### 获取统计信息 -- **总商品数量**:账号下所有商品的总数 -- **在售商品数**:当前在售状态的商品数量 -- **已售出商品数**:已售出的商品数量 -- **平均价格**:所有商品的平均售价 -- **价格分布**:不同价格区间的商品分布 - -### 性能指标 -- **获取速度**:每秒获取的商品数量 -- **成功率**:获取成功的商品比例 -- **错误率**:获取失败的商品比例 -- **响应时间**:API响应时间统计 - -## 🔧 故障排除 - -### 常见问题及解决方案 - -**问题1:获取失败** -- 检查账号Cookie是否有效 -- 确认网络连接是否正常 -- 验证账号是否被限制 -- 查看详细错误日志 - -**问题2:获取速度慢** -- 检查网络连接质量 -- 确认服务器负载情况 -- 优化获取策略 -- 考虑分批次获取 - -**问题3:数据不完整** -- 检查API返回数据格式 -- 确认商品状态是否正常 -- 验证解析逻辑是否正确 -- 查看控制台错误信息 - -**问题4:Token频繁失效** -- 检查Cookie有效期 -- 确认账号登录状态 -- 优化Token刷新策略 -- 考虑降低获取频率 - -### 调试技巧 -1. **开启详细日志**:查看完整的获取过程 -2. **单步测试**:先测试单个商品获取 -3. **网络监控**:监控网络请求和响应 -4. **数据验证**:验证获取数据的完整性 - -## 💡 使用建议 - -### 最佳实践 -1. **合理频率**:避免过于频繁的获取操作 -2. **错峰使用**:在网络较好的时段进行获取 -3. **数据备份**:定期备份重要的商品数据 -4. **监控告警**:设置获取失败的告警机制 - -### 性能优化 -1. **缓存机制**:缓存已获取的商品信息 -2. **增量更新**:只获取变更的商品信息 -3. **并发控制**:合理控制并发获取数量 -4. **资源管理**:及时释放不需要的资源 - -### 安全考虑 -1. **权限控制**:限制获取功能的使用权限 -2. **频率限制**:设置合理的获取频率限制 -3. **数据保护**:保护获取的商品数据安全 -4. **审计日志**:记录所有获取操作的审计日志 - -## 🔮 未来规划 - -### 即将推出的功能 -1. **商品同步**:支持与其他平台的商品信息同步 -2. **智能推荐**:基于商品数据的智能推荐算法 -3. **自动定价**:根据市场数据自动调整商品价格 -4. **竞品分析**:分析同类商品的价格和销量 - -### 长期发展方向 -1. **大数据分析**:基于海量商品数据的深度分析 -2. **机器学习**:使用AI技术优化商品运营策略 -3. **API开放**:提供开放API供第三方系统集成 -4. **移动端支持**:开发移动端应用,随时随地管理商品 - ---- - -🎉 **获取所有商品功能为商品管理提供了强大的数据获取能力,是商品分析和运营的重要工具!通过持续优化和功能扩展,将为用户提供更加完善的商品管理解决方案。** +- 商品信息表格显示 +- 商品图片预览 +- 筛选和搜索功能 ---