242 lines
7.2 KiB
Python
242 lines
7.2 KiB
Python
#!/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) |