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