按 docs/v2/05-implementation-plan.md §1 候选迁移表与 claude_use/T00 白名单, 从 55e2cdb 抽取 224 个文件(2.48 MB)到独立目录 F:/mini-OpenClaw-v2。 - 排除:凭据(.env/server-deploy.conf/旧DELIVERY.md)、运行数据(xingbang_data 等 4 个 SQLite)、依赖(venv/node_modules 符号链接)、归档(_backup*/test-evidence/ ori_file)、Office 临时文件 - 目标目录独立 git 仓库,初始恢复点;Gitea 远程与分支待 OQ-06 Q2 定案 - 未部署、未启动服务、未调用模型 Co-Authored-By: Claude Code <noreply@anthropic.com>
131 lines
4.1 KiB
Python
131 lines
4.1 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
mini-OpenClaw 一键启动脚本(纯 Python) - PyCharm 兼容版
|
|
用法:
|
|
python start.py # 同时启动 后端(FastAPI:8002) + 前端(Next.js:3000)
|
|
python start.py -b # 只启动后端
|
|
python start.py -f # 只启动前端
|
|
访问:
|
|
前端界面: http://localhost:3000
|
|
后端API : http://localhost:8002 (docs: /docs)
|
|
"""
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import platform
|
|
|
|
ROOT = os.path.dirname(os.path.abspath(__file__))
|
|
BACKEND_DIR = os.path.join(ROOT, "backend")
|
|
FRONTEND_DIR = ROOT
|
|
|
|
# 检测操作系统
|
|
IS_WINDOWS = platform.system() == "Windows"
|
|
VENV_PY = os.path.join(BACKEND_DIR, "venv", "Scripts", "python.exe") if IS_WINDOWS else os.path.join(BACKEND_DIR, "venv", "bin", "python")
|
|
|
|
|
|
def check_port(port):
|
|
"""检查端口是否已被占用"""
|
|
import socket
|
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
return s.connect_ex(('localhost', port)) == 0
|
|
|
|
|
|
def run_backend():
|
|
"""启动 FastAPI 后端(8002)"""
|
|
print("\n[后端] 正在启动 FastAPI (端口 8002) ...", flush=True)
|
|
|
|
# 检查虚拟环境是否存在
|
|
if not os.path.exists(VENV_PY):
|
|
print(f"❌ 错误: 虚拟环境不存在: {VENV_PY}")
|
|
print(" 请先运行: cd backend && python -m venv venv && venv\\Scripts\\activate && pip install -r requirements.txt")
|
|
return None
|
|
|
|
# 检查端口是否已被占用
|
|
if check_port(8002):
|
|
print("⚠️ 警告: 端口 8002 已被占用,后端可能已在运行")
|
|
return None
|
|
|
|
# 设置环境变量(禁用代理)
|
|
env = os.environ.copy()
|
|
env["NO_PROXY"] = "*"
|
|
env["HTTP_PROXY"] = ""
|
|
env["HTTPS_PROXY"] = ""
|
|
|
|
cmd = [VENV_PY, "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8002"]
|
|
|
|
if IS_WINDOWS:
|
|
# Windows: 创建新的控制台窗口
|
|
proc = subprocess.Popen(cmd, cwd=BACKEND_DIR, env=env, creationflags=subprocess.CREATE_NEW_CONSOLE)
|
|
else:
|
|
# Linux/Mac: 后台运行
|
|
proc = subprocess.Popen(cmd, cwd=BACKEND_DIR, env=env)
|
|
|
|
print("✅ 后端启动成功 (PID: {})".format(proc.pid), flush=True)
|
|
return proc
|
|
|
|
|
|
def run_frontend():
|
|
"""启动 Next.js 前端(3000)"""
|
|
print("\n[前端] 正在启动 Next.js (端口 3000) ...", flush=True)
|
|
|
|
# 检查 node_modules 是否存在
|
|
if not os.path.exists(os.path.join(FRONTEND_DIR, "node_modules")):
|
|
print("⚠️ 警告: node_modules 不存在,正在安装依赖...")
|
|
subprocess.run(["npm", "install"], cwd=FRONTEND_DIR, shell=True)
|
|
|
|
# 检查端口是否已被占用
|
|
if check_port(3000):
|
|
print("⚠️ 警告: 端口 3000 已被占用,前端可能已在运行")
|
|
return None
|
|
|
|
cmd = ["npm", "run", "dev"]
|
|
|
|
if IS_WINDOWS:
|
|
# Windows: 创建新的控制台窗口
|
|
proc = subprocess.Popen(cmd, cwd=FRONTEND_DIR, shell=True, creationflags=subprocess.CREATE_NEW_CONSOLE)
|
|
else:
|
|
# Linux/Mac: 后台运行
|
|
proc = subprocess.Popen(cmd, cwd=FRONTEND_DIR, shell=True)
|
|
|
|
print("✅ 前端启动成功 (PID: {})".format(proc.pid), flush=True)
|
|
return proc
|
|
|
|
|
|
def main():
|
|
args = sys.argv[1:]
|
|
only_backend = "-b" in args
|
|
only_frontend = "-f" in args
|
|
|
|
if only_backend:
|
|
run_backend()
|
|
print("\n后端已启动: http://localhost:8002 (API文档 /docs)")
|
|
return
|
|
if only_frontend:
|
|
run_frontend()
|
|
print("\n前端已启动: http://localhost:3000")
|
|
return
|
|
|
|
# 默认同时启动前后端,各自独立窗口
|
|
run_backend()
|
|
run_frontend()
|
|
|
|
print("\n" + "=" * 50)
|
|
print(" mini-OpenClaw 已启动!")
|
|
print(" 前端界面: http://localhost:3000")
|
|
print(" 后端 API: http://localhost:8002 (docs: /docs)")
|
|
print(" 每个服务在独立命令行窗口运行,关闭窗口即停服务")
|
|
print("=" * 50)
|
|
print("\n本脚本会保持运行(可 Ctrl+C 退出)。想只起一个,用: python start.py -b 或 -f")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
# 保持主进程存活
|
|
try:
|
|
while True:
|
|
time.sleep(60)
|
|
except KeyboardInterrupt:
|
|
print("\n已退出启动器。")
|