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