145 lines
4.0 KiB
Python
145 lines
4.0 KiB
Python
"""
|
|
故事提取工具 - 打包构建脚本
|
|
使用方法: python build.py
|
|
"""
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import subprocess
|
|
|
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
BACKEND_DIR = os.path.join(BASE_DIR, "backend")
|
|
FRONTEND_DIR = os.path.join(BASE_DIR, "frontend")
|
|
DIST_DIR = os.path.join(BASE_DIR, "dist")
|
|
BUILD_DIR = os.path.join(BASE_DIR, "build")
|
|
|
|
|
|
def step(msg: str):
|
|
print(f"\n{'='*50}")
|
|
print(f" {msg}")
|
|
print(f"{'='*50}")
|
|
|
|
|
|
def build_frontend():
|
|
"""构建前端"""
|
|
step("1/4 构建前端...")
|
|
os.chdir(FRONTEND_DIR)
|
|
subprocess.run([sys.executable, "-m", "npm", "run", "build"], check=True, shell=False)
|
|
os.chdir(BASE_DIR)
|
|
print("前端构建完成!")
|
|
|
|
|
|
def create_package_structure():
|
|
"""创建打包目录结构"""
|
|
step("2/4 准备打包文件...")
|
|
|
|
# 清理旧的 dist
|
|
if os.path.exists(DIST_DIR):
|
|
shutil.rmtree(DIST_DIR)
|
|
os.makedirs(DIST_DIR, exist_ok=True)
|
|
|
|
# 复制 backend 目录
|
|
pkg_backend = os.path.join(DIST_DIR, "backend")
|
|
if os.path.exists(pkg_backend):
|
|
shutil.rmtree(pkg_backend)
|
|
shutil.copytree(BACKEND_DIR, pkg_backend)
|
|
|
|
# 复制 frontend/dist
|
|
pkg_frontend = os.path.join(DIST_DIR, "frontend", "dist")
|
|
os.makedirs(pkg_frontend, exist_ok=True)
|
|
src_dist = os.path.join(FRONTEND_DIR, "dist")
|
|
if os.path.exists(src_dist):
|
|
for item in os.listdir(src_dist):
|
|
s = os.path.join(src_dist, item)
|
|
d = os.path.join(pkg_frontend, item)
|
|
if os.path.isdir(s):
|
|
shutil.copytree(s, d)
|
|
else:
|
|
shutil.copy2(s, d)
|
|
|
|
# 复制 run.py
|
|
shutil.copy2(os.path.join(BASE_DIR, "run.py"), os.path.join(DIST_DIR, "run.py"))
|
|
|
|
print("打包文件准备完成!")
|
|
|
|
|
|
def build_exe():
|
|
"""使用 PyInstaller 打包"""
|
|
step("3/4 打包成 exe...")
|
|
|
|
os.chdir(DIST_DIR)
|
|
|
|
cmd = [
|
|
sys.executable, "-m", "PyInstaller",
|
|
"--name=故事提取工具",
|
|
"--onefile",
|
|
"--windowed",
|
|
"--noconfirm",
|
|
"--clean",
|
|
# 隐藏导入
|
|
"--hidden-import=uvicorn.logging",
|
|
"--hidden-import=uvicorn.loops",
|
|
"--hidden-import=uvicorn.loops.auto",
|
|
"--hidden-import=uvicorn.protocols",
|
|
"--hidden-import=uvicorn.protocols.http",
|
|
"--hidden-import=uvicorn.protocols.http.auto",
|
|
"--hidden-import=uvicorn.protocols.websockets",
|
|
"--hidden-import=uvicorn.protocols.websockets.auto",
|
|
"--hidden-import=uvicorn.lifespan",
|
|
"--hidden-import=uvicorn.lifespan.on",
|
|
"--hidden-import=multipart",
|
|
# 收集数据文件
|
|
f"--add-data=backend;backend",
|
|
f"--add-data=frontend;frontend",
|
|
# 入口
|
|
"run.py",
|
|
]
|
|
|
|
subprocess.run(cmd, check=True, shell=False)
|
|
os.chdir(BASE_DIR)
|
|
print("打包完成!")
|
|
|
|
|
|
def copy_output():
|
|
"""复制最终输出"""
|
|
step("4/4 整理输出...")
|
|
|
|
exe_name = "故事提取工具.exe"
|
|
src = os.path.join(DIST_DIR, "dist", exe_name)
|
|
dst = os.path.join(BASE_DIR, exe_name)
|
|
|
|
if os.path.exists(src):
|
|
shutil.copy2(src, dst)
|
|
size_mb = os.path.getsize(dst) / (1024 * 1024)
|
|
print(f"\n✅ 打包成功!")
|
|
print(f" 输出文件: {dst}")
|
|
print(f" 文件大小: {size_mb:.1f} MB")
|
|
print(f"\n 使用方法:")
|
|
print(f" 1. 将 {exe_name} 发送给用户")
|
|
print(f" 2. 用户双击运行,自动打开浏览器")
|
|
print(f" 3. 首次使用需要在设置页面配置 API Key")
|
|
else:
|
|
print(f"\n❌ 打包失败,未找到输出文件: {src}")
|
|
|
|
|
|
def main():
|
|
print("故事提取工具 - 打包构建")
|
|
print("=" * 50)
|
|
|
|
# 检查 PyInstaller
|
|
try:
|
|
import PyInstaller
|
|
except ImportError:
|
|
print("正在安装 PyInstaller...")
|
|
subprocess.run([sys.executable, "-m", "pip", "install", "pyinstaller", "--break-system-packages"],
|
|
check=True, shell=False)
|
|
|
|
build_frontend()
|
|
create_package_structure()
|
|
build_exe()
|
|
copy_output()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|