BodyBalanceEvaluation/backend/app.py

1026 lines
35 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
平衡体态检测系统 - 后端服务
基于Flask的本地API服务
"""
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
from flask_socketio import SocketIO, emit
import cv2
import configparser
import os
# 添加当前目录到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'
socketio = SocketIO(app,
cors_allowed_origins='*',
async_mode='threading',
logger=True,
engineio_logger=True)
# 启用CORS支持
CORS(app, origins='*', supports_credentials=True, allow_headers=['Content-Type', 'Authorization'], methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'])
# 注册Blueprint如需要可在此处添加
# 读取RTSP配置
config = configparser.ConfigParser()
config.read(os.path.join(os.path.dirname(__file__), '..', 'config.ini'), encoding='utf-8')
device_index = config.get('CAMERA', 'device_index', fallback=None)
# 全局变量
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:
# 创建必要的目录
os.makedirs('logs', exist_ok=True)
os.makedirs('data', exist_ok=True)
# 从配置文件读取数据库路径
db_path_config = app_config.get('DATABASE', 'path', 'backend/data/body_balance.db')
# 如果是相对路径,基于当前脚本目录解析
if not os.path.isabs(db_path_config):
# 获取当前脚本所在目录backend目录
current_dir = os.path.dirname(os.path.abspath(__file__))
# 如果配置路径以 'backend/' 开头,去掉这个前缀
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)
# 初始化数据库
db_manager = DatabaseManager(db_path)
db_manager.init_database()
# 初始化设备管理器
device_manager = DeviceManager(db_manager)
device_manager.set_socketio(socketio) # 设置WebSocket连接
# 初始化视频流管理器
video_stream_manager = VideoStreamManager(socketio)
logger.info('应用初始化完成')
except Exception as e:
logger.error(f'应用初始化失败: {e}')
raise
# ==================== 基础API ====================
@app.route('/health', methods=['GET'])
def health_check():
"""健康检查"""
return jsonify({
'status': 'ok',
'timestamp': datetime.now().isoformat(),
'version': '1.0.0'
})
@app.route('/api/health', methods=['GET'])
def api_health_check():
"""API健康检查"""
return jsonify({
'status': 'ok',
'timestamp': datetime.now().isoformat(),
'version': '1.0.0'
})
# ==================== 认证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
# 使用数据库验证用户
user = db_manager.authenticate_user(username, password)
if user:
# 检查用户是否已激活
if not user['is_active']:
return jsonify({
'success': False,
'message': '账户未激活,请联系管理员审核'
}), 403
# 构建用户数据
user_data = {
'id': user['id'],
'username': user['username'],
'name': user['name'],
'role': 'admin' if user['user_type'] == 'admin' else 'user',
'user_type': user['user_type'],
'avatar': ''
}
# 生成token实际项目中应使用JWT等安全token
token = f"token_{username}_{int(time.time())}"
logger.info(f'用户 {username} 登录成功')
return jsonify({
'success': True,
'data': {
'token': token,
'user': user_data
},
'message': '登录成功'
})
else:
logger.warning(f'用户 {username} 登录失败:用户名或密码错误')
return jsonify({
'success': False,
'message': '用户名或密码错误'
}), 401
except Exception as e:
logger.error(f'登录失败: {e}')
return jsonify({'success': False, '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')
name = data.get('name') or data.get('email', '')
phone = data.get('phone')
if not username or not password:
return jsonify({
'success': False,
'message': '用户名和密码不能为空'
}), 400
if len(password) < 6:
return jsonify({
'success': False,
'message': '密码长度不能少于6位'
}), 400
# 构建用户数据字典
user_data = {
'username': username,
'password': password,
'name': name,
'phone': phone
}
# 使用数据库注册用户
result = db_manager.register_user(user_data)
if result['success']:
logger.info(f'用户 {username} 注册成功,等待管理员审核')
return jsonify({
'success': True,
'message': '注册成功,请等待管理员审核后登录'
})
else:
return jsonify({
'success': False,
'message': result['message']
}), 400
except Exception as e:
logger.error(f'注册失败: {e}')
return jsonify({'success': False, 'message': '注册失败'}), 500
@app.route('/api/auth/logout', methods=['POST'])
def logout():
"""用户退出"""
try:
return jsonify({
'success': True,
'message': '退出成功'
})
except Exception as e:
logger.error(f'退出失败: {e}')
return jsonify({'success': False, 'message': '退出失败'}), 500
@app.route('/api/auth/verify', methods=['GET'])
def verify_token():
"""验证token"""
try:
# 简单的token验证实际项目中应验证JWT等
auth_header = flask_request.headers.get('Authorization')
if auth_header and auth_header.startswith('Bearer '):
token = auth_header.split(' ')[1]
# 这里可以添加真实的token验证逻辑
return jsonify({
'success': True,
'data': {'valid': True}
})
else:
return jsonify({
'success': True,
'data': {'valid': True} # 暂时总是返回有效
})
except Exception as e:
logger.error(f'验证token失败: {e}')
return jsonify({'success': False, 'message': '验证失败'}), 500
@app.route('/api/auth/forgot-password', methods=['POST'])
def forgot_password():
"""忘记密码 - 根据用户名和手机号找回密码"""
try:
data = flask_request.get_json()
username = data.get('username')
phone = data.get('phone')
if not username:
return jsonify({
'success': False,
'error': '请输入用户名'
}), 400
if not phone:
return jsonify({
'success': False,
'error': '请输入手机号码'
}), 400
# 验证手机号格式
import re
phone_pattern = r'^1[3-9]\d{9}$'
if not re.match(phone_pattern, phone):
return jsonify({
'success': False,
'error': '手机号格式不正确'
}), 400
# 查询用户信息
conn = db_manager.get_connection()
cursor = conn.cursor()
cursor.execute('''
SELECT username, password, phone FROM users
WHERE username = ? AND phone = ?
''', (username, phone))
user = cursor.fetchone()
if user:
# 用户存在且手机号匹配,返回数据库中存储的实际密码
actual_password = user['password']
logger.info(f'用户 {username} 密码查询成功')
return jsonify({
'success': True,
'password': actual_password, # 返回数据库中存储的实际密码
'message': '密码找回成功'
})
else:
# 检查用户是否存在
cursor.execute('SELECT username FROM users WHERE username = ?', (username,))
user_exists = cursor.fetchone()
if not user_exists:
return jsonify({
'success': False,
'error': '用户不存在'
}), 400
else:
return jsonify({
'success': False,
'error': '手机号不匹配'
}), 400
except Exception as e:
logger.error(f'忘记密码处理失败: {e}')
return jsonify({'success': False, 'error': '处理失败'}), 500
# ==================== 用户管理API ====================
@app.route('/api/users', methods=['GET'])
def get_users():
"""获取用户列表(管理员功能)"""
try:
# 这里应该验证管理员权限
page = int(flask_request.args.get('page', 1))
size = int(flask_request.args.get('size', 10))
status = flask_request.args.get('status') # active, inactive, all
users = db_manager.get_users(page, size, status)
total = db_manager.get_users_count(status)
return jsonify({
'success': True,
'data': {
'users': users,
'total': total,
'page': page,
'size': size
}
})
except Exception as e:
logger.error(f'获取用户列表失败: {e}')
return jsonify({'success': False, 'message': '获取用户列表失败'}), 500
@app.route('/api/users/<int:user_id>/approve', methods=['POST'])
def approve_user(user_id):
"""审核用户(管理员功能)"""
try:
# 这里应该验证管理员权限
data = flask_request.get_json()
approve = data.get('approve', True)
result = db_manager.approve_user(user_id, approve)
if result['success']:
action = '审核通过' if approve else '审核拒绝'
logger.info(f'用户 {user_id} {action}')
return jsonify({
'success': True,
'message': f'用户{action}成功'
})
else:
return jsonify({
'success': False,
'message': result['message']
}), 400
except Exception as e:
logger.error(f'审核用户失败: {e}')
return jsonify({'success': False, 'message': '审核用户失败'}), 500
@app.route('/api/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
"""删除用户(管理员功能)"""
try:
# 这里应该验证管理员权限
result = db_manager.delete_user(user_id)
if result['success']:
logger.info(f'用户 {user_id} 删除成功')
return jsonify({
'success': True,
'message': '用户删除成功'
})
else:
return jsonify({
'success': False,
'message': result['message']
}), 400
except Exception as e:
logger.error(f'删除用户失败: {e}')
return jsonify({'success': False, 'message': '删除用户失败'}), 500
@app.route('/api/system/info', methods=['GET'])
def get_system_info():
"""获取系统信息"""
try:
info = {
'version': '1.0.0',
'start_time': datetime.now().isoformat(),
'database_status': 'connected' if db_manager else 'disconnected',
'device_count': len(device_manager.get_connected_devices()) if device_manager else 0
}
return jsonify({'success': True, 'data': info})
except Exception as e:
logger.error(f'获取系统信息失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
# ==================== 患者管理API ====================
@app.route('/api/patients', methods=['GET'])
def get_patients():
"""获取患者列表"""
try:
page = int(flask_request.args.get('page', 1))
size = int(flask_request.args.get('size', 10))
keyword = flask_request.args.get('keyword', '')
patients = db_manager.get_patients(page, size, keyword)
total = db_manager.get_patients_count(keyword)
return jsonify({
'success': True,
'data': {
'patients': patients,
'total': total,
'page': page,
'size': size
}
})
except Exception as e:
logger.error(f'获取患者列表失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/patients', methods=['POST'])
def create_patient():
"""创建患者"""
try:
data = flask_request.get_json()
patient_id = db_manager.create_patient(data)
return jsonify({
'success': True,
'data': {'patient_id': patient_id},
'message': '患者创建成功'
})
except Exception as e:
logger.error(f'创建患者失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/patients/<patient_id>', methods=['PUT'])
def update_patient(patient_id):
"""更新患者信息"""
try:
data = flask_request.get_json()
db_manager.update_patient(patient_id, data)
return jsonify({'success': True, 'message': '患者信息更新成功'})
except Exception as e:
logger.error(f'更新患者信息失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/patients/<patient_id>', methods=['GET'])
def get_patient(patient_id):
"""获取单个患者信息"""
try:
patient = db_manager.get_patient(patient_id)
if patient:
return jsonify({'success': True, 'data': patient})
else:
return jsonify({'success': False, 'error': '患者不存在'}), 404
except Exception as e:
logger.error(f'获取患者信息失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/patients/<patient_id>', methods=['DELETE'])
def delete_patient(patient_id):
"""删除患者"""
try:
db_manager.delete_patient(patient_id)
return jsonify({'success': True, 'message': '患者删除成功'})
except Exception as e:
logger.error(f'删除患者失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
# ==================== 设备管理API ====================
@app.route('/api/devices/status', methods=['GET'])
def get_device_status():
"""获取设备状态"""
try:
if not device_manager:
return jsonify({'camera': False, 'imu': False, 'pressure': False})
status = device_manager.get_device_status()
return jsonify(status)
except Exception as e:
logger.error(f'获取设备状态失败: {e}')
return jsonify({'camera': False, 'imu': False, 'pressure': False})
@app.route('/api/devices/refresh', methods=['POST'])
def refresh_devices():
"""刷新设备连接"""
try:
if device_manager:
device_manager.refresh_devices()
return jsonify({'success': True, 'message': '设备已刷新'})
except Exception as e:
logger.error(f'刷新设备失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/devices/calibrate', methods=['POST'])
def calibrate_devices():
"""校准设备"""
try:
if device_manager:
result = device_manager.calibrate_devices()
return jsonify({'success': True, 'data': result})
return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500
except Exception as e:
logger.error(f'设备校准失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
# ==================== 视频推流API ====================
@app.route('/api/streaming/start', methods=['POST'])
def start_video_streaming():
"""启动视频推流"""
try:
if not device_manager:
return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500
# 设置WebSocket连接
device_manager.set_socketio(socketio)
result = device_manager.start_streaming()
logger.info(f'视频推流启动结果: {result}')
return jsonify({
'success': True,
'message': '视频推流已启动',
'streaming_status': result
})
except Exception as e:
logger.error(f'启动视频推流失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/streaming/stop', methods=['POST'])
def stop_video_streaming():
"""停止视频推流"""
try:
if not device_manager:
return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500
result = device_manager.stop_streaming()
if result:
logger.info('视频推流已停止')
return jsonify({
'success': True,
'message': '视频推流已停止'
})
else:
return jsonify({
'success': False,
'error': '停止推流失败'
}), 500
except Exception as e:
logger.error(f'停止视频推流失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
# ==================== 检测API ====================
@app.route('/api/detection/start', methods=['POST'])
def start_detection():
"""开始检测"""
try:
if not db_manager:
return jsonify({'success': False, 'error': '数据库管理器未初始化'}), 500
data = flask_request.get_json()
patient_id = data.get('patientId') or data.get('patient_id')
settings = data.get('settings', '{}')
creator_id = data.get('creator_id')
if not patient_id:
return jsonify({
'success': False,
'error': '缺少必要参数: patient_id'
}), 400
# 解析设置参数
if isinstance(settings, str):
try:
settings = json.loads(settings)
except json.JSONDecodeError:
settings = {}
# 创建检测会话
session_id = db_manager.create_detection_session(
patient_id=str(patient_id),
settings=settings,
creator_id=creator_id
)
if session_id:
logger.info(f'检测会话已创建 - 会话ID: {session_id}, 患者ID: {patient_id}')
return jsonify({
'success': True,
'session_id': session_id,
'message': '检测会话创建成功'
})
else:
return jsonify({
'success': False,
'error': '创建检测会话失败'
}), 500
except Exception as e:
logger.error(f'开始检测失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/detection/<session_id>/stop', methods=['POST'])
def stop_detection(session_id):
"""停止检测"""
try:
if not db_manager:
return jsonify({'success': False, 'error': '数据库管理器未初始化'}), 500
if not session_id:
return jsonify({
'success': False,
'error': '缺少会话ID'
}), 400
# 更新会话状态为已完成
success = db_manager.update_session_status(session_id, 'completed')
if success:
logger.info(f'检测会话已停止 - 会话ID: {session_id}')
return jsonify({
'success': True,
'message': '检测已停止'
})
else:
return jsonify({
'success': False,
'error': '停止检测失败'
}), 500
except Exception as e:
logger.error(f'停止检测失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/detection/<session_id>/status', methods=['GET'])
def get_detection_status(session_id):
"""获取检测状态"""
try:
if not db_manager:
return jsonify({'success': False, 'error': '数据库管理器未初始化'}), 500
if not session_id:
return jsonify({
'success': False,
'error': '缺少会话ID'
}), 400
# 获取会话数据
session_data = db_manager.get_session_data(session_id)
if session_data:
return jsonify({
'success': True,
'data': session_data
})
else:
return jsonify({
'success': False,
'error': '会话不存在'
}), 404
except Exception as e:
logger.error(f'获取检测状态失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/detection/<session_id>/collect', methods=['POST'])
def collect_detection_data(session_id):
"""采集检测数据"""
try:
if not db_manager:
return jsonify({'success': False, 'error': '数据库管理器未初始化'}), 500
if not device_manager:
return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500
# 获取请求数据
data = flask_request.get_json() or {}
patient_id = data.get('patient_id')
screen_image_base64 = data.get('screen_image')
# 如果没有提供patient_id从会话信息中获取
if not patient_id:
session_data = db_manager.get_session_data(session_id)
if not session_data:
return jsonify({
'success': False,
'error': '检测会话不存在'
}), 404
patient_id = session_data.get('patient_id')
if not patient_id:
return jsonify({
'success': False,
'error': '无法获取患者ID'
}), 400
# 调用设备管理器采集数据
collected_data = device_manager.collect_data(
session_id=session_id,
patient_id=patient_id,
screen_image_base64=screen_image_base64
)
# 将采集的数据保存到数据库
if collected_data:
db_manager.save_detection_data(session_id, collected_data)
logger.info(f'检测数据采集并保存成功: {session_id}')
return jsonify({
'success': True,
'data': {
'session_id': session_id,
'timestamp': collected_data.get('timestamp'),
'data_collected': bool(collected_data)
},
'message': '数据采集成功'
})
except Exception as e:
logger.error(f'采集检测数据失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
# ==================== 同步录制API ====================
@app.route('/api/recording/sync/start', methods=['POST'])
def start_sync_recording():
"""启动同步录制"""
try:
if not device_manager:
return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500
data = flask_request.get_json()
session_id = data.get('session_id')
patient_id = data.get('patient_id')
if not session_id or not patient_id:
return jsonify({
'success': False,
'error': '缺少必要参数: session_id 和 patient_id'
}), 400
result = device_manager.start_recording(session_id, patient_id)
if result['success']:
logger.info(f'同步录制已启动 - 会话ID: {session_id}, 患者ID: {patient_id}')
return jsonify(result)
else:
return jsonify(result), 500
except Exception as e:
logger.error(f'启动同步录制失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/recording/sync/stop', methods=['POST'])
def stop_sync_recording():
"""停止同步录制"""
try:
if not device_manager:
return jsonify({'success': False, 'error': '设备管理器未初始化'}), 500
data = flask_request.get_json()
session_id = data.get('session_id')
if not session_id:
return jsonify({
'success': False,
'error': '缺少必要参数: session_id'
}), 400
result = device_manager.stop_recording(session_id)
if result['success']:
logger.info(f'同步录制已停止 - 会话ID: {session_id}')
return jsonify(result)
else:
return jsonify(result), 500
except Exception as e:
logger.error(f'停止同步录制失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/history/sessions', methods=['GET'])
def get_detection_sessions():
"""获取检测会话历史"""
try:
page = int(flask_request.args.get('page', 1))
size = int(flask_request.args.get('size', 10))
patient_id = flask_request.args.get('patient_id')
sessions = db_manager.get_detection_sessions(page, size, patient_id)
total = db_manager.get_sessions_count(patient_id)
return jsonify({
'success': True,
'data': {
'sessions': sessions,
'total': total,
'page': page,
'size': size
}
})
except Exception as e:
logger.error(f'获取检测历史失败: {e}')
return jsonify({'success': False, 'error': str(e)}), 500
# ==================== 错误处理 ====================
@app.errorhandler(404)
def not_found(error):
return jsonify({'success': False, 'error': 'API接口不存在'}), 404
@app.errorhandler(500)
def internal_error(error):
return jsonify({'success': False, 'error': '服务器内部错误'}), 500
if __name__ == '__main__':
import argparse
# 解析命令行参数
parser = argparse.ArgumentParser(description='Body Balance Evaluation System Backend')
parser.add_argument('--host', default=None, help='Host address to bind to')
parser.add_argument('--port', type=int, default=None, help='Port number to bind to')
parser.add_argument('--debug', action='store_true', help='Enable debug mode')
args = parser.parse_args()
try:
# 初始化应用
init_app()
# 确定主机和端口
host = args.host if args.host else config.get('SERVER', 'host', fallback='127.0.0.1')
port = args.port if args.port else config.getint('SERVER', 'port', fallback=5000)
debug = args.debug if args.debug else config.getboolean('APP', 'debug', fallback=False)
# 启动Flask+SocketIO服务
logger.info(f'启动后端服务... Host: {host}, Port: {port}, Debug: {debug}')
socketio.run(app,
host=host,
port=port,
debug=debug,
use_reloader=False, # 禁用热重载以避免进程问题
log_output=True, # 启用详细日志
allow_unsafe_werkzeug=True
)
except KeyboardInterrupt:
logger.info('服务被用户中断')
except Exception as e:
logger.error(f'服务启动失败: {e}')
sys.exit(1)
finally:
logger.info('后端服务已停止')
# ==================== WebSocket 事件处理 ====================
# 简单的测试事件处理器
@socketio.on('connect')
def handle_connect():
print('CLIENT CONNECTED!!!', flush=True)
logger.info('客户端已连接')
@socketio.on('disconnect')
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):
try:
results = {'status': 'success', 'cameras': {}}
logger.info(f'video_stream_manager状态: {video_stream_manager is not None}')
logger.info(f'device_manager状态: {device_manager is not None}')
# 启动视频流管理器(普通摄像头)
if video_stream_manager:
logger.info('正在启动视频流管理器...')
video_result = video_stream_manager.start_video_stream()
logger.info(f'视频流管理器启动结果: {video_result}')
results['cameras']['normal'] = video_result
else:
logger.error('视频流管理器未初始化')
results['cameras']['normal'] = {'status': 'error', 'message': '视频流管理器未初始化'}
# 启动FemtoBolt深度相机
if device_manager:
logger.info('正在启动FemtoBolt深度相机...')
femtobolt_result = device_manager.start_femtobolt_stream()
logger.info(f'FemtoBolt启动结果: {femtobolt_result}')
if femtobolt_result:
results['cameras']['femtobolt'] = {'status': 'success', 'message': 'FemtoBolt深度相机推流已启动'}
else:
results['cameras']['femtobolt'] = {'status': 'error', 'message': 'FemtoBolt深度相机启动失败'}
else:
logger.error('设备管理器未初始化')
results['cameras']['femtobolt'] = {'status': 'error', 'message': '设备管理器未初始化'}
# 检查是否有任何相机启动成功
success_count = sum(1 for cam_result in results['cameras'].values() if cam_result.get('status') == 'success')
if success_count == 0:
results['status'] = 'error'
results['message'] = '所有相机启动失败'
elif success_count < len(results['cameras']):
results['status'] = 'partial'
results['message'] = f'{success_count}/{len(results["cameras"])}个相机启动成功'
else:
results['message'] = '所有相机启动成功'
logger.info(f'发送video_status事件: {results}')
emit('video_status', results)
except Exception as e:
logger.error(f'启动视频流失败: {e}', exc_info=True)
emit('video_status', {'status': 'error', 'message': f'启动失败: {str(e)}'})
@socketio.on('stop_video')
def handle_stop_video(data=None):
logger.info(f'收到stop_video事件数据: {data}')
try:
results = {'status': 'success', 'cameras': {}}
# 停止视频流管理器(普通摄像头)
if video_stream_manager:
video_result = video_stream_manager.stop_video_stream()
results['cameras']['normal'] = video_result
else:
results['cameras']['normal'] = {'status': 'error', 'message': '视频流管理器未初始化'}
# 停止FemtoBolt深度相机
if device_manager:
device_manager.stop_femtobolt_stream()
results['cameras']['femtobolt'] = {'status': 'success', 'message': 'FemtoBolt深度相机推流已停止'}
else:
results['cameras']['femtobolt'] = {'status': 'error', 'message': '设备管理器未初始化'}
# 检查是否有任何相机停止成功
success_count = sum(1 for cam_result in results['cameras'].values() if cam_result.get('status') == 'success')
if success_count == 0:
results['status'] = 'error'
results['message'] = '所有相机停止失败'
elif success_count < len(results['cameras']):
results['status'] = 'partial'
results['message'] = f'{success_count}/{len(results["cameras"])}个相机停止成功'
else:
results['message'] = '所有相机停止成功'
emit('video_status', results)
except Exception as e:
logger.error(f'停止视频流失败: {e}')
emit('video_status', {'status': 'error', 'message': f'停止失败: {str(e)}'})
# 重复的事件处理器已删除,使用前面定义的版本