From 60359b54eeda0fc816eb0a49055a304af4a1b30d Mon Sep 17 00:00:00 2001 From: 3 Date: Wed, 18 Jun 2025 16:18:42 +0800 Subject: [PATCH] 114514 --- src/backend/app/api/command_parser.py | 7 +++--- src/backend/app/api/endpoints.py | 4 ++-- src/backend/app/api/network_config.py | 5 +++-- src/backend/app/utils/exceptions.py | 13 ++++++++--- src/backend/app/utils/logger.py | 31 ++++++++++++++++++--------- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/backend/app/api/command_parser.py b/src/backend/app/api/command_parser.py index 071473e..a1e2a7b 100644 --- a/src/backend/app/api/command_parser.py +++ b/src/backend/app/api/command_parser.py @@ -19,7 +19,8 @@ class CommandParser: # 本地无法解析则调用AI服务 return await self.ai_service.parse_command(command) - def _try_local_parse(self, command: str) -> Dict[str, Any]: + @staticmethod + def _try_local_parse(command: str) -> dict[str, str | list[Any]] | dict[str, str] | None: """ 尝试本地解析常见命令 """ @@ -32,7 +33,7 @@ class CommandParser: if vlan_id: return { "type": "vlan", - "vlan_id": int(vlan_id), + "vlan_id": vlan_id, "name": f"VLAN{vlan_id}", "interfaces": [] } @@ -62,7 +63,7 @@ class CommandParser: if "vlan" in command: vlan_id = next((p for p in parts if p.isdigit()), None) if vlan_id: - config["vlan"] = int(vlan_id) + config["vlan"] = vlan_id return config diff --git a/src/backend/app/api/endpoints.py b/src/backend/app/api/endpoints.py index 917bb2a..f812243 100644 --- a/src/backend/app/api/endpoints.py +++ b/src/backend/app/api/endpoints.py @@ -20,7 +20,7 @@ async def batch_apply_config(request: BatchConfigRequest): for ip in request.switch_ips: try: configurator = SwitchConfigurator() - results[ip] = await configurator.apply_config(ip, request.config) + results[ip] = await configurator.safe_apply(ip, request.config) except Exception as e: results[ip] = str(e) return {"results": results} @@ -80,7 +80,7 @@ async def apply_config(request: ConfigRequest): password=settings.SWITCH_PASSWORD, timeout=settings.SWITCH_TIMEOUT ) - result = await configurator.apply_config(request.switch_ip, request.config) + result = await configurator.safe_apply(request.switch_ip, request.config) return {"success": True, "result": result} except Exception as e: raise HTTPException( diff --git a/src/backend/app/api/network_config.py b/src/backend/app/api/network_config.py index c155400..54cce3b 100644 --- a/src/backend/app/api/network_config.py +++ b/src/backend/app/api/network_config.py @@ -64,7 +64,7 @@ class SwitchConfigurator: self.ensp_delay = ensp_command_delay self.ssh_options = ssh_options - async def _apply_config(self, ip: str, config: Union[Dict, SwitchConfig]) -> str: + async def apply_config(self, ip: str, config: Union[Dict, SwitchConfig]) -> str: """实际配置逻辑""" if isinstance(config, dict): config = SwitchConfig(**config) @@ -127,6 +127,7 @@ class SwitchConfigurator: # 关闭连接 writer.close() + # noinspection PyBroadException try: await writer.wait_closed() except: @@ -253,7 +254,7 @@ class SwitchConfigurator: """安全配置应用(自动回滚)""" backup_path = await self._backup_config(ip) try: - result = await self._apply_config(ip, config) + result = await self.apply_config(ip, config) if not await self._validate_config(ip, config): raise SwitchConfigException("配置验证失败") return { diff --git a/src/backend/app/utils/exceptions.py b/src/backend/app/utils/exceptions.py index ccbd2de..6183d50 100644 --- a/src/backend/app/utils/exceptions.py +++ b/src/backend/app/utils/exceptions.py @@ -1,5 +1,4 @@ from fastapi import HTTPException, status -from typing import Optional class AICommandParseException(HTTPException): def __init__(self, detail: str): @@ -23,9 +22,10 @@ class ConfigBackupException(SwitchConfigException): """配置备份失败异常""" def __init__(self, ip: str): super().__init__( - detail=f"无法备份设备 {ip} 的配置", - recovery_guide="检查设备存储空间或权限" + detail=f"无法备份设备 {ip} 的配置" ) + # 将恢复指南作为实例属性 + self.recovery_guide = "检查设备存储空间或权限" class ConfigRollbackException(SwitchConfigException): """回滚失败异常""" @@ -34,3 +34,10 @@ class ConfigRollbackException(SwitchConfigException): detail=f"设备 {ip} 回滚失败(原始错误:{original_error})", status_code=status.HTTP_422_UNPROCESSABLE_ENTITY ) + +class SiliconFlowAPIException(HTTPException): + def __init__(self, detail: str, status_code: int = 400): + super().__init__( + status_code=status_code, + detail=f"SiliconFlow API error: {detail}" + ) \ No newline at end of file diff --git a/src/backend/app/utils/logger.py b/src/backend/app/utils/logger.py index 3021c0e..f0177f8 100644 --- a/src/backend/app/utils/logger.py +++ b/src/backend/app/utils/logger.py @@ -1,33 +1,44 @@ + import logging from loguru import logger import sys + class InterceptHandler(logging.Handler): def emit(self, record): - # Get corresponding Loguru level if it exists + # 获取对应的Loguru日志级别 try: level = logger.level(record.levelname).name except ValueError: level = record.levelno - # Find caller from where originated the logged message + # 查找日志来源 frame, depth = logging.currentframe(), 2 - while frame.f_code.co_filename == logging.__file__: + while frame and frame.f_code.co_filename == logging.__file__: frame = frame.f_back depth += 1 + # 使用Loguru记录日志 logger.opt(depth=depth, exception=record.exc_info).log(level, record.getMessage()) def setup_logging(): # 拦截标准logging - logging.basicConfig(handlers=[InterceptHandler()], level=0) + logging.basicConfig(handlers=[InterceptHandler()], level=logging.NOTSET) - # 配置loguru - logger.configure( - handlers=[ - {"sink": sys.stdout, - "format": "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}"} - ] + # 移除所有现有处理器 + logger.remove() + + # 直接添加处理器(避免configure方法) + logger.add( + sys.stdout, + format=( + "{time:YYYY-MM-DD HH:mm:ss.SSS} | " + "{level: <8} | " + "{name}:{function}:{line} - " + "{message}" + ), + level="DEBUG", + enqueue=True ) \ No newline at end of file