diff --git a/backend/BUILD_README.md b/backend/BUILD_README.md deleted file mode 100644 index d3b3c61f..00000000 --- a/backend/BUILD_README.md +++ /dev/null @@ -1,165 +0,0 @@ -# 身体平衡评估系统 - 后端打包说明 - -本文档说明如何将后端Python应用程序打包成独立的exe可执行文件。 - -## 📋 打包前准备 - -### 1. 环境要求 -- Python 3.8+ (推荐 3.9-3.11) -- Windows 10/11 操作系统 -- 至少 2GB 可用磁盘空间 - -### 2. 依赖检查 -确保以下核心依赖已安装: -```bash -pip install Flask Flask-CORS Flask-SocketIO -pip install numpy opencv-python psutil -pip install PyInstaller -``` - -## 🚀 快速打包 - -### 方法一:使用批处理脚本(推荐) -1. 在backend目录下双击运行 `build_backend.bat` -2. 脚本会自动完成所有打包步骤 -3. 等待打包完成 - -### 方法二:手动打包 -1. 打开命令提示符,切换到backend目录 -2. 运行打包脚本: - ```bash - python build_exe.py - ``` - -### 方法三:直接使用PyInstaller -```bash -# 生成spec文件 -pyinstaller --onefile --windowed --name=BodyBalanceBackend app.py - -# 或使用自定义spec文件 -pyinstaller backend.spec --clean --noconfirm -``` - -## 📁 输出文件结构 - -打包完成后,在 `dist/` 目录下会生成: - -``` -dist/ -├── BodyBalanceBackend.exe # 主可执行文件 -├── start_backend.bat # 启动脚本 -├── config.ini # 配置文件 -├── config.json # JSON配置文件 -└── logs/ # 日志目录(运行时创建) -``` - -## 🔧 配置说明 - -### PyInstaller配置 (backend.spec) -- **--onefile**: 打包成单个exe文件 -- **--windowed**: 隐藏控制台窗口(可选) -- **--add-data**: 包含数据文件 -- **--add-binary**: 包含二进制文件(如DLL) -- **--hidden-import**: 包含隐式导入的模块 - -### 包含的文件 -- 配置文件:`config.ini`, `config.json` -- 动态库:`dll/k4a.dll`(如果存在) -- 数据目录:`data/`, `captured_images/`, `tests/` - -## 🚀 部署和运行 - -### 1. 部署到目标机器 -1. 将整个 `dist/` 文件夹复制到目标机器 -2. 确保目标机器安装了必要的运行时库 - -### 2. 运行方式 - -**方式一:直接运行** -```bash -BodyBalanceBackend.exe -``` - -**方式二:使用启动脚本** -```bash -start_backend.bat -``` - -**方式三:命令行运行** -```bash -cd dist -BodyBalanceBackend.exe -``` - -### 3. 访问服务 -- 服务器地址:`http://localhost:5000` -- 健康检查:`http://localhost:5000/health` -- API文档:`http://localhost:5000/api/health` - -## 🔍 故障排除 - -### 常见问题 - -**1. 打包失败** -- 检查Python版本是否兼容 -- 确保所有依赖已正确安装 -- 检查磁盘空间是否充足 - -**2. exe运行失败** -- 检查是否缺少Visual C++ Redistributable -- 查看logs目录下的错误日志 -- 确保配置文件存在且格式正确 - -**3. 模块导入错误** -- 在spec文件中添加缺失的模块到 `hiddenimports` -- 检查第三方库的兼容性 - -**4. 文件路径问题** -- 确保所有相对路径正确 -- 检查数据文件是否正确包含 - -### 调试方法 - -**1. 启用控制台输出** -修改spec文件中的 `console=True` - -**2. 查看详细日志** -```bash -BodyBalanceBackend.exe --debug -``` - -**3. 测试模式运行** -```bash -python app.py -``` - -## 📝 自定义打包 - -### 修改打包配置 -编辑 `build_exe.py` 文件,可以自定义: -- 输出文件名 -- 包含的文件和目录 -- 隐式导入的模块 -- 图标文件 - -### 添加新的依赖 -1. 在 `requirements_build.txt` 中添加新依赖 -2. 在spec文件的 `hiddenimports` 中添加模块名 -3. 重新打包 - -## 🔒 安全注意事项 - -1. **配置文件安全**:确保配置文件中不包含敏感信息 -2. **网络安全**:默认绑定所有接口(0.0.0.0),生产环境建议修改 -3. **文件权限**:确保exe文件有适当的执行权限 - -## 📞 技术支持 - -如果遇到问题,请检查: -1. 日志文件:`logs/backend.log` -2. 系统要求是否满足 -3. 依赖版本是否兼容 - ---- - -**注意**:首次打包可能需要较长时间,请耐心等待。建议在虚拟环境中进行打包以避免依赖冲突。 \ No newline at end of file diff --git a/backend/app.spec b/backend/app.spec index 822c05f2..10b968ed 100644 --- a/backend/app.spec +++ b/backend/app.spec @@ -7,18 +7,19 @@ a = Analysis( ['app.py'], pathex=[], binaries=[ - ('dll/femtobolt/bin/k4a.dll', '.'), # K4A动态库 - ('dll/femtobolt/bin/k4arecord.dll', '.'), # K4A录制库 - ('dll/femtobolt/bin/depthengine_2_0.dll', '.'), # 深度引擎 - ('dll/femtobolt/bin/OrbbecSDK.dll', '.'), # Orbbec SDK - ('dll/femtobolt/bin/ob_usb.dll', '.'), # Orbbec USB库 - ('dll/femtobolt/bin/live555.dll', '.'), # Live555库 - ('dll/smitsense/SMiTSenseUsb-F3.0.dll', '.'), # SMiTSense传感器库 - ('dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml', '.'), # Orbbec配置文件 + ('dll/femtobolt/bin/k4a.dll', 'dll/femtobolt/bin'), # K4A动态库 + ('dll/femtobolt/bin/k4arecord.dll', 'dll/femtobolt/bin'), # K4A录制库 + ('dll/femtobolt/bin/depthengine_2_0.dll', 'dll/femtobolt/bin'), # 深度引擎 + ('dll/femtobolt/bin/OrbbecSDK.dll', 'dll/femtobolt/bin'), # Orbbec SDK + ('dll/femtobolt/bin/ob_usb.dll', 'dll/femtobolt/bin'), # Orbbec USB库 + ('dll/femtobolt/bin/live555.dll', 'dll/femtobolt/bin'), # Live555库 + ('dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml', 'dll/femtobolt/bin'), # Orbbec配置文件 ('dll/smitsense/SMiTSenseUsb-F3.0.dll', 'dll/smitsense'), # SMiTSense传感器库 + ('dll/smitsense/SMiTSenseUsbWrapper.dll', 'dll/smitsense'), # SMiTSense传感器库包装类 ], datas=[ ('config.ini', '.'), # 配置文件 ('data', 'data'), # 数据文件夹 + ('dll', 'dll'), # DLL目录结构 ], hiddenimports=[ 'flask', diff --git a/backend/app_minimal.py b/backend/app_minimal.py deleted file mode 100644 index 464e9ca3..00000000 --- a/backend/app_minimal.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -平衡体态检测系统 - 后端服务(最小版本) -基于Flask的本地API服务,暂时移除SocketIO功能 -""" - -import os -import sys -import json -import time -import threading -from datetime import datetime -from flask import Flask, jsonify, send_file -from flask import request as flask_request -from flask_cors import CORS -import sqlite3 -import logging -from pathlib import Path -import cv2 -import configparser - -# 添加当前目录到Python路径 -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -# 导入自定义模块 -from database import DatabaseManager -from device_manager import DeviceManager -from utils import config as app_config - -# 配置日志 -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__) - -# 创建Flask应用 -app = Flask(__name__) -app.config['SECRET_KEY'] = 'body-balance-detection-system-2024' - -# 启用CORS -CORS(app, origins=['http://localhost:3000', 'http://127.0.0.1:3000', 'http://192.168.1.58:3000']) - -# 全局变量 -db_manager = None -device_manager = None -socketio = None # 暂时禁用SocketIO - -def init_app(): - """初始化应用""" - global db_manager, device_manager - - try: - # 创建必要的目录 - os.makedirs('logs', exist_ok=True) - os.makedirs('data', exist_ok=True) - - # 从配置文件读取数据库路径 - db_path_config = app_config.get('DATABASE', 'path', 'data/body_balance.db') - - # 对于打包后的exe,确保数据库路径基于exe所在目录 - if getattr(sys, 'frozen', False): - # 如果是打包后的exe,使用exe所在目录 - exe_dir = os.path.dirname(sys.executable) - if not os.path.isabs(db_path_config): - db_path = os.path.join(exe_dir, db_path_config) - else: - db_path = db_path_config - else: - # 如果是开发环境,使用脚本所在目录 - if not os.path.isabs(db_path_config): - current_dir = os.path.dirname(os.path.abspath(__file__)) - if db_path_config.startswith('backend/'): - db_path_config = db_path_config[8:] # 去掉 'backend/' 前缀 - db_path = os.path.join(current_dir, db_path_config) - else: - db_path = db_path_config - - # 确保数据库目录存在 - db_dir = os.path.dirname(db_path) - os.makedirs(db_dir, exist_ok=True) - - # 打印数据库路径信息用于调试 - logger.info(f'数据库配置路径: {db_path_config}') - logger.info(f'数据库实际路径: {db_path}') - logger.info(f'数据库目录: {db_dir}') - logger.info(f'当前工作目录: {os.getcwd()}') - - # 初始化数据库 - db_manager = DatabaseManager(db_path) - db_manager.init_database() - - # 初始化设备管理器(不使用SocketIO) - device_manager = DeviceManager(db_manager) - - logger.info('应用初始化完成(最小版本,无SocketIO)') - - except Exception as e: - logger.error(f'应用初始化失败: {e}') - logger.warning('部分功能可能不可用,但服务将继续运行') - -# ==================== 基础API ==================== - -@app.route('/health', methods=['GET']) -def health_check(): - """健康检查""" - return jsonify({ - 'status': 'ok', - 'timestamp': datetime.now().isoformat(), - 'version': '1.0.0-minimal', - 'socketio_enabled': False - }) - -@app.route('/api/health', methods=['GET']) -def api_health_check(): - """API健康检查""" - return jsonify({ - 'status': 'ok', - 'timestamp': datetime.now().isoformat(), - 'version': '1.0.0-minimal', - 'socketio_enabled': False - }) - -@app.route('/api/test', methods=['GET']) -def test_endpoint(): - """测试端点""" - return jsonify({ - 'message': 'Backend is running!', - 'timestamp': datetime.now().isoformat(), - 'database_status': 'connected' if db_manager else 'not_connected', - 'device_manager_status': 'initialized' if device_manager else 'not_initialized' - }) - -# ==================== 认证API ==================== - -@app.route('/api/auth/login', methods=['POST']) -def login(): - """用户登录""" - try: - data = flask_request.get_json() - username = data.get('username') - password = data.get('password') - remember = data.get('remember', False) - - if not username or not password: - return jsonify({ - 'success': False, - 'message': '用户名或密码不能为空' - }), 400 - - # 简单的测试登录逻辑 - if username == 'admin' and password == 'admin': - # 生成token(实际项目中应使用JWT等安全token) - token = f"token_{username}_{int(time.time())}" - - return jsonify({ - 'success': True, - 'message': '登录成功', - 'data': { - 'token': token, - 'user': { - 'id': 1, - 'username': username, - 'role': 'admin' - } - } - }) - else: - return jsonify({ - 'success': False, - 'message': '用户名或密码错误' - }), 401 - - except Exception as e: - logger.error(f'登录失败: {e}') - return jsonify({ - 'success': False, - 'message': '登录过程中发生错误' - }), 500 - -@app.route('/api/auth/logout', methods=['POST']) -def logout(): - """用户登出""" - return jsonify({ - 'success': True, - 'message': '登出成功' - }) - -# ==================== 设备API ==================== - -@app.route('/api/devices/status', methods=['GET']) -def get_device_status(): - """获取设备状态""" - try: - if device_manager: - status = { - 'cameras': device_manager.get_camera_status(), - 'sensors': device_manager.get_sensor_status() - } - else: - status = { - 'cameras': {}, - 'sensors': {}, - 'error': '设备管理器未初始化' - } - - return jsonify({ - 'success': True, - 'data': status - }) - - except Exception as e: - logger.error(f'获取设备状态失败: {e}') - return jsonify({ - 'success': False, - 'message': f'获取设备状态失败: {str(e)}' - }), 500 - -# ==================== 错误处理 ==================== - -@app.errorhandler(404) -def not_found(error): - return jsonify({ - 'success': False, - 'message': '接口不存在' - }), 404 - -@app.errorhandler(500) -def internal_error(error): - return jsonify({ - 'success': False, - 'message': '服务器内部错误' - }), 500 - -if __name__ == '__main__': - init_app() - app.run(host='0.0.0.0', port=5000, debug=True) \ No newline at end of file diff --git a/backend/app_minimal.spec b/backend/app_minimal.spec deleted file mode 100644 index 875948f8..00000000 --- a/backend/app_minimal.spec +++ /dev/null @@ -1,71 +0,0 @@ - -# -*- 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 -) diff --git a/backend/app_simple.py b/backend/app_simple.py deleted file mode 100644 index 6e7998c4..00000000 --- a/backend/app_simple.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -身体平衡评估系统 - 后端服务器 (简化版本) -专门用于PyInstaller打包的版本,移除了SocketIO功能 -""" - -import os -import sys -import json -import time -import threading -from datetime import datetime -from flask import Flask, jsonify, send_file -from flask import request as flask_request -from flask_cors import CORS -import sqlite3 -import logging -from pathlib import Path -import cv2 -import configparser - -# 添加当前目录到Python路径 -sys.path.append(os.path.dirname(os.path.abspath(__file__))) - -# 导入自定义模块 -from database import DatabaseManager -from device_manager import DeviceManager, VideoStreamManager -from utils import config as app_config - -# 配置日志 -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__) - -# 创建Flask应用 -app = Flask(__name__) -app.config['SECRET_KEY'] = 'body-balance-detection-system-2024' - -# 启用CORS支持 -CORS(app, origins='*', supports_credentials=True, allow_headers=['Content-Type', 'Authorization'], methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']) - -# 读取RTSP配置 -config = configparser.ConfigParser() -config_path = os.path.join(os.path.dirname(__file__), 'config.ini') -if not os.path.exists(config_path): - # 如果当前目录没有config.ini,尝试上级目录 - config_path = os.path.join(os.path.dirname(__file__), '..', 'config.ini') -config.read(config_path, encoding='utf-8') - -# 全局变量 -db_manager = None -device_manager = None -current_detection = None -detection_thread = None -video_stream_manager = None - -def init_app(): - """初始化应用""" - global db_manager, device_manager, video_stream_manager - - try: - # 初始化数据库管理器 - db_path = os.path.join(os.path.dirname(__file__), 'data', 'body_balance.db') - os.makedirs(os.path.dirname(db_path), exist_ok=True) - db_manager = DatabaseManager(db_path) - # 初始化数据库表结构 - db_manager.init_database() - logger.info("数据库管理器初始化成功") - - # 初始化设备管理器 - device_manager = DeviceManager() - logger.info("设备管理器初始化成功") - - # 初始化视频流管理器 - video_stream_manager = VideoStreamManager(device_manager=device_manager) - logger.info("视频流管理器初始化成功") - - logger.info("应用初始化完成") - - except Exception as e: - logger.error(f"应用初始化失败: {e}") - raise - -@app.route('/health', methods=['GET']) -def health_check(): - """健康检查接口""" - return jsonify({ - 'status': 'ok', - 'timestamp': datetime.now().isoformat(), - 'message': '身体平衡评估系统后端服务正常运行' - }) - -@app.route('/api/health', methods=['GET']) -def api_health_check(): - """API健康检查接口""" - return jsonify({ - 'status': 'success', - 'data': { - 'service': '身体平衡评估系统', - 'version': '1.0.0', - 'timestamp': datetime.now().isoformat() - } - }) - -@app.route('/api/auth/login', methods=['POST']) -def login(): - """用户登录接口""" - try: - data = flask_request.get_json() - username = data.get('username') - password = data.get('password') - - if not username or not password: - return jsonify({ - 'status': 'error', - 'message': '用户名和密码不能为空' - }), 400 - - # 验证用户凭据 - user = db_manager.authenticate_user(username, password) - if user: - return jsonify({ - 'status': 'success', - 'message': '登录成功', - 'data': { - 'user_id': user['id'], - 'username': user['username'], - 'role': user['role'], - 'token': 'simple_token_' + str(user['id']) - } - }) - else: - return jsonify({ - 'status': 'error', - 'message': '用户名或密码错误' - }), 401 - - except Exception as e: - logger.error(f"登录失败: {e}") - return jsonify({'status': 'error', 'message': '登录失败'}), 500 - -@app.route('/api/auth/register', methods=['POST']) -def register(): - """用户注册接口""" - try: - data = flask_request.get_json() - username = data.get('username') - password = data.get('password') - email = data.get('email', '') - - if not username or not password: - return jsonify({ - 'status': 'error', - 'message': '用户名和密码不能为空' - }), 400 - - # 创建用户 - user_id = db_manager.create_user(username, password, email) - if user_id: - return jsonify({ - 'status': 'success', - 'message': '注册成功', - 'data': {'user_id': user_id} - }) - else: - return jsonify({ - 'status': 'error', - 'message': '注册失败,用户名可能已存在' - }), 400 - - except Exception as e: - logger.error(f"注册失败: {e}") - return jsonify({'status': 'error', 'message': '注册失败'}), 500 - -if __name__ == '__main__': - try: - # 初始化应用 - init_app() - - # 启动服务器 - logger.info("启动身体平衡评估系统后端服务器...") - logger.info("服务器地址: http://localhost:5000") - - app.run( - host='0.0.0.0', - port=5000, - debug=False, - threaded=True - ) - - except KeyboardInterrupt: - logger.info("服务器已停止") - except Exception as e: - logger.error(f"服务器启动失败: {e}") - sys.exit(1) \ No newline at end of file diff --git a/backend/backend.spec b/backend/backend.spec deleted file mode 100644 index e43c860d..00000000 --- a/backend/backend.spec +++ /dev/null @@ -1,76 +0,0 @@ - -# -*- mode: python ; coding: utf-8 -*- - -a = Analysis( - ['main_exe.py'], - pathex=[], - binaries=[ - # 只包含确实存在的DLL文件 - ], - datas=[ - ('config.ini', '.'), # 配置文件 - ('data', 'data'), # 数据文件夹 - ('tests', 'tests'), # 测试文件夹 - ('app_minimal.py', '.'), # 应用入口文件 - ], - hiddenimports=[ - 'flask', - 'flask_socketio', - 'flask_cors', - 'socketio', - 'engineio', - 'engineio.async_drivers.threading', - 'socketio.namespace', - 'cv2', - 'numpy', - 'psutil', - 'sqlite3', - 'configparser', - 'logging', - 'threading', - 'queue', - 'base64', - 'requests', - 'click', - 'colorama', - 'database', - 'device_manager', - 'utils', - 'dns', - 'dns.resolver', - 'dns.asyncresolver' - ], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[ - 'eventlet', - 'gevent', - 'gevent_uwsgi' - ], - noarchive=False, -) - -pyz = PYZ(a.pure) - -exe = EXE( - pyz, - a.scripts, - a.binaries, - 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 -) diff --git a/backend/build_app.py b/backend/build_app.py index 866e6fce..a9d59e28 100644 --- a/backend/build_app.py +++ b/backend/build_app.py @@ -35,18 +35,19 @@ a = Analysis( ['app.py'], pathex=[], binaries=[ - ('dll/femtobolt/bin/k4a.dll', '.'), # K4A动态库 - ('dll/femtobolt/bin/k4arecord.dll', '.'), # K4A录制库 - ('dll/femtobolt/bin/depthengine_2_0.dll', '.'), # 深度引擎 - ('dll/femtobolt/bin/OrbbecSDK.dll', '.'), # Orbbec SDK - ('dll/femtobolt/bin/ob_usb.dll', '.'), # Orbbec USB库 - ('dll/femtobolt/bin/live555.dll', '.'), # Live555库 - ('dll/smitsense/SMiTSenseUsb-F3.0.dll', '.'), # SMiTSense传感器库 - ('dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml', '.'), # Orbbec配置文件 + ('dll/femtobolt/bin/k4a.dll', 'dll/femtobolt/bin'), # K4A动态库 + ('dll/femtobolt/bin/k4arecord.dll', 'dll/femtobolt/bin'), # K4A录制库 + ('dll/femtobolt/bin/depthengine_2_0.dll', 'dll/femtobolt/bin'), # 深度引擎 + ('dll/femtobolt/bin/OrbbecSDK.dll', 'dll/femtobolt/bin'), # Orbbec SDK + ('dll/femtobolt/bin/ob_usb.dll', 'dll/femtobolt/bin'), # Orbbec USB库 + ('dll/femtobolt/bin/live555.dll', 'dll/femtobolt/bin'), # Live555库 + ('dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml', 'dll/femtobolt/bin'), # Orbbec配置文件 ('dll/smitsense/SMiTSenseUsb-F3.0.dll', 'dll/smitsense'), # SMiTSense传感器库 + ('dll/smitsense/SMiTSenseUsbWrapper.dll', 'dll/smitsense'), # SMiTSense传感器库包装类 ], datas=[ ('config.ini', '.'), # 配置文件 ('data', 'data'), # 数据文件夹 + ('dll', 'dll'), # DLL目录结构 ], hiddenimports=[ 'flask', diff --git a/backend/build_backend.bat b/backend/build_backend.bat deleted file mode 100644 index bb742550..00000000 --- a/backend/build_backend.bat +++ /dev/null @@ -1,64 +0,0 @@ -@echo off -chcp 65001 >nul -echo ================================================ -echo 身体平衡评估系统 - 后端打包工具 -echo ================================================ -echo. - -:: 检查是否在正确的目录 -if not exist "app.py" ( - echo ❌ 错误:请在backend目录下运行此脚本 - pause - exit /b 1 -) - -:: 检查Python环境 -echo 🔍 检查Python环境... -python --version -if errorlevel 1 ( - echo ❌ 错误:Python未安装或未添加到PATH - pause - exit /b 1 -) - -:: 安装打包依赖 -echo. -echo 📦 安装打包依赖... -pip install pyinstaller -if errorlevel 1 ( - echo ❌ 错误:PyInstaller安装失败 - pause - exit /b 1 -) - -:: 清理之前的构建 -echo. -echo 🧹 清理之前的构建文件... -if exist "build" rmdir /s /q "build" -if exist "dist" rmdir /s /q "dist" -if exist "*.spec" del /q "*.spec" -echo ✓ 清理完成 - -:: 运行打包脚本 -echo. -echo 🚀 开始打包... -python build_exe.py -if errorlevel 1 ( - echo ❌ 打包失败 - pause - exit /b 1 -) - -echo. -echo 🎉 打包完成! -echo. -echo 📁 输出目录:dist/ -echo 🚀 可执行文件:dist/BodyBalanceBackend.exe -echo 📋 启动脚本:dist/start_backend.bat -echo. -echo 使用说明: -echo 1. 将整个dist文件夹复制到目标机器 -echo 2. 确保目标机器有必要的运行时库(Visual C++ Redistributable) -echo 3. 运行 BodyBalanceBackend.exe 或 start_backend.bat -echo. -pause \ No newline at end of file diff --git a/backend/build_exe.py b/backend/build_exe.py deleted file mode 100644 index 3b78cee5..00000000 --- a/backend/build_exe.py +++ /dev/null @@ -1,233 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -身体平衡评估系统后端打包脚本 -基于最小测试框架的成功经验,简化打包配置 -""" - -import os -import sys -import shutil -import subprocess -from pathlib import Path - -def check_dependencies(): - """检查必需的依赖""" - print("检查依赖模块...") - required_modules = [ - 'flask', - 'flask_socketio', - 'flask_cors', - 'socketio', - 'engineio', - 'numpy', - 'cv2', - 'psutil' - ] - - missing_modules = [] - for module in required_modules: - try: - __import__(module) - print(f"✓ {module}") - except ImportError: - print(f"✗ {module} (缺失)") - missing_modules.append(module) - - if missing_modules: - print(f"\n缺失模块: {', '.join(missing_modules)}") - print("请运行: pip install -r requirements_build.txt") - return False - - print("✓ 所有依赖模块检查通过") - return True - -def create_spec_file(): - """创建PyInstaller spec文件""" - spec_content = ''' -# -*- mode: python ; coding: utf-8 -*- - -a = Analysis( - ['main_exe.py'], - pathex=[], - binaries=[ - # 只包含确实存在的DLL文件 - ], - datas=[ - ('config.ini', '.'), # 配置文件 - ('data', 'data'), # 数据文件夹 - ('tests', 'tests'), # 测试文件夹 - ('app_minimal.py', '.'), # 应用入口文件 - ], - hiddenimports=[ - 'flask', - 'flask_socketio', - 'flask_cors', - 'socketio', - 'engineio', - 'engineio.async_drivers.threading', - 'socketio.namespace', - 'cv2', - 'numpy', - 'psutil', - 'sqlite3', - 'configparser', - 'logging', - 'threading', - 'queue', - 'base64', - 'requests', - 'click', - 'colorama', - 'database', - 'device_manager', - 'utils', - 'dns', - 'dns.resolver', - 'dns.asyncresolver' - ], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[ - 'eventlet', - 'gevent', - 'gevent_uwsgi' - ], - noarchive=False, -) - -pyz = PYZ(a.pure) - -exe = EXE( - pyz, - a.scripts, - a.binaries, - 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('backend.spec', 'w', encoding='utf-8') as f: - f.write(spec_content) - - print("✓ 已创建 backend.spec 文件") - -def build_exe(): - """构建exe文件""" - print("开始构建exe文件...") - - # 检查依赖模块 - print("\n检查依赖模块...") - if not check_dependencies(): - print("\n❌ 依赖检查失败,请先安装缺失的模块") - return False - - # 检查PyInstaller是否安装 - try: - import PyInstaller - print(f"\n✓ PyInstaller版本: {PyInstaller.__version__}") - except ImportError: - print("❌ PyInstaller未安装,正在安装...") - subprocess.run([sys.executable, '-m', 'pip', 'install', 'pyinstaller>=6.10.0']) - - # 清理之前的构建 - print("\n清理构建目录...") - if os.path.exists('build'): - shutil.rmtree('build') - print("✓ 清理build目录") - - if os.path.exists('dist'): - shutil.rmtree('dist') - print("✓ 清理dist目录") - - # 创建spec文件 - create_spec_file() - - # 使用spec文件构建 - print("\n开始打包...") - cmd = [sys.executable, '-m', 'PyInstaller', 'backend.spec', '--clean', '--noconfirm'] - print(f"执行命令: {' '.join(cmd)}") - - result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8') - - if result.returncode == 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('chcp 65001 >nul\n') - f.write('echo Starting Body Balance Backend...\n') - f.write('BodyBalanceBackend.exe\n') - f.write('pause\n') - print("✓ 创建启动脚本: start_backend.bat") - - print("\n🎉 打包完成!") - print("\n测试方法:") - print("1. 直接运行: dist/BodyBalanceBackend.exe") - print("2. 使用脚本: dist/start_backend.bat") - print("3. 在浏览器中访问: http://localhost:5000") - - return True - else: - print("\n❌ 构建失败") - print(f"错误信息: {result.stderr}") - return False - -def main(): - """主函数""" - print("================================================") - print("身体平衡评估系统 - 后端打包工具 (简化版)") - print("基于最小测试框架的成功经验") - print("================================================") - print() - - try: - # 检查是否在正确的目录 - if not os.path.exists('main_exe.py'): - print("❌ 错误:请在backend目录下运行此脚本") - print("当前目录应包含 main_exe.py 文件") - return - - # 构建exe - if build_exe(): - print("\n✅ 所有操作完成!") - else: - print("\n❌ 构建过程中出现错误") - - except Exception as e: - print(f"❌ 错误: {e}") - import traceback - traceback.print_exc() - - input("\n按回车键退出...") - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/backend/build_exe_original.py b/backend/build_exe_original.py deleted file mode 100644 index d1f0abae..00000000 --- a/backend/build_exe_original.py +++ /dev/null @@ -1,524 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -后端应用程序打包脚本 -使用PyInstaller将Flask应用程序打包成独立的exe文件 -""" - -import os -import sys -import shutil -import subprocess -from pathlib import Path - -def create_spec_file(): - """创建PyInstaller spec文件""" - spec_content = ''' -# -*- mode: python ; coding: utf-8 -*- - -block_cipher = None - -a = Analysis( - ['main_exe.py'], - pathex=[], - binaries=[ - ('dll/femtobolt/bin/k4a.dll', '.'), # K4A动态库 - ('dll/femtobolt/bin/k4arecord.dll', '.'), # K4A录制库 - ('dll/femtobolt/bin/depthengine_2_0.dll', '.'), # 深度引擎 - ('dll/femtobolt/bin/OrbbecSDK.dll', '.'), # Orbbec SDK - ('dll/femtobolt/bin/ob_usb.dll', '.'), # Orbbec USB库 - ('dll/femtobolt/bin/live555.dll', '.'), # Live555库 - ('dll/smitsense/SMiTSenseUsb-F3.0.dll', '.'), # SMiTSense传感器库 - ('dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml', '.'), # Orbbec配置文件 - ], - datas=[ - ('..\\config.ini', '.'), # 配置文件 - ('..\\config.json', '.'), # JSON配置文件 - ('tests', 'tests'), # 测试文件夹 - ('data', 'data'), # 数据文件夹 - ], - hiddenimports=[ - 'flask', - 'flask_socketio', - 'flask_cors', - 'cv2', - 'numpy', - 'pandas', - 'scipy', - 'matplotlib', - 'seaborn', - 'sklearn', - 'PIL', - 'reportlab', - 'sqlite3', - 'configparser', - 'logging', - 'threading', - 'queue', - 'base64', - 'psutil', - 'pykinect_azure', - 'pyserial', - 'requests', - 'yaml', - 'click', - 'colorama', - 'tqdm', - '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=None, # 图标文件不存在,暂时禁用 -) -''' - - with open('backend.spec', 'w', encoding='utf-8') as f: - f.write(spec_content) - print("✓ 已创建 backend.spec 文件") - -def create_debug_spec(): - """创建诊断脚本的spec文件""" - import subprocess - - spec_content = f'''# -*- mode: python ; coding: utf-8 -*- - -block_cipher = None - -a = Analysis( - ['test_socketio_debug.py'], - pathex=['{os.getcwd()}'], - binaries=[], - datas=[], - hiddenimports=[ - 'flask', - 'flask_socketio', - 'eventlet', - 'threading', - 'engineio.async_drivers.threading', - 'engineio.async_drivers.eventlet', - 'engineio.async_eventlet', - 'socketio.async_eventlet', - 'greenlet', - ], - 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='test_socketio_debug', - 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, -) -''' - - with open('debug.spec', 'w', encoding='utf-8') as f: - f.write(spec_content) - print("✓ 已创建 debug.spec 文件") - - # 直接构建诊断exe - print("开始构建诊断exe文件...") - result = subprocess.run([sys.executable, '-m', 'PyInstaller', 'debug.spec'], - capture_output=True, text=True, encoding='utf-8') - - if result.returncode == 0: - print("✓ 诊断exe构建成功!") - print("运行诊断: dist/test_socketio_debug.exe") - else: - print(f"❌ 诊断exe构建失败: {result.stderr}") - -def create_minimal_spec(): - """创建最小化测试脚本的spec文件""" - print("创建最小化测试脚本的spec文件...") - - spec_content = '''# -*- mode: python ; coding: utf-8 -*- - -block_cipher = None - -a = Analysis( - ['test_socketio_minimal.py'], - pathex=[], - binaries=[], - datas=[], - hiddenimports=[ - 'flask', - 'flask_socketio', - 'eventlet', - 'eventlet.hubs', - 'eventlet.hubs.epolls', - 'eventlet.hubs.kqueue', - 'eventlet.hubs.selects', - 'threading', - 'engineio', - 'engineio.async_drivers', - 'engineio.async_drivers.threading', - 'engineio.async_drivers.eventlet', - 'engineio.async_drivers.gevent', - 'socketio', - 'socketio.namespace' - ], - 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='test_socketio_minimal', - 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, -) -''' - - with open('minimal.spec', 'w', encoding='utf-8') as f: - f.write(spec_content) - - print("✓ 已创建 minimal.spec 文件") - - # 直接构建 - print("开始构建最小化测试exe...") - result = subprocess.run([sys.executable, '-m', 'PyInstaller', 'minimal.spec', '--clean'], - capture_output=True, text=True, encoding='utf-8') - if result.returncode == 0: - print("✓ 最小化测试exe构建完成: dist/test_socketio_minimal.exe") - else: - print(f"❌ 最小化测试exe构建失败: {result.stderr}") - -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 - ) - - 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 check_dependencies(): - """检查必需的依赖模块""" - required_modules = [ - 'flask', 'flask_cors', 'flask_socketio', 'numpy', 'pandas', - 'cv2', 'matplotlib', 'seaborn', 'PIL', 'reportlab', - 'serial', 'requests', 'sqlite3', 'configparser', 'scipy', 'eventlet' - ] - - missing_modules = [] - for module in required_modules: - try: - __import__(module) - print(f"✓ {module}") - except ImportError: - missing_modules.append(module) - print(f"❌ {module} - 未安装") - - if missing_modules: - print(f"\n警告: 发现 {len(missing_modules)} 个缺失的依赖模块") - print("建议运行: pip install -r requirements.txt") - return False - - print("✓ 所有必需依赖模块检查通过") - return True - -def build_exe(): - """构建exe文件""" - print("开始构建exe文件...") - - # 检查依赖模块 - print("\n检查依赖模块...") - if not check_dependencies(): - print("\n❌ 依赖检查失败,请先安装缺失的模块") - return False - - # 检查PyInstaller是否安装 - try: - import PyInstaller - print(f"\n✓ 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 check_required_files(): - """检查必需的文件是否存在""" - required_files = { - 'app.py': '主应用文件', - 'database.py': '数据库模块', - 'device_manager.py': '设备管理模块', - 'utils.py': '工具模块', - '../config.ini': '配置文件', - '../config.json': 'JSON配置文件' - } - - required_dlls = { - 'dll/femtobolt/bin/k4a.dll': 'K4A动态库', - 'dll/femtobolt/bin/k4arecord.dll': 'K4A录制库', - 'dll/femtobolt/bin/depthengine_2_0.dll': '深度引擎', - 'dll/femtobolt/bin/OrbbecSDK.dll': 'Orbbec SDK', - 'dll/femtobolt/bin/ob_usb.dll': 'Orbbec USB库', - 'dll/femtobolt/bin/live555.dll': 'Live555库', - 'dll/smitsense/SMiTSenseUsb-F3.0.dll': 'SMiTSense传感器库', - 'dll/femtobolt/bin/OrbbecSDKConfig_v1.0.xml': 'Orbbec配置文件' - } - - missing_files = [] - - print("检查必需文件...") - for file_path, description in required_files.items(): - if os.path.exists(file_path): - print(f"✓ {description}: {file_path}") - else: - missing_files.append((file_path, description)) - print(f"❌ {description}: {file_path} - 文件不存在") - - print("\n检查DLL文件...") - for dll_path, description in required_dlls.items(): - if os.path.exists(dll_path): - print(f"✓ {description}: {dll_path}") - else: - missing_files.append((dll_path, description)) - print(f"❌ {description}: {dll_path} - 文件不存在") - - if missing_files: - print(f"\n警告: 发现 {len(missing_files)} 个缺失文件") - print("缺失的文件可能导致打包失败或运行时错误") - return False - - print("\n✓ 所有必需文件检查通过") - return True - -def main(): - """主函数""" - print("=" * 50) - print("身体平衡评估系统 - 后端打包工具") - print("=" * 50) - print() - - # 检查当前目录 - if not os.path.exists('app.py'): - print("❌ 请在backend目录下运行此脚本") - return - - # 检查必需文件 - print("\n检查必需文件...") - if not check_required_files(): - print("\n⚠️ 文件检查发现问题,但将继续执行打包") - print("如果打包失败,请检查上述缺失的文件") - input("按回车键继续...") - - try: - # 创建配置文件 - create_spec_file() - # create_main_entry() # 注释掉以保留现有的main_exe.py修改 - - # 临时:为诊断脚本创建spec文件 - if len(sys.argv) > 1 and sys.argv[1] == 'debug': - create_debug_spec() - return - elif len(sys.argv) > 1 and sys.argv[1] == 'minimal': - create_minimal_spec() - return - - # 构建exe - if build_exe(): - print("\n✅ 所有操作完成!") - else: - print("\n❌ 构建过程中出现错误") - - except Exception as e: - print(f"❌ 错误: {e}") - - input("\n按回车键退出...") - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/backend/build_minimal.py b/backend/build_minimal.py deleted file mode 100644 index 5271ac31..00000000 --- a/backend/build_minimal.py +++ /dev/null @@ -1,244 +0,0 @@ -#!/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() \ No newline at end of file diff --git a/frontend/src/renderer/dist-electron/win-unpacked/resources/backend/Log/OrbbecSDK.log.txt b/frontend/src/renderer/dist-electron/win-unpacked/resources/backend/Log/OrbbecSDK.log.txt new file mode 100644 index 00000000..94749615 --- /dev/null +++ b/frontend/src/renderer/dist-electron/win-unpacked/resources/backend/Log/OrbbecSDK.log.txt @@ -0,0 +1,60 @@ +[08/15 11:08:00.007828][debug][1996][Context.cpp:30] Context creating, work_dir=D:\Trae_space\BodyBalanceEvaluation\backend\dist +[08/15 11:08:00.007990][debug][1996][Context.cpp:49] Config file version=1.1 +[08/15 11:08:00.008057][debug][1996][FrameBufferManager.cpp:23] Max global frame buffer size updated! size=2048.000MB +[08/15 11:08:00.008095][info][1996][Context.cpp:68] Context created with config: default config! +[08/15 11:08:00.008265][info][1996][Context.cpp:73] Work directory=D:\Trae_space\BodyBalanceEvaluation\backend\dist, SDK version=v1.10.11-20240724-aeaa107e5 +[08/15 11:08:00.008455][debug][1996][DeviceManager.cpp:30] DeviceManager init ... +[08/15 11:08:00.008674][info][1996][MfPal.cpp:105] createObPal: create WinPal! +[08/15 11:08:00.008795][debug][1996][MfPal.cpp:110] WmfPal init ... +[08/15 11:08:00.039058][debug][1996][MfPal.cpp:117] WmfPal created! +[08/15 11:08:00.039105][debug][1996][DeviceManager.cpp:34] Enable USB Device Enumerator ... +[08/15 11:08:00.066384][debug][1996][EnumeratorLibusb.cpp:321] queryDevicesInfo done! +[08/15 11:08:00.066623][debug][1996][MfPal.cpp:216] Create WinEventDeviceWatcher! +[08/15 11:08:00.066791][debug][1996][UsbDeviceEnumerator.cpp:78] No matched usb device found! +[08/15 11:08:00.066833][info][1996][DeviceManager.cpp:15] Current found device(s): (0) +[08/15 11:08:00.066975][debug][1996][DeviceManager.cpp:52] DeviceManager construct done! +[08/15 11:08:00.067012][debug][1996][Context.cpp:81] Context destroying ... +[08/15 11:08:00.067024][debug][1996][DeviceManager.cpp:56] DeviceManager destroy ... +[08/15 11:08:00.067033][debug][1996][DeviceManager.cpp:64] DeviceManager Destructors done +[08/15 11:08:00.214042][debug][1996][MfPal.cpp:128] WmfPal destroyed! +[08/15 11:08:00.214700][info][1996][Context.cpp:84] Context destroyed +[08/15 11:11:00.761881][debug][12088][Context.cpp:30] Context creating, work_dir=D:\Trae_space\BodyBalanceEvaluation\backend\dist +[08/15 11:11:00.762009][debug][12088][Context.cpp:49] Config file version=1.1 +[08/15 11:11:00.762057][debug][12088][FrameBufferManager.cpp:23] Max global frame buffer size updated! size=2048.000MB +[08/15 11:11:00.762081][info][12088][Context.cpp:68] Context created with config: default config! +[08/15 11:11:00.762166][info][12088][Context.cpp:73] Work directory=D:\Trae_space\BodyBalanceEvaluation\backend\dist, SDK version=v1.10.11-20240724-aeaa107e5 +[08/15 11:11:00.762526][debug][12088][DeviceManager.cpp:30] DeviceManager init ... +[08/15 11:11:00.762542][info][12088][MfPal.cpp:105] createObPal: create WinPal! +[08/15 11:11:00.763193][debug][12088][MfPal.cpp:110] WmfPal init ... +[08/15 11:11:00.790457][debug][12088][MfPal.cpp:117] WmfPal created! +[08/15 11:11:00.790495][debug][12088][DeviceManager.cpp:34] Enable USB Device Enumerator ... +[08/15 11:11:00.815795][debug][12088][EnumeratorLibusb.cpp:321] queryDevicesInfo done! +[08/15 11:11:00.816035][debug][12088][MfPal.cpp:216] Create WinEventDeviceWatcher! +[08/15 11:11:00.816179][debug][12088][UsbDeviceEnumerator.cpp:78] No matched usb device found! +[08/15 11:11:00.816215][info][12088][DeviceManager.cpp:15] Current found device(s): (0) +[08/15 11:11:00.816652][debug][12088][DeviceManager.cpp:52] DeviceManager construct done! +[08/15 11:11:00.816690][debug][12088][Context.cpp:81] Context destroying ... +[08/15 11:11:00.816703][debug][12088][DeviceManager.cpp:56] DeviceManager destroy ... +[08/15 11:11:00.816712][debug][12088][DeviceManager.cpp:64] DeviceManager Destructors done +[08/15 11:11:00.960762][debug][12088][MfPal.cpp:128] WmfPal destroyed! +[08/15 11:11:00.961818][info][12088][Context.cpp:84] Context destroyed +[08/15 11:17:16.080184][debug][27992][Context.cpp:30] Context creating, work_dir=D:\Trae_space\BodyBalanceEvaluation\frontend\src\renderer\dist-electron\win-unpacked\resources\backend +[08/15 11:17:16.080326][debug][27992][Context.cpp:49] Config file version=1.1 +[08/15 11:17:16.080380][debug][27992][FrameBufferManager.cpp:23] Max global frame buffer size updated! size=2048.000MB +[08/15 11:17:16.080407][info][27992][Context.cpp:68] Context created with config: default config! +[08/15 11:17:16.080471][info][27992][Context.cpp:73] Work directory=D:\Trae_space\BodyBalanceEvaluation\frontend\src\renderer\dist-electron\win-unpacked\resources\backend, SDK version=v1.10.11-20240724-aeaa107e5 +[08/15 11:17:16.080501][debug][27992][DeviceManager.cpp:30] DeviceManager init ... +[08/15 11:17:16.080518][info][27992][MfPal.cpp:105] createObPal: create WinPal! +[08/15 11:17:16.080537][debug][27992][MfPal.cpp:110] WmfPal init ... +[08/15 11:17:16.106317][debug][27992][MfPal.cpp:117] WmfPal created! +[08/15 11:17:16.106358][debug][27992][DeviceManager.cpp:34] Enable USB Device Enumerator ... +[08/15 11:17:16.132353][debug][27992][EnumeratorLibusb.cpp:321] queryDevicesInfo done! +[08/15 11:17:16.132619][debug][27992][MfPal.cpp:216] Create WinEventDeviceWatcher! +[08/15 11:17:16.132822][debug][27992][UsbDeviceEnumerator.cpp:78] No matched usb device found! +[08/15 11:17:16.132867][info][27992][DeviceManager.cpp:15] Current found device(s): (0) +[08/15 11:17:16.132889][debug][27992][DeviceManager.cpp:52] DeviceManager construct done! +[08/15 11:17:16.132917][debug][27992][Context.cpp:81] Context destroying ... +[08/15 11:17:16.132929][debug][27992][DeviceManager.cpp:56] DeviceManager destroy ... +[08/15 11:17:16.132938][debug][27992][DeviceManager.cpp:64] DeviceManager Destructors done +[08/15 11:17:16.274031][debug][27992][MfPal.cpp:128] WmfPal destroyed! +[08/15 11:17:16.274987][info][27992][Context.cpp:84] Context destroyed diff --git a/frontend/src/renderer/dist-electron/win-unpacked/resources/backend/dll/smitsense/SMiTSenseUsbWrapper.dll b/frontend/src/renderer/dist-electron/win-unpacked/resources/backend/dll/smitsense/SMiTSenseUsbWrapper.dll new file mode 100644 index 00000000..04eb4e48 Binary files /dev/null and b/frontend/src/renderer/dist-electron/win-unpacked/resources/backend/dll/smitsense/SMiTSenseUsbWrapper.dll differ diff --git a/frontend/src/renderer/dist-electron/win-unpacked/resources/backend/start_backend.bat b/frontend/src/renderer/dist-electron/win-unpacked/resources/backend/start_backend.bat new file mode 100644 index 00000000..aa7d1cdc --- /dev/null +++ b/frontend/src/renderer/dist-electron/win-unpacked/resources/backend/start_backend.bat @@ -0,0 +1,16 @@ +@echo off +echo 启动身体平衡评估系统后端服务(完整版)... +echo. +echo 服务信息: +echo - HTTP API: http://localhost:5000 +echo - SocketIO: ws://localhost:5000 +echo - 管理界面: http://localhost:5000 +echo. +echo 按Ctrl+C停止服务 +echo. +"BodyBalanceBackend.exe" +if %errorlevel% neq 0 ( + echo. + echo 服务启动失败,请检查错误信息 + pause +) diff --git a/frontend/src/renderer/package-lock.json b/frontend/src/renderer/package-lock.json index 2590b83c..f520bf5c 100644 --- a/frontend/src/renderer/package-lock.json +++ b/frontend/src/renderer/package-lock.json @@ -12,6 +12,7 @@ "axios": "^1.5.0", "echarts": "^5.4.3", "element-plus": "^2.3.9", + "html2canvas": "^1.4.1", "pinia": "^2.1.6", "socket.io-client": "^4.7.2", "vue": "^3.3.4", @@ -1728,6 +1729,15 @@ "dev": true, "license": "MIT" }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", @@ -2330,6 +2340,15 @@ "node": ">= 10" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", @@ -3872,6 +3891,19 @@ "node": ">=10" } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http-cache-semantics": { "version": "4.2.0", "resolved": "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", @@ -5749,6 +5781,15 @@ "node": ">= 10.0.0" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/tmp": { "version": "0.2.5", "resolved": "https://registry.npmmirror.com/tmp/-/tmp-0.2.5.tgz", @@ -5888,6 +5929,15 @@ "license": "MIT", "peer": true }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/frontend/src/renderer/package.json b/frontend/src/renderer/package.json index b63041fb..d7bd6c7b 100644 --- a/frontend/src/renderer/package.json +++ b/frontend/src/renderer/package.json @@ -19,6 +19,7 @@ "axios": "^1.5.0", "echarts": "^5.4.3", "element-plus": "^2.3.9", + "html2canvas": "^1.4.1", "pinia": "^2.1.6", "socket.io-client": "^4.7.2", "vue": "^3.3.4", @@ -53,7 +54,9 @@ { "from": "../../../backend/dist", "to": "resources/backend", - "filter": ["**/*"] + "filter": [ + "**/*" + ] } ], "win": {