新增多种通知渠道,支持ai模型自定义

This commit is contained in:
zhinianboke 2025-08-02 20:23:33 +08:00
parent 49693760b8
commit 789870b334
6 changed files with 1383 additions and 232 deletions

View File

@ -2,10 +2,12 @@
FROM python:3.11-slim FROM python:3.11-slim
# 设置标签信息 # 设置标签信息
LABEL maintainer="Xianyu Auto Reply System" LABEL maintainer="zhinianboke"
LABEL version="2.0.0" LABEL version="2.0.0"
LABEL description="闲鱼自动回复系统 - 企业级多用户版本" LABEL description="闲鱼自动回复系统 - 企业级多用户版本"
LABEL repository="https://github.com/zhinianboke/xianyu-auto-reply" LABEL repository="https://github.com/zhinianboke/xianyu-auto-reply"
LABEL license="仅供学习使用,禁止商业用途"
LABEL author="zhinianboke"
# 设置工作目录 # 设置工作目录
WORKDIR /app WORKDIR /app
@ -20,14 +22,18 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
# 安装系统依赖包括Playwright浏览器依赖 # 安装系统依赖包括Playwright浏览器依赖
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
# 基础工具
nodejs \ nodejs \
npm \ npm \
tzdata \ tzdata \
curl \ curl \
ca-certificates \
# 图像处理依赖
libjpeg-dev \ libjpeg-dev \
libpng-dev \ libpng-dev \
libfreetype6-dev \ libfreetype6-dev \
fonts-dejavu-core \ fonts-dejavu-core \
fonts-liberation \
# Playwright浏览器依赖 # Playwright浏览器依赖
libnss3 \ libnss3 \
libnspr4 \ libnspr4 \
@ -50,31 +56,15 @@ RUN apt-get update && \
libx11-6 \ libx11-6 \
libxft2 \ libxft2 \
libxinerama1 \ libxinerama1 \
libxrandr2 \
libxss1 \
libxtst6 \ libxtst6 \
ca-certificates \
fonts-liberation \
libappindicator3-1 \ libappindicator3-1 \
libasound2 \
libatk-bridge2.0-0 \
libdrm2 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libx11-xcb1 \ libx11-xcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxfixes3 \ libxfixes3 \
libxi6 \
libxrandr2 \
libxrender1 \
libxss1 \
libxtst6 \
xdg-utils \ xdg-utils \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/* \
&& rm -rf /var/tmp/*
# 设置时区 # 设置时区
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
@ -110,18 +100,22 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1 CMD curl -f http://localhost:8080/health || exit 1
# 创建启动脚本 # 创建启动脚本
RUN echo '#!/bin/bash' > /app/entrypoint.sh && \ COPY <<EOF /app/entrypoint.sh
echo 'set -e' >> /app/entrypoint.sh && \ #!/bin/bash
echo '' >> /app/entrypoint.sh && \ set -e
echo 'echo "🚀 启动闲鱼自动回复系统..."' >> /app/entrypoint.sh && \
echo '' >> /app/entrypoint.sh && \ echo "🚀 启动闲鱼自动回复系统..."
echo '# 数据库将在应用启动时自动初始化' >> /app/entrypoint.sh && \ echo "📊 数据库将在应用启动时自动初始化..."
echo 'echo "📊 数据库将在应用启动时自动初始化..."' >> /app/entrypoint.sh && \ echo "🎯 启动主应用..."
echo '' >> /app/entrypoint.sh && \
echo '# 启动主应用' >> /app/entrypoint.sh && \ # 确保数据目录存在
echo 'echo "🎯 启动主应用..."' >> /app/entrypoint.sh && \ mkdir -p /app/data /app/logs /app/backups
echo 'exec python Start.py' >> /app/entrypoint.sh && \
chmod +x /app/entrypoint.sh # 启动主应用
exec python Start.py
EOF
RUN chmod +x /app/entrypoint.sh
# 启动命令 # 启动命令
CMD ["/app/entrypoint.sh"] CMD ["/app/entrypoint.sh"]

183
README.md
View File

@ -160,14 +160,132 @@ cd xianyu-auto-reply
# http://localhost:8080 # http://localhost:8080
``` ```
#### 🔧 Docker部署故障排除 ### 方式三:本地部署(开发环境)
如果遇到构建问题,请参考 [Docker修复指南](DOCKER_FIX.md) ```bash
# 1. 克隆项目
git clone https://github.com/zhinianboke/xianyu-auto-reply.git
cd xianyu-auto-reply
**常见问题** # 2. 创建虚拟环境(推荐)
- **sqlite3错误**已修复sqlite3是Python内置模块无需安装 python -m venv venv
- **Docker未运行**确保Docker Desktop正在运行 source venv/bin/activate # Linux/macOS
- **端口冲突**修改docker-compose.yml中的端口映射为其他端口 # 或 venv\Scripts\activate # Windows
# 3. 安装Python依赖
pip install --upgrade pip
pip install -r requirements.txt
# 4. 安装Playwright浏览器
playwright install chromium
playwright install-deps chromium # Linux需要
# 5. 启动系统
python Start.py
# 6. 访问系统
# http://localhost:8080
```
### 📋 环境要求
- **Python**: 3.11+
- **Node.js**: 16+ (用于JavaScript执行)
- **系统**: Windows/Linux/macOS
- **内存**: 建议2GB+
- **存储**: 建议10GB+
- **Docker**: 20.10+ (Docker部署)
- **Docker Compose**: 2.0+ (Docker部署)
### 🌐 访问系统
部署完成后,您可以通过以下方式访问系统:
- **Web管理界面**http://localhost:8080
- **默认管理员账号**
- 用户名:`admin`
- 密码:`admin123`
- **API文档**http://localhost:8080/docs
- **健康检查**http://localhost:8080/health
> ⚠️ **安全提示**:首次登录后请立即修改默认密码!
### 🔧 Docker部署管理
使用 `docker-deploy.sh` 脚本可以方便地管理Docker部署
```bash
# 查看所有可用命令
./docker-deploy.sh help
# 初始化配置
./docker-deploy.sh init
# 构建镜像
./docker-deploy.sh build
# 启动服务
./docker-deploy.sh start
# 启动包含Nginx的完整服务
./docker-deploy.sh start with-nginx
# 查看服务状态
./docker-deploy.sh status
# 查看实时日志
./docker-deploy.sh logs
# 备份数据
./docker-deploy.sh backup
# 更新部署
./docker-deploy.sh update
# 停止服务
./docker-deploy.sh stop
# 重启服务
./docker-deploy.sh restart
# 清理环境
./docker-deploy.sh cleanup
```
### 🛠️ 故障排除
**常见问题及解决方案**
1. **Docker未运行**
```bash
# 启动Docker Desktop或Docker服务
sudo systemctl start docker # Linux
```
2. **端口冲突**
```bash
# 修改.env文件中的WEB_PORT
WEB_PORT=8081
```
3. **权限问题**
```bash
# 确保数据目录有正确权限
sudo chown -R $USER:$USER ./data ./logs ./backups
```
4. **内存不足**
```bash
# 调整.env文件中的资源限制
MEMORY_LIMIT=1024
CPU_LIMIT=1.0
```
5. **Playwright浏览器安装失败**
```bash
# 手动安装浏览器
playwright install chromium --with-deps
```
- **权限问题**Linux系统下使用 `sudo ./docker-deploy.sh` - **权限问题**Linux系统下使用 `sudo ./docker-deploy.sh`
### 方式三:本地部署 ### 方式三:本地部署
@ -270,6 +388,59 @@ docker rm -f xianyu-auto-reply
└─────────────────────────────────────┘ └─────────────────────────────────────┘
``` ```
## ✨ 核心功能特性
### 🚀 自动回复系统
- **智能关键词匹配** - 支持精确匹配和模糊匹配,灵活配置回复规则
- **AI智能回复** - 集成多种AI模型通义千问、GPT等智能理解用户意图
- **多账号管理** - 支持同时管理多个闲鱼账号,独立配置和运行
- **实时消息处理** - WebSocket长连接毫秒级响应用户消息
- **自定义回复模板** - 支持占位符和动态内容,个性化回复体验
### 🛒 自动发货系统
- **智能订单识别** - 自动识别虚拟商品订单,精准匹配发货规则
- **多重安全验证** - 超级加密保护,防止误操作和数据泄露
- **批量处理能力** - 支持批量确认发货,提高处理效率
- **异常处理机制** - 完善的错误处理和重试机制,确保发货成功
- **多渠道通知** - 支持QQ、钉钉、邮件等多种发货通知方式
### 👥 多用户系统
- **用户注册登录** - 支持邮箱验证和图形验证码,安全可靠
- **权限管理** - 管理员和普通用户权限分离,精细化权限控制
- **数据隔离** - 每个用户的数据完全隔离,保护隐私安全
- **会话管理** - JWT Token认证支持自动续期和安全登出
### 📊 数据管理
- **商品信息管理** - 自动获取和同步商品信息,实时更新状态
- **订单数据统计** - 详细的订单数据分析和可视化图表
- **关键词管理** - 灵活的关键词配置,支持正则表达式
- **数据导入导出** - 支持Excel格式的批量数据操作
- **自动备份** - 定期自动备份重要数据,防止数据丢失
### 🔍 商品搜索
- **真实数据获取** - 基于Playwright技术获取真实闲鱼商品数据
- **多页搜索** - 支持分页搜索和批量获取,无限制数据采集
- **数据可视化** - 美观的商品展示界面,支持排序和筛选
- **搜索历史** - 保存搜索历史和结果,方便数据分析
### 📱 通知系统
- **多渠道支持** - QQ、钉钉、邮件、微信、Telegram等6种通知方式
- **智能配置** - 可视化配置界面,支持复杂参数和加密设置
- **实时推送** - 重要事件实时通知,及时了解系统状态
- **通知模板** - 自定义通知内容和格式,个性化消息推送
### 🔐 安全特性
- **Cookie安全管理** - 加密存储用户凭证,定期自动刷新
- **Token自动刷新** - 智能检测和刷新过期Token保持连接稳定
- **操作日志** - 详细记录所有操作日志,支持审计和追踪
- **异常监控** - 实时监控系统异常和错误,主动预警
### 🎨 用户界面
- **现代化设计** - 基于Bootstrap 5的响应式界面美观易用
- **多主题支持** - 支持明暗主题切换,个性化界面体验
- **移动端适配** - 完美适配手机和平板设备,随时随地管理
- **实时更新** - 界面数据实时更新,无需手动刷新
## 📁 核心文件功能说明 ## 📁 核心文件功能说明
### 🚀 启动和核心模块 ### 🚀 启动和核心模块

View File

@ -918,11 +918,22 @@ class XianyuLive:
channel_config = notification.get('channel_config') channel_config = notification.get('channel_config')
try: try:
# 解析配置数据
config_data = self._parse_notification_config(channel_config)
match channel_type: match channel_type:
case 'qq': case 'qq':
await self._send_qq_notification(channel_config, notification_msg) await self._send_qq_notification(config_data, notification_msg)
case 'ding_talk': case 'ding_talk' | 'dingtalk':
await self._send_ding_talk_notification(channel_config, notification_msg) await self._send_dingtalk_notification(config_data, notification_msg)
case 'email':
await self._send_email_notification(config_data, notification_msg)
case 'webhook':
await self._send_webhook_notification(config_data, notification_msg)
case 'wechat':
await self._send_wechat_notification(config_data, notification_msg)
case 'telegram':
await self._send_telegram_notification(config_data, notification_msg)
case _: case _:
logger.warning(f"不支持的通知渠道类型: {channel_type}") logger.warning(f"不支持的通知渠道类型: {channel_type}")
@ -932,13 +943,25 @@ class XianyuLive:
except Exception as e: except Exception as e:
logger.error(f"处理消息通知失败: {self._safe_str(e)}") logger.error(f"处理消息通知失败: {self._safe_str(e)}")
async def _send_qq_notification(self, config: str, message: str): def _parse_notification_config(self, config: str) -> dict:
"""解析通知配置数据"""
try:
import json
# 尝试解析JSON格式的配置
return json.loads(config)
except (json.JSONDecodeError, TypeError):
# 兼容旧格式(直接字符串)
return {"config": config}
async def _send_qq_notification(self, config_data: dict, message: str):
"""发送QQ通知""" """发送QQ通知"""
try: try:
import aiohttp import aiohttp
# 解析配置QQ号码 # 解析配置QQ号码
qq_number = config.strip() qq_number = config_data.get('qq_number') or config_data.get('config', '')
qq_number = qq_number.strip() if qq_number else ''
if not qq_number: if not qq_number:
logger.warning("QQ通知配置为空") logger.warning("QQ通知配置为空")
return return
@ -961,17 +984,35 @@ class XianyuLive:
except Exception as e: except Exception as e:
logger.error(f"发送QQ通知异常: {self._safe_str(e)}") logger.error(f"发送QQ通知异常: {self._safe_str(e)}")
async def _send_ding_talk_notification(self, config: str, message: str): async def _send_dingtalk_notification(self, config_data: dict, message: str):
"""发送钉钉通知""" """发送钉钉通知"""
try: try:
import aiohttp import aiohttp
import json import json
# 解析配置钉钉机器人Webhook URL import hmac
webhook_url = config.strip() import hashlib
import base64
import time
# 解析配置
webhook_url = config_data.get('webhook_url') or config_data.get('config', '')
secret = config_data.get('secret', '')
webhook_url = webhook_url.strip() if webhook_url else ''
if not webhook_url: if not webhook_url:
logger.warning("钉钉通知配置为空") logger.warning("钉钉通知配置为空")
return return
# 如果有加签密钥,生成签名
if secret:
timestamp = str(round(time.time() * 1000))
secret_enc = secret.encode('utf-8')
string_to_sign = f'{timestamp}\n{secret}'
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = base64.b64encode(hmac_code).decode('utf-8')
webhook_url += f'&timestamp={timestamp}&sign={sign}'
data = { data = {
"msgtype": "markdown", "msgtype": "markdown",
"markdown": { "markdown": {
@ -983,13 +1024,165 @@ class XianyuLive:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.post(webhook_url, json=data, timeout=10) as response: async with session.post(webhook_url, json=data, timeout=10) as response:
if response.status == 200: if response.status == 200:
logger.info(f"钉钉通知发送成功: {webhook_url}") logger.info(f"钉钉通知发送成功")
else: else:
logger.warning(f"钉钉通知发送失败: {response.status}") logger.warning(f"钉钉通知发送失败: {response.status}")
except Exception as e: except Exception as e:
logger.error(f"发送钉钉通知异常: {self._safe_str(e)}") logger.error(f"发送钉钉通知异常: {self._safe_str(e)}")
async def _send_email_notification(self, config_data: dict, message: str):
"""发送邮件通知"""
try:
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# 解析配置
smtp_server = config_data.get('smtp_server', '')
smtp_port = int(config_data.get('smtp_port', 587))
email_user = config_data.get('email_user', '')
email_password = config_data.get('email_password', '')
recipient_email = config_data.get('recipient_email', '')
if not all([smtp_server, email_user, email_password, recipient_email]):
logger.warning("邮件通知配置不完整")
return
# 创建邮件
msg = MIMEMultipart()
msg['From'] = email_user
msg['To'] = recipient_email
msg['Subject'] = "闲鱼自动回复通知"
# 添加邮件正文
msg.attach(MIMEText(message, 'plain', 'utf-8'))
# 发送邮件
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
server.login(email_user, email_password)
server.send_message(msg)
server.quit()
logger.info(f"邮件通知发送成功: {recipient_email}")
except Exception as e:
logger.error(f"发送邮件通知异常: {self._safe_str(e)}")
async def _send_webhook_notification(self, config_data: dict, message: str):
"""发送Webhook通知"""
try:
import aiohttp
import json
# 解析配置
webhook_url = config_data.get('webhook_url', '')
http_method = config_data.get('http_method', 'POST').upper()
headers_str = config_data.get('headers', '{}')
if not webhook_url:
logger.warning("Webhook通知配置为空")
return
# 解析自定义请求头
try:
custom_headers = json.loads(headers_str) if headers_str else {}
except json.JSONDecodeError:
custom_headers = {}
# 设置默认请求头
headers = {'Content-Type': 'application/json'}
headers.update(custom_headers)
# 构建请求数据
data = {
'message': message,
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
'source': 'xianyu-auto-reply'
}
async with aiohttp.ClientSession() as session:
if http_method == 'POST':
async with session.post(webhook_url, json=data, headers=headers, timeout=10) as response:
if response.status == 200:
logger.info(f"Webhook通知发送成功")
else:
logger.warning(f"Webhook通知发送失败: {response.status}")
elif http_method == 'PUT':
async with session.put(webhook_url, json=data, headers=headers, timeout=10) as response:
if response.status == 200:
logger.info(f"Webhook通知发送成功")
else:
logger.warning(f"Webhook通知发送失败: {response.status}")
else:
logger.warning(f"不支持的HTTP方法: {http_method}")
except Exception as e:
logger.error(f"发送Webhook通知异常: {self._safe_str(e)}")
async def _send_wechat_notification(self, config_data: dict, message: str):
"""发送微信通知"""
try:
import aiohttp
import json
# 解析配置
webhook_url = config_data.get('webhook_url', '')
if not webhook_url:
logger.warning("微信通知配置为空")
return
data = {
"msgtype": "text",
"text": {
"content": message
}
}
async with aiohttp.ClientSession() as session:
async with session.post(webhook_url, json=data, timeout=10) as response:
if response.status == 200:
logger.info(f"微信通知发送成功")
else:
logger.warning(f"微信通知发送失败: {response.status}")
except Exception as e:
logger.error(f"发送微信通知异常: {self._safe_str(e)}")
async def _send_telegram_notification(self, config_data: dict, message: str):
"""发送Telegram通知"""
try:
import aiohttp
# 解析配置
bot_token = config_data.get('bot_token', '')
chat_id = config_data.get('chat_id', '')
if not all([bot_token, chat_id]):
logger.warning("Telegram通知配置不完整")
return
# 构建API URL
api_url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
data = {
'chat_id': chat_id,
'text': message,
'parse_mode': 'HTML'
}
async with aiohttp.ClientSession() as session:
async with session.post(api_url, json=data, timeout=10) as response:
if response.status == 200:
logger.info(f"Telegram通知发送成功")
else:
logger.warning(f"Telegram通知发送失败: {response.status}")
except Exception as e:
logger.error(f"发送Telegram通知异常: {self._safe_str(e)}")
async def send_token_refresh_notification(self, error_message: str, notification_type: str = "token_refresh"): async def send_token_refresh_notification(self, error_message: str, notification_type: str = "token_refresh"):
"""发送Token刷新异常通知带防重复机制""" """发送Token刷新异常通知带防重复机制"""
try: try:
@ -1036,11 +1229,30 @@ class XianyuLive:
channel_config = notification.get('channel_config') channel_config = notification.get('channel_config')
try: try:
if channel_type == 'qq': # 解析配置数据
await self._send_qq_notification(channel_config, notification_msg) config_data = self._parse_notification_config(channel_config)
notification_sent = True
else: match channel_type:
logger.warning(f"不支持的通知渠道类型: {channel_type}") case 'qq':
await self._send_qq_notification(config_data, notification_msg)
notification_sent = True
case 'ding_talk' | 'dingtalk':
await self._send_dingtalk_notification(config_data, notification_msg)
notification_sent = True
case 'email':
await self._send_email_notification(config_data, notification_msg)
notification_sent = True
case 'webhook':
await self._send_webhook_notification(config_data, notification_msg)
notification_sent = True
case 'wechat':
await self._send_wechat_notification(config_data, notification_msg)
notification_sent = True
case 'telegram':
await self._send_telegram_notification(config_data, notification_msg)
notification_sent = True
case _:
logger.warning(f"不支持的通知渠道类型: {channel_type}")
except Exception as notify_error: except Exception as notify_error:
logger.error(f"发送Token刷新通知失败 ({notification.get('channel_name', 'Unknown')}): {self._safe_str(notify_error)}") logger.error(f"发送Token刷新通知失败 ({notification.get('channel_name', 'Unknown')}): {self._safe_str(notify_error)}")
@ -1106,9 +1318,34 @@ class XianyuLive:
channel_type = notification.get('channel_type', 'qq') channel_type = notification.get('channel_type', 'qq')
channel_config = notification.get('channel_config', '') channel_config = notification.get('channel_config', '')
if channel_type == 'qq': try:
await self._send_qq_notification(channel_config, notification_message) # 解析配置数据
logger.info(f"已发送自动发货通知到QQ: {channel_config}") config_data = self._parse_notification_config(channel_config)
match channel_type:
case 'qq':
await self._send_qq_notification(config_data, notification_message)
logger.info(f"已发送自动发货通知到QQ")
case 'ding_talk' | 'dingtalk':
await self._send_dingtalk_notification(config_data, notification_message)
logger.info(f"已发送自动发货通知到钉钉")
case 'email':
await self._send_email_notification(config_data, notification_message)
logger.info(f"已发送自动发货通知到邮箱")
case 'webhook':
await self._send_webhook_notification(config_data, notification_message)
logger.info(f"已发送自动发货通知到Webhook")
case 'wechat':
await self._send_wechat_notification(config_data, notification_message)
logger.info(f"已发送自动发货通知到微信")
case 'telegram':
await self._send_telegram_notification(config_data, notification_message)
logger.info(f"已发送自动发货通知到Telegram")
case _:
logger.warning(f"不支持的通知渠道类型: {channel_type}")
except Exception as notify_error:
logger.error(f"发送自动发货通知失败: {self._safe_str(notify_error)}")
except Exception as e: except Exception as e:
logger.error(f"发送自动发货通知异常: {self._safe_str(e)}") logger.error(f"发送自动发货通知异常: {self._safe_str(e)}")

View File

@ -371,6 +371,13 @@ class DBManager:
self.set_system_setting("db_version", "1.1", "数据库版本号") self.set_system_setting("db_version", "1.1", "数据库版本号")
logger.info("数据库升级到版本1.1完成") logger.info("数据库升级到版本1.1完成")
# 升级到版本1.2 - 支持更多通知渠道类型
if current_version < "1.2":
logger.info("开始升级数据库到版本1.2...")
self.upgrade_notification_channels_types(cursor)
self.set_system_setting("db_version", "1.2", "数据库版本号")
logger.info("数据库升级到版本1.2完成")
except Exception as e: except Exception as e:
logger.error(f"数据库版本检查或升级失败: {e}") logger.error(f"数据库版本检查或升级失败: {e}")
@ -527,6 +534,70 @@ class DBManager:
except Exception as e: except Exception as e:
logger.error(f"升级notification_channels表失败: {e}") logger.error(f"升级notification_channels表失败: {e}")
raise raise
def upgrade_notification_channels_types(self, cursor):
"""升级notification_channels表支持更多渠道类型"""
try:
logger.info("开始升级notification_channels表支持更多渠道类型...")
# 检查表是否存在
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='notification_channels'")
if not cursor.fetchone():
logger.info("notification_channels表不存在无需升级")
return True
# 检查表中是否有数据
cursor.execute("SELECT COUNT(*) FROM notification_channels")
count = cursor.fetchone()[0]
# 获取现有数据
existing_data = []
if count > 0:
cursor.execute("SELECT * FROM notification_channels")
existing_data = cursor.fetchall()
logger.info(f"备份 {count} 条通知渠道数据")
# 创建新表,支持更多渠道类型
cursor.execute('''
CREATE TABLE notification_channels_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
user_id INTEGER NOT NULL,
type TEXT NOT NULL CHECK (type IN ('qq','ding_talk','dingtalk','email','webhook','wechat','telegram')),
config TEXT NOT NULL,
enabled BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# 复制数据,同时处理类型映射
if existing_data:
logger.info(f"迁移 {len(existing_data)} 条通知渠道数据到新表")
for row in existing_data:
# 处理类型映射ding_talk -> dingtalk
channel_type = row[3] # type字段
if channel_type == 'ding_talk':
channel_type = 'dingtalk'
# 插入到新表
cursor.execute('''
INSERT INTO notification_channels_new
(id, name, user_id, type, config, enabled, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
''', (row[0], row[1], row[2], channel_type, row[4], row[5], row[6], row[7]))
# 删除旧表
cursor.execute("DROP TABLE notification_channels")
# 重命名新表
cursor.execute("ALTER TABLE notification_channels_new RENAME TO notification_channels")
logger.info("notification_channels表类型升级完成")
return True
except Exception as e:
logger.error(f"升级notification_channels表类型失败: {e}")
raise
def _migrate_keywords_table_constraints(self, cursor): def _migrate_keywords_table_constraints(self, cursor):
"""迁移keywords表的约束支持基于商品ID的唯一性校验""" """迁移keywords表的约束支持基于商品ID的唯一性校验"""

View File

@ -2,68 +2,174 @@
# 闲鱼自动回复系统 - Python依赖包 # 闲鱼自动回复系统 - Python依赖包
# ================================ # ================================
# 核心Web框架 # ==================== 核心Web框架 ====================
fastapi>=0.111.0 fastapi>=0.111.0
uvicorn[standard]>=0.29.0 uvicorn[standard]>=0.29.0
pydantic>=2.7.0 pydantic>=2.7.0
# 日志记录 # ==================== 日志记录 ====================
loguru>=0.7.0 loguru>=0.7.0
# 网络通信 # ==================== 网络通信 ====================
websockets>=10.0,<13.0 websockets>=10.0,<13.0
aiohttp>=3.9.0 aiohttp>=3.9.0
requests>=2.31.0 requests>=2.31.0
httpx>=0.25.0 httpx>=0.25.0
# 配置文件处理 # ==================== 配置文件处理 ====================
PyYAML>=6.0.0 PyYAML>=6.0.0
python-dotenv>=1.0.1 python-dotenv>=1.0.1
# JavaScript执行引擎 # ==================== JavaScript执行引擎 ====================
PyExecJS>=1.5.1 PyExecJS>=1.5.1
# 协议缓冲区解析 # ==================== 协议缓冲区解析 ====================
blackboxprotobuf>=1.0.1 blackboxprotobuf>=1.0.1
# 系统监控 # ==================== 系统监控 ====================
psutil>=5.9.0 psutil>=5.9.0
# 文件上传支持 # ==================== 文件上传支持 ====================
python-multipart>=0.0.6 python-multipart>=0.0.6
# AI回复引擎 # ==================== AI回复引擎 ====================
openai>=1.65.5 openai>=1.65.5
# 图像处理(验证码生成、二维码生成) # ==================== 图像处理 ====================
# 验证码生成、二维码生成
Pillow>=10.0.0 Pillow>=10.0.0
qrcode[pil]>=7.4.2 qrcode[pil]>=7.4.2
# 浏览器自动化(商品搜索、订单详情获取) # ==================== 浏览器自动化 ====================
# 商品搜索、订单详情获取
playwright>=1.40.0 playwright>=1.40.0
# 加密和安全 # ==================== 加密和安全 ====================
PyJWT>=2.8.0 PyJWT>=2.8.0
passlib[bcrypt]>=1.7.4 passlib[bcrypt]>=1.7.4
cryptography>=41.0.0 cryptography>=41.0.0
# 时间处理 # ==================== 时间处理 ====================
python-dateutil>=2.8.2 python-dateutil>=2.8.2
# 正则表达式增强 # ==================== 正则表达式增强 ====================
regex>=2023.10.3 regex>=2023.10.3
# Excel文件处理数据导入导出 # ==================== Excel文件处理 ====================
# 数据导入导出功能
pandas>=2.0.0 pandas>=2.0.0
openpyxl>=3.1.0 openpyxl>=3.1.0
# 邮件发送(用户注册验证) # ==================== 邮件发送 ====================
# 用户注册验证
email-validator>=2.0.0 email-validator>=2.0.0
# 其他工具库 # ==================== 其他工具库 ====================
typing-extensions>=4.7.0 typing-extensions>=4.7.0
# 注意: # ==================== 说明 ====================
# - sqlite3 是Python内置模块无需安装 # 以下模块是Python内置模块无需安装
# - smtplib 是Python内置模块无需安装 # - sqlite3 (数据库)
# - email 是Python内置模块无需安装 # - smtplib (邮件发送)
# - email (邮件处理)
# - json (JSON处理)
# - base64 (编码解码)
# - hashlib (哈希算法)
# - hmac (消息认证码)
# - time (时间处理)
# - datetime (日期时间)
# - os (操作系统接口)
# - sys (系统相关)
# - re (正则表达式)
# - urllib (URL处理)
# - asyncio (异步编程)
# - threading (多线程)
# - multiprocessing (多进程)
# - pathlib (路径处理)
# - uuid (UUID生成)
# - random (随机数)
# - secrets (安全随机数)
# - traceback (异常追踪)
# - logging (日志记录)
# - collections (集合类型)
# - itertools (迭代工具)
# - functools (函数工具)
# - operator (操作符函数)
# - copy (对象复制)
# - pickle (对象序列化)
# - gzip (压缩)
# - zipfile (ZIP文件)
# - tarfile (TAR文件)
# - shutil (文件操作)
# - tempfile (临时文件)
# - io (输入输出)
# - csv (CSV文件)
# - xml (XML处理)
# - html (HTML处理)
# - http (HTTP客户端/服务器)
# - socket (网络编程)
# - ssl (SSL/TLS)
# - ftplib (FTP客户端)
# - poplib (POP3客户端)
# - imaplib (IMAP客户端)
# - telnetlib (Telnet客户端)
# - subprocess (子进程)
# - signal (信号处理)
# - atexit (退出处理)
# - weakref (弱引用)
# - gc (垃圾回收)
# - inspect (对象检查)
# - ast (抽象语法树)
# - dis (字节码反汇编)
# - keyword (关键字)
# - token (令牌)
# - tokenize (词法分析)
# - parser (语法分析)
# - symbol (符号)
# - code (代码对象)
# - codeop (代码编译)
# - py_compile (Python编译)
# - compileall (批量编译)
# - importlib (导入机制)
# - pkgutil (包工具)
# - modulefinder (模块查找)
# - runpy (运行Python模块)
# - argparse (命令行参数)
# - getopt (命令行选项)
# - optparse (选项解析)
# - configparser (配置文件)
# - fileinput (文件输入)
# - linecache (行缓存)
# - glob (文件名模式匹配)
# - fnmatch (文件名匹配)
# - difflib (差异比较)
# - textwrap (文本包装)
# - string (字符串)
# - struct (二进制数据)
# - codecs (编解码器)
# - unicodedata (Unicode数据)
# - stringprep (字符串预处理)
# - readline (行编辑)
# - rlcompleter (自动补全)
# - pprint (美化打印)
# - reprlib (repr替代)
# - enum (枚举)
# - numbers (数字抽象基类)
# - math (数学函数)
# - cmath (复数数学)
# - decimal (十进制浮点)
# - fractions (分数)
# - statistics (统计函数)
# - array (数组)
# - bisect (二分查找)
# - heapq (堆队列)
# - queue (队列)
# - types (动态类型)
# - contextlib (上下文管理)
# - abc (抽象基类)
# - atexit (退出处理)
# - traceback (异常追踪)
# - __future__ (未来特性)
# - warnings (警告)
# - dataclasses (数据类)
# - typing (类型提示)

File diff suppressed because it is too large Load Diff