#!/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()