diff --git a/backend/BUILD_README.md b/backend/BUILD_README.md new file mode 100644 index 00000000..d3b3c61f --- /dev/null +++ b/backend/BUILD_README.md @@ -0,0 +1,165 @@ +# 身体平衡评估系统 - 后端打包说明 + +本文档说明如何将后端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.py b/backend/app.py index 073c955d..61299597 100644 --- a/backend/app.py +++ b/backend/app.py @@ -44,11 +44,7 @@ logger = logging.getLogger(__name__) # 创建Flask应用 app = Flask(__name__) app.config['SECRET_KEY'] = 'body-balance-detection-system-2024' -socketio = SocketIO(app, - cors_allowed_origins='*', - async_mode='threading', - logger=True, - engineio_logger=True) +socketio = SocketIO(app, cors_allowed_origins='*') # 启用CORS支持 CORS(app, origins='*', supports_credentials=True, allow_headers=['Content-Type', 'Authorization'], methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']) @@ -559,7 +555,6 @@ def calibrate_devices(): # ==================== 视频推流API ==================== - @app.route('/api/streaming/start', methods=['POST']) def start_video_streaming(): """启动视频推流""" @@ -926,15 +921,6 @@ def handle_disconnect(): # print('CLIENT DISCONNECTED!!!', flush=True) # 控制台打印测试已关闭 logger.info('客户端已断开连接') -# @socketio.on('start_video') -# def handle_start_video_new(data=None): -# print('=== START VIDEO EVENT RECEIVED ===', flush=True) -# print(f'Data received: {data}', flush=True) -# logger.info('=== START VIDEO EVENT RECEIVED ===') -# logger.info(f'Data received: {data}') -# emit('video_status', {'status': 'received', 'message': 'start_video事件已接收'}) -# return {'status': 'success'} - # 原始的start_video处理逻辑(暂时注释) @socketio.on('start_video') def handle_start_video(data=None): @@ -1023,4 +1009,29 @@ def handle_stop_video(data=None): logger.error(f'停止视频流失败: {e}') emit('video_status', {'status': 'error', 'message': f'停止失败: {str(e)}'}) -# 重复的事件处理器已删除,使用前面定义的版本 \ No newline at end of file +# 重复的事件处理器已删除,使用前面定义的版本 + +if __name__ == '__main__': + """主入口点 - 用于直接运行和PyInstaller打包""" + try: + # 初始化应用 + init_app() + + # 启动服务器 + logger.info("启动身体平衡评估系统后端服务...") + 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) \ No newline at end of file diff --git a/backend/app_simple.py b/backend/app_simple.py new file mode 100644 index 00000000..87404f22 --- /dev/null +++ b/backend/app_simple.py @@ -0,0 +1,202 @@ +#!/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() + 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 new file mode 100644 index 00000000..64b32ed6 --- /dev/null +++ b/backend/backend.spec @@ -0,0 +1,69 @@ + +# -*- 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, +) diff --git a/backend/build_backend.bat b/backend/build_backend.bat new file mode 100644 index 00000000..bb742550 --- /dev/null +++ b/backend/build_backend.bat @@ -0,0 +1,64 @@ +@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 new file mode 100644 index 00000000..1f2f9677 --- /dev/null +++ b/backend/build_exe.py @@ -0,0 +1,257 @@ +#!/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() \ No newline at end of file diff --git a/backend/config.ini b/backend/config.ini new file mode 100644 index 00000000..812d421a --- /dev/null +++ b/backend/config.ini @@ -0,0 +1,41 @@ +[APP] +name = Body Balance Evaluation System +version = 1.0.0 +debug = false +log_level = INFO + +[SERVER] +host = 0.0.0.0 +port = 5000 +cors_origins = * + +[DATABASE] +path = backend/data/body_balance.db +backup_interval = 24 +max_backups = 7 + +[DEVICES] +camera_index = 0 +camera_width = 640 +camera_height = 480 +camera_fps = 30 +imu_port = COM3 +pressure_port = COM4 + +[DETECTION] +default_duration = 60 +sampling_rate = 30 +balance_threshold = 0.2 +posture_threshold = 5.0 + +[DATA_PROCESSING] +filter_window = 5 +outlier_threshold = 2.0 +chart_dpi = 300 +export_format = csv + +[SECURITY] +secret_key = 9179711d0d1bed10e105f39c9210cce273cbd73f85fbdfcd41e2d1e20d5c50bd +session_timeout = 3600 +max_login_attempts = 5 + diff --git a/backend/data/body_balance.db b/backend/data/body_balance.db index b902be8e..d5d3cd99 100644 Binary files a/backend/data/body_balance.db and b/backend/data/body_balance.db differ diff --git a/backend/main_exe.py b/backend/main_exe.py new file mode 100644 index 00000000..beb94852 --- /dev/null +++ b/backend/main_exe.py @@ -0,0 +1,71 @@ + +#!/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() diff --git a/backend/requirements_build.txt b/backend/requirements_build.txt new file mode 100644 index 00000000..1138f5be --- /dev/null +++ b/backend/requirements_build.txt @@ -0,0 +1,24 @@ +# 打包专用依赖文件 +# 只包含运行时必需的核心依赖 + +# Web framework +Flask==2.3.3 +Flask-CORS==4.0.0 +Flask-SocketIO==5.3.6 + +# Core dependencies +numpy==1.24.3 +opencv-python==4.8.1.78 +psutil==5.9.5 +requests==2.31.0 +python-dateutil==2.8.2 + +# PyInstaller for building +PyInstaller==6.2.0 + +# Optional - only if available +# pykinect_azure # Comment out if not available + +# System utilities +colorama==0.4.6 +click==8.1.7 \ No newline at end of file