BodyBalanceEvaluation/backend/build_minimal.py
2025-08-13 14:17:50 +08:00

244 lines
6.3 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
app_minimal.py 打包脚本
使用PyInstaller将最小版本Flask应用程序打包成独立的exe文件
"""
import os
import sys
import shutil
import subprocess
from pathlib import Path
def clean_build_dirs():
"""清理构建目录"""
print("清理构建目录...")
dirs_to_clean = ['build', 'dist', '__pycache__']
for dir_name in dirs_to_clean:
if os.path.exists(dir_name):
try:
shutil.rmtree(dir_name)
print(f"✓ 已删除 {dir_name}")
except Exception as e:
print(f"⚠️ 删除 {dir_name} 失败: {e}")
def create_minimal_spec():
"""创建app_minimal.py的PyInstaller spec文件"""
spec_content = '''
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['app_minimal.py'],
pathex=[],
binaries=[
('dll/smitsense/SMiTSenseUsb-F3.0.dll', '.'), # SMiTSense传感器库
],
datas=[
('config.ini', '.'), # 配置文件
('data', 'data'), # 数据文件夹
],
hiddenimports=[
'flask',
'flask_cors',
'sqlite3',
'configparser',
'logging',
'threading',
'queue',
'base64',
'psutil',
'database',
'device_manager',
'utils',
'cv2',
'numpy',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[
'flask_socketio',
'socketio',
'engineio',
'eventlet',
'gevent',
],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='BodyBalanceBackend',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=None
)
'''
with open('app_minimal.spec', 'w', encoding='utf-8') as f:
f.write(spec_content)
print("✓ 已创建 app_minimal.spec 文件")
def build_exe():
"""构建exe文件"""
print("\n开始构建exe文件...")
try:
# 使用PyInstaller构建
cmd = [sys.executable, '-m', 'PyInstaller', 'app_minimal.spec', '--clean', '--noconfirm']
print(f"执行命令: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
if result.returncode == 0:
print("✓ 构建成功!")
return True
else:
print(f"✗ 构建失败")
print(f"错误输出: {result.stderr}")
return False
except Exception as e:
print(f"✗ 构建过程出错: {e}")
return False
def create_startup_script():
"""创建启动脚本"""
startup_script = '''@echo off
echo 启动身体平衡评估系统后端服务(最小版本)...
echo.
echo 服务信息:
echo - HTTP API: http://localhost:5000
echo - 管理界面: http://localhost:5000
echo.
echo 按Ctrl+C停止服务
echo.
"BodyBalanceBackend.exe"
if %errorlevel% neq 0 (
echo.
echo 服务启动失败,请检查错误信息
pause
)
'''
dist_dir = 'dist'
if not os.path.exists(dist_dir):
os.makedirs(dist_dir)
with open(os.path.join(dist_dir, 'start_backend.bat'), 'w', encoding='utf-8') as f:
f.write(startup_script)
print("✓ 创建启动脚本: dist/start_backend.bat")
def copy_config_files():
"""复制配置文件到dist目录"""
print("复制配置文件...")
config_files = ['config.ini']
dist_dir = 'dist'
if not os.path.exists(dist_dir):
os.makedirs(dist_dir)
for config_file in config_files:
if os.path.exists(config_file):
try:
shutil.copy2(config_file, dist_dir)
print(f"✓ 已复制 {config_file}")
except Exception as e:
print(f"⚠️ 复制 {config_file} 失败: {e}")
else:
print(f"⚠️ 配置文件不存在: {config_file}")
def main():
"""主函数"""
print("=" * 60)
print("身体平衡评估系统 - app_minimal.py 打包工具")
print("=" * 60)
print()
# 检查当前目录
if not os.path.exists('app_minimal.py'):
print("✗ 错误: 找不到 app_minimal.py 文件")
print("请确保在backend目录下运行此脚本")
input("按回车键退出...")
return
try:
# 清理构建目录
clean_build_dirs()
print()
# 创建spec文件
print("创建PyInstaller配置...")
create_minimal_spec()
print()
# 构建exe
if build_exe():
print()
print("后处理...")
# 检查生成的exe文件
exe_path = 'dist/BodyBalanceBackend.exe'
if os.path.exists(exe_path):
print(f"✓ exe文件位置: {exe_path}")
# 复制配置文件
copy_config_files()
# 创建启动脚本
create_startup_script()
print()
print("🎉 打包完成!")
print()
print("输出文件:")
print(f"- 可执行文件: {exe_path}")
print("- 启动脚本: dist/start_backend.bat")
print("- 配置文件: dist/config.ini")
print()
print("使用方式:")
print("1. 直接运行: dist/BodyBalanceBackend.exe")
print("2. 使用脚本: dist/start_backend.bat")
print()
print("服务地址: http://localhost:5000")
else:
print("✗ 错误: 未找到生成的exe文件")
else:
print("\n✗ 打包失败")
except Exception as e:
print(f"\n✗ 打包过程出错: {e}")
print()
input("按回车键退出...")
if __name__ == '__main__':
main()