diff --git a/.gitignore b/.gitignore index 3986ea5..afae4e4 100644 --- a/.gitignore +++ b/.gitignore @@ -104,4 +104,204 @@ keywords_sample.xlsx *.zip *.tar.gz *.rar -*.7z \ No newline at end of file +*.7z + +# ==================== 新增忽略项 ==================== +# Python 字节码和缓存 +*.pyc +*.pyo +*.pyd +__pycache__/ +*.py[cod] +*$py.class + +# 分发/打包 +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +*.manifest +*.spec + +# 单元测试/覆盖率报告 +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +Pipfile.lock + +# PEP 582 +__pypackages__/ + +# Celery +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# ==================== 项目特定新增 ==================== +# 环境变量文件 +.env.example +.env.*.example + +# 数据库文件 +*.db-journal +*.db-wal +*.db-shm + +# 临时文件和缓存 +*.cache +.cache/ +cache/ + +# 编辑器临时文件 +*.swp +*.swo +*.tmp +*~ +.#* + +# 系统文件 +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +desktop.ini + +# 文档生成 +docs/_build/ +docs/build/ + +# 密钥和证书 +*.key +*.pem +*.crt +*.cert +*.p12 +*.pfx + +# 配置文件备份 +*.conf.bak +*.config.bak + +# 运行时文件 +*.pid +*.sock + +# 调试文件 +debug.log +*.debug + +# 性能分析文件 +*.prof + +# 本地开发文件 +local/ +.local/ + +# Docker相关 +.dockerignore.bak +docker-compose.override.yml + +# 版本控制 +.svn/ +.hg/ +.bzr/ + +# 包管理器 +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json +yarn.lock + +# 前端构建 +dist/ +build/ +.next/ +.nuxt/ +.vuepress/dist + +# 移动端 +*.apk +*.ipa +*.app + +# 数据文件 +*.csv.bak +*.json.bak +*.xml.bak + +# 媒体文件缓存 +*.mp4.cache +*.mp3.cache +*.wav.cache +*.avi.cache + +# AI模型文件 +*.model +*.weights +*.h5 +*.pb + +# 大文件 +*.iso +*.dmg +*.img \ No newline at end of file diff --git a/README.md b/README.md index 8598593..3b2371e 100644 --- a/README.md +++ b/README.md @@ -25,12 +25,13 @@ ### 🤖 智能回复系统 - **关键词匹配** - 支持精确关键词匹配回复 -- **商品专用回复** - 支持为特定商品设置专用关键词回复 +- **指定商品回复** - 支持为特定商品设置专门的回复内容,优先级最高 +- **商品专用关键词** - 支持为特定商品设置专用关键词回复 - **通用关键词** - 支持全局通用关键词,适用于所有商品 - **批量导入导出** - 支持Excel格式的关键词批量导入导出 - **AI智能回复** - 集成OpenAI API,支持上下文理解 -- **变量替换** - 回复内容支持动态变量(用户名、商品信息等) -- **优先级策略** - 商品专用关键词 > 通用关键词 > AI回复 +- **变量替换** - 回复内容支持动态变量(用户名、商品信息、商品ID等) +- **优先级策略** - 指定商品回复 > 商品专用关键词 > 通用关键词 > 默认回复 > AI回复 ### 🚚 自动发货功能 - **智能匹配** - 基于商品信息自动匹配发货规则 @@ -41,8 +42,9 @@ - **防重复发货** - 智能防重复机制,避免重复发货 - **多种发货方式** - 支持固定文字、批量数据、API调用、图片发货等方式 - **图片发货** - 支持上传图片并自动发送给买家,图片自动上传到CDN -- **自动确认发货** - 检测到付款后自动调用闲鱼API确认发货 +- **自动确认发货** - 检测到付款后自动调用闲鱼API确认发货,支持锁机制防并发 - **防重复确认** - 智能防重复确认机制,避免重复API调用 +- **订单详情缓存** - 订单详情获取支持数据库缓存,大幅提升性能 - **发货统计** - 完整的发货记录和统计功能 ### 🛍️ 商品管理 @@ -359,31 +361,31 @@ python Start.py ## 📁 核心文件功能说明 ### 🚀 核心启动模块 -- **`Start.py`** - 项目启动入口,初始化CookieManager和FastAPI服务,从数据库加载账号任务并启动后台API服务 -- **`XianyuAutoAsync.py`** - 闲鱼WebSocket连接核心,处理消息收发、自动回复、自动发货、商品信息收集 -- **`reply_server.py`** - FastAPI Web服务器,提供完整的管理界面和RESTful API接口,支持多用户系统 -- **`cookie_manager.py`** - 多账号Cookie管理器,负责账号任务的启动、停止、状态管理和线程安全操作 +- **`Start.py`** - 项目启动入口,初始化CookieManager和FastAPI服务,从数据库加载账号任务并启动后台API服务,支持环境变量配置 +- **`XianyuAutoAsync.py`** - 闲鱼WebSocket连接核心,处理消息收发、自动回复、指定商品回复、自动发货、商品信息收集、AI回复 +- **`reply_server.py`** - FastAPI Web服务器,提供完整的管理界面和RESTful API接口,支持多用户系统、JWT认证、权限管理 +- **`cookie_manager.py`** - 多账号Cookie管理器,负责账号任务的启动、停止、状态管理和线程安全操作,支持数据库持久化 ### 🗄️ 数据和配置管理 -- **`db_manager.py`** - SQLite数据库管理器,支持多用户数据隔离、自动迁移、版本管理、完整的CRUD操作 -- **`config.py`** - 全局配置文件管理器,加载YAML配置和环境变量,提供配置项访问接口 -- **`global_config.yml`** - 全局配置文件,包含WebSocket、API、自动回复、AI等所有系统配置项 +- **`db_manager.py`** - SQLite数据库管理器,支持多用户数据隔离、自动迁移、版本管理、完整的CRUD操作、邮箱验证、系统设置 +- **`config.py`** - 全局配置文件管理器,加载YAML配置和环境变量,提供配置项访问接口,支持动态配置更新 +- **`global_config.yml`** - 全局配置文件,包含WebSocket、API、自动回复、AI、通知等所有系统配置项 ### 🤖 智能功能模块 -- **`ai_reply_engine.py`** - AI智能回复引擎,支持OpenAI、通义千问等多种AI模型,意图识别和上下文管理 -- **`secure_confirm_ultra.py`** - 自动确认发货模块,采用多层加密保护,调用闲鱼API确认发货状态 -- **`secure_freeshipping_ultra.py`** - 自动免拼发货模块,支持批量处理、异常恢复和智能匹配 -- **`file_log_collector.py`** - 实时日志收集器,提供Web界面日志查看、搜索和管理功能 +- **`ai_reply_engine.py`** - AI智能回复引擎,支持OpenAI、通义千问等多种AI模型,意图识别、上下文管理、个性化回复 +- **`secure_confirm_ultra.py`** - 自动确认发货模块,采用多层加密保护,调用闲鱼API确认发货状态,支持锁机制防并发 +- **`secure_freeshipping_ultra.py`** - 自动免拼发货模块,支持批量处理、异常恢复、智能匹配、规格识别 +- **`file_log_collector.py`** - 实时日志收集器,提供Web界面日志查看、搜索、过滤、下载和管理功能 ### 🛠️ 工具模块 (`utils/`) -- **`xianyu_utils.py`** - 闲鱼API核心工具,包含加密算法、签名生成、数据解析、Cookie处理 -- **`message_utils.py`** - 消息处理工具,格式化消息内容、变量替换、内容过滤和模板渲染 -- **`ws_utils.py`** - WebSocket客户端封装,处理连接管理、心跳检测、重连机制和消息队列 -- **`qr_login.py`** - 二维码登录功能,生成登录二维码、状态检测、Cookie获取和验证 -- **`item_search.py`** - 商品搜索功能,基于Playwright获取真实闲鱼商品数据,支持分页和过滤 -- **`order_detail_fetcher.py`** - 订单详情获取工具,解析订单信息、买家信息、SKU详情,支持缓存优化 -- **`image_utils.py`** - 图片处理工具,支持压缩、格式转换、尺寸调整、水印添加 -- **`image_uploader.py`** - 图片上传工具,支持多种CDN服务商,自动压缩和格式优化 +- **`xianyu_utils.py`** - 闲鱼API核心工具,包含加密算法、签名生成、数据解析、Cookie处理、请求封装 +- **`message_utils.py`** - 消息处理工具,格式化消息内容、变量替换、内容过滤、模板渲染、表情处理 +- **`ws_utils.py`** - WebSocket客户端封装,处理连接管理、心跳检测、重连机制、消息队列、异常恢复 +- **`qr_login.py`** - 二维码登录功能,生成登录二维码、状态检测、Cookie获取、验证、自动刷新 +- **`item_search.py`** - 商品搜索功能,基于Playwright获取真实闲鱼商品数据,支持分页、过滤、排序 +- **`order_detail_fetcher.py`** - 订单详情获取工具,解析订单信息、买家信息、SKU详情,支持缓存优化、锁机制 +- **`image_utils.py`** - 图片处理工具,支持压缩、格式转换、尺寸调整、水印添加、质量优化 +- **`image_uploader.py`** - 图片上传工具,支持多种CDN服务商、自动压缩、格式优化、批量上传 ### 🌐 前端界面 (`static/`) - **`index.html`** - 主管理界面,包含账号管理、关键词管理、系统监控、实时状态显示 diff --git a/check_user_credentials.py b/check_user_credentials.py deleted file mode 100644 index 56af85c..0000000 --- a/check_user_credentials.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -检查用户凭据 -""" - -import sys -import os -import hashlib - -# 添加项目根目录到路径 -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -from db_manager import db_manager - - -def check_users(): - """检查用户表中的用户信息""" - print("🔍 检查用户表中的用户信息") - print("=" * 50) - - try: - cursor = db_manager.conn.cursor() - cursor.execute("SELECT id, username, password_hash, is_admin FROM users") - users = cursor.fetchall() - - print(f"用户表中共有 {len(users)} 个用户:") - for user in users: - print(f" - 用户ID: {user[0]}") - print(f" 用户名: {user[1]}") - print(f" 密码哈希: {user[2][:20]}..." if user[2] else " 密码哈希: None") - print(f" 是否管理员: {user[3]}") - print() - - # 测试密码验证 - if users: - test_user = users[0] - username = test_user[1] - stored_hash = test_user[2] - - print(f"🔐 测试用户 '{username}' 的密码验证:") - - # 测试常见密码 - test_passwords = ["admin123", "admin", "123456", "password"] - - for password in test_passwords: - # 计算密码哈希 - password_hash = hashlib.sha256(password.encode()).hexdigest() - - if password_hash == stored_hash: - print(f"✅ 密码 '{password}' 匹配!") - return username, password - else: - print(f"❌ 密码 '{password}' 不匹配") - print(f" 计算哈希: {password_hash[:20]}...") - print(f" 存储哈希: {stored_hash[:20]}...") - - print("⚠️ 没有找到匹配的密码") - - except Exception as e: - print(f"❌ 检查用户失败: {e}") - - return None, None - - -def test_login_with_correct_credentials(): - """使用正确的凭据测试登录""" - username, password = check_users() - - if username and password: - print(f"\n🌐 使用正确凭据测试登录") - print("=" * 50) - - import requests - - try: - login_data = { - "username": username, - "password": password - } - response = requests.post("http://localhost:8080/login", json=login_data, timeout=10) - print(f"登录状态码: {response.status_code}") - print(f"登录响应: {response.text}") - - if response.status_code == 200: - data = response.json() - if data.get('success'): - token = data.get('token') or data.get('access_token') - print(f"✅ 登录成功!Token: {token[:20]}..." if token else "✅ 登录成功但没有token") - - if token: - # 测试cookies/details接口 - headers = {"Authorization": f"Bearer {token}"} - response = requests.get("http://localhost:8080/cookies/details", headers=headers, timeout=10) - print(f"cookies/details状态码: {response.status_code}") - - if response.status_code == 200: - details = response.json() - print(f"✅ 获取到 {len(details)} 个账号详情") - for detail in details: - print(f" - {detail['id']}: {'启用' if detail['enabled'] else '禁用'}") - else: - print(f"❌ 获取账号详情失败: {response.text}") - else: - print(f"❌ 登录失败: {data.get('message', '未知错误')}") - else: - print(f"❌ 登录请求失败: {response.status_code}") - - except Exception as e: - print(f"❌ 登录测试失败: {e}") - - -def create_test_user(): - """创建测试用户""" - print(f"\n🔧 创建测试用户") - print("=" * 50) - - try: - # 创建一个新的测试用户 - test_username = "testuser" - test_password = "test123" - password_hash = hashlib.sha256(test_password.encode()).hexdigest() - - cursor = db_manager.conn.cursor() - cursor.execute(""" - INSERT OR REPLACE INTO users (username, password_hash, is_admin) - VALUES (?, ?, ?) - """, (test_username, password_hash, 1)) - db_manager.conn.commit() - - print(f"✅ 创建测试用户成功:") - print(f" 用户名: {test_username}") - print(f" 密码: {test_password}") - print(f" 密码哈希: {password_hash[:20]}...") - - return test_username, test_password - - except Exception as e: - print(f"❌ 创建测试用户失败: {e}") - return None, None - - -if __name__ == "__main__": - print("🚀 检查用户凭据和登录问题") - print("=" * 60) - - # 检查现有用户 - username, password = check_users() - - if not username: - # 如果没有找到有效用户,创建一个测试用户 - print("\n没有找到有效的用户凭据,创建测试用户...") - username, password = create_test_user() - - if username and password: - # 使用正确凭据测试登录 - test_login_with_correct_credentials() - - print("\n" + "=" * 60) - print("🎯 检查完成!") - print("\n📋 总结:") - print("1. 检查了用户表中的用户信息") - print("2. 验证了密码哈希") - print("3. 测试了登录功能") - print("4. 测试了cookies/details接口") - - if username and password: - print(f"\n✅ 可用的登录凭据:") - print(f" 用户名: {username}") - print(f" 密码: {password}") - print(f"\n请使用这些凭据登录管理后台测试账号下拉框功能") diff --git a/check_user_table.py b/check_user_table.py deleted file mode 100644 index 3d38f4a..0000000 --- a/check_user_table.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -检查用户表结构 -""" - -import sys -import os -import hashlib - -# 添加项目根目录到路径 -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -from db_manager import db_manager - - -def check_user_table_structure(): - """检查用户表结构""" - print("🔍 检查用户表结构") - print("=" * 50) - - try: - cursor = db_manager.conn.cursor() - - # 检查用户表是否存在 - cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users'") - table_exists = cursor.fetchone() - - if table_exists: - print("✅ users表存在") - - # 检查表结构 - cursor.execute("PRAGMA table_info(users)") - columns = cursor.fetchall() - print("users表结构:") - for col in columns: - print(f" - {col[1]} ({col[2]}) - {'NOT NULL' if col[3] else 'NULL'} - {'PRIMARY KEY' if col[5] else ''}") - - # 查看表中的数据 - cursor.execute("SELECT * FROM users") - users = cursor.fetchall() - print(f"\nusers表中共有 {len(users)} 条记录:") - for i, user in enumerate(users): - print(f" 记录{i+1}: {user}") - - else: - print("❌ users表不存在") - - except Exception as e: - print(f"❌ 检查用户表失败: {e}") - - -def fix_user_table(): - """修复用户表""" - print("\n🔧 修复用户表") - print("=" * 50) - - try: - cursor = db_manager.conn.cursor() - - # 检查是否有is_admin列 - cursor.execute("PRAGMA table_info(users)") - columns = cursor.fetchall() - column_names = [col[1] for col in columns] - - if 'is_admin' not in column_names: - print("添加is_admin列...") - cursor.execute("ALTER TABLE users ADD COLUMN is_admin INTEGER DEFAULT 1") - db_manager.conn.commit() - print("✅ 添加is_admin列成功") - - # 检查是否有用户数据 - cursor.execute("SELECT COUNT(*) FROM users") - user_count = cursor.fetchone()[0] - - if user_count == 0: - print("创建默认管理员用户...") - username = "admin" - password = "admin123" - password_hash = hashlib.sha256(password.encode()).hexdigest() - - cursor.execute(""" - INSERT INTO users (username, password_hash, is_admin) - VALUES (?, ?, ?) - """, (username, password_hash, 1)) - db_manager.conn.commit() - - print(f"✅ 创建默认用户成功:") - print(f" 用户名: {username}") - print(f" 密码: {password}") - - return username, password - else: - # 获取第一个用户并重置密码 - cursor.execute("SELECT username FROM users LIMIT 1") - username = cursor.fetchone()[0] - password = "admin123" - password_hash = hashlib.sha256(password.encode()).hexdigest() - - cursor.execute(""" - UPDATE users SET password_hash = ?, is_admin = 1 - WHERE username = ? - """, (password_hash, username)) - db_manager.conn.commit() - - print(f"✅ 重置用户密码成功:") - print(f" 用户名: {username}") - print(f" 密码: {password}") - - return username, password - - except Exception as e: - print(f"❌ 修复用户表失败: {e}") - return None, None - - -def test_login_after_fix(): - """修复后测试登录""" - username, password = fix_user_table() - - if username and password: - print(f"\n🌐 测试修复后的登录") - print("=" * 50) - - import requests - - try: - login_data = { - "username": username, - "password": password - } - response = requests.post("http://localhost:8080/login", json=login_data, timeout=10) - print(f"登录状态码: {response.status_code}") - - if response.status_code == 200: - data = response.json() - print(f"登录响应: {data}") - - if data.get('success'): - token = data.get('token') or data.get('access_token') - print(f"✅ 登录成功!") - - if token: - print(f"Token: {token[:20]}...") - - # 测试cookies/details接口 - headers = {"Authorization": f"Bearer {token}"} - response = requests.get("http://localhost:8080/cookies/details", headers=headers, timeout=10) - print(f"cookies/details状态码: {response.status_code}") - - if response.status_code == 200: - details = response.json() - print(f"✅ 获取到 {len(details)} 个账号详情") - - if len(details) > 0: - print("🎉 账号下拉框应该有数据了!") - print("账号列表:") - for detail in details: - status = "🟢" if detail['enabled'] else "🔴" - print(f" {status} {detail['id']}") - else: - print("⚠️ 账号列表为空,但API接口正常") - else: - print(f"❌ 获取账号详情失败: {response.text}") - else: - print("⚠️ 登录成功但没有获取到token") - else: - print(f"❌ 登录失败: {data.get('message', '未知错误')}") - else: - print(f"❌ 登录请求失败: {response.status_code} - {response.text}") - - except Exception as e: - print(f"❌ 登录测试失败: {e}") - - -if __name__ == "__main__": - print("🚀 检查和修复用户表") - print("=" * 60) - - # 检查用户表结构 - check_user_table_structure() - - # 修复用户表并测试登录 - test_login_after_fix() - - print("\n" + "=" * 60) - print("🎯 修复完成!") - print("\n📋 现在可以:") - print("1. 使用 admin/admin123 登录管理后台") - print("2. 进入指定商品回复界面") - print("3. 检查账号下拉框是否有数据") - print("4. 如果仍然没有数据,请检查浏览器开发者工具") diff --git a/requirements.txt b/requirements.txt index eae45da..0317c68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -57,10 +57,14 @@ openpyxl>=3.1.0 # ==================== 邮件发送 ==================== email-validator>=2.0.0 +# ==================== 数据处理和验证 ==================== +xlsxwriter>=3.1.0 + # ==================== 说明 ==================== # 以下模块是Python内置模块,无需安装: # sqlite3, json, base64, hashlib, hmac, time, datetime, os, sys, re, urllib # asyncio, threading, pathlib, uuid, random, secrets, traceback, logging # collections, itertools, functools, copy, pickle, gzip, zipfile, shutil # tempfile, io, csv, xml, html, http, socket, ssl, subprocess, signal -# inspect, ast, enum, math, decimal, array, queue, contextlib, warnings \ No newline at end of file +# inspect, ast, enum, math, decimal, array, queue, contextlib, warnings +# typing, dataclasses, weakref, gc, platform, stat, glob, fnmatch \ No newline at end of file