#!/usr/bin/env python3 """ Neural Sync 启动器 - 跨平台版本 一键启动前后端服务 """ import os import sys import time import subprocess import signal import platform from pathlib import Path # 颜色输出 class Colors: GREEN = '\033[0;32m' YELLOW = '\033[1;33m' RED = '\033[0;31m' BLUE = '\033[0;34m' NC = '\033[0m' def print_colored(color, text): print(f"{color}{text}{Colors.NC}") def get_project_dir(): return Path(__file__).parent def check_venv(): venv_dir = get_project_dir() / "venv" if not venv_dir.exists(): print_colored(Colors.RED, "❌ 虚拟环境不存在,请先创建: python -m venv venv") sys.exit(1) def kill_port(port): """终止占用指定端口的进程""" system = platform.system() try: if system == "Darwin": # macOS subprocess.run(["lsof", "-ti", f"{port}"], capture_output=True, text=True, check=True) result = subprocess.run(["lsof", "-ti", f"{port}"], capture_output=True, text=True) if result.stdout.strip(): subprocess.run(["kill", "-9"] + result.stdout.strip().split(), capture_output=True) elif system == "Linux": result = subprocess.run(["fuser", "-k", f"{port}/tcp"], capture_output=True) except: pass def start_backend(): """启动后端服务""" print_colored(Colors.GREEN, "▶️ 启动后端服务...") project_dir = get_project_dir() backend_dir = project_dir / "backend" log_dir = project_dir / "logs" log_dir.mkdir(exist_ok=True) # 激活虚拟环境并启动 venv_python = get_project_dir() / "venv" / "bin" / "python" if platform.system() == "Windows": venv_python = get_project_dir() / "venv" / "Scripts" / "python.exe" log_file = log_dir / "backend.log" process = subprocess.Popen( [str(venv_python), "-m", "uvicorn", "app.main:app", "--reload", "--port", "8000"], cwd=backend_dir, stdout=open(log_file, "w"), stderr=subprocess.STDOUT ) # 等待后端启动 for i in range(10): try: response = subprocess.run( ["curl", "-s", "http://127.0.0.1:8000/docs"], capture_output=True, timeout=2 ) if response.returncode == 0: print_colored(Colors.GREEN, f"✅ 后端启动成功 (PID: {process.pid})") return process except: pass time.sleep(1) print_colored(Colors.RED, "❌ 后端启动失败") return None def start_frontend(): """启动前端服务""" print_colored(Colors.GREEN, "▶️ 启动前端服务...") project_dir = get_project_dir() frontend_dir = project_dir / "frontend" log_dir = project_dir / "logs" log_dir.mkdir(exist_ok=True) log_file = log_dir / "frontend.log" process = subprocess.Popen( ["npm", "run", "dev", "--", "--host"], cwd=frontend_dir, stdout=open(log_file, "w"), stderr=subprocess.STDOUT, shell=True ) # 等待前端启动 for i in range(15): try: response = subprocess.run( ["curl", "-s", "http://127.0.0.1:5173"], capture_output=True, timeout=2 ) if response.returncode == 0: print_colored(Colors.GREEN, f"✅ 前端启动成功 (PID: {process.pid})") return process except: pass time.sleep(1) print_colored(Colors.YELLOW, "⚠️ 前端可能还在启动中") return process def main(): print_colored(Colors.BLUE, "🚀 Neural Sync 启动器") print("=" * 30) project_dir = get_project_dir() os.chdir(project_dir) # 检查环境 check_venv() # 清理端口 print_colored(Colors.BLUE, "🧹 清理端口...") kill_port(8000) kill_port(5173) time.sleep(1) # 启动服务 backend_proc = start_backend() if not backend_proc: sys.exit(1) frontend_proc = start_frontend() # 保存 PID log_dir = project_dir / "logs" (log_dir / "backend.pid").write_text(str(backend_proc.pid)) (log_dir / "frontend.pid").write_text(str(frontend_proc.pid)) # 显示结果 print() print_colored(Colors.GREEN, "🎉 所有服务启动完成!") print("=" * 30) print(f" 后端: {Colors.YELLOW}http://127.0.0.1:8000{Colors.NC}") print(f" 前端: {Colors.YELLOW}http://127.0.0.1:5173{Colors.NC}") print(f" API 文档: {Colors.YELLOW}http://127.0.0.1:8000/docs{Colors.NC}") print() print("📝 日志文件:") print(" 后端: logs/backend.log") print(" 前端: logs/frontend.log") print() print_colored(Colors.YELLOW, "💡 按 Ctrl+C 停止所有服务,或运行: python stop.py") # 等待中断信号 def signal_handler(sig, frame): print_colored(Colors.YELLOW, "\n🛑 正在停止服务...") backend_proc.terminate() frontend_proc.terminate() print_colored(Colors.GREEN, "🎉 所有服务已停止") sys.exit(0) signal.signal(signal.SIGINT, signal_handler) # 保持运行 try: backend_proc.wait() except KeyboardInterrupt: signal_handler(None, None) if __name__ == "__main__": main()