mirror of
https://github.com/Jerryplusy/AI-powered-switches.git
synced 2025-07-04 21:29:18 +00:00
114514
This commit is contained in:
parent
b3e6aa7d5c
commit
60359b54ee
@ -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
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
@ -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}"
|
||||
)
|
@ -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": "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"}
|
||||
]
|
||||
# 移除所有现有处理器
|
||||
logger.remove()
|
||||
|
||||
# 直接添加处理器(避免configure方法)
|
||||
logger.add(
|
||||
sys.stdout,
|
||||
format=(
|
||||
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
|
||||
"<level>{level: <8}</level> | "
|
||||
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
|
||||
"<level>{message}</level>"
|
||||
),
|
||||
level="DEBUG",
|
||||
enqueue=True
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user