Files
ds2api/dev.py

152 lines
4.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
DS2API 开发服务器 - 统一启动后端和前端
使用方法:
python dev.py # 同时启动后端和前端
python dev.py --backend # 仅启动后端
python dev.py --frontend # 仅启动前端
python dev.py --install # 安装所有依赖
环境变量:
PORT - 后端服务端口,默认 5001
LOG_LEVEL - 日志级别,默认 INFO
"""
import os
import sys
import signal
import subprocess
import time
from pathlib import Path
# 配置
BACKEND_PORT = int(os.getenv("PORT", "5001"))
FRONTEND_PORT = 5173
HOST = os.getenv("HOST", "0.0.0.0")
LOG_LEVEL = os.getenv("LOG_LEVEL", "info").lower()
PROJECT_DIR = Path(__file__).parent
WEBUI_DIR = PROJECT_DIR / "webui"
REQUIREMENTS_FILE = PROJECT_DIR / "requirements.txt"
processes = []
def install_dependencies():
"""安装所有 Python 和 Node.js 依赖"""
print("\n📦 安装 Python 依赖...")
subprocess.run([
sys.executable, "-m", "pip", "install", "-r", str(REQUIREMENTS_FILE), "-q"
], check=True)
print("✅ Python 依赖安装完成")
if WEBUI_DIR.exists():
print("\n📦 安装前端依赖...")
subprocess.run(["npm", "install"], cwd=WEBUI_DIR, check=True)
print("✅ 前端依赖安装完成")
print("\n🎉 所有依赖安装完成!运行 `python dev.py` 启动服务\n")
def signal_handler(sig, frame):
"""处理退出信号,终止所有子进程"""
print("\n\n🛑 正在关闭所有服务...")
for proc in processes:
if proc.poll() is None:
proc.terminate()
try:
proc.wait(timeout=3)
except subprocess.TimeoutExpired:
proc.kill()
print("👋 已退出\n")
sys.exit(0)
def start_backend():
"""启动后端服务"""
print(f"🚀 启动后端服务... http://localhost:{BACKEND_PORT}")
proc = subprocess.Popen(
[
sys.executable, "-m", "uvicorn",
"app:app",
"--host", HOST,
"--port", str(BACKEND_PORT),
"--reload",
"--reload-dir", str(PROJECT_DIR),
"--log-level", LOG_LEVEL,
],
cwd=PROJECT_DIR,
)
processes.append(proc)
return proc
def start_frontend():
"""启动前端开发服务器"""
if not WEBUI_DIR.exists():
print("⚠️ webui 目录不存在,跳过前端启动")
return None
node_modules = WEBUI_DIR / "node_modules"
if not node_modules.exists():
print("📦 安装前端依赖...")
subprocess.run(["npm", "install"], cwd=WEBUI_DIR, check=True)
print(f"🎨 启动前端服务... http://localhost:{FRONTEND_PORT}")
proc = subprocess.Popen(
["npm", "run", "dev"],
cwd=WEBUI_DIR,
)
processes.append(proc)
return proc
def main():
# 解析参数
if "--install" in sys.argv or "-i" in sys.argv:
install_dependencies()
return
backend_only = "--backend" in sys.argv or "-b" in sys.argv
frontend_only = "--frontend" in sys.argv or "-f" in sys.argv
# 注册信号处理
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
print("\n" + "=" * 50)
print(" DS2API 开发服务器")
print("=" * 50)
if frontend_only:
start_frontend()
elif backend_only:
start_backend()
else:
# 同时启动
start_backend()
time.sleep(1) # 等待后端启动
start_frontend()
print("\n" + "-" * 50)
if not frontend_only:
print(f"📡 后端 API: http://localhost:{BACKEND_PORT}")
if not backend_only:
print(f"🎨 管理界面: http://localhost:{FRONTEND_PORT}")
print("-" * 50)
print("按 Ctrl+C 停止所有服务\n")
# 等待进程结束
try:
while processes:
for proc in processes[:]:
if proc.poll() is not None:
processes.remove(proc)
time.sleep(0.5)
except KeyboardInterrupt:
signal_handler(None, None)
if __name__ == "__main__":
main()