mirror of
https://github.com/Jerryplusy/AI-powered-switches.git
synced 2025-07-05 13:49:19 +00:00
修改(存在未调用库error)
This commit is contained in:
parent
628726e6b1
commit
495ec0df40
26
src/backend/Dockerfile/Dockerfile
Normal file
26
src/backend/Dockerfile/Dockerfile
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
FROM python:3.13.2-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 安装系统依赖
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends gcc python3-dev libffi-dev && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# 安装Python依赖
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# 复制应用代码
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# 设置环境变量
|
||||||
|
ENV FLASK_APP=run.py
|
||||||
|
ENV FLASK_ENV=production
|
||||||
|
ENV PYTHONPATH=/app
|
||||||
|
|
||||||
|
# 暴露端口
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
# 启动命令
|
||||||
|
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "run:app"]
|
@ -1 +1,26 @@
|
|||||||
# 解析中文命令逻辑
|
# 解析中文命令逻辑
|
||||||
|
from flask import request, jsonify
|
||||||
|
from ...services.ai_service import get_network_config
|
||||||
|
from ...exceptions import InvalidInputError
|
||||||
|
|
||||||
|
|
||||||
|
@api_blueprint.route('/parse_command', methods=['POST'])
|
||||||
|
def parse_command_handler():
|
||||||
|
"""处理自然语言命令解析"""
|
||||||
|
try:
|
||||||
|
data = request.get_json()
|
||||||
|
if not data or 'command' not in data:
|
||||||
|
raise InvalidInputError("缺少命令参数")
|
||||||
|
|
||||||
|
command = data['command']
|
||||||
|
config = get_network_config(command)
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"status": "success",
|
||||||
|
"config": config
|
||||||
|
})
|
||||||
|
|
||||||
|
except InvalidInputError as e:
|
||||||
|
return jsonify({"status": "error", "message": str(e)}), 400
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"status": "error", "message": f"服务器内部错误: {str(e)}"}), 500
|
@ -1 +1,6 @@
|
|||||||
# 注册api蓝图
|
# 注册api蓝图
|
||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
|
api_blueprint = Blueprint('api', __name__)
|
||||||
|
|
||||||
|
from . import command_parser, network_config
|
@ -1 +1,64 @@
|
|||||||
#配置生成和交换机交互逻辑
|
#配置生成和交换机交互逻辑
|
||||||
|
from flask import request, jsonify
|
||||||
|
from netmiko import ConnectHandler
|
||||||
|
from ...config import Config
|
||||||
|
from ...exceptions import NetworkDeviceError
|
||||||
|
|
||||||
|
|
||||||
|
@api_blueprint.route('/apply_config', methods=['POST'])
|
||||||
|
def apply_config_handler():
|
||||||
|
"""应用配置到网络设备"""
|
||||||
|
try:
|
||||||
|
data = request.get_json()
|
||||||
|
required_fields = ['config', 'device_ip']
|
||||||
|
if not all(field in data for field in required_fields):
|
||||||
|
raise InvalidInputError("缺少必要参数")
|
||||||
|
|
||||||
|
# 安全验证
|
||||||
|
validate_configuration(data['config'])
|
||||||
|
|
||||||
|
# 执行配置
|
||||||
|
output = execute_switch_config(
|
||||||
|
device_ip=data['device_ip'],
|
||||||
|
commands=data['config'],
|
||||||
|
username=Config.SWITCH_USERNAME,
|
||||||
|
password=Config.SWITCH_PASSWORD
|
||||||
|
)
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"status": "success",
|
||||||
|
"output": output
|
||||||
|
})
|
||||||
|
|
||||||
|
except NetworkDeviceError as e:
|
||||||
|
return jsonify({"status": "error", "message": str(e)}), 502
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"status": "error", "message": str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
|
def validate_configuration(commands):
|
||||||
|
"""配置安全验证"""
|
||||||
|
dangerous_commands = ['delete', 'erase', 'format', 'reload']
|
||||||
|
for cmd in dangerous_commands:
|
||||||
|
if any(cmd in line.lower() for line in commands):
|
||||||
|
raise InvalidInputError(f"检测到危险命令: {cmd}")
|
||||||
|
|
||||||
|
|
||||||
|
def execute_switch_config(device_ip, commands, username, password):
|
||||||
|
"""执行交换机配置"""
|
||||||
|
device = {
|
||||||
|
'device_type': 'cisco_ios',
|
||||||
|
'host': device_ip,
|
||||||
|
'username': username,
|
||||||
|
'password': password,
|
||||||
|
'timeout': 10
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
with ConnectHandler(**device) as conn:
|
||||||
|
conn.enable() # 进入特权模式
|
||||||
|
output = conn.send_config_set(commands)
|
||||||
|
conn.save_config() # 保存配置
|
||||||
|
return output
|
||||||
|
except Exception as e:
|
||||||
|
raise NetworkDeviceError(f"设备配置失败: {str(e)}")
|
@ -1,12 +1,17 @@
|
|||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from .api import api_blueprint
|
from flask_cors import CORS
|
||||||
|
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config.from_object('config.Config')
|
app.config.from_object('config.Config')
|
||||||
|
|
||||||
|
# 启用CORS(开发环境)
|
||||||
|
CORS(app, resources={r"/api/*": {"origins": "*"}})
|
||||||
|
|
||||||
# 注册蓝图
|
# 注册蓝图
|
||||||
|
from .api import api_blueprint
|
||||||
app.register_blueprint(api_blueprint, url_prefix='/api')
|
app.register_blueprint(api_blueprint, url_prefix='/api')
|
||||||
|
|
||||||
return app
|
return app
|
61
src/backend/app/services/ai_services.py
Normal file
61
src/backend/app/services/ai_services.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# 调用api
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from ...config import Config
|
||||||
|
from ...exceptions import AIServiceError
|
||||||
|
|
||||||
|
|
||||||
|
def get_network_config(command: str) -> list:
|
||||||
|
"""调用AI服务生成配置"""
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {Config.AI_API_KEY}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"command": command,
|
||||||
|
"vendor": "cisco",
|
||||||
|
"strict_mode": True
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(
|
||||||
|
Config.AI_API_ENDPOINT,
|
||||||
|
headers=headers,
|
||||||
|
json=payload,
|
||||||
|
timeout=8
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
result = response.json()
|
||||||
|
if not result.get('success'):
|
||||||
|
raise AIServiceError(result.get('message', 'AI服务返回错误'))
|
||||||
|
|
||||||
|
return result['config']
|
||||||
|
|
||||||
|
except requests.exceptions.Timeout:
|
||||||
|
raise AIServiceError("AI服务响应超时")
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
raise AIServiceError(f"API请求失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
# --------------- backend/config.py ---------------
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
# 应用配置
|
||||||
|
ENV = os.getenv("FLASK_ENV", "production")
|
||||||
|
SECRET_KEY = os.getenv("SECRET_KEY", "supersecretkey")
|
||||||
|
|
||||||
|
# AI服务配置
|
||||||
|
AI_API_KEY = os.getenv("AI_API_KEY", "")
|
||||||
|
AI_API_ENDPOINT = os.getenv("AI_API_ENDPOINT", "https://api.siliconflow.ai/v1/network")
|
||||||
|
|
||||||
|
# 网络设备配置
|
||||||
|
SWITCH_USERNAME = os.getenv("SWITCH_USER", "admin")
|
||||||
|
SWITCH_PASSWORD = os.getenv("SWITCH_PASS", "Cisco123!")
|
||||||
|
DEFAULT_DEVICE_IP = os.getenv("DEFAULT_DEVICE_IP", "192.168.1.1")
|
11
src/backend/exceptions.py
Normal file
11
src/backend/exceptions.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
class InvalidInputError(Exception):
|
||||||
|
"""输入验证异常"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class NetworkDeviceError(Exception):
|
||||||
|
"""网络设备通信异常"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AIServiceError(Exception):
|
||||||
|
"""AI服务异常"""
|
||||||
|
pass
|
@ -0,0 +1,6 @@
|
|||||||
|
from app import create_app
|
||||||
|
|
||||||
|
app = create_app()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(host="0.0.0.0", port=5000)
|
Loading…
x
Reference in New Issue
Block a user