Files
Story-extractor/build.py
2026-04-24 16:02:16 +08:00

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()