From 2fa19599467263dcf582bb12906e03328e03b4a4 Mon Sep 17 00:00:00 2001 From: zhang <zc857179121@qq.com> Date: 星期三, 02 七月 2025 13:12:26 +0800 Subject: [PATCH] 初版提交 --- algorithm_system/algorithm_server.py | 623 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 623 insertions(+), 0 deletions(-) diff --git a/algorithm_system/algorithm_server.py b/algorithm_system/algorithm_server.py new file mode 100644 index 0000000..f338288 --- /dev/null +++ b/algorithm_system/algorithm_server.py @@ -0,0 +1,623 @@ +""" +绠楁硶绯荤粺鏈嶅姟鍣� +""" +import json +import logging +import os +import time +from typing import Dict, List, Optional, Any, Tuple +from flask import Flask, request, jsonify + +from common.data_models import ( + TaskData, AGVStatus, TaskAssignment, PlannedPath, + create_success_response, create_error_response, ResponseCode, to_dict, from_dict +) +from common.utils import load_path_mapping +from algorithm_system.models.agv_model import AGVModelManager +from algorithm_system.algorithms.task_allocation import TaskAllocationFactory +from algorithm_system.algorithms.path_planning import PathPlanningFactory +from common.api_client import RCSAPIClient +from algorithm_system.path_monitor import PathMonitorService + +try: + from config.settings import ( + ALGORITHM_SERVER_HOST, ALGORITHM_SERVER_PORT, + RCS_SERVER_HOST, RCS_SERVER_PORT, + MONITOR_POLLING_INTERVAL + ) +except ImportError: + ALGORITHM_SERVER_HOST = "10.10.10.239" + ALGORITHM_SERVER_PORT = 8002 + RCS_SERVER_HOST = "10.10.10.156" + RCS_SERVER_PORT = 8088 + MONITOR_POLLING_INTERVAL = 5.0 + logging.warning("鏃犳硶浠巆onfig.settings瀵煎叆閰嶇疆锛屼娇鐢ㄩ粯璁ゅ��") + + +class AlgorithmServer: + """绠楁硶绯荤粺鏈嶅姟鍣�""" + + def __init__(self, host: str = None, port: int = None, enable_path_monitor: bool = True, + monitor_interval: float = None): + """鍒濆鍖栫畻娉曟湇鍔″櫒""" + self.host = host or ALGORITHM_SERVER_HOST + self.port = port or ALGORITHM_SERVER_PORT + self.enable_path_monitor = enable_path_monitor + self.monitor_interval = monitor_interval or MONITOR_POLLING_INTERVAL + self.logger = logging.getLogger(__name__) + + self.app = Flask(__name__) + + self.path_mapping = load_path_mapping() + + self.agv_manager = AGVModelManager(self.path_mapping) + + self.rcs_client = RCSAPIClient() + + self.task_allocation_algorithm = "LOAD_BALANCED" # 榛樿浠诲姟鍒嗛厤 + self.path_planning_algorithm = "A_STAR" # 榛樿璺緞瑙勫垝 + + self.path_monitor = None + if self.enable_path_monitor: + self.path_monitor = PathMonitorService( + rcs_host=RCS_SERVER_HOST, + rcs_port=RCS_SERVER_PORT, + poll_interval=self.monitor_interval, + path_algorithm=self.path_planning_algorithm, + auto_send_paths=True # 鑷姩鍙戦�佽矾寰勫埌RCS + ) + self.logger.info(f"璺緞鐩戞帶鏈嶅姟宸插垵濮嬪寲 - 杞闂撮殧: {self.monitor_interval}s, 鑷姩鍙戦�佽矾寰�: True") + + self._setup_routes() + + self.logger.info("绠楁硶绯荤粺鏈嶅姟鍣ㄥ垵濮嬪寲瀹屾垚") + + def _setup_routes(self): + """璁剧疆API璺敱""" + + @self.app.route('/open/task/send/v1', methods=['POST']) + def task_send_endpoint(): + """浠诲姟涓嬪彂鎺ュ彛""" + return self._handle_task_send_request() + + @self.app.route('/open/path/plan/v1', methods=['POST']) + def path_plan_endpoint(): + """璺緞瑙勫垝鎺ュ彛""" + return self._handle_path_planning_request() + + @self.app.route('/open/path/batch/plan/v1', methods=['POST']) + def batch_path_plan_endpoint(): + """鎵归噺璺緞瑙勫垝鎺ュ彛""" + return self._handle_batch_path_planning_request() + + @self.app.route('/open/algorithm/config/v1', methods=['POST']) + def algorithm_config_endpoint(): + """绠楁硶閰嶇疆鎺ュ彛""" + return self._handle_algorithm_config_request() + + @self.app.route('/monitor/path/start/v1', methods=['POST']) + def start_path_monitor_endpoint(): + """鍚姩璺緞鐩戞帶鏈嶅姟鎺ュ彛""" + return self._handle_start_path_monitor_request() + + @self.app.route('/monitor/path/stop/v1', methods=['POST']) + def stop_path_monitor_endpoint(): + """鍋滄璺緞鐩戞帶鏈嶅姟鎺ュ彛""" + return self._handle_stop_path_monitor_request() + + @self.app.route('/monitor/path/status/v1', methods=['GET']) + def path_monitor_status_endpoint(): + """璺緞鐩戞帶鏈嶅姟鐘舵�佹煡璇㈡帴鍙�""" + return self._handle_path_monitor_status_request() + + @self.app.route('/health', methods=['GET']) + def health_check(): + """鍋ュ悍妫�鏌ユ帴鍙�""" + monitor_status = None + if self.path_monitor: + monitor_status = self.path_monitor.get_monitoring_status() + + return jsonify({ + "status": "healthy", + "service": "algorithm_system", + "timestamp": time.time(), + "path_mapping_loaded": len(self.path_mapping) > 0, + "algorithms": { + "task_allocation": self.task_allocation_algorithm, + "path_planning": self.path_planning_algorithm + }, + "agv_count": len(self.agv_manager.get_all_agvs()), + "path_monitor": monitor_status, + "available_endpoints": [ + "POST /open/task/send/v1 - 浠诲姟鍒嗛厤鎺ュ彛", + "POST /open/path/plan/v1 - 鍗曡矾寰勮鍒掓帴鍙�", + "POST /open/path/batch/plan/v1 - 鎵归噺璺緞瑙勫垝鎺ュ彛", + "POST /open/algorithm/config/v1 - 绠楁硶閰嶇疆鎺ュ彛", + "POST /monitor/path/start/v1 - 鍚姩璺緞鐩戞帶鏈嶅姟", + "POST /monitor/path/stop/v1 - 鍋滄璺緞鐩戞帶鏈嶅姟", + "GET /monitor/path/status/v1 - 璺緞鐩戞帶鏈嶅姟鐘舵�佹煡璇�", + "GET /health - 鍋ュ悍妫�鏌ユ帴鍙�" + ] + }) + + @self.app.errorhandler(404) + def not_found(error): + """404閿欒澶勭悊""" + return jsonify(to_dict(create_error_response(404, "鎺ュ彛涓嶅瓨鍦�"))), 404 + + @self.app.errorhandler(500) + def internal_error(error): + """500閿欒澶勭悊""" + self.logger.error(f"鍐呴儴鏈嶅姟鍣ㄩ敊璇�: {error}") + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, "鍐呴儴鏈嶅姟鍣ㄩ敊璇�"))), 500 + + def _handle_task_send_request(self) -> Dict[str, Any]: + """澶勭悊浠诲姟涓嬪彂璇锋眰""" + try: + if not request.is_json: + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "璇锋眰鏁版嵁鏍煎紡閿欒"))) + + request_data = request.get_json() + if not request_data: + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "璇锋眰鏁版嵁涓虹┖"))) + + if isinstance(request_data, dict) and "tasks" in request_data: + task_data = request_data.get("tasks", []) + agv_status_data = request_data.get("agvStatus", []) + self.logger.info(f"鏀跺埌缁撴瀯鍖栦换鍔″垎閰嶈姹傦紝浠诲姟鏁伴噺: {len(task_data)}, AGV鏁伴噺: {len(agv_status_data)}") + elif isinstance(request_data, list): + task_data = request_data + agv_status_data = [] + self.logger.info(f"鏀跺埌浠诲姟鍒嗛厤璇锋眰锛屼换鍔℃暟閲�: {len(task_data)}") + else: + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "浠诲姟鏁版嵁鏍煎紡鏃犳晥"))) + + if not task_data or not isinstance(task_data, list): + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "浠诲姟鏁版嵁鏃犳晥"))) + + tasks = [] + for task_dict in task_data: + try: + task = TaskData( + taskId=task_dict.get("taskId", ""), + start=task_dict.get("start", ""), + end=task_dict.get("end", ""), + type=task_dict.get("type", "1"), + priority=task_dict.get("priority", 5) + ) + tasks.append(task) + except Exception as e: + self.logger.warning(f"瑙f瀽浠诲姟鏁版嵁澶辫触: {task_dict} - {e}") + continue + + if not tasks: + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "娌℃湁鏈夋晥鐨勪换鍔℃暟鎹�"))) + + agv_status_list = [] + if agv_status_data: + self.logger.info("浣跨敤璇锋眰涓彁渚涚殑AGV鐘舵�佹暟鎹�") + for agv_data in agv_status_data: + try: + agv_status = from_dict(AGVStatus, agv_data) + agv_status_list.append(agv_status) + except Exception as e: + self.logger.warning(f"瑙f瀽璇锋眰涓殑AGV鐘舵�佹暟鎹け璐�: {agv_data} - {e}") + continue + else: + self.logger.info("浠嶳CS绯荤粺鑾峰彇AGV鐘舵�佹暟鎹�") + agv_response = self.rcs_client.get_agv_status() + if agv_response.code == ResponseCode.SUCCESS and agv_response.data: + for agv_data in agv_response.data: + try: + agv_status = from_dict(AGVStatus, agv_data) + agv_status_list.append(agv_status) + except Exception as e: + self.logger.warning(f"瑙f瀽RCS杩斿洖鐨凙GV鐘舵�佹暟鎹け璐�: {agv_data} - {e}") + continue + else: + error_msg = f"鏃犳硶鑾峰彇AGV鐘舵��: {agv_response.msg if agv_response else 'RCS绯荤粺杩炴帴澶辫触'}" + self.logger.error(error_msg) + + use_fallback_allocation = getattr(self, 'use_fallback_allocation', True) + + if use_fallback_allocation: + self.logger.warning("浣跨敤杞鍒嗛厤浣滀负澶囩敤鏂规") + return self._simple_round_robin_allocation(tasks) + else: + return jsonify(to_dict(create_error_response( + ResponseCode.SERVER_ERROR, + error_msg + ))) + + if not agv_status_list: + return jsonify(to_dict(create_error_response(ResponseCode.NO_DATA, "娌℃湁鍙敤鐨凙GV鐘舵�佹暟鎹�"))) + + self.agv_manager.update_agv_data(agv_status_list) + self.logger.info(f"鏇存柊浜� {len(agv_status_list)} 涓狝GV鐘舵��") + + all_agvs = self.agv_manager.get_all_agvs() + self.logger.info(f"绠楁硶绯荤粺涓綋鍓嶆湁 {len(all_agvs)} 涓狝GV妯″瀷") + + available_count = 0 + for agv in all_agvs: + can_accept = agv.can_accept_task(5) + self.logger.debug(f"AGV {agv.agvId}: status={agv.status}, can_accept_task={can_accept}, " + f"is_overloaded={agv.is_overloaded()}, task_count={agv.current_task_count}") + if can_accept: + available_count += 1 + + self.logger.info(f"鍏朵腑 {available_count} 涓狝GV鍙互鎺ュ彈浠诲姟") + + if available_count == 0: + self.logger.warning("娌℃湁AGV鍙互鎺ュ彈浠诲姟锛佽缁嗙姸鎬�:") + for agv in all_agvs: + status_str = str(agv.status) + self.logger.warning(f" AGV {agv.agvId}: 鐘舵��={status_str}, 绫诲瀷={type(agv.status)}, " + f"浠诲姟鏁�={agv.current_task_count}/{agv.max_capacity}") + + allocator = TaskAllocationFactory.create_allocator( + self.task_allocation_algorithm, + self.agv_manager + ) + + start_time = time.time() + assignments = allocator.allocate_tasks(tasks) + end_time = time.time() + + allocation_time = (end_time - start_time) * 1000 # 杞崲涓烘绉� + + assignment_data = [to_dict(assignment) for assignment in assignments] + + self.logger.info(f"浠诲姟鍒嗛厤瀹屾垚锛屽垎閰嶄簡 {len(assignments)} 涓换鍔★紝鑰楁椂: {allocation_time:.2f}ms") + + response = create_success_response(assignment_data) + return jsonify(to_dict(response)) + + except Exception as e: + self.logger.error(f"澶勭悊浠诲姟鍒嗛厤璇锋眰澶辫触: {e}", exc_info=True) + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, f"鏈嶅姟鍣ㄩ敊璇�: {str(e)}"))) + + def _handle_path_planning_request(self) -> Dict[str, Any]: + """澶勭悊璺緞瑙勫垝璇锋眰""" + try: + # 楠岃瘉璇锋眰鏁版嵁 + if not request.is_json: + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "璇锋眰鏁版嵁鏍煎紡閿欒"))) + + request_data = request.get_json() + if not request_data: + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "璇锋眰鏁版嵁涓虹┖"))) + + agv_id = request_data.get("agvId") + start_code = request_data.get("start") + end_code = request_data.get("end") + constraints = request_data.get("constraints", []) + + if not agv_id or not start_code or not end_code: + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "缂哄皯蹇呰鍙傛暟"))) + + self.logger.info(f"鏀跺埌璺緞瑙勫垝璇锋眰 - AGV: {agv_id}, 浠� {start_code} 鍒� {end_code}") + + # 鍒涘缓璺緞瑙勫垝鍣� + path_planner = PathPlanningFactory.create_path_planner( + self.path_planning_algorithm, + self.path_mapping + ) + + # 鎵ц璺緞瑙勫垝 + start_time = time.time() + planned_path = path_planner.plan_path(start_code, end_code, constraints) + end_time = time.time() + + planning_time = (end_time - start_time) * 1000 # 杞崲涓烘绉� + + if planned_path: + # 璁剧疆AGV ID + planned_path.agvId = agv_id + + # 杞崲涓哄搷搴旀牸寮� + path_data = to_dict(planned_path) + + self.logger.info(f"璺緞瑙勫垝瀹屾垚 - AGV: {agv_id}, 璺緞闀垮害: {len(planned_path.codeList)}, 鑰楁椂: {planning_time:.2f}ms") + + response = create_success_response(path_data) + return jsonify(to_dict(response)) + else: + self.logger.warning(f"璺緞瑙勫垝澶辫触 - AGV: {agv_id}, 浠� {start_code} 鍒� {end_code}") + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, "鏃犳硶瑙勫垝璺緞"))) + + except Exception as e: + self.logger.error(f"澶勭悊璺緞瑙勫垝璇锋眰澶辫触: {e}", exc_info=True) + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, f"鏈嶅姟鍣ㄩ敊璇�: {str(e)}"))) + + def _handle_batch_path_planning_request(self) -> Dict[str, Any]: + """澶勭悊鎵归噺璺緞瑙勫垝璇锋眰""" + try: + if not request.is_json: + request_data = {} + else: + request_data = request.get_json() or {} + + constraints = request_data.get("constraints", []) + include_idle_agv = request_data.get("includeIdleAgv", False) + use_enhanced_planning = request_data.get("useEnhancedPlanning", True) + + agv_status_from_request = ( + request_data.get("agvStatusList", []) or + request_data.get("agvs", []) + ) + + self.logger.info(f"鏀跺埌鎵归噺璺緞瑙勫垝璇锋眰锛屽寘鍚┖闂睞GV: {include_idle_agv}, " + f"璇锋眰涓瑼GV鏁伴噺: {len(agv_status_from_request)}, " + f"浣跨敤澧炲己瑙勫垝: {use_enhanced_planning}") + + agv_status_list = [] + if agv_status_from_request: + self.logger.info("浣跨敤璇锋眰涓彁渚涚殑AGV鐘舵�佹暟鎹繘琛岃矾寰勮鍒�") + for agv_data in agv_status_from_request: + try: + agv_status = from_dict(AGVStatus, agv_data) + agv_status_list.append(agv_status) + except Exception as e: + self.logger.warning(f"瑙f瀽璇锋眰涓殑AGV鐘舵�佹暟鎹け璐�: {agv_data} - {e}") + continue + else: + self.logger.info("浠嶳CS绯荤粺鑾峰彇AGV鐘舵�佹暟鎹繘琛岃矾寰勮鍒�") + agv_response = self.rcs_client.get_agv_status() + if agv_response.code != ResponseCode.SUCCESS or not agv_response.data: + error_msg = f"鏃犳硶鑾峰彇AGV鐘舵�佽繘琛岃矾寰勮鍒�: {agv_response.msg if agv_response else 'RCS绯荤粺杩炴帴澶辫触'}" + self.logger.error(error_msg) + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, error_msg))) + + for agv_data in agv_response.data: + try: + agv_status = from_dict(AGVStatus, agv_data) + agv_status_list.append(agv_status) + except Exception as e: + self.logger.warning(f"瑙f瀽RCS杩斿洖鐨凙GV鐘舵�佹暟鎹け璐�: {agv_data} - {e}") + continue + + if not agv_status_list: + error_msg = "娌℃湁鍙敤鐨凙GV鐘舵�佹暟鎹繘琛岃矾寰勮鍒�" + self.logger.error(error_msg) + return jsonify(to_dict(create_error_response(ResponseCode.NO_DATA, error_msg))) + + # 鏇存柊AGV妯″瀷绠$悊鍣� + self.agv_manager.update_agv_data(agv_status_list) + + self.logger.info(f"寮哄埗浣跨敤璺緞瑙勫垝浠ョ‘淇濆寘鍚柊瀛楁") + result = self._enhanced_batch_path_planning(agv_status_list, include_idle_agv, constraints) + + response = create_success_response(result) + return jsonify(to_dict(response)) + + except Exception as e: + self.logger.error(f"澶勭悊鎵归噺璺緞瑙勫垝璇锋眰澶辫触: {e}", exc_info=True) + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, f"鏈嶅姟鍣ㄩ敊璇�: {str(e)}"))) + + def _enhanced_batch_path_planning(self, agv_status_list: List[AGVStatus], + include_idle_agv: bool, + constraints: List[Tuple[int, int, float]]) -> Dict[str, Any]: + """鎵归噺璺緞瑙勫垝""" + from algorithm_system.algorithms.path_planning import PathPlanningFactory + + # 鍒涘缓鎵归噺璺緞瑙勫垝鍣� + batch_planner = PathPlanningFactory.create_batch_path_planner( + algorithm_type=self.path_planning_algorithm, + path_mapping=self.path_mapping + ) + + # 鎵ц鎵归噺璺緞瑙勫垝 + result = batch_planner.plan_all_agv_paths( + agv_status_list=agv_status_list, + include_idle_agv=include_idle_agv, + constraints=constraints + ) + + # 鎻愬彇plannedPaths浣滀负鏈�缁堣繑鍥炴暟鎹� + planned_paths = result.get('plannedPaths', []) + + self.logger.info(f"鎵归噺璺緞瑙勫垝瀹屾垚 - 鎬籄GV: {result['totalAgvs']}, " + f"鎵ц浠诲姟: {result['executingTasksCount']}, " + f"瑙勫垝璺緞: {result['plannedPathsCount']}, " + f"鍐茬獊妫�娴�: {result['conflictsDetected']}, " + f"鎬昏�楁椂: {result['totalPlanningTime']:.2f}ms") + + # 鍙繑鍥炶矾寰勬暟缁勶紝涓嶅寘鍚叾浠栫粺璁′俊鎭� + return planned_paths + + def _handle_algorithm_config_request(self) -> Dict[str, Any]: + """ + 澶勭悊绠楁硶閰嶇疆璇锋眰 + + Returns: + Dict: 鍝嶅簲鏁版嵁 + """ + try: + # 楠岃瘉璇锋眰鏁版嵁 + if not request.is_json: + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "璇锋眰鏁版嵁鏍煎紡閿欒"))) + + config_data = request.get_json() + if not config_data: + return jsonify(to_dict(create_error_response(ResponseCode.PARAM_EMPTY, "閰嶇疆鏁版嵁涓虹┖"))) + + # 鏇存柊绠楁硶閰嶇疆 + if "task_allocation_algorithm" in config_data: + self.task_allocation_algorithm = config_data["task_allocation_algorithm"] + self.logger.info(f"浠诲姟鍒嗛厤绠楁硶鏇存柊涓�: {self.task_allocation_algorithm}") + + if "path_planning_algorithm" in config_data: + self.path_planning_algorithm = config_data["path_planning_algorithm"] + self.logger.info(f"璺緞瑙勫垝绠楁硶鏇存柊涓�: {self.path_planning_algorithm}") + + # 杩斿洖褰撳墠閰嶇疆 + current_config = { + "task_allocation_algorithm": self.task_allocation_algorithm, + "path_planning_algorithm": self.path_planning_algorithm + } + + response = create_success_response(current_config) + return jsonify(to_dict(response)) + + except Exception as e: + self.logger.error(f"澶勭悊绠楁硶閰嶇疆璇锋眰澶辫触: {e}", exc_info=True) + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, f"鏈嶅姟鍣ㄩ敊璇�: {str(e)}"))) + + def _simple_round_robin_allocation(self, tasks: List[TaskData]) -> Dict[str, Any]: + """绠�鍗曠殑杞鍒嗛厤""" + assignments = [] + + # 灏濊瘯浠嶳CS绯荤粺鑾峰彇AGV鏁伴噺 + agv_count = 5 # 榛樿鍊� + try: + agv_response = self.rcs_client.get_agv_status() + if agv_response.code == ResponseCode.SUCCESS and agv_response.data: + agv_count = len(agv_response.data) + self.logger.info(f"浠嶳CS绯荤粺鑾峰彇鍒癆GV鏁伴噺: {agv_count}") + else: + # 濡傛灉RCS杩斿洖鏃犳暟鎹紝浣跨敤閰嶇疆鐨勯粯璁ゅ�� + from config.settings import DEFAULT_AGV_COUNT + agv_count = DEFAULT_AGV_COUNT + self.logger.warning(f"鏃犳硶浠嶳CS鑾峰彇AGV鏁伴噺锛屼娇鐢ㄩ粯璁ゅ��: {agv_count}") + except Exception as e: + # 濡傛灉瀹屽叏鏃犳硶杩炴帴RCS锛屼娇鐢ㄩ厤缃殑榛樿鍊� + from config.settings import DEFAULT_AGV_COUNT + agv_count = DEFAULT_AGV_COUNT + self.logger.error(f"鑾峰彇AGV鏁伴噺澶辫触锛屼娇鐢ㄩ粯璁ゅ��: {agv_count} - {e}") + + for i, task in enumerate(tasks): + agv_id = f"AGV_{10001 + (i % agv_count)}" + assignment = TaskAssignment( + taskId=task.taskId, + agvId=agv_id + ) + assignments.append(assignment) + + assignment_data = [to_dict(assignment) for assignment in assignments] + + self.logger.info(f"浣跨敤绠�鍗曡疆璇㈠垎閰嶄簡 {len(assignments)} 涓换鍔★紝AGV鏁伴噺: {agv_count}") + + response = create_success_response(assignment_data) + return jsonify(to_dict(response)) + + def _handle_start_path_monitor_request(self) -> Dict[str, Any]: + """澶勭悊鍚姩璺緞鐩戞帶鏈嶅姟璇锋眰""" + try: + if not self.path_monitor: + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, "璺緞鐩戞帶鏈嶅姟鏈垵濮嬪寲"))) + + if self.path_monitor.is_running: + return jsonify(to_dict(create_success_response({"message": "璺緞鐩戞帶鏈嶅姟宸插湪杩愯涓�"}))) + + # 鍚姩璺緞鐩戞帶鏈嶅姟 + self.path_monitor.start_monitoring() + + self.logger.info("璺緞鐩戞帶鏈嶅姟宸查�氳繃API鍚姩") + + response = create_success_response({ + "message": "璺緞鐩戞帶鏈嶅姟鍚姩鎴愬姛", + "monitor_status": self.path_monitor.get_monitoring_status() + }) + + return jsonify(to_dict(response)) + + except Exception as e: + self.logger.error(f"鍚姩璺緞鐩戞帶鏈嶅姟澶辫触: {e}") + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, f"鍚姩璺緞鐩戞帶鏈嶅姟澶辫触: {str(e)}"))) + + def _handle_stop_path_monitor_request(self) -> Dict[str, Any]: + """澶勭悊鍋滄璺緞鐩戞帶鏈嶅姟璇锋眰""" + try: + if not self.path_monitor: + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, "璺緞鐩戞帶鏈嶅姟鏈垵濮嬪寲"))) + + if not self.path_monitor.is_running: + return jsonify(to_dict(create_success_response({"message": "璺緞鐩戞帶鏈嶅姟鏈湪杩愯"}))) + + # 鍋滄璺緞鐩戞帶鏈嶅姟 + self.path_monitor.stop_monitoring() + + self.logger.info("璺緞鐩戞帶鏈嶅姟宸查�氳繃API鍋滄") + + response = create_success_response({ + "message": "璺緞鐩戞帶鏈嶅姟鍋滄鎴愬姛", + "monitor_status": self.path_monitor.get_monitoring_status() + }) + + return jsonify(to_dict(response)) + + except Exception as e: + self.logger.error(f"鍋滄璺緞鐩戞帶鏈嶅姟澶辫触: {e}") + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, f"鍋滄璺緞鐩戞帶鏈嶅姟澶辫触: {str(e)}"))) + + def _handle_path_monitor_status_request(self) -> Dict[str, Any]: + """澶勭悊璺緞鐩戞帶鏈嶅姟鐘舵�佹煡璇㈣姹�""" + try: + if not self.path_monitor: + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, "璺緞鐩戞帶鏈嶅姟鏈垵濮嬪寲"))) + + monitor_status = self.path_monitor.get_monitoring_status() + + response = create_success_response({ + "monitor_status": monitor_status, + "description": "璺緞鐩戞帶鏈嶅姟鐘舵�佷俊鎭�" + }) + + return jsonify(to_dict(response)) + + except Exception as e: + self.logger.error(f"鑾峰彇璺緞鐩戞帶鏈嶅姟鐘舵�佸け璐�: {e}") + return jsonify(to_dict(create_error_response(ResponseCode.SERVER_ERROR, f"鑾峰彇璺緞鐩戞帶鏈嶅姟鐘舵�佸け璐�: {str(e)}"))) + + def start_server(self): + """鍚姩绠楁硶鏈嶅姟鍣�""" + self.logger.info(f"鍚姩绠楁硶绯荤粺鏈嶅姟鍣�: http://{self.host}:{self.port}") + + try: + # 濡傛灉鍚敤浜嗚矾寰勭洃鎺ф湇鍔★紝鑷姩鍚姩 + if self.path_monitor and self.enable_path_monitor: + self.path_monitor.start_monitoring() + self.logger.info("璺緞鐩戞帶鏈嶅姟宸茶嚜鍔ㄥ惎鍔�") + + self.app.run( + host=self.host, + port=self.port, + debug=False, + threaded=True + ) + except Exception as e: + self.logger.error(f"鍚姩绠楁硶鏈嶅姟鍣ㄥけ璐�: {e}") + # 纭繚鍦ㄥ惎鍔ㄥけ璐ユ椂鍋滄璺緞鐩戞帶鏈嶅姟 + if self.path_monitor and self.path_monitor.is_running: + self.path_monitor.stop_monitoring() + raise + + def stop_server(self): + """鍋滄绠楁硶鏈嶅姟鍣�""" + self.logger.info("鍋滄绠楁硶鏈嶅姟鍣�") + + # 鍋滄璺緞鐩戞帶鏈嶅姟 + if self.path_monitor and self.path_monitor.is_running: + self.path_monitor.stop_monitoring() + self.logger.info("璺緞鐩戞帶鏈嶅姟宸插仠姝�") + + + def get_server_status(self) -> Dict[str, Any]: + """鑾峰彇鏈嶅姟鍣ㄧ姸鎬�""" + monitor_status = None + if self.path_monitor: + monitor_status = self.path_monitor.get_monitoring_status() + + return { + "host": self.host, + "port": self.port, + "path_mapping_loaded": len(self.path_mapping) > 0, + "agv_count": len(self.agv_manager.get_all_agvs()), + "algorithms": { + "task_allocation": self.task_allocation_algorithm, + "path_planning": self.path_planning_algorithm + }, + "path_monitor": monitor_status, + "timestamp": time.time() + } \ No newline at end of file -- Gitblit v1.9.1