diff --git a/.idea/AI-powered-switches.iml b/.idea/AI-powered-switches.iml index a1bf3bb..b5db305 100644 --- a/.idea/AI-powered-switches.iml +++ b/.idea/AI-powered-switches.iml @@ -9,7 +9,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index 1d3ce46..0ce539e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/src/backend/app/api/endpoints.py b/src/backend/app/api/endpoints.py index e2dd6fd..44e75fa 100644 --- a/src/backend/app/api/endpoints.py +++ b/src/backend/app/api/endpoints.py @@ -126,6 +126,40 @@ async def apply_config(request: ConfigRequest): status_code=500, detail=f"Failed to apply config: {str(e)}" ) + + +class CLICommandRequest(BaseModel): + switch_ip: str + commands: List[str] # 前端生成的CLI命令列表 + is_ensp: bool = False # 是否为eNSP模拟器模式 + + +@router.post("/execute_cli_commands", response_model=dict) +async def execute_cli_commands(request: CLICommandRequest): + """ + 执行前端生成的CLI命令 + """ + try: + configurator = SwitchConfigurator( + username=settings.SWITCH_USERNAME, + password=settings.SWITCH_PASSWORD, + timeout=settings.SWITCH_TIMEOUT, + ensp_mode=request.is_ensp + ) + + # 直接发送命令到交换机 + result = await configurator.execute_raw_commands( + ip=request.switch_ip, + commands=request.commands + ) + return { + "success": True, + "output": result, + "mode": "eNSP" if request.is_ensp else "SSH" + } + except Exception as e: + raise HTTPException(500, detail=str(e)) + @router.get("/traffic/interfaces", summary="获取所有网络接口") async def get_network_interfaces(): return { diff --git a/src/backend/app/api/network_config.py b/src/backend/app/api/network_config.py index 54cce3b..edd2371 100644 --- a/src/backend/app/api/network_config.py +++ b/src/backend/app/api/network_config.py @@ -179,6 +179,13 @@ class SwitchConfigurator: except Exception as e: raise SSHConnectionException(f"连接异常: {str(e)}") + async def execute_raw_commands(self, ip: str, commands: List[str]) -> str: + """ + 执行原始CLI命令 + """ + return await self._send_commands(ip, commands) + + @staticmethod def _generate_standard_commands(config: SwitchConfig) -> List[str]: """生成标准CLI命令""" @@ -242,6 +249,7 @@ class SwitchConfigurator: logging.error(f"恢复失败: {str(e)}") return False + @retry( stop=stop_after_attempt(2), wait=wait_exponential(multiplier=1, min=4, max=10) diff --git a/src/backend/app/services/ai_services.py b/src/backend/app/services/ai_services.py index 8953941..442efae 100644 --- a/src/backend/app/services/ai_services.py +++ b/src/backend/app/services/ai_services.py @@ -1,4 +1,6 @@ from typing import Dict, Any, Coroutine + +import httpx from openai import OpenAI import json from src.backend.app.utils.exceptions import SiliconFlowAPIException @@ -12,7 +14,8 @@ class AIService: self.api_url = api_url self.client = OpenAI( api_key=self.api_key, - base_url=self.api_url + base_url=self.api_url, + # timeout=httpx.Timeout(30.0) ) async def parse_command(self, command: str) -> Any | None: diff --git a/src/backend/requirements.txt b/src/backend/requirements.txt index 880ac77..3febf22 100644 --- a/src/backend/requirements.txt +++ b/src/backend/requirements.txt @@ -4,12 +4,12 @@ python-dotenv==1.0.1 pysnmp pydantic==2.6.4 pydantic-settings==2.2.1 - +openai==1.93.2 asyncssh==2.14.2 telnetlib3==2.0.3 httpx==0.27.0 python-nmap==0.7.1 - +pysnmp==7.1.21 aiofiles==23.2.1 loguru==0.7.2