388 lines
13 KiB
Python
388 lines
13 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
彩票数据分析系统启动脚本
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import time
|
|
import requests
|
|
from pathlib import Path
|
|
|
|
|
|
def check_python_version():
|
|
"""检查Python版本"""
|
|
if sys.version_info < (3, 8):
|
|
print("❌ 错误: 需要Python 3.8或更高版本")
|
|
print(f"当前版本: {sys.version}")
|
|
return False
|
|
print(f"✅ Python版本检查通过: {sys.version}")
|
|
return True
|
|
|
|
|
|
def check_dependencies():
|
|
"""检查依赖是否安装"""
|
|
try:
|
|
import fastapi
|
|
import uvicorn
|
|
import sqlalchemy
|
|
import pandas
|
|
import requests
|
|
import schedule
|
|
print("✅ 后端依赖检查通过")
|
|
return True
|
|
except ImportError as e:
|
|
print(f"❌ 后端依赖缺失: {e}")
|
|
print("请运行: cd backend && pip install -r requirements.txt")
|
|
return False
|
|
|
|
|
|
def start_scheduler():
|
|
"""启动定时任务调度器"""
|
|
print("\n⏰ 启动定时任务调度器...")
|
|
|
|
backend_dir = Path("backend")
|
|
if not backend_dir.exists():
|
|
print("❌ 错误: 找不到backend目录")
|
|
return False
|
|
|
|
try:
|
|
# 切换到backend目录
|
|
os.chdir(backend_dir)
|
|
|
|
# 启动定时任务调度器
|
|
print("📝 启动命令: python scheduler.py")
|
|
process = subprocess.Popen([
|
|
sys.executable, "scheduler.py"
|
|
], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
|
|
# 等待调度器启动
|
|
print("⏳ 等待定时任务调度器启动...")
|
|
time.sleep(3)
|
|
|
|
# 检查进程是否还在运行
|
|
if process.poll() is None:
|
|
print("✅ 定时任务调度器启动成功")
|
|
print("📅 定时任务设置:")
|
|
print(" - 每天早上6点: 更新开奖数据")
|
|
print(" - 每天下午5点: 生成拼盘推荐")
|
|
return process
|
|
else:
|
|
print("❌ 定时任务调度器启动失败")
|
|
# 检查进程输出
|
|
stdout, stderr = process.communicate(timeout=1)
|
|
if stderr:
|
|
print(f"错误输出: {stderr}")
|
|
if stdout:
|
|
print(f"标准输出: {stdout}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"❌ 启动定时任务调度器时出错: {e}")
|
|
return False
|
|
|
|
|
|
def start_backend():
|
|
"""启动后端服务"""
|
|
print("\n🚀 启动后端服务...")
|
|
|
|
backend_dir = Path("backend")
|
|
if not backend_dir.exists():
|
|
print("❌ 错误: 找不到backend目录")
|
|
return False
|
|
|
|
try:
|
|
# 切换到backend目录
|
|
os.chdir(backend_dir)
|
|
|
|
# 启动后端服务
|
|
print("📝 启动命令: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload")
|
|
process = subprocess.Popen([
|
|
sys.executable, "-m", "uvicorn", "app.main:app",
|
|
"--host", "0.0.0.0", "--port", "8000", "--reload"
|
|
], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
|
|
# 等待服务启动
|
|
print("⏳ 等待后端服务启动...")
|
|
time.sleep(8) # 增加等待时间
|
|
|
|
# 检查服务是否启动成功
|
|
try:
|
|
response = requests.get("http://localhost:8000/", timeout=10)
|
|
if response.status_code == 200:
|
|
print("✅ 后端服务启动成功")
|
|
print("📊 API文档地址: http://localhost:8000/docs")
|
|
return process
|
|
else:
|
|
print(f"❌ 后端服务启动失败,状态码: {response.status_code}")
|
|
# 检查进程输出
|
|
stdout, stderr = process.communicate(timeout=1)
|
|
if stderr:
|
|
print(f"错误输出: {stderr}")
|
|
return False
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"❌ 后端服务启动失败,无法连接到服务: {e}")
|
|
# 检查进程是否还在运行
|
|
if process.poll() is None:
|
|
print("⚠️ 进程仍在运行,可能是数据库连接问题")
|
|
# 检查进程输出
|
|
try:
|
|
stdout, stderr = process.communicate(timeout=2)
|
|
if stderr:
|
|
print(f"错误输出: {stderr}")
|
|
if stdout:
|
|
print(f"标准输出: {stdout}")
|
|
except subprocess.TimeoutExpired:
|
|
process.kill()
|
|
print("⚠️ 进程被强制终止")
|
|
else:
|
|
print(f"⚠️ 进程已退出,退出码: {process.returncode}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"❌ 启动后端服务时出错: {e}")
|
|
return False
|
|
|
|
|
|
def start_frontend(original_dir):
|
|
"""启动前端服务"""
|
|
print("\n🚀 启动前端服务...")
|
|
|
|
# 确保回到根目录
|
|
os.chdir(original_dir)
|
|
|
|
frontend_dir = Path("frontend")
|
|
if not frontend_dir.exists():
|
|
print("❌ 错误: 找不到frontend目录")
|
|
return False
|
|
|
|
try:
|
|
# 切换到frontend目录
|
|
os.chdir(frontend_dir)
|
|
|
|
# 检查node_modules是否存在
|
|
if not Path("node_modules").exists():
|
|
print("📦 安装前端依赖...")
|
|
subprocess.run(["npm", "install"], check=True)
|
|
|
|
# 启动前端服务
|
|
print("📝 启动命令: npm run dev")
|
|
process = subprocess.Popen([
|
|
"npm", "run", "dev"
|
|
], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
|
|
# 等待服务启动
|
|
print("⏳ 等待前端服务启动...")
|
|
time.sleep(10) # 增加等待时间
|
|
|
|
# 检查服务是否启动成功
|
|
try:
|
|
response = requests.get("http://localhost:5173/", timeout=10)
|
|
if response.status_code == 200:
|
|
print("✅ 前端服务启动成功")
|
|
print("🌐 前端地址: http://localhost:5173")
|
|
return process
|
|
else:
|
|
print(f"❌ 前端服务启动失败,状态码: {response.status_code}")
|
|
# 检查进程输出
|
|
stdout, stderr = process.communicate(timeout=1)
|
|
if stderr:
|
|
print(f"错误输出: {stderr}")
|
|
return False
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"❌ 前端服务启动失败,无法连接到服务: {e}")
|
|
# 检查进程是否还在运行
|
|
if process.poll() is None:
|
|
print("⚠️ 进程仍在运行,可能是端口被占用")
|
|
# 检查进程输出
|
|
try:
|
|
stdout, stderr = process.communicate(timeout=2)
|
|
if stderr:
|
|
print(f"错误输出: {stderr}")
|
|
if stdout:
|
|
print(f"标准输出: {stdout}")
|
|
except subprocess.TimeoutExpired:
|
|
process.kill()
|
|
print("⚠️ 进程被强制终止")
|
|
else:
|
|
print(f"⚠️ 进程已退出,退出码: {process.returncode}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"❌ 启动前端服务时出错: {e}")
|
|
return False
|
|
|
|
|
|
def check_database_connection():
|
|
"""检查数据库连接"""
|
|
print("\n🔍 检查数据库连接...")
|
|
try:
|
|
import pymysql
|
|
from backend.app.core.database import SQLALCHEMY_DATABASE_URL
|
|
|
|
# 解析数据库URL
|
|
if SQLALCHEMY_DATABASE_URL.startswith("mysql+pymysql://"):
|
|
# 提取连接信息
|
|
url_parts = SQLALCHEMY_DATABASE_URL.replace(
|
|
"mysql+pymysql://", "").split("@")
|
|
if len(url_parts) == 2:
|
|
credentials = url_parts[0]
|
|
host_port_db = url_parts[1]
|
|
|
|
username, password = credentials.split(":")
|
|
host_port, database = host_port_db.split("/")
|
|
host, port = host_port.split(":")
|
|
|
|
print(f"📊 数据库信息:")
|
|
print(f" 主机: {host}")
|
|
print(f" 端口: {port}")
|
|
print(f" 数据库: {database}")
|
|
print(f" 用户: {username}")
|
|
|
|
# 尝试连接数据库
|
|
try:
|
|
connection = pymysql.connect(
|
|
host=host,
|
|
port=int(port),
|
|
user=username,
|
|
password=password,
|
|
database=database,
|
|
connect_timeout=10
|
|
)
|
|
connection.close()
|
|
print("✅ 数据库连接成功")
|
|
return True
|
|
except Exception as e:
|
|
print(f"❌ 数据库连接失败: {e}")
|
|
print("💡 请检查:")
|
|
print(" 1. 数据库服务器是否运行")
|
|
print(" 2. 网络连接是否正常")
|
|
print(" 3. 数据库凭据是否正确")
|
|
return False
|
|
else:
|
|
print("❌ 数据库URL格式错误")
|
|
return False
|
|
else:
|
|
print("❌ 不支持的数据库类型")
|
|
return False
|
|
|
|
except ImportError:
|
|
print("❌ 缺少pymysql依赖")
|
|
return False
|
|
except Exception as e:
|
|
print(f"❌ 检查数据库连接时出错: {e}")
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""主函数"""
|
|
print("🎯 彩票数据分析系统启动器")
|
|
print("=" * 50)
|
|
|
|
# 检查Python版本
|
|
if not check_python_version():
|
|
return
|
|
|
|
# 检查依赖
|
|
if not check_dependencies():
|
|
return
|
|
|
|
# 检查数据库连接
|
|
if not check_database_connection():
|
|
print("\n💡 建议:")
|
|
print("1. 检查数据库服务器是否正常运行")
|
|
print("2. 确认网络连接是否正常")
|
|
print("3. 验证数据库凭据是否正确")
|
|
print("4. 如果使用本地数据库,请修改 backend/app/core/database.py 中的配置")
|
|
|
|
response = input("\n是否继续启动系统?(y/N): ")
|
|
if response.lower() != 'y':
|
|
print("❌ 用户取消启动")
|
|
return
|
|
|
|
# 询问是否启动定时任务
|
|
print("\n⏰ 定时任务选项:")
|
|
print("1. 启动定时任务(推荐)")
|
|
print("2. 不启动定时任务")
|
|
scheduler_choice = input("请选择 (1/2): ").strip()
|
|
start_scheduler_task = scheduler_choice == "1"
|
|
|
|
# 保存当前目录
|
|
original_dir = os.getcwd()
|
|
|
|
try:
|
|
# 启动后端
|
|
backend_process = start_backend()
|
|
if not backend_process:
|
|
print("\n💡 后端启动失败,可能的原因:")
|
|
print("1. 数据库连接问题")
|
|
print("2. 端口8000被占用")
|
|
print("3. 依赖包缺失")
|
|
print("4. 代码错误")
|
|
print("\n请检查后端日志获取详细错误信息")
|
|
return
|
|
|
|
# 启动定时任务(如果选择)
|
|
scheduler_process = None
|
|
if start_scheduler_task:
|
|
scheduler_process = start_scheduler()
|
|
if not scheduler_process:
|
|
print("⚠️ 定时任务启动失败,但系统将继续运行")
|
|
print("💡 您可以稍后手动启动定时任务: cd backend && python scheduler.py")
|
|
|
|
# 启动前端
|
|
frontend_process = start_frontend(original_dir)
|
|
if not frontend_process:
|
|
backend_process.terminate()
|
|
if scheduler_process:
|
|
scheduler_process.terminate()
|
|
print("\n💡 前端启动失败,可能的原因:")
|
|
print("1. Node.js未安装或版本过低")
|
|
print("2. 端口5173被占用")
|
|
print("3. 依赖包缺失")
|
|
print("\n请检查前端日志获取详细错误信息")
|
|
return
|
|
|
|
print("\n🎉 系统启动成功!")
|
|
print("=" * 50)
|
|
print("📊 后端API: http://localhost:8000")
|
|
print("📊 API文档: http://localhost:8000/docs")
|
|
print("🌐 前端界面: http://localhost:5173")
|
|
if scheduler_process:
|
|
print("⏰ 定时任务: 已启动")
|
|
print(" - 每天早上6点: 更新开奖数据")
|
|
print(" - 每天下午5点: 生成拼盘推荐")
|
|
else:
|
|
print("⏰ 定时任务: 未启动")
|
|
print("=" * 50)
|
|
print("💡 使用说明:")
|
|
print("1. 打开浏览器访问 http://localhost:5173")
|
|
print("2. 在首页点击'补全场早点'按钮获取最新开奖信息")
|
|
print("3. 在一键下单页面查看今日拼盘推荐")
|
|
print("4. 使用各种分析功能进行数据分析")
|
|
print("=" * 50)
|
|
print("按 Ctrl+C 停止服务")
|
|
|
|
# 等待用户中断
|
|
try:
|
|
while True:
|
|
time.sleep(1)
|
|
except KeyboardInterrupt:
|
|
print("\n🛑 正在停止服务...")
|
|
backend_process.terminate()
|
|
frontend_process.terminate()
|
|
if scheduler_process:
|
|
scheduler_process.terminate()
|
|
print("✅ 服务已停止")
|
|
|
|
except Exception as e:
|
|
print(f"❌ 启动过程中出错: {e}")
|
|
finally:
|
|
# 恢复原始目录
|
|
os.chdir(original_dir)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|