220 lines
6.6 KiB
Python
220 lines
6.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
启动脚本
|
|
|
|
支持开发模式和生产模式启动
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import argparse
|
|
from pathlib import Path
|
|
from config import config
|
|
|
|
|
|
def check_rust_executable():
|
|
"""检查 Rust 可执行文件是否存在"""
|
|
rust_config = config.get("rust")
|
|
executable_name = rust_config.get("executable_name", "video_keyframe_extractor")
|
|
executable_path = rust_config.get("executable_path", "target/release")
|
|
|
|
possible_paths = [
|
|
f"./{executable_path}/{executable_name}.exe",
|
|
f"./{executable_path}/{executable_name}",
|
|
f"./{executable_name}.exe",
|
|
f"./{executable_name}"
|
|
]
|
|
|
|
for path in possible_paths:
|
|
if Path(path).exists():
|
|
print(f"✓ Found Rust executable: {path}")
|
|
return str(Path(path).absolute())
|
|
|
|
print("⚠ Warning: Rust executable not found")
|
|
print("Please compile first: cargo build --release")
|
|
return None
|
|
|
|
|
|
def check_dependencies():
|
|
"""检查 Python 依赖"""
|
|
try:
|
|
import fastapi
|
|
import uvicorn
|
|
print("✓ FastAPI dependencies available")
|
|
return True
|
|
except ImportError as e:
|
|
print(f"✗ Missing dependencies: {e}")
|
|
print("Please install: pip install -r requirements.txt")
|
|
return False
|
|
|
|
|
|
def install_dependencies():
|
|
"""安装依赖"""
|
|
print("Installing dependencies...")
|
|
try:
|
|
subprocess.run([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"],
|
|
check=True)
|
|
print("✓ Dependencies installed successfully")
|
|
return True
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"✗ Failed to install dependencies: {e}")
|
|
return False
|
|
|
|
|
|
def start_development_server(host="127.0.0.1", port=8050, reload=True):
|
|
"""启动开发服务器"""
|
|
print(f" Starting development server on http://{host}:{port}")
|
|
print(f" API docs: http://{host}:{port}/docs")
|
|
print(f" Health check: http://{host}:{port}/health")
|
|
|
|
try:
|
|
import uvicorn
|
|
uvicorn.run(
|
|
"api_server:app",
|
|
host=host,
|
|
port=port,
|
|
reload=reload,
|
|
log_level="info"
|
|
)
|
|
except ImportError:
|
|
print("uvicorn not found, trying with subprocess...")
|
|
subprocess.run([
|
|
sys.executable, "-m", "uvicorn",
|
|
"api_server:app",
|
|
"--host", host,
|
|
"--port", str(port),
|
|
"--reload" if reload else ""
|
|
])
|
|
|
|
|
|
def start_production_server(host="0.0.0.0", port=8000, workers=4):
|
|
"""启动生产服务器"""
|
|
print(f"🚀 Starting production server on http://{host}:{port}")
|
|
print(f"Workers: {workers}")
|
|
|
|
subprocess.run([
|
|
sys.executable, "-m", "uvicorn",
|
|
"api_server:app",
|
|
"--host", host,
|
|
"--port", str(port),
|
|
"--workers", str(workers),
|
|
"--log-level", "warning"
|
|
])
|
|
|
|
|
|
def create_systemd_service():
|
|
"""创建 systemd 服务文件"""
|
|
current_dir = Path.cwd()
|
|
python_path = sys.executable
|
|
|
|
service_content = f"""[Unit]
|
|
Description=Video Keyframe Extraction API Server
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=exec
|
|
User=www-data
|
|
WorkingDirectory={current_dir}
|
|
Environment=PATH=/usr/bin:/usr/local/bin
|
|
ExecStart={python_path} -m uvicorn api_server:app --host 0.0.0.0 --port 8000 --workers 4
|
|
Restart=always
|
|
RestartSec=10
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
"""
|
|
|
|
service_file = Path("/etc/systemd/system/video-keyframe-api.service")
|
|
|
|
try:
|
|
with open(service_file, 'w') as f:
|
|
f.write(service_content)
|
|
|
|
print(f"✓ Systemd service created: {service_file}")
|
|
print("To enable and start:")
|
|
print(" sudo systemctl enable video-keyframe-api")
|
|
print(" sudo systemctl start video-keyframe-api")
|
|
|
|
except PermissionError:
|
|
print("✗ Permission denied. Please run with sudo for systemd service creation")
|
|
|
|
# 创建本地副本
|
|
local_service = Path("./video-keyframe-api.service")
|
|
with open(local_service, 'w') as f:
|
|
f.write(service_content)
|
|
|
|
print(f"✓ Service file created locally: {local_service}")
|
|
print(f"To install: sudo cp {local_service} /etc/systemd/system/")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Video Keyframe Extraction API Server")
|
|
|
|
# 从配置文件获取默认值
|
|
server_config = config.get_server_config()
|
|
|
|
parser.add_argument("--mode", choices=["dev", "prod", "install"], default="dev",
|
|
help="运行模式: dev (开发), prod (生产), install (安装依赖)")
|
|
parser.add_argument("--host", default=server_config.get("host", "127.0.0.1"), help="绑定主机")
|
|
parser.add_argument("--port", type=int, default=server_config.get("port", 8000), help="端口号")
|
|
parser.add_argument("--workers", type=int, default=server_config.get("workers", 4), help="生产模式工作进程数")
|
|
parser.add_argument("--no-reload", action="store_true", help="禁用自动重载")
|
|
parser.add_argument("--check", action="store_true", help="仅检查环境")
|
|
parser.add_argument("--create-service", action="store_true", help="创建 systemd 服务")
|
|
|
|
args = parser.parse_args()
|
|
|
|
print("=== Video Keyframe Extraction API Server ===")
|
|
|
|
# 检查环境
|
|
rust_exe = check_rust_executable()
|
|
deps_ok = check_dependencies()
|
|
|
|
if args.check:
|
|
print("\n=== Environment Check ===")
|
|
print(f"Rust executable: {'✓' if rust_exe else '✗'}")
|
|
print(f"Python dependencies: {'✓' if deps_ok else '✗'}")
|
|
return
|
|
|
|
if args.create_service:
|
|
create_systemd_service()
|
|
return
|
|
|
|
# 安装模式
|
|
if args.mode == "install":
|
|
if not deps_ok:
|
|
install_dependencies()
|
|
else:
|
|
print("✓ Dependencies already installed")
|
|
return
|
|
|
|
# 检查必要条件
|
|
if not rust_exe:
|
|
print("✗ Cannot start without Rust executable")
|
|
print("Please run: cargo build --release")
|
|
sys.exit(1)
|
|
|
|
if not deps_ok:
|
|
print("Installing missing dependencies...")
|
|
if not install_dependencies():
|
|
sys.exit(1)
|
|
|
|
# 启动服务器
|
|
if args.mode == "dev":
|
|
start_development_server(
|
|
host=args.host,
|
|
port=args.port,
|
|
reload=not args.no_reload
|
|
)
|
|
elif args.mode == "prod":
|
|
start_production_server(
|
|
host=args.host,
|
|
port=args.port,
|
|
workers=args.workers
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|