2025-08-06 09:04:13 +08:00
|
|
|
|
#!/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("设备管理器初始化成功")
|
|
|
|
|
|
|
|
|
|
# 初始化视频流管理器
|
2025-08-07 14:38:08 +08:00
|
|
|
|
video_stream_manager = VideoStreamManager(device_manager=device_manager)
|
2025-08-06 09:04:13 +08:00
|
|
|
|
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)
|