BodyBalanceEvaluation/backend/build_exe.py

257 lines
6.5 KiB
Python
Raw Normal View History

2025-08-06 09:04:13 +08:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
后端应用程序打包脚本
使用PyInstaller将Flask应用程序打包成独立的exe文件
"""
import os
import sys
import shutil
from pathlib import Path
def create_spec_file():
"""创建PyInstaller spec文件"""
spec_content = '''
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['app.py'],
pathex=[],
binaries=[
('dll/k4a.dll', '.'), # 包含K4A动态库
],
datas=[
('..\\config.ini', '.'), # 配置文件
('..\\config.json', '.'), # JSON配置文件
('tests', 'tests'), # 测试文件夹
('data', 'data'), # 数据文件夹
],
hiddenimports=[
'flask',
'flask_socketio',
'flask_cors',
'cv2',
'numpy',
'sqlite3',
'configparser',
'logging',
'threading',
'queue',
'base64',
'psutil',
'pykinect_azure',
'database',
'device_manager',
'utils',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
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='..\\document\\icon.ico' if os.path.exists('..\\document\\icon.ico') else None,
)
'''
with open('backend.spec', 'w', encoding='utf-8') as f:
f.write(spec_content)
print("✓ 已创建 backend.spec 文件")
def create_main_entry():
"""创建主入口文件"""
main_content = '''
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
身体平衡评估系统 - 后端服务入口
独立运行的exe版本
"""
import os
import sys
import logging
from pathlib import Path
# 设置工作目录
if getattr(sys, 'frozen', False):
# 如果是打包后的exe
application_path = os.path.dirname(sys.executable)
else:
# 如果是开发环境
application_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(application_path)
sys.path.insert(0, application_path)
# 创建必要的目录
os.makedirs('logs', exist_ok=True)
os.makedirs('data', exist_ok=True)
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('logs/backend.log', encoding='utf-8'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def main():
"""主函数"""
try:
logger.info("启动身体平衡评估系统后端服务...")
logger.info(f"工作目录: {os.getcwd()}")
# 导入并启动Flask应用
from app import app, socketio, init_app
# 初始化应用
init_app()
# 启动服务器
logger.info("后端服务器启动在 http://localhost:5000")
socketio.run(
app,
host='0.0.0.0',
port=5000,
debug=False,
allow_unsafe_werkzeug=True
)
except KeyboardInterrupt:
logger.info("用户中断,正在关闭服务器...")
except Exception as e:
logger.error(f"启动失败: {e}")
input("按回车键退出...")
sys.exit(1)
if __name__ == '__main__':
main()
'''
with open('main_exe.py', 'w', encoding='utf-8') as f:
f.write(main_content)
print("✓ 已创建 main_exe.py 入口文件")
def build_exe():
"""构建exe文件"""
print("开始构建exe文件...")
# 检查PyInstaller是否安装
try:
import PyInstaller
print(f"✓ PyInstaller版本: {PyInstaller.__version__}")
except ImportError:
print("❌ PyInstaller未安装正在安装...")
os.system('pip install pyinstaller')
# 清理之前的构建
if os.path.exists('build'):
shutil.rmtree('build')
print("✓ 清理build目录")
if os.path.exists('dist'):
shutil.rmtree('dist')
print("✓ 清理dist目录")
# 使用spec文件构建
cmd = 'python -m PyInstaller backend.spec --clean --noconfirm'
print(f"执行命令: {cmd}")
result = os.system(cmd)
if result == 0:
print("\n✓ 构建成功!")
print("exe文件位置: dist/BodyBalanceBackend.exe")
# 复制额外的文件
dist_path = Path('dist')
if dist_path.exists():
# 复制配置文件
config_files = ['../config.ini', '../config.json']
for config_file in config_files:
if os.path.exists(config_file):
shutil.copy2(config_file, dist_path)
print(f"✓ 复制配置文件: {config_file}")
# 创建启动脚本
start_script = dist_path / 'start_backend.bat'
with open(start_script, 'w', encoding='utf-8') as f:
f.write('@echo off\n')
f.write('echo 启动身体平衡评估系统后端服务...\n')
f.write('BodyBalanceBackend.exe\n')
f.write('pause\n')
print("✓ 创建启动脚本: start_backend.bat")
print("\n🎉 打包完成!")
print("运行方式:")
print("1. 直接运行: dist/BodyBalanceBackend.exe")
print("2. 使用脚本: dist/start_backend.bat")
else:
print("❌ 构建失败")
return False
return True
def main():
"""主函数"""
print("=" * 50)
print("身体平衡评估系统 - 后端打包工具")
print("=" * 50)
print()
# 检查当前目录
if not os.path.exists('app.py'):
print("❌ 请在backend目录下运行此脚本")
return
try:
# 创建配置文件
create_spec_file()
create_main_entry()
# 构建exe
if build_exe():
print("\n✅ 所有操作完成!")
else:
print("\n❌ 构建过程中出现错误")
except Exception as e:
print(f"❌ 错误: {e}")
input("\n按回车键退出...")
if __name__ == '__main__':
main()