""" FAM-Core 主应用 - Flask 单进程(新架构 v2) 承载: Oracle-Sync(每 30 分钟拉取增量镜像)+ Member-Manager + Chat-Handler NAS 不再处理视频:无 Scheduler / Dispatcher / Poller / Event-Receiver / Video-Server。 所有视频分析在 Oracle 完成,NAS 仅作管理后台拉取展示,CPU 占用大幅降低。 """ import os import sys from flask import Flask, jsonify # 确保包路径 sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from .config_loader import load_config from .logger import setup_logger from .oracle_sync import get_sync from .motion_notifier.motion_notifier import get_motion_notifier from .chat_handler.chat_handler import chat_bp from .member_manager.member_manager import member_bp from .img_proxy import img_bp from .motion_bp import motion_bp from .ui_api import ui_bp from .static_app import static_bp logger = setup_logger('fam-core.app') app = Flask(__name__) # 注册蓝图:/api/* 系列必须先于 static_bp 注册——static_bp 是通配兜底路由 # (Vue Router history 模式回退 index.html),排在前面会吞掉 API 请求。 app.register_blueprint(chat_bp) app.register_blueprint(member_bp) app.register_blueprint(img_bp) app.register_blueprint(motion_bp) app.register_blueprint(ui_bp) app.register_blueprint(static_bp) # 健康检查 @app.route('/health', methods=['GET']) def health(): return jsonify({"status": "ok", "service": "fam-core"}), 200 # 初始化后台同步线程(NAS 唯一常驻线程) _sync = None try: _sync = get_sync() _sync.start() logger.info("Oracle-Sync 已启动") # 启动后立刻拉一次,前端无需等待首个周期即有数据 try: _sync.trigger_now() logger.info("启动首次同步完成") except Exception as e: logger.warning(f"启动首次同步失败(后续周期会重试): {e}") except Exception as e: logger.error(f"Oracle-Sync 启动失败: {e}") # 初始化运动监测通知服务(Webhook 驱动,不轮询;提供推送客户端 + 摄像头名映射) _notifier = None try: _notifier = get_motion_notifier() _notifier.start() # 启动时一次性从 SS 拉取摄像头名->id 映射(非轮询),失败仅告警,Webhook 仍可运行 try: _notifier.refresh_camera_map() logger.info("MotionNotifier 摄像头映射已加载") except Exception as e: logger.warning(f"摄像头映射加载失败(Webhook 仍可运行,camera_id 可能为空): {e}") logger.info("MotionNotifier 已初始化") except Exception as e: logger.error(f"MotionNotifier 初始化失败: {e}") @app.route('/api/status', methods=['GET']) def status(): """系统状态""" return jsonify({ "service": "fam-core", "sync": _sync.status() if _sync else {"running": False, "error": "未初始化"}, "motion": _notifier.status() if _notifier else {"running": False, "error": "未初始化"}, }), 200 if __name__ == '__main__': cfg = load_config() port = cfg.get('server', {}).get('port', 8000) app.run(host='0.0.0.0', port=port, debug=False)